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#ifndef MSG_NOSIGNAL
47static 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
53static constexpr const char* ZM_PROTOCOL_VERSION { "11" };
54
55static inline void ADD_STR(std::string& list, const std::string& s)
56{ list += s; list += "[]:[]"; };
57static inline void ADD_INT(std::string& list, int n)
58{ list += std::to_string(n); list += "[]:[]"; };
59
60// error messages
61static constexpr const char* ERROR_TOKEN_COUNT { "Invalid token count" };
62static constexpr const char* ERROR_MYSQL_QUERY { "Mysql Query Error" };
63static constexpr const char* ERROR_MYSQL_ROW { "Mysql Get Row Error" };
64static constexpr const char* ERROR_FILE_OPEN { "Cannot open event file" };
65static constexpr const char* ERROR_INVALID_MONITOR { "Invalid Monitor" };
66static constexpr const char* ERROR_INVALID_POINTERS { "Cannot get shared memory pointers" };
67static constexpr const char* ERROR_INVALID_MONITOR_FUNCTION { "Invalid Monitor Function" };
68static constexpr const char* ERROR_INVALID_MONITOR_ENABLE_VALUE { "Invalid Monitor Enable Value" };
69static 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.
74enum ZM_SUBPIX_ORDER : std::uint8_t {
82};
83
85std::string g_zmversion;
86std::string g_password;
87std::string g_server;
88std::string g_database;
89std::string g_webPath;
90std::string g_user;
91std::string g_webUser;
92std::string g_binPath;
93std::string g_mmapPath;
94std::string g_eventsPath;
98
100
101// returns true if the ZM version >= the requested version
102bool checkVersion(int major, int minor, int revision)
103{
104 return g_majorVersion >= major &&
106 g_revisionVersion >= revision;
107}
108
109void 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
176using reconnect_t = int;
177#else
178using 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
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
233void 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 += (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 += (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 += (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
430std::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)
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
494}
495
497{
498 if (m_sharedData)
500
501 if (m_sharedData26)
503
504 if (m_sharedData32)
506
507 if (m_sharedData34)
509
510 return 0;
511}
512
514
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 {
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
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
611void 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
634bool 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")
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")
689 else
690 send("UNKNOWN_COMMAND");
691
692 return false;
693}
694
695bool 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
709bool 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
728void 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");
742 send(outStr);
743}
744
745long 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
828void 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
921void 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
1078std::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
1092void 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
1143void 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
1226void 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
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
1398void 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
1466void 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
1625void 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
1662void 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
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 {
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
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
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 }
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
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
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
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
1920std::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
1952void 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
2059void 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
2104void 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}
int getSubpixelOrder(void)
Definition: zmserver.cpp:475
SharedData * m_sharedData
Definition: zmserver.h:295
void initMonitor(bool debug, const std::string &mmapPath, int shmKey)
Definition: zmserver.cpp:233
int m_imageBufferCount
Definition: zmserver.h:281
int m_monId
Definition: zmserver.h:285
int m_trackMotion
Definition: zmserver.h:291
std::string m_device
Definition: zmserver.h:279
std::string getIdStr(void)
Definition: zmserver.cpp:430
bool isValid(void)
Definition: zmserver.cpp:414
int m_controllable
Definition: zmserver.h:290
SharedData32 * m_sharedData32
Definition: zmserver.h:297
int m_bytesPerPixel
Definition: zmserver.h:284
int m_lastRead
Definition: zmserver.h:287
SharedData26 * m_sharedData26
Definition: zmserver.h:296
int getLastWriteIndex(void)
Definition: zmserver.cpp:441
int m_enabled
Definition: zmserver.h:278
std::string m_function
Definition: zmserver.h:277
int m_mapFile
Definition: zmserver.h:292
std::string m_status
Definition: zmserver.h:288
SharedData34 * m_sharedData34
Definition: zmserver.h:298
int m_height
Definition: zmserver.h:283
int getFrameSize(void)
Definition: zmserver.cpp:496
std::string m_id
Definition: zmserver.h:299
int getState(void)
Definition: zmserver.cpp:458
void * m_shmPtr
Definition: zmserver.h:293
std::string m_type
Definition: zmserver.h:276
int m_width
Definition: zmserver.h:282
unsigned char * m_sharedImages
Definition: zmserver.h:286
bool m_debug
Definition: zmserver.h:344
void handleHello(void)
Definition: zmserver.cpp:735
std::vector< MONITOR * > m_monitors
Definition: zmserver.h:346
static std::string runCommand(const std::string &command)
Definition: zmserver.cpp:1078
void zmaControl(MONITOR *monitor, const std::string &mode)
Definition: zmserver.cpp:2104
void handleGetAlarmStates(void)
Definition: zmserver.cpp:808
key_t m_shmKey
Definition: zmserver.h:352
static long long getDiskSpace(const std::string &filename, long long &total, long long &used)
Definition: zmserver.cpp:745
void zmcControl(MONITOR *monitor, const std::string &mode)
Definition: zmserver.cpp:2059
void handleGetMonitorStatus(void)
Definition: zmserver.cpp:985
std::string getZMSetting(const std::string &setting) const
Definition: zmserver.cpp:1920
void handleGetEventDates(std::vector< std::string > tokens)
Definition: zmserver.cpp:921
std::string m_eventFileFormat
Definition: zmserver.h:350
void handleGetEventList(std::vector< std::string > tokens)
Definition: zmserver.cpp:828
static void tokenize(const std::string &command, std::vector< std::string > &tokens)
Definition: zmserver.cpp:611
bool m_useDeepStorage
Definition: zmserver.h:348
void handleSetMonitorFunction(std::vector< std::string > tokens)
Definition: zmserver.cpp:1952
void handleGetServerStatus(void)
Definition: zmserver.cpp:774
void handleGetMonitorList(void)
Definition: zmserver.cpp:1590
bool processRequest(char *buf, int nbytes)
Definition: zmserver.cpp:634
std::string m_mmapPath
Definition: zmserver.h:353
static int getFrame(FrameData &buffer, MONITOR *monitor)
Definition: zmserver.cpp:1787
void getMonitorList(void)
Definition: zmserver.cpp:1715
std::map< int, MONITOR * > m_monitorMap
Definition: zmserver.h:347
bool m_useAnalysisImages
Definition: zmserver.h:349
void handleGetAnalysisFrame(std::vector< std::string > tokens)
Definition: zmserver.cpp:1226
void handleGetEventFrame(std::vector< std::string > tokens)
Definition: zmserver.cpp:1143
void handleGetLiveFrame(std::vector< std::string > tokens)
Definition: zmserver.cpp:1398
void handleDeleteEvent(std::vector< std::string > tokens)
Definition: zmserver.cpp:1625
bool send(const std::string &s) const
Definition: zmserver.cpp:695
void handleRunZMAudit(void)
Definition: zmserver.cpp:1697
void sendError(const std::string &error)
Definition: zmserver.cpp:728
int m_sock
Definition: zmserver.h:345
ZMServer(int sock, bool debug)
Definition: zmserver.cpp:515
void handleGetFrameList(std::vector< std::string > tokens)
Definition: zmserver.cpp:1466
void handleDeleteEventList(std::vector< std::string > tokens)
Definition: zmserver.cpp:1662
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
std::string m_analysisFileFormat
Definition: zmserver.h:351
void handleGetCameraList(void)
Definition: zmserver.cpp:1574
#define getloadavg(x, y)
Definition: compat.h:190
#define close
Definition: compat.h:39
int statfs(const char *path, struct statfs *buffer)
Definition: compat.h:103
#define minor(X)
Definition: compat.h:74
static guint32 * tmp
Definition: goom_core.cpp:26
def error(message)
Definition: smolt.py:409
int FILE
Definition: mythburn.py:138
uint32_t state
Definition: zmserver.h:110
uint8_t format
Definition: zmserver.h:122
uint32_t last_write_index
Definition: zmserver.h:108
uint32_t imagesize
Definition: zmserver.h:123
uint32_t state
Definition: zmserver.h:143
uint32_t imagesize
Definition: zmserver.h:156
uint32_t last_write_index
Definition: zmserver.h:141
uint8_t format
Definition: zmserver.h:155
uint32_t imagesize
Definition: zmserver.h:194
uint8_t format
Definition: zmserver.h:193
uint32_t last_write_index
Definition: zmserver.h:179
uint32_t state
Definition: zmserver.h:181
int last_write_index
Definition: zmserver.h:89
State state
Definition: zmserver.h:88
Definition: compat.h:89
long f_blocks
Definition: compat.h:92
long f_bsize
Definition: compat.h:91
long f_bavail
Definition: compat.h:94
VERBOSE_PREAMBLE Most debug(nodatabase, notimestamp, noextra)") VERBOSE_MAP(VB_GENERAL
void loadZMConfig(const std::string &configfile)
Definition: zmserver.cpp:109
static constexpr const char * ERROR_NO_FRAMES
Definition: zmserver.cpp:69
std::string g_eventsPath
Definition: zmserver.cpp:94
TimePoint g_lastDBKick
Definition: zmserver.cpp:99
static constexpr const char * ERROR_MYSQL_QUERY
Definition: zmserver.cpp:62
static constexpr const char * ERROR_INVALID_MONITOR_FUNCTION
Definition: zmserver.cpp:67
static constexpr const char * ERROR_INVALID_MONITOR
Definition: zmserver.cpp:65
static constexpr const char * ERROR_FILE_OPEN
Definition: zmserver.cpp:64
bool checkVersion(int major, int minor, int revision)
Definition: zmserver.cpp:102
std::string g_server
Definition: zmserver.cpp:87
int g_revisionVersion
Definition: zmserver.cpp:97
static constexpr const char * ERROR_INVALID_MONITOR_ENABLE_VALUE
Definition: zmserver.cpp:68
my_bool reconnect_t
Definition: zmserver.cpp:178
static constexpr int MSG_NOSIGNAL
Definition: zmserver.cpp:47
std::string g_user
Definition: zmserver.cpp:90
std::string g_database
Definition: zmserver.cpp:88
int g_majorVersion
Definition: zmserver.cpp:95
static void ADD_INT(std::string &list, int n)
Definition: zmserver.cpp:57
std::string g_webUser
Definition: zmserver.cpp:91
static constexpr const char * ZM_PROTOCOL_VERSION
Definition: zmserver.cpp:53
void kickDatabase(bool debug)
Definition: zmserver.cpp:206
ZM_SUBPIX_ORDER
Definition: zmserver.cpp:74
@ ZM_SUBPIX_ORDER_NONE
Definition: zmserver.cpp:75
@ ZM_SUBPIX_ORDER_ABGR
Definition: zmserver.cpp:80
@ ZM_SUBPIX_ORDER_ARGB
Definition: zmserver.cpp:81
@ ZM_SUBPIX_ORDER_BGR
Definition: zmserver.cpp:77
@ ZM_SUBPIX_ORDER_RGB
Definition: zmserver.cpp:76
@ ZM_SUBPIX_ORDER_RGBA
Definition: zmserver.cpp:79
@ ZM_SUBPIX_ORDER_BGRA
Definition: zmserver.cpp:78
static constexpr const char * ERROR_TOKEN_COUNT
Definition: zmserver.cpp:61
static constexpr const char * ERROR_INVALID_POINTERS
Definition: zmserver.cpp:66
int g_minorVersion
Definition: zmserver.cpp:96
std::string g_zmversion
Definition: zmserver.cpp:85
MYSQL g_dbConn
Definition: zmserver.cpp:84
static void ADD_STR(std::string &list, const std::string &s)
Definition: zmserver.cpp:55
static constexpr const char * ERROR_MYSQL_ROW
Definition: zmserver.cpp:63
std::string g_password
Definition: zmserver.cpp:86
std::string g_webPath
Definition: zmserver.cpp:89
std::string g_mmapPath
Definition: zmserver.cpp:93
void connectToDatabase(void)
Definition: zmserver.cpp:181
std::string g_binPath
Definition: zmserver.cpp:92
const std::string FUNCTION_NODECT
Definition: zmserver.h:59
@ TAPE
Definition: zmserver.h:74
@ ALERT
Definition: zmserver.h:73
@ ALARM
Definition: zmserver.h:72
@ PREALARM
Definition: zmserver.h:71
@ IDLE
Definition: zmserver.h:70
const std::string RELOAD
Definition: zmserver.h:65
std::array< uint8_t, MAX_IMAGE_SIZE > FrameData
Definition: zmserver.h:33
const std::string RUNNING
Definition: zmserver.h:66
const std::string FUNCTION_MONITOR
Definition: zmserver.h:57
const std::string FUNCTION_MODECT
Definition: zmserver.h:58
const std::string FUNCTION_RECORD
Definition: zmserver.h:60
std::chrono::time_point< Clock > TimePoint
Definition: zmserver.h:29
const std::string FUNCTION_MOCORD
Definition: zmserver.h:61
const std::string FUNCTION_NONE
Definition: zmserver.h:62
const std::string RESTART
Definition: zmserver.h:64
static constexpr std::chrono::seconds DB_CHECK_TIME
Definition: zmserver.h:54