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