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