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