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