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