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