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