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