MythTV  master
zmserver.cpp
Go to the documentation of this file.
1 /* Implementation of the ZMServer class.
2  * ============================================================
3  * This program is free software; you can redistribute it
4  * and/or modify it under the terms of the GNU General
5  * Public License as published bythe Free Software Foundation;
6  * either version 2, or (at your option)
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * ============================================================ */
15 
16 
17 #include <algorithm>
18 #include <array>
19 #include <fstream>
20 #include <iostream>
21 #include <cstdlib>
22 #include <cstring>
23 #include <cstdio>
24 #include <cerrno>
25 #include <sys/socket.h>
26 #include <fcntl.h>
27 #include <netinet/in.h>
28 #include <sys/stat.h>
29 #include <sys/shm.h>
30 #include <sys/mman.h>
31 
32 #ifdef __linux__
33 # include <sys/vfs.h>
34 # include <sys/statvfs.h>
35 # include <sys/sysinfo.h>
36 #else
37 # include <sys/param.h>
38 # include <sys/mount.h>
39 # ifdef __CYGWIN__
40 # include <sys/statfs.h>
41 # else // if !__CYGWIN__
42 # include <sys/sysctl.h>
43 # endif // !__CYGWIN__
44 #endif
45 
46 #ifdef __APPLE__
47 static constexpr int MSG_NOSIGNAL { 0 }; // Apple also has SO_NOSIGPIPE?
48 #endif
49 
50 #include "zmserver.h"
51 
52 // the version of the protocol we understand
53 static constexpr const char* ZM_PROTOCOL_VERSION { "11" };
54 
55 static inline void ADD_STR(std::string& list, const std::string& s)
56 { list += s; list += "[]:[]"; };
57 static inline void ADD_INT(std::string& list, int n)
58 { list += std::to_string(n); list += "[]:[]"; };
59 
60 // error messages
61 static constexpr const char* ERROR_TOKEN_COUNT { "Invalid token count" };
62 static constexpr const char* ERROR_MYSQL_QUERY { "Mysql Query Error" };
63 static constexpr const char* ERROR_MYSQL_ROW { "Mysql Get Row Error" };
64 static constexpr const char* ERROR_FILE_OPEN { "Cannot open event file" };
65 static constexpr const char* ERROR_INVALID_MONITOR { "Invalid Monitor" };
66 static constexpr const char* ERROR_INVALID_POINTERS { "Cannot get shared memory pointers" };
67 static constexpr const char* ERROR_INVALID_MONITOR_FUNCTION { "Invalid Monitor Function" };
68 static constexpr const char* ERROR_INVALID_MONITOR_ENABLE_VALUE { "Invalid Monitor Enable Value" };
69 static constexpr const char* ERROR_NO_FRAMES { "No frames found for event" };
70 
71 // Subpixel ordering (from zm_rgb.h)
72 // Based on byte order naming. For example, for ARGB (on both little endian or big endian)
73 // byte+0 should be alpha, byte+1 should be red, and so on.
82 };
83 
84 MYSQL g_dbConn;
85 std::string g_zmversion;
86 std::string g_password;
87 std::string g_server;
88 std::string g_database;
89 std::string g_webPath;
90 std::string g_user;
91 std::string g_webUser;
92 std::string g_binPath;
93 std::string g_mmapPath;
94 std::string g_eventsPath;
98 
100 
101 // returns true if the ZM version >= the requested version
102 bool checkVersion(int major, int minor, int revision)
103 {
104  return g_majorVersion >= major &&
105  g_minorVersion >= minor &&
106  g_revisionVersion >= revision;
107 }
108 
109 void loadZMConfig(const std::string &configfile)
110 {
111  std::cout << "loading zm config from " << configfile << std::endl;
112 
113  std::ifstream ifs(configfile);
114  if ( ifs.fail() )
115  {
116  fprintf(stderr, "Can't open %s\n", configfile.c_str());
117  }
118 
119  std::string line {};
120  while ( std::getline(ifs, line) )
121  {
122  // Trim off begining and ending whitespace including cr/lf line endings
123  constexpr const char *whitespace = " \t\r\n";
124  auto begin = line.find_first_not_of(whitespace);
125  if (begin == std::string::npos)
126  continue; // Only whitespace
127  auto end = line.find_last_not_of(whitespace);
128  if (end != std::string::npos)
129  end = end + 1;
130  line = line.substr(begin, end);
131 
132  // Check for comment or empty line
133  if ( line.empty() || line[0] == '#' )
134  continue;
135 
136  // Now look for the '=' in the middle of the line
137  auto index = line.find('=');
138  if (index == std::string::npos)
139  {
140  fprintf(stderr,"Invalid data in %s: '%s'\n", configfile.c_str(), line.c_str() );
141  continue;
142  }
143 
144  // Assign the name and value parts
145  std::string name = line.substr(0,index);
146  std::string val = line.substr(index+1);
147 
148  // Trim trailing space from the name part
149  end = name.find_last_not_of(whitespace);
150  if (end != std::string::npos)
151  end = end + 1;
152  name = name.substr(0, end);
153 
154  // Remove leading white space from the value part
155  begin = val.find_first_not_of(whitespace);
156  if (begin != std::string::npos)
157  val = val.substr(begin);
158 
159  // convert name to uppercase
160  std::transform(name.cbegin(), name.cend(), name.begin(), ::toupper);
161 
162  if ( name == "ZM_DB_HOST" ) g_server = val;
163  else if ( name == "ZM_DB_NAME" ) g_database = val;
164  else if ( name == "ZM_DB_USER" ) g_user = val;
165  else if ( name == "ZM_DB_PASS" ) g_password = val;
166  else if ( name == "ZM_PATH_WEB" ) g_webPath = val;
167  else if ( name == "ZM_PATH_BIN" ) g_binPath = val;
168  else if ( name == "ZM_WEB_USER" ) g_webUser = val;
169  else if ( name == "ZM_VERSION" ) g_zmversion = val;
170  else if ( name == "ZM_PATH_MAP" ) g_mmapPath = val;
171  else if ( name == "ZM_DIR_EVENTS" ) g_eventsPath = val;
172  }
173 }
174 
175 #if !defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 80000
176 using reconnect_t = int;
177 #else
178 using reconnect_t = my_bool;
179 #endif
180 
182 {
183  if (!mysql_init(&g_dbConn))
184  {
185  std::cout << "Error: Can't initialise structure: " << mysql_error(&g_dbConn) << std::endl;
186  exit(static_cast<int>(mysql_errno(&g_dbConn)));
187  }
188 
189  reconnect_t reconnect = 1;
190  mysql_options(&g_dbConn, MYSQL_OPT_RECONNECT, &reconnect);
191 
192  if (!mysql_real_connect(&g_dbConn, g_server.c_str(), g_user.c_str(),
193  g_password.c_str(), nullptr, 0, nullptr, 0))
194  {
195  std::cout << "Error: Can't connect to server: " << mysql_error(&g_dbConn) << std::endl;
196  exit(static_cast<int>(mysql_errno( &g_dbConn)));
197  }
198 
199  if (mysql_select_db(&g_dbConn, g_database.c_str()))
200  {
201  std::cout << "Error: Can't select database: " << mysql_error(&g_dbConn) << std::endl;
202  exit(static_cast<int>(mysql_errno(&g_dbConn)));
203  }
204 }
205 
206 void kickDatabase(bool debug)
207 {
208  if (Clock::now() < g_lastDBKick + DB_CHECK_TIME)
209  return;
210 
211  if (debug)
212  std::cout << "Kicking database connection" << std::endl;
213 
214  g_lastDBKick = Clock::now();
215 
216  if (mysql_query(&g_dbConn, "SELECT NULL;") == 0)
217  {
218  MYSQL_RES *res = mysql_store_result(&g_dbConn);
219  if (res)
220  mysql_free_result(res);
221  return;
222  }
223 
224  std::cout << "Lost connection to DB - trying to reconnect" << std::endl;
225 
226  // failed so try to reconnect to the DB
227  mysql_close(&g_dbConn);
229 }
230 
232 
233 void MONITOR::initMonitor(bool debug, const std::string &mmapPath, int shmKey)
234 {
235  size_t shared_data_size = 0;
236  size_t frame_size = static_cast<size_t>(m_width) * m_height * m_bytesPerPixel;
237 
238  if (!m_enabled)
239  return;
240 
241  if (checkVersion(1, 34, 0))
242  {
243  shared_data_size = sizeof(SharedData34) +
244  sizeof(TriggerData26) +
245  ((m_imageBufferCount) * (sizeof(struct timeval))) +
246  ((m_imageBufferCount) * frame_size) + 64;
247  }
248  else if (checkVersion(1, 32, 0))
249  {
250  shared_data_size = sizeof(SharedData32) +
251  sizeof(TriggerData26) +
252  ((m_imageBufferCount) * (sizeof(struct timeval))) +
253  ((m_imageBufferCount) * frame_size) + 64;
254  }
255  else if (checkVersion(1, 26, 0))
256  {
257  shared_data_size = sizeof(SharedData26) +
258  sizeof(TriggerData26) +
259  ((m_imageBufferCount) * (sizeof(struct timeval))) +
260  ((m_imageBufferCount) * frame_size) + 64;
261  }
262  else
263  {
264  shared_data_size = sizeof(SharedData) +
265  sizeof(TriggerData) +
266  ((m_imageBufferCount) * (sizeof(struct timeval))) +
267  ((m_imageBufferCount) * frame_size);
268  }
269 
270 #if _POSIX_MAPPED_FILES > 0L
271  /*
272  * Try to open the mmap file first if the architecture supports it.
273  * Otherwise, legacy shared memory will be used below.
274  */
275  std::stringstream mmap_filename;
276  mmap_filename << mmapPath << "/zm.mmap." << m_monId;
277 
278  m_mapFile = open(mmap_filename.str().c_str(), O_RDONLY, 0x0);
279  if (m_mapFile >= 0)
280  {
281  if (debug)
282  std::cout << "Opened mmap file: " << mmap_filename.str() << std::endl;
283 
284  m_shmPtr = mmap(nullptr, shared_data_size, PROT_READ,
285  MAP_SHARED, m_mapFile, 0x0);
286  if (m_shmPtr == MAP_FAILED)
287  {
288  std::cout << "Failed to map shared memory from file ["
289  << mmap_filename.str() << "] " << "for monitor: "
290  << m_monId << std::endl;
291  m_status = "Error";
292 
293  if (close(m_mapFile) == -1)
294  std::cout << "Failed to close mmap file" << std::endl;
295 
296  m_mapFile = -1;
297  m_shmPtr = nullptr;
298 
299  return;
300  }
301  }
302  else
303  {
304  // this is not necessarily a problem, maybe the user is still
305  // using the legacy shared memory support
306  if (debug)
307  {
308  std::cout << "Failed to open mmap file [" << mmap_filename.str() << "] "
309  << "for monitor: " << m_monId
310  << " : " << strerror(errno) << std::endl;
311  std::cout << "Falling back to the legacy shared memory method" << std::endl;
312  }
313  }
314 #endif
315 
316  if (m_shmPtr == nullptr)
317  {
318  // fail back to shmget() functionality if mapping memory above failed.
319  int shmid = shmget((shmKey & 0xffff0000) | m_monId,
320  shared_data_size, SHM_R);
321  if (shmid == -1)
322  {
323  std::cout << "Failed to shmget for monitor: " << m_monId << std::endl;
324  m_status = "Error";
325  switch(errno)
326  {
327  case EACCES: std::cout << "EACCES - no rights to access segment\n"; break;
328  case EEXIST: std::cout << "EEXIST - segment already exists\n"; break;
329  case EINVAL: std::cout << "EINVAL - size < SHMMIN or size > SHMMAX\n"; break;
330  case ENFILE: std::cout << "ENFILE - limit on open files has been reached\n"; break;
331  case ENOENT: std::cout << "ENOENT - no segment exists for the given key\n"; break;
332  case ENOMEM: std::cout << "ENOMEM - couldn't reserve memory for segment\n"; break;
333  case ENOSPC: std::cout << "ENOSPC - shmmni or shmall limit reached\n"; break;
334  }
335 
336  return;
337  }
338 
339  m_shmPtr = shmat(shmid, nullptr, SHM_RDONLY);
340 
341 
342  if (m_shmPtr == nullptr)
343  {
344  std::cout << "Failed to shmat for monitor: " << m_monId << std::endl;
345  m_status = "Error";
346  return;
347  }
348  }
349 
350  if (checkVersion(1, 34, 0))
351  {
352  m_sharedData = nullptr;
353  m_sharedData26 = nullptr;
354  m_sharedData32 = nullptr;
356 
357  m_sharedImages = (unsigned char*) m_shmPtr +
358  sizeof(SharedData34) + sizeof(TriggerData26) + sizeof(VideoStoreData) +
359  ((m_imageBufferCount) * sizeof(struct timeval)) ;
360 
361  if (((unsigned long)m_sharedImages % 64) != 0)
362  {
363  // align images buffer to nearest 64 byte boundary
364  m_sharedImages = (unsigned char*)((unsigned long)m_sharedImages + (64 - ((unsigned long)m_sharedImages % 64)));
365  }
366  }
367  else if (checkVersion(1, 32, 0))
368  {
369  m_sharedData = nullptr;
370  m_sharedData26 = nullptr;
372  m_sharedData34 = nullptr;
373 
374  m_sharedImages = (unsigned char*) m_shmPtr +
375  sizeof(SharedData32) + sizeof(TriggerData26) + sizeof(VideoStoreData) +
376  ((m_imageBufferCount) * sizeof(struct timeval)) ;
377 
378  if (((unsigned long)m_sharedImages % 64) != 0)
379  {
380  // align images buffer to nearest 64 byte boundary
381  m_sharedImages = (unsigned char*)((unsigned long)m_sharedImages + (64 - ((unsigned long)m_sharedImages % 64)));
382  }
383  }
384  else if (checkVersion(1, 26, 0))
385  {
386  m_sharedData = nullptr;
388  m_sharedData32 = nullptr;
389  m_sharedData34 = nullptr;
390 
391  m_sharedImages = (unsigned char*) m_shmPtr +
392  sizeof(SharedData26) + sizeof(TriggerData26) +
393  ((m_imageBufferCount) * sizeof(struct timeval));
394 
395  if (((unsigned long)m_sharedImages % 16) != 0)
396  {
397  // align images buffer to nearest 16 byte boundary
398  m_sharedImages = (unsigned char*)((unsigned long)m_sharedImages + (16 - ((unsigned long)m_sharedImages % 16)));
399  }
400  }
401  else
402  {
404  m_sharedData26 = nullptr;
405  m_sharedData32 = nullptr;
406  m_sharedData34 = nullptr;
407 
408  m_sharedImages = (unsigned char*) m_shmPtr +
409  sizeof(SharedData) + sizeof(TriggerData) +
410  ((m_imageBufferCount) * sizeof(struct timeval));
411  }
412 }
413 
415 {
416  if (checkVersion(1, 34, 0))
417  return m_sharedData34 != nullptr && m_sharedImages != nullptr;
418 
419  if (checkVersion(1, 32, 0))
420  return m_sharedData32 != nullptr && m_sharedImages != nullptr;
421 
422  if (checkVersion(1, 26, 0))
423  return m_sharedData26 != nullptr && m_sharedImages != nullptr;
424 
425  // must be version >= 1.24.0 and < 1.26.0
426  return m_sharedData != nullptr && m_sharedImages != nullptr;
427 }
428 
429 
430 std::string MONITOR::getIdStr(void)
431 {
432  if (m_id.empty())
433  {
434  std::stringstream out;
435  out << m_monId;
436  m_id = out.str();
437  }
438  return m_id;
439 }
440 
442 {
443  if (m_sharedData)
445 
446  if (m_sharedData26)
448 
449  if (m_sharedData32)
451 
452  if (m_sharedData34)
454 
455  return 0;
456 }
457 
459 {
460  if (m_sharedData)
461  return m_sharedData->state;
462 
463  if (m_sharedData26)
464  return m_sharedData26->state;
465 
466  if (m_sharedData32)
467  return m_sharedData32->state;
468 
469  if (m_sharedData34)
470  return m_sharedData34->state;
471 
472  return 0;
473 }
474 
476 {
477  if (m_sharedData)
478  {
479  if (m_bytesPerPixel == 1)
480  return ZM_SUBPIX_ORDER_NONE;
481  return ZM_SUBPIX_ORDER_RGB;
482  }
483 
484  if (m_sharedData26)
485  return m_sharedData26->format;
486 
487  if (m_sharedData32)
488  return m_sharedData32->format;
489 
490  if (m_sharedData34)
491  return m_sharedData34->format;
492 
493  return ZM_SUBPIX_ORDER_NONE;
494 }
495 
497 {
498  if (m_sharedData)
499  return m_width * m_height * m_bytesPerPixel;
500 
501  if (m_sharedData26)
502  return m_sharedData26->imagesize;
503 
504  if (m_sharedData32)
505  return m_sharedData32->imagesize;
506 
507  if (m_sharedData34)
508  return m_sharedData34->imagesize;
509 
510  return 0;
511 }
512 
514 
515 ZMServer::ZMServer(int sock, bool debug)
516 {
517  if (debug)
518  std::cout << "Using server protocol version '" << ZM_PROTOCOL_VERSION << "'\n";
519 
520  m_sock = sock;
521  m_debug = debug;
522 
523  // get the shared memory key
524  m_shmKey = 0x7a6d2000;
525  std::string setting = getZMSetting("ZM_SHM_KEY");
526 
527  if (!setting.empty())
528  {
529  unsigned long long tmp = m_shmKey;
530  sscanf(setting.c_str(), "%20llx", &tmp);
531  m_shmKey = tmp;
532  }
533 
534  if (m_debug)
535  {
536  std::cout << "Shared memory key is: 0x"
537  << std::hex << (unsigned int)m_shmKey
538  << std::dec << std::endl;
539  }
540 
541  // get the MMAP path
542  if (checkVersion(1, 32, 0))
544  else
545  m_mmapPath = getZMSetting("ZM_PATH_MAP");
546 
547  if (m_debug)
548  {
549  std::cout << "Memory path directory is: " << m_mmapPath << std::endl;
550  }
551 
552  // get the event filename format
553  setting = getZMSetting("ZM_EVENT_IMAGE_DIGITS");
554  int eventDigits = atoi(setting.c_str());
555  std::string eventDigitsFmt = "%0" + std::to_string(eventDigits) + "d";
556  m_eventFileFormat = eventDigitsFmt + "-capture.jpg";
557  if (m_debug)
558  std::cout << "Event file format is: " << m_eventFileFormat << std::endl;
559 
560  // get the analysis filename format
561  m_analysisFileFormat = eventDigitsFmt + "-analyse.jpg";
562  if (m_debug)
563  std::cout << "Analysis file format is: " << m_analysisFileFormat << std::endl;
564 
565  // is ZM using the deep storage directory format?
566  m_useDeepStorage = (getZMSetting("ZM_USE_DEEP_STORAGE") == "1");
567  if (m_debug)
568  {
569  if (m_useDeepStorage)
570  std::cout << "using deep storage directory structure" << std::endl;
571  else
572  std::cout << "using flat directory structure" << std::endl;
573  }
574 
575  // is ZM creating analysis images?
576  m_useAnalysisImages = (getZMSetting("ZM_CREATE_ANALYSIS_IMAGES") == "1");
577  if (m_debug)
578  {
580  std::cout << "using analysis images" << std::endl;
581  else
582  std::cout << "not using analysis images" << std::endl;
583  }
584 
585  getMonitorList();
586 }
587 
589 {
590  for (auto *mon : m_monitors)
591  {
592  if (mon->m_mapFile != -1)
593  {
594  if (close(mon->m_mapFile) == -1)
595  std::cout << "Failed to close mapFile" << std::endl;
596  else
597  if (m_debug)
598  std::cout << "Closed mapFile for monitor: " << mon->m_name << std::endl;
599  }
600 
601  delete mon;
602  }
603 
604  m_monitors.clear();
605  m_monitorMap.clear();
606 
607  if (m_debug)
608  std::cout << "ZMServer destroyed\n";
609 }
610 
611 void ZMServer::tokenize(const std::string &command, std::vector<std::string> &tokens)
612 {
613  std::string token;
614  tokens.clear();
615  std::string::size_type startPos = 0;
616  std::string::size_type endPos = 0;
617 
618  while((endPos = command.find("[]:[]", startPos)) != std::string::npos)
619  {
620  token = command.substr(startPos, endPos - startPos);
621  tokens.push_back(token);
622  startPos = endPos + 5;
623  }
624 
625  // make sure we add the last token
626  if (endPos != command.length())
627  {
628  token = command.substr(startPos);
629  tokens.push_back(token);
630  }
631 }
632 
633 // returns true if we get a QUIT command from the client
634 bool ZMServer::processRequest(char* buf, int nbytes)
635 {
636 #if 0
637  // first 8 bytes is the length of the following data
638  char len[9];
639  memcpy(len, buf, 8);
640  len[8] = '\0';
641  int dataLen = atoi(len);
642 #endif
643 
644  buf[nbytes] = '\0';
645  std::string s(buf+8);
646  std::vector<std::string> tokens;
647  tokenize(s, tokens);
648 
649  if (tokens.empty())
650  return false;
651 
652  if (m_debug)
653  std::cout << "Processing: '" << tokens[0] << "'" << std::endl;
654 
655  if (tokens[0] == "HELLO")
656  handleHello();
657  else if (tokens[0] == "QUIT")
658  return true;
659  else if (tokens[0] == "GET_SERVER_STATUS")
661  else if (tokens[0] == "GET_MONITOR_STATUS")
663  else if (tokens[0] == "GET_ALARM_STATES")
665  else if (tokens[0] == "GET_EVENT_LIST")
666  handleGetEventList(tokens);
667  else if (tokens[0] == "GET_EVENT_DATES")
668  handleGetEventDates(tokens);
669  else if (tokens[0] == "GET_EVENT_FRAME")
670  handleGetEventFrame(tokens);
671  else if (tokens[0] == "GET_ANALYSE_FRAME")
672  handleGetAnalysisFrame(tokens);
673  else if (tokens[0] == "GET_LIVE_FRAME")
674  handleGetLiveFrame(tokens);
675  else if (tokens[0] == "GET_FRAME_LIST")
676  handleGetFrameList(tokens);
677  else if (tokens[0] == "GET_CAMERA_LIST")
679  else if (tokens[0] == "GET_MONITOR_LIST")
681  else if (tokens[0] == "DELETE_EVENT")
682  handleDeleteEvent(tokens);
683  else if (tokens[0] == "DELETE_EVENT_LIST")
684  handleDeleteEventList(tokens);
685  else if (tokens[0] == "RUN_ZMAUDIT")
687  else if (tokens[0] == "SET_MONITOR_FUNCTION")
688  handleSetMonitorFunction(tokens);
689  else
690  send("UNKNOWN_COMMAND");
691 
692  return false;
693 }
694 
695 bool ZMServer::send(const std::string &s) const
696 {
697  // send length
698  std::string str = "0000000" + std::to_string(s.size());
699  str.erase(0, str.size()-8);
700  int status = ::send(m_sock, str.data(), 8, MSG_NOSIGNAL);
701  if (status == -1)
702  return false;
703 
704  // send message
705  status = ::send(m_sock, s.c_str(), s.size(), MSG_NOSIGNAL);
706  return status != -1;
707 }
708 
709 bool ZMServer::send(const std::string &s, const unsigned char *buffer, int dataLen) const
710 {
711  // send length
712  std::string str = "0000000" + std::to_string(s.size());
713  str.erase(0, str.size()-8);
714  int status = ::send(m_sock, str.data(), 8, MSG_NOSIGNAL);
715  if (status == -1)
716  return false;
717 
718  // send message
719  status = ::send(m_sock, s.c_str(), s.size(), MSG_NOSIGNAL);
720  if ( status == -1 )
721  return false;
722 
723  // send data
724  status = ::send(m_sock, buffer, dataLen, MSG_NOSIGNAL);
725  return status != -1;
726 }
727 
728 void ZMServer::sendError(const std::string &error)
729 {
730  std::string outStr;
731  ADD_STR(outStr, std::string("ERROR - ") + error);
732  send(outStr);
733 }
734 
736 {
737  // just send OK so the client knows all is well
738  // followed by the protocol version we understand
739  std::string outStr;
740  ADD_STR(outStr, "OK");
741  ADD_STR(outStr, ZM_PROTOCOL_VERSION);
742  send(outStr);
743 }
744 
745 long long ZMServer::getDiskSpace(const std::string &filename, long long &total, long long &used)
746 {
747  struct statfs statbuf {};
748  long long freespace = -1;
749 
750  total = used = -1;
751 
752  // there are cases where statfs will return 0 (good), but f_blocks and
753  // others are invalid and set to 0 (such as when an automounted directory
754  // is not mounted but still visible because --ghost was used),
755  // so check to make sure we can have a total size > 0
756  if ((statfs(filename.c_str(), &statbuf) == 0) &&
757  (statbuf.f_blocks > 0) &&
758  (statbuf.f_bsize > 0))
759  {
760  total = statbuf.f_blocks;
761  total *= statbuf.f_bsize;
762  total = total >> 10;
763 
764  freespace = statbuf.f_bavail;
765  freespace *= statbuf.f_bsize;
766  freespace = freespace >> 10;
767 
768  used = total - freespace;
769  }
770 
771  return freespace;
772 }
773 
775 {
776  std::string outStr;
777  ADD_STR(outStr, "OK");
778 
779  // server status
780  std::string status = runCommand(g_binPath + "/zmdc.pl check");
781  ADD_STR(outStr, status);
782 
783  // get load averages
784  std::array<double,3> loads {};
785  if (getloadavg(loads.data(), 3) == -1)
786  {
787  ADD_STR(outStr, "Unknown");
788  }
789  else
790  {
791  // to_string gives six decimal places. Drop last four.
792  std::string buf = std::to_string(loads[0]);
793  buf.resize(buf.size() - 4);
794  ADD_STR(outStr, buf);
795  }
796 
797  // get free space on the disk where the events are stored
798  long long total = 0;
799  long long used = 0;
800  std::string eventsDir = g_webPath + "/events/";
801  getDiskSpace(eventsDir, total, used);
802  std::string buf = std::to_string(static_cast<int>((used * 100) / total)) + "%";
803  ADD_STR(outStr, buf);
804 
805  send(outStr);
806 }
807 
809 {
810  std::string outStr;
811  ADD_STR(outStr, "OK");
812 
813  // add the monitor count
814  ADD_INT(outStr, (int)m_monitors.size());
815 
816  for (auto *monitor : m_monitors)
817  {
818  // add monitor ID
819  ADD_INT(outStr, monitor->m_monId);
820 
821  // add monitor status
822  ADD_INT(outStr, monitor->getState());
823  }
824 
825  send(outStr);
826 }
827 
828 void ZMServer::handleGetEventList(std::vector<std::string> tokens)
829 {
830  std::string outStr;
831 
832  if (tokens.size() != 5)
833  {
835  return;
836  }
837 
838  std::string monitor = tokens[1];
839  bool oldestFirst = (tokens[2] == "1");
840  std::string date = tokens[3];
841  bool includeContinuous = (tokens[4] == "1");
842 
843  if (m_debug)
844  std::cout << "Loading events for monitor: " << monitor << ", date: " << date << std::endl;
845 
846  ADD_STR(outStr, "OK");
847 
848  std::string sql("SELECT E.Id, E.Name, M.Id AS MonitorID, M.Name AS MonitorName, E.StartTime, "
849  "E.Length, M.Width, M.Height, M.DefaultRate, M.DefaultScale "
850  "from Events as E inner join Monitors as M on E.MonitorId = M.Id ");
851 
852  if (monitor != "<ANY>")
853  {
854  sql += "WHERE M.Name = '" + monitor + "' ";
855 
856  if (date != "<ANY>")
857  sql += "AND DATE(E.StartTime) = DATE('" + date + "') ";
858  }
859  else
860  {
861  if (date != "<ANY>")
862  {
863  sql += "WHERE DATE(E.StartTime) = DATE('" + date + "') ";
864 
865  if (!includeContinuous)
866  sql += "AND Cause != 'Continuous' ";
867  }
868  else
869  if (!includeContinuous)
870  sql += "WHERE Cause != 'Continuous' ";
871  }
872 
873  if (oldestFirst)
874  sql += "ORDER BY E.StartTime ASC";
875  else
876  sql += "ORDER BY E.StartTime DESC";
877 
878  if (mysql_query(&g_dbConn, sql.c_str()))
879  {
880  fprintf(stderr, "%s\n", mysql_error(&g_dbConn));
882  return;
883  }
884 
885  MYSQL_RES *res = mysql_store_result(&g_dbConn);
886  int eventCount = mysql_num_rows(res);
887 
888  if (m_debug)
889  std::cout << "Got " << eventCount << " events" << std::endl;
890 
891  ADD_INT(outStr, eventCount);
892 
893  for (int x = 0; x < eventCount; x++)
894  {
895  MYSQL_ROW row = mysql_fetch_row(res);
896  if (row)
897  {
898  ADD_STR(outStr, row[0]); // eventID
899  ADD_STR(outStr, row[1]); // event name
900  ADD_STR(outStr, row[2]); // monitorID
901  ADD_STR(outStr, row[3]); // monitor name
902  row[4][10] = 'T';
903  ADD_STR(outStr, row[4]); // start time
904  ADD_STR(outStr, row[5]); // length
905  }
906  else
907  {
908  std::cout << "Failed to get mysql row" << std::endl;
910  return;
911  }
912  }
913 
914  mysql_free_result(res);
915 
916  send(outStr);
917 }
918 
919 void ZMServer::handleGetEventDates(std::vector<std::string> tokens)
920 {
921  std::string outStr;
922 
923  if (tokens.size() != 3)
924  {
926  return;
927  }
928 
929  std::string monitor = tokens[1];
930  bool oldestFirst = (tokens[2] == "1");
931 
932  if (m_debug)
933  std::cout << "Loading event dates for monitor: " << monitor << std::endl;
934 
935  ADD_STR(outStr, "OK");
936 
937  std::string sql("SELECT DISTINCT DATE(E.StartTime) "
938  "from Events as E inner join Monitors as M on E.MonitorId = M.Id ");
939 
940  if (monitor != "<ANY>")
941  sql += "WHERE M.Name = '" + monitor + "' ";
942 
943  if (oldestFirst)
944  sql += "ORDER BY E.StartTime ASC";
945  else
946  sql += "ORDER BY E.StartTime DESC";
947 
948  if (mysql_query(&g_dbConn, sql.c_str()))
949  {
950  fprintf(stderr, "%s\n", mysql_error(&g_dbConn));
952  return;
953  }
954 
955  MYSQL_RES *res = mysql_store_result(&g_dbConn);
956  int dateCount = mysql_num_rows(res);
957 
958  if (m_debug)
959  std::cout << "Got " << dateCount << " dates" << std::endl;
960 
961  ADD_INT(outStr, dateCount);
962 
963  for (int x = 0; x < dateCount; x++)
964  {
965  MYSQL_ROW row = mysql_fetch_row(res);
966  if (row)
967  {
968  ADD_STR(outStr, row[0]); // event date
969  }
970  else
971  {
972  std::cout << "Failed to get mysql row" << std::endl;
974  return;
975  }
976  }
977 
978  mysql_free_result(res);
979 
980  send(outStr);
981 }
982 
984 {
985  std::string outStr;
986  ADD_STR(outStr, "OK");
987 
988  // get monitor list
989  // Function is reserverd word so but ticks around it
990  std::string sql("SELECT Id, Name, Type, Device, Host, Channel, `Function`, Enabled "
991  "FROM Monitors;");
992  if (mysql_query(&g_dbConn, sql.c_str()))
993  {
994  fprintf(stderr, "%s\n", mysql_error(&g_dbConn));
996  return;
997  }
998 
999  MYSQL_RES *res = mysql_store_result(&g_dbConn);
1000 
1001  // add monitor count
1002  int monitorCount = mysql_num_rows(res);
1003 
1004  if (m_debug)
1005  std::cout << "Got " << monitorCount << " monitors" << std::endl;
1006 
1007  ADD_INT(outStr, monitorCount);
1008 
1009  for (int x = 0; x < monitorCount; x++)
1010  {
1011  MYSQL_ROW row = mysql_fetch_row(res);
1012  if (row)
1013  {
1014  std::string id = row[0];
1015  std::string type = row[2];
1016  std::string device = row[3];
1017  std::string host = row[4] ? row[4] : "";
1018  std::string channel = row[5];
1019  std::string function = row[6];
1020  std::string enabled = row[7];
1021  std::string name = row[1];
1022  std::string events;
1023  std::string zmcStatus;
1024  std::string zmaStatus;
1025  getMonitorStatus(id, type, device, host, channel, function,
1026  zmcStatus, zmaStatus, enabled);
1027 
1028  std::string sql2("SELECT count(if(Archived=0,1,NULL)) AS EventCount "
1029  "FROM Events AS E "
1030  "WHERE MonitorId = " + id);
1031 
1032  if (mysql_query(&g_dbConn, sql2.c_str()))
1033  {
1034  fprintf(stderr, "%s\n", mysql_error(&g_dbConn));
1036  return;
1037  }
1038 
1039  MYSQL_RES *res2 = mysql_store_result(&g_dbConn);
1040  if (mysql_num_rows(res2) > 0)
1041  {
1042  MYSQL_ROW row2 = mysql_fetch_row(res2);
1043  if (row2)
1044  events = row2[0];
1045  else
1046  {
1047  std::cout << "Failed to get mysql row" << std::endl;
1049  return;
1050  }
1051  }
1052 
1053  ADD_STR(outStr, id);
1054  ADD_STR(outStr, name);
1055  ADD_STR(outStr, zmcStatus);
1056  ADD_STR(outStr, zmaStatus);
1057  ADD_STR(outStr, events);
1058  ADD_STR(outStr, function);
1059  ADD_STR(outStr, enabled);
1060 
1061  mysql_free_result(res2);
1062  }
1063  else
1064  {
1065  std::cout << "Failed to get mysql row" << std::endl;
1067  return;
1068  }
1069  }
1070 
1071  mysql_free_result(res);
1072 
1073  send(outStr);
1074 }
1075 
1076 std::string ZMServer::runCommand(const std::string& command)
1077 {
1078  std::string outStr;
1079  FILE *fd = popen(command.c_str(), "r");
1080  std::array<char,100> buffer {};
1081 
1082  while (fgets(buffer.data(), buffer.size(), fd) != nullptr)
1083  {
1084  outStr += buffer.data();
1085  }
1086  pclose(fd);
1087  return outStr;
1088 }
1089 
1090 void ZMServer::getMonitorStatus(const std::string &id, const std::string &type,
1091  const std::string &device, const std::string &host,
1092  const std::string &channel, const std::string &function,
1093  std::string &zmcStatus, std::string &zmaStatus,
1094  const std::string &enabled)
1095 {
1096  zmaStatus = "";
1097  zmcStatus = "";
1098 
1099  std::string command(g_binPath + "/zmdc.pl status");
1100  std::string status = runCommand(command);
1101 
1102  if (type == "Local")
1103  {
1104  if (enabled == "0")
1105  zmaStatus = device + "(" + channel + ") [-]";
1106  else if (status.find("'zma -m " + id + "' running") != std::string::npos)
1107  zmaStatus = device + "(" + channel + ") [R]";
1108  else
1109  zmaStatus = device + "(" + channel + ") [S]";
1110  }
1111  else
1112  {
1113  if (enabled == "0")
1114  zmaStatus = host + " [-]";
1115  else if (status.find("'zma -m " + id + "' running") != std::string::npos)
1116  zmaStatus = host + " [R]";
1117  else
1118  zmaStatus = host + " [S]";
1119  }
1120 
1121  if (type == "Local")
1122  {
1123  if (enabled == "0")
1124  zmcStatus = function + " [-]";
1125  else if (status.find("'zmc -d "+ device + "' running") != std::string::npos)
1126  zmcStatus = function + " [R]";
1127  else
1128  zmcStatus = function + " [S]";
1129  }
1130  else
1131  {
1132  if (enabled == "0")
1133  zmcStatus = function + " [-]";
1134  else if (status.find("'zmc -m " + id + "' running") != std::string::npos)
1135  zmcStatus = function + " [R]";
1136  else
1137  zmcStatus = function + " [S]";
1138  }
1139 }
1140 
1141 void ZMServer::handleGetEventFrame(std::vector<std::string> tokens)
1142 {
1143  static FrameData s_buffer {};
1144 
1145  if (tokens.size() != 5)
1146  {
1148  return;
1149  }
1150 
1151  std::string monitorID(tokens[1]);
1152  std::string eventID(tokens[2]);
1153  int frameNo = atoi(tokens[3].c_str());
1154  std::string eventTime(tokens[4]);
1155 
1156  if (m_debug)
1157  {
1158  std::cout << "Getting frame " << frameNo << " for event " << eventID
1159  << " on monitor " << monitorID << " event time is " << eventTime
1160  << std::endl;
1161  }
1162 
1163  std::string outStr;
1164 
1165  ADD_STR(outStr, "OK");
1166 
1167  // try to find the frame file
1168  std::string filepath;
1169  std::string str (100,'\0');
1170 
1171  if (checkVersion(1, 32, 0))
1172  {
1173  int year = 0;
1174  int month = 0;
1175  int day = 0;
1176 
1177  sscanf(eventTime.data(), "%2d/%2d/%2d", &year, &month, &day);
1178  sprintf(str.data(), "20%02d-%02d-%02d", year, month, day);
1179 
1180  filepath = g_eventsPath + "/" + monitorID + "/" + str + "/" + eventID + "/";
1181  sprintf(str.data(), m_eventFileFormat.c_str(), frameNo);
1182  filepath += str;
1183  }
1184  else
1185  {
1186  if (m_useDeepStorage)
1187  {
1188  filepath = g_webPath + "/events/" + monitorID + "/" + eventTime + "/";
1189  sprintf(str.data(), m_eventFileFormat.c_str(), frameNo);
1190  filepath += str;
1191  }
1192  else
1193  {
1194  filepath = g_webPath + "/events/" + monitorID + "/" + eventID + "/";
1195  sprintf(str.data(), m_eventFileFormat.c_str(), frameNo);
1196  filepath += str;
1197  }
1198  }
1199 
1200  int fileSize = 0;
1201  FILE *fd = fopen(filepath.c_str(), "r" );
1202  if (fd != nullptr)
1203  {
1204  fileSize = fread(s_buffer.data(), 1, s_buffer.size(), fd);
1205  fclose(fd);
1206  }
1207  else
1208  {
1209  std::cout << "Can't open " << filepath << ": " << strerror(errno) << std::endl;
1210  sendError(ERROR_FILE_OPEN + std::string(" - ") + filepath + " : " + strerror(errno));
1211  return;
1212  }
1213 
1214  if (m_debug)
1215  std::cout << "Frame size: " << fileSize << std::endl;
1216 
1217  // get the file size
1218  ADD_INT(outStr, fileSize);
1219 
1220  // send the data
1221  send(outStr, s_buffer.data(), fileSize);
1222 }
1223 
1224 void ZMServer::handleGetAnalysisFrame(std::vector<std::string> tokens)
1225 {
1226  static FrameData s_buffer {};
1227  std::array<char,100> str {};
1228 
1229  if (tokens.size() != 5)
1230  {
1232  return;
1233  }
1234 
1235  std::string monitorID(tokens[1]);
1236  std::string eventID(tokens[2]);
1237  int frameNo = atoi(tokens[3].c_str());
1238  std::string eventTime(tokens[4]);
1239  int frameID = 0;
1240  int frameCount = 0;
1241 
1242  if (m_debug)
1243  {
1244  std::cout << "Getting analysis frame " << frameNo << " for event " << eventID
1245  << " on monitor " << monitorID << " event time is " << eventTime
1246  << std::endl;
1247  }
1248 
1249  // get the 'alarm' frames from the Frames table for this event
1250  std::string sql;
1251  sql += "SELECT FrameId FROM Frames ";
1252  sql += "WHERE EventID = " + eventID + " ";
1253  sql += "AND Type = 'Alarm' ";
1254  sql += "ORDER BY FrameID";
1255 
1256  if (mysql_query(&g_dbConn, sql.c_str()))
1257  {
1258  fprintf(stderr, "%s\n", mysql_error(&g_dbConn));
1260  return;
1261  }
1262 
1263  MYSQL_RES *res = mysql_store_result(&g_dbConn);
1264  frameCount = mysql_num_rows(res);
1265 
1266  // if we didn't find any alarm frames get the list of normal frames
1267  if (frameCount == 0)
1268  {
1269  mysql_free_result(res);
1270 
1271  sql = "SELECT FrameId FROM Frames ";
1272  sql += "WHERE EventID = " + eventID + " ";
1273  sql += "ORDER BY FrameID";
1274 
1275  if (mysql_query(&g_dbConn, sql.c_str()))
1276  {
1277  fprintf(stderr, "%s\n", mysql_error(&g_dbConn));
1279  return;
1280  }
1281 
1282  res = mysql_store_result(&g_dbConn);
1283  frameCount = mysql_num_rows(res);
1284  }
1285 
1286  // if frameCount is 0 then we can't go any further
1287  if (frameCount == 0)
1288  {
1289  std::cout << "handleGetAnalyseFrame: Failed to find any frames" << std::endl;
1291  return;
1292  }
1293 
1294  // if the required frame mumber is 0 or out of bounds then use the middle frame
1295  if (frameNo == 0 || frameNo < 0 || frameNo > frameCount)
1296  frameNo = (frameCount / 2) + 1;
1297 
1298  // move to the required frame in the table
1299  MYSQL_ROW row = nullptr;
1300  for (int x = 0; x < frameNo; x++)
1301  {
1302  row = mysql_fetch_row(res);
1303  }
1304 
1305  if (row)
1306  {
1307  frameID = atoi(row[0]);
1308  }
1309  else
1310  {
1311  std::cout << "handleGetAnalyseFrame: Failed to get mysql row for frameNo " << frameNo << std::endl;
1313  return;
1314  }
1315 
1316  mysql_free_result(res);
1317 
1318  std::string outStr;
1319  std::string filepath;
1320  std::string frameFile;
1321 
1322  if (checkVersion(1, 32, 0))
1323  {
1324  int year = 0;
1325  int month = 0;
1326  int day = 0;
1327 
1328  sscanf(eventTime.c_str(), "%2d/%2d/%2d", &year, &month, &day);
1329  sprintf(str.data(), "20%02d-%02d-%02d", year, month, day);
1330  filepath = g_eventsPath + "/" + monitorID + "/" + str.data() + "/" + eventID + "/";
1331  }
1332  else
1333  {
1334  if (m_useDeepStorage)
1335  filepath = g_webPath + "/events/" + monitorID + "/" + eventTime + "/";
1336  else
1337  filepath = g_webPath + "/events/" + monitorID + "/" + eventID + "/";
1338  }
1339 
1340  ADD_STR(outStr, "OK");
1341 
1342  FILE *fd = nullptr;
1343  int fileSize = 0;
1344 
1345  // try to find an analysis frame for the frameID
1346  if (m_useAnalysisImages)
1347  {
1348  sprintf(str.data(), m_analysisFileFormat.c_str(), frameID);
1349  frameFile = filepath + str.data();
1350 
1351  if ((fd = fopen(frameFile.c_str(), "r" )))
1352  {
1353  fileSize = fread(s_buffer.data(), 1, s_buffer.size(), fd);
1354  fclose(fd);
1355 
1356  if (m_debug)
1357  std::cout << "Frame size: " << fileSize << std::endl;
1358 
1359  // get the file size
1360  ADD_INT(outStr, fileSize);
1361 
1362  // send the data
1363  send(outStr, s_buffer.data(), fileSize);
1364  return;
1365  }
1366  }
1367 
1368  // try to find a normal frame for the frameID these should always be available
1369  sprintf(str.data(), m_eventFileFormat.c_str(), frameID);
1370  frameFile = filepath + str.data();
1371 
1372  if ((fd = fopen(frameFile.c_str(), "r" )))
1373  {
1374  fileSize = fread(s_buffer.data(), 1, s_buffer.size(), fd);
1375  fclose(fd);
1376  }
1377  else
1378  {
1379  std::cout << "Can't open " << frameFile << ": " << strerror(errno) << std::endl;
1380  sendError(ERROR_FILE_OPEN + std::string(" - ") + frameFile + " : " + strerror(errno));
1381  return;
1382  }
1383 
1384  if (m_debug)
1385  std::cout << "Frame size: " << fileSize << std::endl;
1386 
1387  // get the file size
1388  ADD_INT(outStr, fileSize);
1389 
1390  // send the data
1391  send(outStr, s_buffer.data(), fileSize);
1392 }
1393 
1394 void ZMServer::handleGetLiveFrame(std::vector<std::string> tokens)
1395 {
1396  static FrameData s_buffer {};
1397 
1398  // we need to periodically kick the DB connection here to make sure it
1399  // stays alive because the user may have left the frontend on the live
1400  // view which doesn't query the DB at all and eventually the connection
1401  // will timeout
1403 
1404  if (tokens.size() != 2)
1405  {
1407  return;
1408  }
1409 
1410  int monitorID = atoi(tokens[1].c_str());
1411 
1412  if (m_debug)
1413  std::cout << "Getting live frame from monitor: " << monitorID << std::endl;
1414 
1415  std::string outStr;
1416 
1417  ADD_STR(outStr, "OK");
1418 
1419  // echo the monitor id
1420  ADD_INT(outStr, monitorID);
1421 
1422  // try to find the correct MONITOR
1423  if (m_monitorMap.find(monitorID) == m_monitorMap.end())
1424  {
1426  return;
1427  }
1428  MONITOR *monitor = m_monitorMap[monitorID];
1429 
1430  // are the data pointers valid?
1431  if (!monitor->isValid())
1432  {
1434  return;
1435  }
1436 
1437  // read a frame from the shared memory
1438  int dataSize = getFrame(s_buffer, monitor);
1439 
1440  if (m_debug)
1441  std::cout << "Frame size: " << dataSize << std::endl;
1442 
1443  if (dataSize == 0)
1444  {
1445  // not really an error
1446  outStr = "";
1447  ADD_STR(outStr, "WARNING - No new frame available");
1448  send(outStr);
1449  return;
1450  }
1451 
1452  // add status
1453  ADD_STR(outStr, monitor->m_status);
1454 
1455  // send the data size
1456  ADD_INT(outStr, dataSize);
1457 
1458  // send the data
1459  send(outStr, s_buffer.data(), dataSize);
1460 }
1461 
1462 void ZMServer::handleGetFrameList(std::vector<std::string> tokens)
1463 {
1464  std::string eventID;
1465  std::string outStr;
1466 
1467  if (tokens.size() != 2)
1468  {
1470  return;
1471  }
1472 
1473  eventID = tokens[1];
1474 
1475  if (m_debug)
1476  std::cout << "Loading frames for event: " << eventID << std::endl;
1477 
1478  ADD_STR(outStr, "OK");
1479 
1480  // check to see what type of event this is
1481  std::string sql = "SELECT Cause, Length, Frames FROM Events ";
1482  sql += "WHERE Id = " + eventID + " ";
1483 
1484  if (mysql_query(&g_dbConn, sql.c_str()))
1485  {
1486  fprintf(stderr, "%s\n", mysql_error(&g_dbConn));
1488  return;
1489  }
1490 
1491  MYSQL_RES *res = mysql_store_result(&g_dbConn);
1492  MYSQL_ROW row = mysql_fetch_row(res);
1493 
1494  // make sure we have some frames to display
1495  if (row[1] == nullptr || row[2] == nullptr)
1496  {
1498  return;
1499  }
1500 
1501  std::string cause = row[0];
1502  double length = atof(row[1]);
1503  int frameCount = atoi(row[2]);
1504 
1505  mysql_free_result(res);
1506 
1507  if (cause == "Continuous")
1508  {
1509  // event is a continuous recording so guess the frame delta's
1510 
1511  if (m_debug)
1512  std::cout << "Got " << frameCount << " frames (continuous event)" << std::endl;
1513 
1514  ADD_INT(outStr, frameCount);
1515 
1516  if (frameCount > 0)
1517  {
1518  double delta = length / frameCount;
1519 
1520  for (int x = 0; x < frameCount; x++)
1521  {
1522  ADD_STR(outStr, "Normal"); // Type
1523  ADD_STR(outStr, std::to_string(delta)); // Delta
1524  }
1525  }
1526  }
1527  else
1528  {
1529  sql = "SELECT Type, Delta FROM Frames ";
1530  sql += "WHERE EventID = " + eventID + " ";
1531  sql += "ORDER BY FrameID";
1532 
1533  if (mysql_query(&g_dbConn, sql.c_str()))
1534  {
1535  fprintf(stderr, "%s\n", mysql_error(&g_dbConn));
1537  return;
1538  }
1539 
1540  res = mysql_store_result(&g_dbConn);
1541  frameCount = mysql_num_rows(res);
1542 
1543  if (m_debug)
1544  std::cout << "Got " << frameCount << " frames" << std::endl;
1545 
1546  ADD_INT(outStr, frameCount);
1547 
1548  for (int x = 0; x < frameCount; x++)
1549  {
1550  row = mysql_fetch_row(res);
1551  if (row)
1552  {
1553  ADD_STR(outStr, row[0]); // Type
1554  ADD_STR(outStr, row[1]); // Delta
1555  }
1556  else
1557  {
1558  std::cout << "handleGetFrameList: Failed to get mysql row " << x << std::endl;
1560  return;
1561  }
1562  }
1563 
1564  mysql_free_result(res);
1565  }
1566 
1567  send(outStr);
1568 }
1569 
1571 {
1572  std::string outStr;
1573 
1574  ADD_STR(outStr, "OK");
1575 
1576  ADD_INT(outStr, (int)m_monitors.size());
1577 
1578  for (auto & monitor : m_monitors)
1579  {
1580  ADD_STR(outStr, monitor->m_name);
1581  }
1582 
1583  send(outStr);
1584 }
1585 
1587 {
1588  std::string outStr;
1589 
1590  ADD_STR(outStr, "OK");
1591 
1592  if (m_debug)
1593  std::cout << "We have " << m_monitors.size() << " monitors" << std::endl;
1594 
1595  ADD_INT(outStr, (int)m_monitors.size());;
1596 
1597  for (auto *mon : m_monitors)
1598  {
1599  ADD_INT(outStr, mon->m_monId);
1600  ADD_STR(outStr, mon->m_name);
1601  ADD_INT(outStr, mon->m_width);
1602  ADD_INT(outStr, mon->m_height);
1603  ADD_INT(outStr, mon->m_bytesPerPixel);
1604 
1605  if (m_debug)
1606  {
1607  std::cout << "id: " << mon->m_monId << std::endl;
1608  std::cout << "name: " << mon->m_name << std::endl;
1609  std::cout << "width: " << mon->m_width << std::endl;
1610  std::cout << "height: " << mon->m_height << std::endl;
1611  std::cout << "palette: " << mon->m_palette << std::endl;
1612  std::cout << "byte per pixel: " << mon->m_bytesPerPixel << std::endl;
1613  std::cout << "sub pixel order:" << mon->getSubpixelOrder() << std::endl;
1614  std::cout << "-------------------" << std::endl;
1615  }
1616  }
1617 
1618  send(outStr);
1619 }
1620 
1621 void ZMServer::handleDeleteEvent(std::vector<std::string> tokens)
1622 {
1623  std::string eventID;
1624  std::string outStr;
1625 
1626  if (tokens.size() != 2)
1627  {
1629  return;
1630  }
1631 
1632  eventID = tokens[1];
1633 
1634  if (m_debug)
1635  std::cout << "Deleting event: " << eventID << std::endl;
1636 
1637  ADD_STR(outStr, "OK");
1638 
1639  std::string sql;
1640  sql += "DELETE FROM Events WHERE Id = " + eventID;
1641 
1642  if (mysql_query(&g_dbConn, sql.c_str()))
1643  {
1644  fprintf(stderr, "%s\n", mysql_error(&g_dbConn));
1646  return;
1647  }
1648 
1649  // run zmaudit.pl to clean everything up
1650  std::string command(g_binPath + "/zmaudit.pl &");
1651  errno = 0;
1652  if (system(command.c_str()) < 0 && errno)
1653  std::cerr << "Failed to run '" << command << "'" << std::endl;
1654 
1655  send(outStr);
1656 }
1657 
1658 void ZMServer::handleDeleteEventList(std::vector<std::string> tokens)
1659 {
1660  std::string eventList;
1661  std::string outStr;
1662 
1663  auto it = tokens.begin();
1664  if (it != tokens.end())
1665  ++it;
1666  while (it != tokens.end())
1667  {
1668  if (eventList.empty())
1669  eventList = (*it);
1670  else
1671  eventList += "," + (*it);
1672 
1673  ++it;
1674  }
1675 
1676  if (m_debug)
1677  std::cout << "Deleting events: " << eventList << std::endl;
1678 
1679  std::string sql;
1680  sql += "DELETE FROM Events WHERE Id IN (" + eventList + ")";
1681 
1682  if (mysql_query(&g_dbConn, sql.c_str()))
1683  {
1684  fprintf(stderr, "%s\n", mysql_error(&g_dbConn));
1686  return;
1687  }
1688 
1689  ADD_STR(outStr, "OK");
1690  send(outStr);
1691 }
1692 
1694 {
1695  std::string outStr;
1696 
1697  // run zmaudit.pl to clean up orphaned db entries etc
1698  std::string command(g_binPath + "/zmaudit.pl &");
1699 
1700  if (m_debug)
1701  std::cout << "Running command: " << command << std::endl;
1702 
1703  errno = 0;
1704  if (system(command.c_str()) < 0 && errno)
1705  std::cerr << "Failed to run '" << command << "'" << std::endl;
1706 
1707  ADD_STR(outStr, "OK");
1708  send(outStr);
1709 }
1710 
1712 {
1713  m_monitors.clear();
1714  m_monitorMap.clear();
1715 
1716  // Function is reserverd word so but ticks around it
1717  std::string sql("SELECT Id, Name, Width, Height, ImageBufferCount, MaxFPS, Palette, ");
1718  sql += " Type, `Function`, Enabled, Device, Host, Controllable, TrackMotion";
1719 
1720  if (checkVersion(1, 26, 0))
1721  sql += ", Colours";
1722 
1723  sql += " FROM Monitors";
1724  sql += " ORDER BY Sequence";
1725 
1726  if (mysql_query(&g_dbConn, sql.c_str()))
1727  {
1728  fprintf(stderr, "%s\n", mysql_error(&g_dbConn));
1729  return;
1730  }
1731 
1732  MYSQL_RES *res = mysql_store_result(&g_dbConn);
1733  int monitorCount = mysql_num_rows(res);
1734 
1735  if (m_debug)
1736  std::cout << "Got " << monitorCount << " monitors" << std::endl;
1737 
1738  for (int x = 0; x < monitorCount; x++)
1739  {
1740  MYSQL_ROW row = mysql_fetch_row(res);
1741  if (row)
1742  {
1743  auto *m = new MONITOR;
1744  m->m_monId = atoi(row[0]);
1745  m->m_name = row[1];
1746  m->m_width = atoi(row[2]);
1747  m->m_height = atoi(row[3]);
1748  m->m_imageBufferCount = atoi(row[4]);
1749  m->m_palette = atoi(row[6]);
1750  m->m_type = row[7];
1751  m->m_function = row[8];
1752  m->m_enabled = atoi(row[9]);
1753  m->m_device = row[10];
1754  m->m_host = row[11] ? row[11] : "";
1755  m->m_controllable = atoi(row[12]);
1756  m->m_trackMotion = atoi(row[13]);
1757 
1758  // from version 1.26.0 ZM can have 1, 3 or 4 bytes per pixel
1759  // older versions can be 1 or 3
1760  if (checkVersion(1, 26, 0))
1761  m->m_bytesPerPixel = atoi(row[14]);
1762  else
1763  if (m->m_palette == 1)
1764  m->m_bytesPerPixel = 1;
1765  else
1766  m->m_bytesPerPixel = 3;
1767 
1768  m_monitors.push_back(m);
1769  m_monitorMap[m->m_monId] = m;
1770 
1771  m->initMonitor(m_debug, m_mmapPath, m_shmKey);
1772  }
1773  else
1774  {
1775  std::cout << "Failed to get mysql row" << std::endl;
1776  return;
1777  }
1778  }
1779 
1780  mysql_free_result(res);
1781 }
1782 
1783 int ZMServer::getFrame(FrameData &buffer, MONITOR *monitor)
1784 {
1785  // is there a new frame available?
1786  if (monitor->getLastWriteIndex() == monitor->m_lastRead )
1787  return 0;
1788 
1789  // sanity check last_read
1790  if (monitor->getLastWriteIndex() < 0 ||
1791  monitor->getLastWriteIndex() >= (monitor->m_imageBufferCount - 1))
1792  return 0;
1793 
1794  monitor->m_lastRead = monitor->getLastWriteIndex();
1795 
1796  switch (monitor->getState())
1797  {
1798  case IDLE:
1799  monitor->m_status = "Idle";
1800  break;
1801  case PREALARM:
1802  monitor->m_status = "Pre Alarm";
1803  break;
1804  case ALARM:
1805  monitor->m_status = "Alarm";
1806  break;
1807  case ALERT:
1808  monitor->m_status = "Alert";
1809  break;
1810  case TAPE:
1811  monitor->m_status = "Tape";
1812  break;
1813  default:
1814  monitor->m_status = "Unknown";
1815  break;
1816  }
1817 
1818  // FIXME: should do some sort of compression JPEG??
1819  // just copy the data to our buffer for now
1820 
1821  // fixup the colours if necessary we aim to always send RGB24 images
1822  unsigned char *data = monitor->m_sharedImages +
1823  static_cast<ptrdiff_t>(monitor->getFrameSize()) * monitor->m_lastRead;
1824  unsigned int rpos = 0;
1825  unsigned int wpos = 0;
1826 
1827  switch (monitor->getSubpixelOrder())
1828  {
1829  case ZM_SUBPIX_ORDER_NONE:
1830  {
1831  for (wpos = 0, rpos = 0; wpos < (unsigned int) (monitor->m_width * monitor->m_height * 3); wpos += 3, rpos += 1)
1832  {
1833  buffer[wpos + 0] = data[rpos + 0]; // r
1834  buffer[wpos + 1] = data[rpos + 0]; // g
1835  buffer[wpos + 2] = data[rpos + 0]; // b
1836  }
1837 
1838  break;
1839  }
1840 
1841  case ZM_SUBPIX_ORDER_RGB:
1842  {
1843  for (wpos = 0, rpos = 0; wpos < (unsigned int) (monitor->m_width * monitor->m_height * 3); wpos += 3, rpos += 3)
1844  {
1845  buffer[wpos + 0] = data[rpos + 0]; // r
1846  buffer[wpos + 1] = data[rpos + 1]; // g
1847  buffer[wpos + 2] = data[rpos + 2]; // b
1848  }
1849 
1850  break;
1851  }
1852 
1853  case ZM_SUBPIX_ORDER_BGR:
1854  {
1855  for (wpos = 0, rpos = 0; wpos < (unsigned int) (monitor->m_width * monitor->m_height * 3); wpos += 3, rpos += 3)
1856  {
1857  buffer[wpos + 0] = data[rpos + 2]; // r
1858  buffer[wpos + 1] = data[rpos + 1]; // g
1859  buffer[wpos + 2] = data[rpos + 0]; // b
1860  }
1861 
1862  break;
1863  }
1864  case ZM_SUBPIX_ORDER_BGRA:
1865  {
1866  for (wpos = 0, rpos = 0; wpos < (unsigned int) (monitor->m_width * monitor->m_height * 3); wpos += 3, rpos += 4)
1867  {
1868  buffer[wpos + 0] = data[rpos + 2]; // r
1869  buffer[wpos + 1] = data[rpos + 1]; // g
1870  buffer[wpos + 2] = data[rpos + 0]; // b
1871  }
1872 
1873  break;
1874  }
1875 
1876  case ZM_SUBPIX_ORDER_RGBA:
1877  {
1878  for (wpos = 0, rpos = 0; wpos < (unsigned int) (monitor->m_width * monitor->m_height * 3 ); wpos += 3, rpos += 4)
1879  {
1880  buffer[wpos + 0] = data[rpos + 0]; // r
1881  buffer[wpos + 1] = data[rpos + 1]; // g
1882  buffer[wpos + 2] = data[rpos + 2]; // b
1883  }
1884 
1885  break;
1886  }
1887 
1888  case ZM_SUBPIX_ORDER_ABGR:
1889  {
1890  for (wpos = 0, rpos = 0; wpos < (unsigned int) (monitor->m_width * monitor->m_height * 3); wpos += 3, rpos += 4)
1891  {
1892  buffer[wpos + 0] = data[rpos + 3]; // r
1893  buffer[wpos + 1] = data[rpos + 2]; // g
1894  buffer[wpos + 2] = data[rpos + 1]; // b
1895  }
1896 
1897  break;
1898  }
1899 
1900  case ZM_SUBPIX_ORDER_ARGB:
1901  {
1902  for (wpos = 0, rpos = 0; wpos < (unsigned int) (monitor->m_width * monitor->m_height * 3); wpos += 3, rpos += 4)
1903  {
1904  buffer[wpos + 0] = data[rpos + 1]; // r
1905  buffer[wpos + 1] = data[rpos + 2]; // g
1906  buffer[wpos + 2] = data[rpos + 3]; // b
1907  }
1908 
1909  break;
1910  }
1911  }
1912 
1913  return monitor->m_width * monitor->m_height * 3;
1914 }
1915 
1916 std::string ZMServer::getZMSetting(const std::string &setting) const
1917 {
1918  std::string result;
1919  std::string sql("SELECT Name, Value FROM Config ");
1920  sql += "WHERE Name = '" + setting + "'";
1921 
1922  if (mysql_query(&g_dbConn, sql.c_str()))
1923  {
1924  fprintf(stderr, "%s\n", mysql_error(&g_dbConn));
1925  return "";
1926  }
1927 
1928  MYSQL_RES *res = mysql_store_result(&g_dbConn);
1929  MYSQL_ROW row = mysql_fetch_row(res);
1930  if (row)
1931  {
1932  result = row[1];
1933  }
1934  else
1935  {
1936  std::cout << "Failed to get mysql row" << std::endl;
1937  result = "";
1938  }
1939 
1940  if (m_debug)
1941  std::cout << "getZMSetting: " << setting << " Result: " << result << std::endl;
1942 
1943  mysql_free_result(res);
1944 
1945  return result;
1946 }
1947 
1948 void ZMServer::handleSetMonitorFunction(std::vector<std::string> tokens)
1949 {
1950  std::string outStr;
1951 
1952  if (tokens.size() != 4)
1953  {
1955  return;
1956  }
1957 
1958  std::string monitorID(tokens[1]);
1959  std::string function(tokens[2]);
1960  std::string enabled(tokens[3]);
1961 
1962  // Check validity of input passed to server. Does monitor exist && is function ok
1963  if (m_monitorMap.find(atoi(monitorID.c_str())) == m_monitorMap.end())
1964  {
1966  return;
1967  }
1968 
1969  if (function != FUNCTION_NONE && function != FUNCTION_MONITOR &&
1970  function != FUNCTION_MODECT && function != FUNCTION_NODECT &&
1971  function != FUNCTION_RECORD && function != FUNCTION_MOCORD)
1972  {
1974  return;
1975  }
1976 
1977  if (enabled != "0" && enabled != "1")
1978  {
1980  return;
1981  }
1982 
1983  if (m_debug)
1984  std::cout << "User input validated OK" << std::endl;
1985 
1986 
1987  // Now perform db update && (re)start/stop daemons as required.
1988  MONITOR *monitor = m_monitorMap[atoi(monitorID.c_str())];
1989  std::string oldFunction = monitor->m_function;
1990  const std::string& newFunction = function;
1991  int oldEnabled = monitor->m_enabled;
1992  int newEnabled = atoi(enabled.c_str());
1993  monitor->m_function = newFunction;
1994  monitor->m_enabled = newEnabled;
1995 
1996  if (m_debug)
1997  {
1998  std::cout << "SetMonitorFunction MonitorId: " << monitorID << std::endl
1999  << " oldEnabled: " << oldEnabled << std::endl
2000  << " newEnabled: " << newEnabled << std::endl
2001  << " oldFunction: " << oldFunction << std::endl
2002  << " newFunction: " << newFunction << std::endl;
2003  }
2004 
2005  if ( newFunction != oldFunction || newEnabled != oldEnabled)
2006  {
2007  std::string sql("UPDATE Monitors ");
2008  sql += "SET Function = '" + function + "', ";
2009  sql += "Enabled = '" + enabled + "' ";
2010  sql += "WHERE Id = '" + monitorID + "'";
2011 
2012  if (mysql_query(&g_dbConn, sql.c_str()))
2013  {
2014  fprintf(stderr, "%s\n", mysql_error(&g_dbConn));
2016  return;
2017  }
2018 
2019  if (m_debug)
2020  std::cout << "Monitor function SQL update OK" << std::endl;
2021 
2022  std::string status = runCommand(g_binPath + "/zmdc.pl check");
2023 
2024  // Now refresh servers
2025  if (RUNNING.compare(0, RUNNING.size(), status, 0, RUNNING.size()) == 0)
2026  {
2027  if (m_debug)
2028  std::cout << "Monitor function Refreshing daemons" << std::endl;
2029 
2030  bool restart = (oldFunction == FUNCTION_NONE) ||
2031  (newFunction == FUNCTION_NONE) ||
2032  (newEnabled != oldEnabled);
2033 
2034  if (restart)
2035  zmcControl(monitor, RESTART);
2036  else
2037  zmcControl(monitor, "");
2038  zmaControl(monitor, RELOAD);
2039  }
2040  else
2041  if (m_debug)
2042  std::cout << "zm daemons are not running" << std::endl;
2043  }
2044  else
2045  std::cout << "Not updating monitor function as identical to existing configuration" << std::endl;
2046 
2047  ADD_STR(outStr, "OK");
2048  send(outStr);
2049 }
2050 
2051 void ZMServer::zmcControl(MONITOR *monitor, const std::string &mode)
2052 {
2053  std::string zmcArgs;
2054  std::string sql;
2055  sql += "SELECT count(if(Function!='None',1,NULL)) as ActiveCount ";
2056  sql += "FROM Monitors ";
2057 
2058  if (monitor->m_type == "Local" )
2059  {
2060  sql += "WHERE Device = '" + monitor->m_device + "'";
2061  zmcArgs = "-d " + monitor->m_device;
2062  }
2063  else
2064  {
2065  sql += "WHERE Id = '" + monitor->getIdStr() + "'";
2066  zmcArgs = "-m " + monitor->getIdStr();
2067  }
2068 
2069  if (mysql_query(&g_dbConn, sql.c_str()))
2070  {
2071  fprintf(stderr, "%s\n", mysql_error(&g_dbConn));
2073  return;
2074  }
2075 
2076  MYSQL_RES *res = mysql_store_result(&g_dbConn);
2077  MYSQL_ROW row = mysql_fetch_row(res);
2078  if (row == nullptr)
2079  {
2081  return;
2082  }
2083  int activeCount = atoi(row[0]);
2084 
2085  if (!activeCount)
2086  runCommand(g_binPath + "/zmdc.pl stop zmc " + zmcArgs);
2087  else
2088  {
2089  if (mode == RESTART)
2090  runCommand(g_binPath + "/zmdc.pl stop zmc " + zmcArgs);
2091 
2092  runCommand(g_binPath + "/zmdc.pl start zmc " + zmcArgs);
2093  }
2094 }
2095 
2096 void ZMServer::zmaControl(MONITOR *monitor, const std::string &mode)
2097 {
2098  int zmOptControl = atoi(getZMSetting("ZM_OPT_CONTROL").c_str());
2099  int zmOptFrameServer = atoi(getZMSetting("ZM_OPT_FRAME_SERVER").c_str());
2100 
2101  if (monitor->m_function == FUNCTION_MODECT ||
2102  monitor->m_function == FUNCTION_RECORD ||
2103  monitor->m_function == FUNCTION_MOCORD ||
2104  monitor->m_function == FUNCTION_NODECT)
2105  {
2106  if (mode == RESTART)
2107  {
2108  if (zmOptControl)
2109  runCommand(g_binPath + "/zmdc.pl stop zmtrack.pl -m " + monitor->getIdStr());
2110 
2111  runCommand(g_binPath + "/zmdc.pl stop zma -m " + monitor->getIdStr());
2112 
2113  if (zmOptFrameServer)
2114  runCommand(g_binPath + "/zmdc.pl stop zmf -m " + monitor->getIdStr());
2115  }
2116 
2117  if (zmOptFrameServer)
2118  runCommand(g_binPath + "/zmdc.pl start zmf -m " + monitor->getIdStr());
2119 
2120  runCommand(g_binPath + "/zmdc.pl start zma -m " + monitor->getIdStr());
2121 
2122  if (zmOptControl && monitor->m_controllable && monitor->m_trackMotion &&
2123  ( monitor->m_function == FUNCTION_MODECT || monitor->m_function == FUNCTION_MOCORD) )
2124  runCommand(g_binPath + "/zmdc.pl start zmtrack.pl -m " + monitor->getIdStr());
2125 
2126  if (mode == RELOAD)
2127  runCommand(g_binPath + "/zmdc.pl reload zma -m " + monitor->getIdStr());
2128  }
2129  else
2130  {
2131  if (zmOptControl)
2132  runCommand(g_binPath + "/zmdc.pl stop zmtrack.pl -m " + monitor->getIdStr());
2133 
2134  runCommand(g_binPath + "/zmdc.pl stop zma -m " + monitor->getIdStr());
2135 
2136  if (zmOptFrameServer)
2137  runCommand(g_binPath + "/zmdc.pl stop zmf -m " + monitor->getIdStr());
2138  }
2139 }
SharedData34::format
uint8_t format
Definition: zmserver.h:193
ZMServer::m_shmKey
key_t m_shmKey
Definition: zmserver.h:352
SharedData26::imagesize
uint32_t imagesize
Definition: zmserver.h:123
SharedData34::state
uint32_t state
Definition: zmserver.h:181
ZMServer::handleHello
void handleHello(void)
Definition: zmserver.cpp:735
SharedData26::format
uint8_t format
Definition: zmserver.h:122
g_majorVersion
int g_majorVersion
Definition: zmserver.cpp:95
ZMServer::handleRunZMAudit
void handleRunZMAudit(void)
Definition: zmserver.cpp:1693
g_lastDBKick
TimePoint g_lastDBKick
Definition: zmserver.cpp:99
ZMServer::m_useAnalysisImages
bool m_useAnalysisImages
Definition: zmserver.h:349
error
static void error(const char *str,...)
Definition: vbi.cpp:36
IDLE
@ IDLE
Definition: zmserver.h:70
MONITOR::isValid
bool isValid(void)
Definition: zmserver.cpp:414
RELOAD
const std::string RELOAD
Definition: zmserver.h:65
ZMServer::m_analysisFileFormat
std::string m_analysisFileFormat
Definition: zmserver.h:351
MONITOR::m_id
std::string m_id
Definition: zmserver.h:299
ERROR_INVALID_POINTERS
static constexpr const char * ERROR_INVALID_POINTERS
Definition: zmserver.cpp:66
MONITOR::m_sharedData34
SharedData34 * m_sharedData34
Definition: zmserver.h:298
ZMServer::handleGetAnalysisFrame
void handleGetAnalysisFrame(std::vector< std::string > tokens)
Definition: zmserver.cpp:1224
MONITOR::m_sharedData32
SharedData32 * m_sharedData32
Definition: zmserver.h:297
TAPE
@ TAPE
Definition: zmserver.h:74
ZM_SUBPIX_ORDER_RGBA
@ ZM_SUBPIX_ORDER_RGBA
Definition: zmserver.cpp:79
ZMServer::handleGetServerStatus
void handleGetServerStatus(void)
Definition: zmserver.cpp:774
SharedData::state
State state
Definition: zmserver.h:88
FUNCTION_NONE
const std::string FUNCTION_NONE
Definition: zmserver.h:62
MONITOR::m_trackMotion
int m_trackMotion
Definition: zmserver.h:291
g_mmapPath
std::string g_mmapPath
Definition: zmserver.cpp:93
FUNCTION_MODECT
const std::string FUNCTION_MODECT
Definition: zmserver.h:58
SharedData26::last_write_index
uint32_t last_write_index
Definition: zmserver.h:108
ZM_PROTOCOL_VERSION
static constexpr const char * ZM_PROTOCOL_VERSION
Definition: zmserver.cpp:53
MONITOR::m_lastRead
int m_lastRead
Definition: zmserver.h:287
g_server
std::string g_server
Definition: zmserver.cpp:87
TimePoint
std::chrono::time_point< Clock > TimePoint
Definition: zmserver.h:29
ZMServer::getFrame
static int getFrame(FrameData &buffer, MONITOR *monitor)
Definition: zmserver.cpp:1783
x0
static int x0
Definition: mythsocket.cpp:49
PREALARM
@ PREALARM
Definition: zmserver.h:71
MONITOR::m_width
int m_width
Definition: zmserver.h:282
MONITOR::m_sharedData26
SharedData26 * m_sharedData26
Definition: zmserver.h:296
ZM_SUBPIX_ORDER_ARGB
@ ZM_SUBPIX_ORDER_ARGB
Definition: zmserver.cpp:81
FUNCTION_MONITOR
const std::string FUNCTION_MONITOR
Definition: zmserver.h:57
ZMServer::zmcControl
void zmcControl(MONITOR *monitor, const std::string &mode)
Definition: zmserver.cpp:2051
ZMServer::zmaControl
void zmaControl(MONITOR *monitor, const std::string &mode)
Definition: zmserver.cpp:2096
MONITOR::initMonitor
void initMonitor(bool debug, const std::string &mmapPath, int shmKey)
Definition: zmserver.cpp:233
ZMServer::handleGetAlarmStates
void handleGetAlarmStates(void)
Definition: zmserver.cpp:808
ZM_SUBPIX_ORDER_BGR
@ ZM_SUBPIX_ORDER_BGR
Definition: zmserver.cpp:77
DB_CHECK_TIME
static constexpr std::chrono::seconds DB_CHECK_TIME
Definition: zmserver.h:54
g_webPath
std::string g_webPath
Definition: zmserver.cpp:89
ZMServer::getZMSetting
std::string getZMSetting(const std::string &setting) const
Definition: zmserver.cpp:1916
loadZMConfig
void loadZMConfig(const std::string &configfile)
Definition: zmserver.cpp:109
MONITOR::getState
int getState(void)
Definition: zmserver.cpp:458
mythburn.FILE
int FILE
Definition: mythburn.py:139
ZMServer::runCommand
static std::string runCommand(const std::string &command)
Definition: zmserver.cpp:1076
getloadavg
#define getloadavg(x, y)
Definition: compat.h:191
close
#define close
Definition: compat.h:43
tmp
static guint32 * tmp
Definition: goom_core.cpp:26
ZM_SUBPIX_ORDER_NONE
@ ZM_SUBPIX_ORDER_NONE
Definition: zmserver.cpp:75
MONITOR::m_imageBufferCount
int m_imageBufferCount
Definition: zmserver.h:281
RUNNING
const std::string RUNNING
Definition: zmserver.h:66
MONITOR::m_function
std::string m_function
Definition: zmserver.h:277
ZMServer::handleGetCameraList
void handleGetCameraList(void)
Definition: zmserver.cpp:1570
ZMServer::getMonitorList
void getMonitorList(void)
Definition: zmserver.cpp:1711
minor
#define minor(X)
Definition: compat.h:78
ERROR_FILE_OPEN
static constexpr const char * ERROR_FILE_OPEN
Definition: zmserver.cpp:64
ZMServer::getDiskSpace
static long long getDiskSpace(const std::string &filename, long long &total, long long &used)
Definition: zmserver.cpp:745
ZMServer::handleGetEventList
void handleGetEventList(std::vector< std::string > tokens)
Definition: zmserver.cpp:828
SharedData
Definition: zmserver.h:82
ERROR_MYSQL_QUERY
static constexpr const char * ERROR_MYSQL_QUERY
Definition: zmserver.cpp:62
MONITOR::m_enabled
int m_enabled
Definition: zmserver.h:278
MONITOR::getIdStr
std::string getIdStr(void)
Definition: zmserver.cpp:430
statfs
int statfs(const char *path, struct statfs *buffer)
Definition: compat.h:105
SharedData34::imagesize
uint32_t imagesize
Definition: zmserver.h:194
ERROR_TOKEN_COUNT
static constexpr const char * ERROR_TOKEN_COUNT
Definition: zmserver.cpp:61
FUNCTION_RECORD
const std::string FUNCTION_RECORD
Definition: zmserver.h:60
debug
VERBOSE_PREAMBLE Most debug(nodatabase, notimestamp, noextra)") VERBOSE_MAP(VB_GENERAL
MONITOR::m_status
std::string m_status
Definition: zmserver.h:288
ZM_SUBPIX_ORDER
ZM_SUBPIX_ORDER
Definition: zmserver.cpp:74
ZMServer::handleDeleteEvent
void handleDeleteEvent(std::vector< std::string > tokens)
Definition: zmserver.cpp:1621
ZMServer::m_sock
int m_sock
Definition: zmserver.h:345
ZMServer::handleGetFrameList
void handleGetFrameList(std::vector< std::string > tokens)
Definition: zmserver.cpp:1462
ZMServer::m_eventFileFormat
std::string m_eventFileFormat
Definition: zmserver.h:350
RESTART
const std::string RESTART
Definition: zmserver.h:64
ALERT
@ ALERT
Definition: zmserver.h:73
hardwareprofile.smolt.long
long
Definition: smolt.py:75
FUNCTION_NODECT
const std::string FUNCTION_NODECT
Definition: zmserver.h:59
VideoStoreData
Definition: zmserver.h:249
MONITOR::m_monId
int m_monId
Definition: zmserver.h:285
g_zmversion
std::string g_zmversion
Definition: zmserver.cpp:85
g_webUser
std::string g_webUser
Definition: zmserver.cpp:91
MONITOR::m_sharedImages
unsigned char * m_sharedImages
Definition: zmserver.h:286
MONITOR::m_device
std::string m_device
Definition: zmserver.h:279
ERROR_INVALID_MONITOR
static constexpr const char * ERROR_INVALID_MONITOR
Definition: zmserver.cpp:65
ZMServer::handleGetMonitorList
void handleGetMonitorList(void)
Definition: zmserver.cpp:1586
g_database
std::string g_database
Definition: zmserver.cpp:88
TriggerData
Definition: zmserver.h:226
ZMServer::handleDeleteEventList
void handleDeleteEventList(std::vector< std::string > tokens)
Definition: zmserver.cpp:1658
zmserver.h
ZMServer::sendError
void sendError(const std::string &error)
Definition: zmserver.cpp:728
ZMServer::handleGetMonitorStatus
void handleGetMonitorStatus(void)
Definition: zmserver.cpp:983
FUNCTION_MOCORD
const std::string FUNCTION_MOCORD
Definition: zmserver.h:61
MONITOR::getSubpixelOrder
int getSubpixelOrder(void)
Definition: zmserver.cpp:475
ZMServer::m_useDeepStorage
bool m_useDeepStorage
Definition: zmserver.h:348
SharedData32::format
uint8_t format
Definition: zmserver.h:155
MONITOR::m_shmPtr
void * m_shmPtr
Definition: zmserver.h:293
ZMServer::getMonitorStatus
static void getMonitorStatus(const std::string &id, const std::string &type, const std::string &device, const std::string &host, const std::string &channel, const std::string &function, std::string &zmcStatus, std::string &zmaStatus, const std::string &enabled)
Definition: zmserver.cpp:1090
ZMServer::m_monitorMap
std::map< int, MONITOR * > m_monitorMap
Definition: zmserver.h:347
bbciplayer.stderr
stderr
Definition: bbciplayer.py:199
g_dbConn
MYSQL g_dbConn
Definition: zmserver.cpp:84
checkVersion
bool checkVersion(int major, int minor, int revision)
Definition: zmserver.cpp:102
statfs::f_blocks
long f_blocks
Definition: compat.h:96
MONITOR::getFrameSize
int getFrameSize(void)
Definition: zmserver.cpp:496
g_minorVersion
int g_minorVersion
Definition: zmserver.cpp:96
MONITOR::m_bytesPerPixel
int m_bytesPerPixel
Definition: zmserver.h:284
g_binPath
std::string g_binPath
Definition: zmserver.cpp:92
g_password
std::string g_password
Definition: zmserver.cpp:86
statfs
Definition: compat.h:93
ZMServer::tokenize
static void tokenize(const std::string &command, std::vector< std::string > &tokens)
Definition: zmserver.cpp:611
TriggerData26
Definition: zmserver.h:237
g_revisionVersion
int g_revisionVersion
Definition: zmserver.cpp:97
ADD_INT
static void ADD_INT(std::string &list, int n)
Definition: zmserver.cpp:57
SharedData32
Definition: zmserver.h:138
MONITOR
Definition: zmserver.h:260
statfs::f_bsize
long f_bsize
Definition: compat.h:95
MONITOR::m_height
int m_height
Definition: zmserver.h:283
ALARM
@ ALARM
Definition: zmserver.h:72
SharedData34
Definition: zmserver.h:176
MONITOR::m_controllable
int m_controllable
Definition: zmserver.h:290
ZM_SUBPIX_ORDER_RGB
@ ZM_SUBPIX_ORDER_RGB
Definition: zmserver.cpp:76
ZMServer::handleSetMonitorFunction
void handleSetMonitorFunction(std::vector< std::string > tokens)
Definition: zmserver.cpp:1948
statfs::f_bavail
long f_bavail
Definition: compat.h:98
MONITOR::m_sharedData
SharedData * m_sharedData
Definition: zmserver.h:295
g_eventsPath
std::string g_eventsPath
Definition: zmserver.cpp:94
ZM_SUBPIX_ORDER_ABGR
@ ZM_SUBPIX_ORDER_ABGR
Definition: zmserver.cpp:80
ZMServer::m_mmapPath
std::string m_mmapPath
Definition: zmserver.h:353
FrameData
std::array< uint8_t, MAX_IMAGE_SIZE > FrameData
Definition: zmserver.h:33
ZMServer::send
bool send(const std::string &s) const
Definition: zmserver.cpp:695
MONITOR::getLastWriteIndex
int getLastWriteIndex(void)
Definition: zmserver.cpp:441
MONITOR::m_type
std::string m_type
Definition: zmserver.h:276
ZMServer::ZMServer
ZMServer(int sock, bool debug)
Definition: zmserver.cpp:515
ERROR_NO_FRAMES
static constexpr const char * ERROR_NO_FRAMES
Definition: zmserver.cpp:69
ZMServer::m_monitors
std::vector< MONITOR * > m_monitors
Definition: zmserver.h:346
SharedData34::last_write_index
uint32_t last_write_index
Definition: zmserver.h:179
kickDatabase
void kickDatabase(bool debug)
Definition: zmserver.cpp:206
SharedData32::last_write_index
uint32_t last_write_index
Definition: zmserver.h:141
build_compdb.filename
filename
Definition: build_compdb.py:21
SharedData26
Definition: zmserver.h:105
ZM_SUBPIX_ORDER_BGRA
@ ZM_SUBPIX_ORDER_BGRA
Definition: zmserver.cpp:78
ADD_STR
static void ADD_STR(std::string &list, const std::string &s)
Definition: zmserver.cpp:55
reconnect_t
my_bool reconnect_t
Definition: zmserver.cpp:178
SharedData32::state
uint32_t state
Definition: zmserver.h:143
ERROR_INVALID_MONITOR_ENABLE_VALUE
static constexpr const char * ERROR_INVALID_MONITOR_ENABLE_VALUE
Definition: zmserver.cpp:68
SharedData::last_write_index
int last_write_index
Definition: zmserver.h:89
ZMServer::~ZMServer
~ZMServer()
Definition: zmserver.cpp:588
ZMServer::processRequest
bool processRequest(char *buf, int nbytes)
Definition: zmserver.cpp:634
ERROR_INVALID_MONITOR_FUNCTION
static constexpr const char * ERROR_INVALID_MONITOR_FUNCTION
Definition: zmserver.cpp:67
g_user
std::string g_user
Definition: zmserver.cpp:90
MONITOR::m_mapFile
int m_mapFile
Definition: zmserver.h:292
SharedData26::state
uint32_t state
Definition: zmserver.h:110
ZMServer::handleGetLiveFrame
void handleGetLiveFrame(std::vector< std::string > tokens)
Definition: zmserver.cpp:1394
ZMServer::handleGetEventFrame
void handleGetEventFrame(std::vector< std::string > tokens)
Definition: zmserver.cpp:1141
ZMServer::m_debug
bool m_debug
Definition: zmserver.h:344
ERROR_MYSQL_ROW
static constexpr const char * ERROR_MYSQL_ROW
Definition: zmserver.cpp:63
connectToDatabase
void connectToDatabase(void)
Definition: zmserver.cpp:181
ZMServer::handleGetEventDates
void handleGetEventDates(std::vector< std::string > tokens)
Definition: zmserver.cpp:919
SharedData32::imagesize
uint32_t imagesize
Definition: zmserver.h:156