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