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