00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include <iostream>
00018 #include <cstdlib>
00019 #include <cstring>
00020 #include <cstdio>
00021 #include <errno.h>
00022 #include <sys/socket.h>
00023 #include <fcntl.h>
00024 #include <netinet/in.h>
00025 #include <sys/stat.h>
00026 #include <sys/shm.h>
00027 #include <sys/mman.h>
00028
00029 #ifdef linux
00030 # include <sys/vfs.h>
00031 # include <sys/statvfs.h>
00032 # include <sys/sysinfo.h>
00033 #else
00034 # include <sys/param.h>
00035 # include <sys/mount.h>
00036 # if CONFIG_CYGWIN
00037 # include <sys/statfs.h>
00038 # else // if !CONFIG_CYGWIN
00039 # include <sys/sysctl.h>
00040 # endif // !CONFIG_CYGWIN
00041 #endif
00042
00043 #include "mythtv/mythconfig.h"
00044
00045 #if CONFIG_DARWIN
00046 #define MSG_NOSIGNAL 0 // Apple also has SO_NOSIGPIPE?
00047 #endif
00048
00049 #include "zmserver.h"
00050
00051
00052 #define ZM_PROTOCOL_VERSION "7"
00053
00054
00055 #define MAX_IMAGE_SIZE (2048*1536*3)
00056
00057 #define ADD_STR(list,s) list += s; list += "[]:[]";
00058
00059
00060 #define ERROR_TOKEN_COUNT "Invalid token count"
00061 #define ERROR_MYSQL_QUERY "Mysql Query Error"
00062 #define ERROR_MYSQL_ROW "Mysql Get Row Error"
00063 #define ERROR_FILE_OPEN "Cannot open event file"
00064 #define ERROR_INVALID_MONITOR "Invalid Monitor"
00065 #define ERROR_INVALID_POINTERS "Cannot get shared memory pointers"
00066 #define ERROR_INVALID_MONITOR_FUNCTION "Invalid Monitor Function"
00067 #define ERROR_INVALID_MONITOR_ENABLE_VALUE "Invalid Monitor Enable Value"
00068
00069 MYSQL g_dbConn;
00070 string g_zmversion = "";
00071 string g_password = "";
00072 string g_server = "";
00073 string g_database = "";
00074 string g_webPath = "";
00075 string g_user = "";
00076 string g_webUser = "";
00077 string g_binPath = "";
00078
00079 time_t g_lastDBKick = 0;
00080
00081 void loadZMConfig(const string &configfile)
00082 {
00083 cout << "loading zm config from " << configfile << endl;
00084 FILE *cfg;
00085 char line[512];
00086 char val[250];
00087
00088 if ( (cfg = fopen(configfile.c_str(), "r")) == NULL )
00089 {
00090 fprintf(stderr,"Can't open %s\n", configfile.c_str());
00091 exit(1);
00092 }
00093
00094 while ( fgets( line, sizeof(line), cfg ) != NULL )
00095 {
00096 char *line_ptr = line;
00097
00098 size_t chomp_len = strcspn( line_ptr, "\r\n" );
00099 line_ptr[chomp_len] = '\0';
00100
00101
00102 size_t white_len = strspn( line_ptr, " \t" );
00103 line_ptr += white_len;
00104
00105
00106 if ( *line_ptr == '\0' || *line_ptr == '#' )
00107 continue;
00108
00109
00110 char *temp_ptr = line_ptr+strlen(line_ptr)-1;
00111 while ( *temp_ptr == ' ' || *temp_ptr == '\t' )
00112 {
00113 *temp_ptr-- = '\0';
00114 temp_ptr--;
00115 }
00116
00117
00118 temp_ptr = strchr( line_ptr, '=' );
00119 if ( !temp_ptr )
00120 {
00121 fprintf(stderr,"Invalid data in %s: '%s'\n", configfile.c_str(), line );
00122 continue;
00123 }
00124
00125
00126 char *name_ptr = line_ptr;
00127 char *val_ptr = temp_ptr+1;
00128
00129
00130 do
00131 {
00132 *temp_ptr = '\0';
00133 temp_ptr--;
00134 }
00135 while ( *temp_ptr == ' ' || *temp_ptr == '\t' );
00136
00137
00138 white_len = strspn( val_ptr, " \t" );
00139 val_ptr += white_len;
00140
00141 strncpy( val, val_ptr, strlen(val_ptr)+1 );
00142 if ( strcasecmp( name_ptr, "ZM_DB_HOST" ) == 0 ) g_server = val;
00143 else if ( strcasecmp( name_ptr, "ZM_DB_NAME" ) == 0 ) g_database = val;
00144 else if ( strcasecmp( name_ptr, "ZM_DB_USER" ) == 0 ) g_user = val;
00145 else if ( strcasecmp( name_ptr, "ZM_DB_PASS" ) == 0 ) g_password = val;
00146 else if ( strcasecmp( name_ptr, "ZM_PATH_WEB" ) == 0 ) g_webPath = val;
00147 else if ( strcasecmp( name_ptr, "ZM_PATH_BIN" ) == 0 ) g_binPath = val;
00148 else if ( strcasecmp( name_ptr, "ZM_WEB_USER" ) == 0 ) g_webUser = val;
00149 else if ( strcasecmp( name_ptr, "ZM_VERSION" ) == 0 ) g_zmversion = val;
00150 }
00151 fclose(cfg);
00152 }
00153
00154 void connectToDatabase(void)
00155 {
00156 if (!mysql_init(&g_dbConn))
00157 {
00158 cout << "Error: Can't initialise structure: " << mysql_error(&g_dbConn) << endl;
00159 exit(mysql_errno(&g_dbConn));
00160 }
00161
00162 if (!mysql_real_connect(&g_dbConn, g_server.c_str(), g_user.c_str(),
00163 g_password.c_str(), 0, 0, 0, 0))
00164 {
00165 cout << "Error: Can't connect to server: " << mysql_error(&g_dbConn) << endl;
00166 exit(mysql_errno( &g_dbConn));
00167 }
00168
00169 if (mysql_select_db(&g_dbConn, g_database.c_str()))
00170 {
00171 cout << "Error: Can't select database: " << mysql_error(&g_dbConn) << endl;
00172 exit(mysql_errno(&g_dbConn));
00173 }
00174 }
00175
00176 void kickDatabase(bool debug)
00177 {
00178 if (time(NULL) < g_lastDBKick + DB_CHECK_TIME)
00179 return;
00180
00181 if (debug)
00182 cout << "Kicking database connection" << endl;
00183
00184 g_lastDBKick = time(NULL);
00185
00186 if (mysql_query(&g_dbConn, "SELECT NULL;") == 0)
00187 {
00188 MYSQL_RES *res = mysql_store_result(&g_dbConn);
00189 if (res)
00190 mysql_free_result(res);
00191 return;
00192 }
00193
00194 cout << "Lost connection to DB - trying to reconnect" << endl;
00195
00196
00197 mysql_close(&g_dbConn);
00198 connectToDatabase();
00199 }
00200
00201 ZMServer::ZMServer(int sock, bool debug)
00202 {
00203 if (debug)
00204 cout << "Using server protocol version '" << ZM_PROTOCOL_VERSION << "'\n";
00205
00206 m_sock = sock;
00207 m_debug = debug;
00208
00209
00210 char buf[100];
00211 m_shmKey = 0x7a6d2000;
00212 string setting = getZMSetting("ZM_SHM_KEY");
00213
00214 if (setting != "")
00215 sscanf(setting.c_str(), "%20x", (unsigned int *)&m_shmKey);
00216 if (m_debug)
00217 {
00218 snprintf(buf, sizeof(buf), "0x%x", (unsigned int)m_shmKey);
00219 cout << "Shared memory key is: " << buf << endl;
00220 }
00221
00222
00223 m_mmapPath = getZMSetting("ZM_PATH_MAP");
00224 if (m_debug)
00225 {
00226 cout << "Memory path directory is: " << m_mmapPath << endl;
00227 }
00228
00229
00230 setting = getZMSetting("ZM_EVENT_IMAGE_DIGITS");
00231 int eventDigits = atoi(setting.c_str());
00232 snprintf(buf, sizeof(buf), "%%0%dd-capture.jpg", eventDigits);
00233 m_eventFileFormat = buf;
00234 if (m_debug)
00235 cout << "Event file format is: " << m_eventFileFormat << endl;
00236
00237
00238 snprintf(buf, sizeof(buf), "%%0%dd-analyse.jpg", eventDigits);
00239 m_analyseFileFormat = buf;
00240 if (m_debug)
00241 cout << "Analyse file format is: " << m_analyseFileFormat << endl;
00242
00243
00244 m_useDeepStorage = (getZMSetting("ZM_USE_DEEP_STORAGE") == "1");
00245 if (m_debug)
00246 {
00247 if (m_useDeepStorage)
00248 cout << "using deep storage directory structure" << endl;
00249 else
00250 cout << "using flat directory structure" << endl;
00251 }
00252
00253 getMonitorList();
00254 }
00255
00256 ZMServer::~ZMServer()
00257 {
00258 if (m_debug)
00259 cout << "ZMServer destroyed\n";
00260 }
00261
00262 void ZMServer::tokenize(const string &command, vector<string> &tokens)
00263 {
00264 string token = "";
00265 tokens.clear();
00266 string::size_type startPos = 0;
00267 string::size_type endPos = 0;
00268
00269 while((endPos = command.find("[]:[]", startPos)) != string::npos)
00270 {
00271 token = command.substr(startPos, endPos - startPos);
00272 tokens.push_back(token);
00273 startPos = endPos + 5;
00274 }
00275
00276
00277 if (endPos != command.length())
00278 {
00279 token = command.substr(startPos);
00280 tokens.push_back(token);
00281 }
00282 }
00283
00284 void ZMServer::processRequest(char* buf, int nbytes)
00285 {
00286 #if 0
00287
00288 char len[9];
00289 memcpy(len, buf, 8);
00290 len[8] = '\0';
00291 int dataLen = atoi(len);
00292 #endif
00293
00294 buf[nbytes] = '\0';
00295 string s(buf+8);
00296 vector<string> tokens;
00297 tokenize(s, tokens);
00298
00299 if (tokens.empty())
00300 return;
00301
00302 if (m_debug)
00303 cout << "Processing: '" << tokens[0] << "'" << endl;
00304
00305 if (tokens[0] == "HELLO")
00306 handleHello();
00307 else if (tokens[0] == "GET_SERVER_STATUS")
00308 handleGetServerStatus();
00309 else if (tokens[0] == "GET_MONITOR_STATUS")
00310 handleGetMonitorStatus();
00311 else if (tokens[0] == "GET_EVENT_LIST")
00312 handleGetEventList(tokens);
00313 else if (tokens[0] == "GET_EVENT_DATES")
00314 handleGetEventDates(tokens);
00315 else if (tokens[0] == "GET_EVENT_FRAME")
00316 handleGetEventFrame(tokens);
00317 else if (tokens[0] == "GET_ANALYSE_FRAME")
00318 handleGetAnalyseFrame(tokens);
00319 else if (tokens[0] == "GET_LIVE_FRAME")
00320 handleGetLiveFrame(tokens);
00321 else if (tokens[0] == "GET_FRAME_LIST")
00322 handleGetFrameList(tokens);
00323 else if (tokens[0] == "GET_CAMERA_LIST")
00324 handleGetCameraList();
00325 else if (tokens[0] == "GET_MONITOR_LIST")
00326 handleGetMonitorList();
00327 else if (tokens[0] == "DELETE_EVENT")
00328 handleDeleteEvent(tokens);
00329 else if (tokens[0] == "DELETE_EVENT_LIST")
00330 handleDeleteEventList(tokens);
00331 else if (tokens[0] == "RUN_ZMAUDIT")
00332 handleRunZMAudit();
00333 else if (tokens[0] == "SET_MONITOR_FUNCTION")
00334 handleSetMonitorFunction(tokens);
00335 else
00336 send("UNKNOWN_COMMAND");
00337 }
00338
00339 bool ZMServer::send(const string s) const
00340 {
00341
00342 uint32_t len = s.size();
00343 char buf[9];
00344 sprintf(buf, "%8d", len);
00345 int status = ::send(m_sock, buf, 8, MSG_NOSIGNAL);
00346 if (status == -1)
00347 return false;
00348
00349
00350 status = ::send(m_sock, s.c_str(), s.size(), MSG_NOSIGNAL);
00351 if ( status == -1 )
00352 return false;
00353 else
00354 return true;
00355 }
00356
00357 bool ZMServer::send(const string s, const unsigned char *buffer, int dataLen) const
00358 {
00359
00360 uint32_t len = s.size();
00361 char buf[9];
00362 sprintf(buf, "%8d", len);
00363 int status = ::send(m_sock, buf, 8, MSG_NOSIGNAL);
00364 if (status == -1)
00365 return false;
00366
00367
00368 status = ::send(m_sock, s.c_str(), s.size(), MSG_NOSIGNAL);
00369 if ( status == -1 )
00370 return false;
00371
00372
00373 status = ::send(m_sock, buffer, dataLen, MSG_NOSIGNAL);
00374 if ( status == -1 )
00375 return false;
00376
00377 return true;
00378 }
00379
00380 void ZMServer::sendError(string error)
00381 {
00382 string outStr("");
00383 ADD_STR(outStr, string("ERROR - ") + error);
00384 send(outStr);
00385 }
00386
00387 void ZMServer::handleHello()
00388 {
00389
00390
00391 string outStr("");
00392 ADD_STR(outStr, "OK");
00393 ADD_STR(outStr, ZM_PROTOCOL_VERSION);
00394 send(outStr);
00395 }
00396
00397 long long ZMServer::getDiskSpace(const string &filename, long long &total, long long &used)
00398 {
00399 struct statfs statbuf;
00400 memset(&statbuf, 0, sizeof(statbuf));
00401 long long freespace = -1;
00402
00403 total = used = -1;
00404
00405
00406
00407
00408
00409 if ((statfs(filename.c_str(), &statbuf) == 0) &&
00410 (statbuf.f_blocks > 0) &&
00411 (statbuf.f_bsize > 0))
00412 {
00413 total = statbuf.f_blocks;
00414 total *= statbuf.f_bsize;
00415 total = total >> 10;
00416
00417 freespace = statbuf.f_bavail;
00418 freespace *= statbuf.f_bsize;
00419 freespace = freespace >> 10;
00420
00421 used = total - freespace;
00422 }
00423
00424 return freespace;
00425 }
00426
00427 void ZMServer::handleGetServerStatus(void)
00428 {
00429 string outStr("");
00430 ADD_STR(outStr, "OK")
00431
00432
00433 string status = runCommand(g_binPath + "/zmdc.pl check");
00434 ADD_STR(outStr, status)
00435
00436
00437 double loads[3];
00438 if (getloadavg(loads, 3) == -1)
00439 {
00440 ADD_STR(outStr, "Unknown")
00441 }
00442 else
00443 {
00444 char buf[30];
00445 sprintf(buf, "%0.2lf", loads[0]);
00446 ADD_STR(outStr, buf)
00447 }
00448
00449
00450 char buf[15];
00451 long long total, used;
00452 string eventsDir = g_webPath + "/events/";
00453 getDiskSpace(eventsDir, total, used);
00454 sprintf(buf, "%d%%", (int) ((100.0 / ((float) total / used))));
00455 ADD_STR(outStr, buf)
00456
00457 send(outStr);
00458 }
00459
00460 void ZMServer::handleGetEventList(vector<string> tokens)
00461 {
00462 string outStr("");
00463
00464 if (tokens.size() != 4)
00465 {
00466 sendError(ERROR_TOKEN_COUNT);
00467 return;
00468 }
00469
00470 string monitor = tokens[1];
00471 bool oldestFirst = (tokens[2] == "1");
00472 string date = tokens[3];
00473
00474 if (m_debug)
00475 cout << "Loading events for monitor: " << monitor << ", date: " << date << endl;
00476
00477 ADD_STR(outStr, "OK")
00478
00479 MYSQL_RES *res;
00480 MYSQL_ROW row;
00481
00482 string sql("SELECT E.Id, E.Name, M.Id AS MonitorID, M.Name AS MonitorName, E.StartTime, "
00483 "E.Length, M.Width, M.Height, M.DefaultRate, M.DefaultScale "
00484 "from Events as E inner join Monitors as M on E.MonitorId = M.Id ");
00485
00486 if (monitor != "<ANY>")
00487 {
00488 sql += "WHERE M.Name = '" + monitor + "' ";
00489
00490 if (date != "<ANY>")
00491 sql += "AND DATE(E.StartTime) = DATE('" + date + "') ";
00492 }
00493 else
00494 {
00495 if (date != "<ANY>")
00496 sql += "WHERE DATE(E.StartTime) = DATE('" + date + "') ";
00497 }
00498
00499 if (oldestFirst)
00500 sql += "ORDER BY E.StartTime ASC";
00501 else
00502 sql += "ORDER BY E.StartTime DESC";
00503
00504 if (mysql_query(&g_dbConn, sql.c_str()))
00505 {
00506 fprintf(stderr, "%s\n", mysql_error(&g_dbConn));
00507 sendError(ERROR_MYSQL_QUERY);
00508 return;
00509 }
00510
00511 res = mysql_store_result(&g_dbConn);
00512 int eventCount = mysql_num_rows(res);
00513
00514 if (m_debug)
00515 cout << "Got " << eventCount << " events" << endl;
00516
00517 char str[10];
00518 sprintf(str, "%d", eventCount);
00519 ADD_STR(outStr, str)
00520
00521 for (int x = 0; x < eventCount; x++)
00522 {
00523 row = mysql_fetch_row(res);
00524 if (row)
00525 {
00526 ADD_STR(outStr, row[0])
00527 ADD_STR(outStr, row[1])
00528 ADD_STR(outStr, row[2])
00529 ADD_STR(outStr, row[3])
00530 row[4][10] = 'T';
00531 ADD_STR(outStr, row[4])
00532 ADD_STR(outStr, row[5])
00533 }
00534 else
00535 {
00536 cout << "Failed to get mysql row" << endl;
00537 sendError(ERROR_MYSQL_ROW);
00538 return;
00539 }
00540 }
00541
00542 mysql_free_result(res);
00543
00544 send(outStr);
00545 }
00546
00547 void ZMServer::handleGetEventDates(vector<string> tokens)
00548 {
00549 string outStr("");
00550
00551 if (tokens.size() != 3)
00552 {
00553 sendError(ERROR_TOKEN_COUNT);
00554 return;
00555 }
00556
00557 string monitor = tokens[1];
00558 bool oldestFirst = (tokens[2] == "1");
00559
00560 if (m_debug)
00561 cout << "Loading event dates for monitor: " << monitor << endl;
00562
00563 ADD_STR(outStr, "OK")
00564
00565 MYSQL_RES *res;
00566 MYSQL_ROW row;
00567
00568 string sql("SELECT DISTINCT DATE(E.StartTime) "
00569 "from Events as E inner join Monitors as M on E.MonitorId = M.Id ");
00570
00571 if (monitor != "<ANY>")
00572 sql += "WHERE M.Name = '" + monitor + "' ";
00573
00574 if (oldestFirst)
00575 sql += "ORDER BY E.StartTime ASC";
00576 else
00577 sql += "ORDER BY E.StartTime DESC";
00578
00579 if (mysql_query(&g_dbConn, sql.c_str()))
00580 {
00581 fprintf(stderr, "%s\n", mysql_error(&g_dbConn));
00582 sendError(ERROR_MYSQL_QUERY);
00583 return;
00584 }
00585
00586 res = mysql_store_result(&g_dbConn);
00587 int dateCount = mysql_num_rows(res);
00588
00589 if (m_debug)
00590 cout << "Got " << dateCount << " dates" << endl;
00591
00592 char str[10];
00593 sprintf(str, "%d", dateCount);
00594 ADD_STR(outStr, str)
00595
00596 for (int x = 0; x < dateCount; x++)
00597 {
00598 row = mysql_fetch_row(res);
00599 if (row)
00600 {
00601 ADD_STR(outStr, row[0])
00602 }
00603 else
00604 {
00605 cout << "Failed to get mysql row" << endl;
00606 sendError(ERROR_MYSQL_ROW);
00607 return;
00608 }
00609 }
00610
00611 mysql_free_result(res);
00612
00613 send(outStr);
00614 }
00615
00616 void ZMServer::handleGetMonitorStatus(void)
00617 {
00618 string outStr("");
00619 ADD_STR(outStr, "OK")
00620
00621
00622 MYSQL_RES *res;
00623 MYSQL_ROW row;
00624
00625 string sql("SELECT Id, Name, Type, Device, Host, Channel, Function, Enabled "
00626 "FROM Monitors;");
00627 if (mysql_query(&g_dbConn, sql.c_str()))
00628 {
00629 fprintf(stderr, "%s\n", mysql_error(&g_dbConn));
00630 sendError(ERROR_MYSQL_QUERY);
00631 return;
00632 }
00633
00634 res = mysql_store_result(&g_dbConn);
00635
00636
00637 int monitorCount = mysql_num_rows(res);
00638
00639 if (m_debug)
00640 cout << "Got " << monitorCount << " monitors" << endl;
00641
00642 char str[10];
00643 sprintf(str, "%d", monitorCount);
00644 ADD_STR(outStr, str)
00645
00646 for (int x = 0; x < monitorCount; x++)
00647 {
00648 row = mysql_fetch_row(res);
00649 if (row)
00650 {
00651 string id = row[0];
00652 string type = row[2];
00653 string device = row[3];
00654 string host = row[4];
00655 string channel = row[5];
00656 string function = row[6];
00657 string enabled = row[7];
00658 string name = row[1];
00659 string events = "";
00660 string zmcStatus = "";
00661 string zmaStatus = "";
00662 getMonitorStatus(id, type, device, host, channel, function,
00663 zmcStatus, zmaStatus, enabled);
00664 MYSQL_RES *res2;
00665 MYSQL_ROW row2;
00666
00667 string sql2("SELECT count(if(Archived=0,1,NULL)) AS EventCount "
00668 "FROM Events AS E "
00669 "WHERE MonitorId = " + id);
00670
00671 if (mysql_query(&g_dbConn, sql2.c_str()))
00672 {
00673 fprintf(stderr, "%s\n", mysql_error(&g_dbConn));
00674 sendError(ERROR_MYSQL_QUERY);
00675 return;
00676 }
00677
00678 res2 = mysql_store_result(&g_dbConn);
00679 if (mysql_num_rows(res2) > 0)
00680 {
00681 row2 = mysql_fetch_row(res2);
00682 if (row2)
00683 events = row2[0];
00684 else
00685 {
00686 cout << "Failed to get mysql row" << endl;
00687 sendError(ERROR_MYSQL_ROW);
00688 return;
00689 }
00690 }
00691
00692 ADD_STR(outStr, id)
00693 ADD_STR(outStr, name)
00694 ADD_STR(outStr, zmcStatus)
00695 ADD_STR(outStr, zmaStatus)
00696 ADD_STR(outStr, events)
00697 ADD_STR(outStr, function)
00698 ADD_STR(outStr, enabled)
00699
00700 mysql_free_result(res2);
00701 }
00702 else
00703 {
00704 cout << "Failed to get mysql row" << endl;
00705 sendError(ERROR_MYSQL_ROW);
00706 return;
00707 }
00708 }
00709
00710 mysql_free_result(res);
00711
00712 send(outStr);
00713 }
00714
00715 string ZMServer::runCommand(string command)
00716 {
00717 string outStr("");
00718 FILE *fd = popen(command.c_str(), "r");
00719 char buffer[100];
00720
00721 while (fgets(buffer, sizeof(buffer), fd) != NULL)
00722 {
00723 outStr += buffer;
00724 }
00725 pclose(fd);
00726 return outStr;
00727 }
00728
00729 void ZMServer::getMonitorStatus(string id, string type, string device, string host, string channel,
00730 string function, string &zmcStatus, string &zmaStatus,
00731 string enabled)
00732 {
00733 zmaStatus = "";
00734 zmcStatus = "";
00735
00736 string command(g_binPath + "/zmdc.pl status");
00737 string status = runCommand(command);
00738
00739 if (type == "Local")
00740 {
00741 if (enabled == "0")
00742 zmaStatus = device + "(" + channel + ") [-]";
00743 else if (status.find("'zma -m " + id + "' running") != string::npos)
00744 zmaStatus = device + "(" + channel + ") [R]";
00745 else
00746 zmaStatus = device + "(" + channel + ") [S]";
00747 }
00748 else
00749 {
00750 if (enabled == "0")
00751 zmaStatus = host + " [-]";
00752 else if (status.find("'zma -m " + id + "' running") != string::npos)
00753 zmaStatus = host + " [R]";
00754 else
00755 zmaStatus = host + " [S]";
00756 }
00757
00758 if (type == "Local")
00759 {
00760 if (enabled == "0")
00761 zmcStatus = function + " [-]";
00762 else if (status.find("'zmc -d "+ device + "' running") != string::npos)
00763 zmcStatus = function + " [R]";
00764 else
00765 zmcStatus = function + " [S]";
00766 }
00767 else
00768 {
00769 if (enabled == "0")
00770 zmcStatus = function + " [-]";
00771 else if (status.find("'zmc -m " + id + "' running") != string::npos)
00772 zmcStatus = function + " [R]";
00773 else
00774 zmcStatus = function + " [S]";
00775 }
00776 }
00777
00778 void ZMServer::handleGetEventFrame(vector<string> tokens)
00779 {
00780 static unsigned char buffer[MAX_IMAGE_SIZE];
00781
00782 if (tokens.size() != 5)
00783 {
00784 sendError(ERROR_TOKEN_COUNT);
00785 return;
00786 }
00787
00788 string monitorID(tokens[1]);
00789 string eventID(tokens[2]);
00790 int frameNo = atoi(tokens[3].c_str());
00791 string eventTime(tokens[4]);
00792
00793 if (m_debug)
00794 cout << "Getting frame " << frameNo << " for event " << eventID
00795 << " on monitor " << monitorID << " event time is " << eventTime << endl;
00796
00797 string outStr("");
00798
00799 ADD_STR(outStr, "OK")
00800
00801
00802 string filepath("");
00803 char str[100];
00804
00805 if (m_useDeepStorage)
00806 {
00807 filepath = g_webPath + "/events/" + monitorID + "/" + eventTime + "/";
00808 sprintf(str, m_eventFileFormat.c_str(), frameNo);
00809 filepath += str;
00810 }
00811 else
00812 {
00813 filepath = g_webPath + "/events/" + monitorID + "/" + eventID + "/";
00814 sprintf(str, m_eventFileFormat.c_str(), frameNo);
00815 filepath += str;
00816 }
00817
00818 FILE *fd;
00819 int fileSize = 0;
00820 if ((fd = fopen(filepath.c_str(), "r" )))
00821 {
00822 fileSize = fread(buffer, 1, sizeof(buffer), fd);
00823 fclose(fd);
00824 }
00825 else
00826 {
00827 cout << "Can't open " << filepath << ": " << strerror(errno) << endl;
00828 sendError(ERROR_FILE_OPEN + string(" - ") + filepath + " : " + strerror(errno));
00829 return;
00830 }
00831
00832 if (m_debug)
00833 cout << "Frame size: " << fileSize << endl;
00834
00835
00836 sprintf(str, "%d", fileSize);
00837 ADD_STR(outStr, str)
00838
00839
00840 send(outStr, buffer, fileSize);
00841 }
00842
00843 void ZMServer::handleGetAnalyseFrame(vector<string> tokens)
00844 {
00845 static unsigned char buffer[MAX_IMAGE_SIZE];
00846 char str[100];
00847
00848 if (tokens.size() != 5)
00849 {
00850 sendError(ERROR_TOKEN_COUNT);
00851 return;
00852 }
00853
00854 string monitorID(tokens[1]);
00855 string eventID(tokens[2]);
00856 int frameNo = atoi(tokens[3].c_str());
00857 string eventTime(tokens[4]);
00858
00859 if (m_debug)
00860 cout << "Getting anaylse frame " << frameNo << " for event " << eventID
00861 << " on monitor " << monitorID << " event time is " << eventTime << endl;
00862
00863
00864 MYSQL_RES *res;
00865 MYSQL_ROW row = NULL;
00866
00867 string sql("");
00868 sql += "SELECT FrameId FROM Frames ";
00869 sql += "WHERE EventID = " + eventID + " ";
00870 sql += "AND Type = 'Alarm' ";
00871 sql += "ORDER BY FrameID";
00872
00873 if (mysql_query(&g_dbConn, sql.c_str()))
00874 {
00875 fprintf(stderr, "%s\n", mysql_error(&g_dbConn));
00876 sendError(ERROR_MYSQL_QUERY);
00877 return;
00878 }
00879
00880 res = mysql_store_result(&g_dbConn);
00881 int frameCount = mysql_num_rows(res);
00882 int frameID;
00883
00884
00885 if (frameNo == 0 || frameNo < 0 || frameNo > frameCount)
00886 frameNo = (frameCount / 2) + 1;
00887
00888
00889 for (int x = 0; x < frameNo; x++)
00890 {
00891 row = mysql_fetch_row(res);
00892 }
00893
00894 if (row)
00895 {
00896 frameID = atoi(row[0]);
00897 }
00898 else
00899 {
00900 cout << "handleGetAnalyseFrame: Failed to get mysql row for frameNo " << frameNo << endl;
00901 sendError(ERROR_MYSQL_ROW);
00902 return;
00903 }
00904
00905 string outStr("");
00906
00907 ADD_STR(outStr, "OK")
00908
00909
00910 string filepath("");
00911 if (m_useDeepStorage)
00912 {
00913 filepath = g_webPath + "/events/" + monitorID + "/" + eventTime + "/";
00914 sprintf(str, m_analyseFileFormat.c_str(), frameID);
00915 filepath += str;
00916 }
00917 else
00918 {
00919 filepath = g_webPath + "/events/" + monitorID + "/" + eventID + "/";
00920 sprintf(str, m_analyseFileFormat.c_str(), frameID);
00921 filepath += str;
00922 }
00923
00924 FILE *fd;
00925 int fileSize = 0;
00926 if ((fd = fopen(filepath.c_str(), "r" )))
00927 {
00928 fileSize = fread(buffer, 1, sizeof(buffer), fd);
00929 fclose(fd);
00930 }
00931 else
00932 {
00933 cout << "Can't open " << filepath << ": " << strerror(errno) << endl;
00934 sendError(ERROR_FILE_OPEN + string(" - ") + filepath + " : " + strerror(errno));
00935 return;
00936 }
00937
00938 if (m_debug)
00939 cout << "Frame size: " << fileSize << endl;
00940
00941
00942 sprintf(str, "%d", fileSize);
00943 ADD_STR(outStr, str)
00944
00945
00946 send(outStr, buffer, fileSize);
00947 }
00948
00949 void ZMServer::handleGetLiveFrame(vector<string> tokens)
00950 {
00951 static unsigned char buffer[MAX_IMAGE_SIZE];
00952 char str[100];
00953
00954
00955
00956
00957
00958 kickDatabase(m_debug);
00959
00960 if (tokens.size() != 2)
00961 {
00962 sendError(ERROR_TOKEN_COUNT);
00963 return;
00964 }
00965
00966 int monitorID = atoi(tokens[1].c_str());
00967
00968 if (m_debug)
00969 cout << "Getting live frame from monitor: " << monitorID << endl;
00970
00971 string outStr("");
00972
00973 ADD_STR(outStr, "OK")
00974
00975
00976 sprintf(str, "%d", monitorID);
00977 ADD_STR(outStr, str)
00978
00979
00980 MONITOR *monitor;
00981 if (m_monitors.find(monitorID) != m_monitors.end())
00982 monitor = m_monitors[monitorID];
00983 else
00984 {
00985 sendError(ERROR_INVALID_MONITOR);
00986 return;
00987 }
00988
00989
00990 if (monitor->shared_data == NULL || monitor->shared_images == NULL)
00991 {
00992 sendError(ERROR_INVALID_POINTERS);
00993 return;
00994 }
00995
00996
00997 int dataSize = getFrame(buffer, sizeof(buffer), monitor);
00998
00999 if (m_debug)
01000 cout << "Frame size: " << dataSize << endl;
01001
01002 if (dataSize == 0)
01003 {
01004
01005 outStr = "";
01006 ADD_STR(outStr, "WARNING - No new frame available");
01007 send(outStr);
01008 return;
01009 }
01010
01011
01012 ADD_STR(outStr, monitor->status)
01013
01014
01015 sprintf(str, "%d", dataSize);
01016 ADD_STR(outStr, str)
01017
01018
01019 send(outStr, buffer, dataSize);
01020 }
01021
01022 void ZMServer::handleGetFrameList(vector<string> tokens)
01023 {
01024 string eventID;
01025 string outStr("");
01026
01027 if (tokens.size() != 2)
01028 {
01029 sendError(ERROR_TOKEN_COUNT);
01030 return;
01031 }
01032
01033 eventID = tokens[1];
01034
01035 if (m_debug)
01036 cout << "Loading frames for event: " << eventID << endl;
01037
01038 ADD_STR(outStr, "OK")
01039
01040 MYSQL_RES *res;
01041 MYSQL_ROW row;
01042
01043 string sql("");
01044 sql += "SELECT Type, Delta FROM Frames ";
01045 sql += "WHERE EventID = " + eventID + " ";
01046 sql += "ORDER BY FrameID";
01047
01048 if (mysql_query(&g_dbConn, sql.c_str()))
01049 {
01050 fprintf(stderr, "%s\n", mysql_error(&g_dbConn));
01051 sendError(ERROR_MYSQL_QUERY);
01052 return;
01053 }
01054
01055 res = mysql_store_result(&g_dbConn);
01056 int frameCount = mysql_num_rows(res);
01057
01058 if (m_debug)
01059 cout << "Got " << frameCount << " frames" << endl;
01060
01061 char str[10];
01062 sprintf(str, "%d\n", frameCount);
01063 ADD_STR(outStr, str)
01064
01065 for (int x = 0; x < frameCount; x++)
01066 {
01067 row = mysql_fetch_row(res);
01068 if (row)
01069 {
01070 ADD_STR(outStr, row[0])
01071 ADD_STR(outStr, row[1])
01072 }
01073 else
01074 {
01075 cout << "handleGetFrameList: Failed to get mysql row " << x << endl;
01076 sendError(ERROR_MYSQL_ROW);
01077 return;
01078 }
01079 }
01080
01081 mysql_free_result(res);
01082
01083 send(outStr);
01084 }
01085
01086 void ZMServer::handleGetCameraList(void)
01087 {
01088 string outStr("");
01089
01090 ADD_STR(outStr, "OK")
01091
01092 MYSQL_RES *res;
01093 MYSQL_ROW row;
01094
01095 string sql("");
01096 sql += "SELECT DISTINCT M.Name FROM Events AS E ";
01097 sql += "INNER JOIN Monitors AS M ON E.MonitorId = M.Id;";
01098
01099 if (mysql_query(&g_dbConn, sql.c_str()))
01100 {
01101 fprintf(stderr, "%s\n", mysql_error(&g_dbConn));
01102 sendError(ERROR_MYSQL_QUERY);
01103 return;
01104 }
01105
01106 res = mysql_store_result(&g_dbConn);
01107 int monitorCount = mysql_num_rows(res);
01108 char str[10];
01109 sprintf(str, "%d", monitorCount);
01110 ADD_STR(outStr, str)
01111
01112 for (int x = 0; x < monitorCount; x++)
01113 {
01114 row = mysql_fetch_row(res);
01115 if (row)
01116 {
01117 ADD_STR(outStr, row[0])
01118 }
01119 else
01120 {
01121 cout << "handleGetCameraList: Failed to get mysql row " << x << endl;
01122 sendError(ERROR_MYSQL_ROW);
01123 return;
01124 }
01125 }
01126
01127 mysql_free_result(res);
01128
01129 send(outStr);
01130 }
01131
01132 void ZMServer::handleGetMonitorList(void)
01133 {
01134 string outStr("");
01135
01136 ADD_STR(outStr, "OK")
01137
01138 MYSQL_RES *res;
01139 MYSQL_ROW row;
01140
01141 string sql("");
01142 sql += "SELECT Id, Name, Width, Height, Palette FROM Monitors ORDER BY Id";
01143
01144 if (mysql_query(&g_dbConn, sql.c_str()))
01145 {
01146 fprintf(stderr, "%s\n", mysql_error(&g_dbConn));
01147 sendError(ERROR_MYSQL_QUERY);
01148 return;
01149 }
01150
01151 res = mysql_store_result(&g_dbConn);
01152 int monitorCount = mysql_num_rows(res);
01153
01154 if (m_debug)
01155 cout << "Got " << monitorCount << " monitors" << endl;
01156
01157 char str[10];
01158 sprintf(str, "%d", monitorCount);
01159 ADD_STR(outStr, str)
01160
01161 for (int x = 0; x < monitorCount; x++)
01162 {
01163 row = mysql_fetch_row(res);
01164 if (row)
01165 {
01166 ADD_STR(outStr, row[0])
01167 ADD_STR(outStr, row[1])
01168 ADD_STR(outStr, row[2])
01169 ADD_STR(outStr, row[3])
01170 ADD_STR(outStr, row[4])
01171
01172 if (m_debug)
01173 {
01174 cout << "id: " << row[0] << endl;
01175 cout << "name: " << row[1] << endl;
01176 cout << "width: " << row[2] << endl;
01177 cout << "height: " << row[3] << endl;
01178 cout << "palette: " << row[4] << endl;
01179 cout << "-------------------" << endl;
01180 }
01181 }
01182 else
01183 {
01184 cout << "Failed to get mysql row" << endl;
01185 sendError(ERROR_MYSQL_ROW);
01186 return;
01187 }
01188 }
01189
01190 mysql_free_result(res);
01191
01192 send(outStr);
01193 }
01194
01195 void ZMServer::handleDeleteEvent(vector<string> tokens)
01196 {
01197 string eventID;
01198 string outStr("");
01199
01200 if (tokens.size() != 2)
01201 {
01202 sendError(ERROR_TOKEN_COUNT);
01203 return;
01204 }
01205
01206 eventID = tokens[1];
01207
01208 if (m_debug)
01209 cout << "Deleting event: " << eventID << endl;
01210
01211 ADD_STR(outStr, "OK")
01212
01213 string sql("");
01214 sql += "DELETE FROM Events WHERE Id = " + eventID;
01215
01216 if (mysql_query(&g_dbConn, sql.c_str()))
01217 {
01218 fprintf(stderr, "%s\n", mysql_error(&g_dbConn));
01219 sendError(ERROR_MYSQL_QUERY);
01220 return;
01221 }
01222
01223
01224 string command(g_binPath + "/zmaudit.pl &");
01225 errno = 0;
01226 if (system(command.c_str()) < 0 && errno)
01227 cerr << "Failed to run '" << command << "'" << endl;
01228
01229 send(outStr);
01230 }
01231
01232 void ZMServer::handleDeleteEventList(vector<string> tokens)
01233 {
01234 string eventList("");
01235 string outStr("");
01236
01237 vector<string>::iterator it = tokens.begin();
01238 if (it != tokens.end())
01239 ++it;
01240 while (it != tokens.end())
01241 {
01242 if (eventList == "")
01243 eventList = (*it);
01244 else
01245 eventList += "," + (*it);
01246
01247 ++it;
01248 }
01249
01250 if (m_debug)
01251 cout << "Deleting events: " << eventList << endl;
01252
01253 string sql("");
01254 sql += "DELETE FROM Events WHERE Id IN (" + eventList + ")";
01255
01256 if (mysql_query(&g_dbConn, sql.c_str()))
01257 {
01258 fprintf(stderr, "%s\n", mysql_error(&g_dbConn));
01259 sendError(ERROR_MYSQL_QUERY);
01260 return;
01261 }
01262
01263 ADD_STR(outStr, "OK")
01264 send(outStr);
01265 }
01266
01267 void ZMServer::handleRunZMAudit(void)
01268 {
01269 string outStr("");
01270
01271
01272 string command(g_binPath + "/zmaudit.pl &");
01273
01274 if (m_debug)
01275 cout << "Running command: " << command << endl;
01276
01277 errno = 0;
01278 if (system(command.c_str()) < 0 && errno)
01279 cerr << "Failed to run '" << command << "'" << endl;
01280
01281 ADD_STR(outStr, "OK")
01282 send(outStr);
01283 }
01284
01285 void ZMServer::getMonitorList(void)
01286 {
01287 m_monitors.clear();
01288
01289 string sql("SELECT Id, Name, Width, Height, ImageBufferCount, MaxFPS, Palette, ");
01290 sql += " Type, Function, Enabled, Device, Host, Controllable, TrackMotion ";
01291 sql += "FROM Monitors";
01292
01293 MYSQL_RES *res;
01294 MYSQL_ROW row;
01295
01296 if (mysql_query(&g_dbConn, sql.c_str()))
01297 {
01298 fprintf(stderr, "%s\n", mysql_error(&g_dbConn));
01299 return;
01300 }
01301
01302 res = mysql_store_result(&g_dbConn);
01303 int monitorCount = mysql_num_rows(res);
01304
01305 if (m_debug)
01306 cout << "Got " << monitorCount << " monitors" << endl;
01307
01308 for (int x = 0; x < monitorCount; x++)
01309 {
01310 row = mysql_fetch_row(res);
01311 if (row)
01312 {
01313 MONITOR *m = new MONITOR;
01314 m->mon_id = atoi(row[0]);
01315 m->name = row[1];
01316 m->width = atoi(row[2]);
01317 m->height = atoi(row[3]);
01318 m->image_buffer_count = atoi(row[4]);
01319 m->palette = atoi(row[6]);
01320 m->type = row[7];
01321 m->function = row[8];
01322 m->enabled = atoi(row[9]);
01323 m->device = row[10];
01324 m->host = row[11];
01325 m->controllable = atoi(row[12]);
01326 m->trackMotion = atoi(row[13]);
01327 m_monitors[m->mon_id] = m;
01328
01329 initMonitor(m);
01330 }
01331 else
01332 {
01333 cout << "Failed to get mysql row" << endl;
01334 return;
01335 }
01336 }
01337
01338 mysql_free_result(res);
01339 }
01340
01341 void ZMServer::initMonitor(MONITOR *monitor)
01342 {
01343 void *shm_ptr = NULL;
01344
01345 monitor->shared_data = NULL;
01346 monitor->shared_images = NULL;
01347
01348 if (monitor->palette == 1)
01349 monitor->frame_size = monitor->width * monitor->height;
01350 else
01351 monitor->frame_size = monitor->width * monitor->height * 3;
01352
01353 int shared_data_size;
01354
01355 if (g_zmversion == "1.22.2")
01356 shared_data_size = sizeof(SharedData) +
01357 sizeof(TriggerData_old) +
01358 ((monitor->image_buffer_count) * (sizeof(struct timeval))) +
01359 ((monitor->image_buffer_count) * monitor->frame_size);
01360 else
01361 shared_data_size = sizeof(SharedData) +
01362 sizeof(TriggerData) +
01363 ((monitor->image_buffer_count) * (sizeof(struct timeval))) +
01364 ((monitor->image_buffer_count) * monitor->frame_size);
01365
01366
01367 #if _POSIX_MAPPED_FILES > 0L
01368
01369
01370
01371
01372 stringstream mmap_filename;
01373 mmap_filename << m_mmapPath << "/zm.mmap." << monitor->mon_id;
01374
01375 int mapFile = open(mmap_filename.str().c_str(), O_RDONLY, 0x0);
01376 if (mapFile >= 0)
01377 {
01378 if (m_debug)
01379 cout << "Opened mmap file: " << mmap_filename << endl;
01380
01381 shm_ptr = mmap(NULL, shared_data_size, PROT_READ,
01382 MAP_SHARED, mapFile, 0x0);
01383 if (shm_ptr == NULL)
01384 {
01385 cout << "Failed to map shared memory from file [" <<
01386 mmap_filename << "] " <<
01387 "for monitor: " <<
01388 monitor->mon_id <<
01389 endl;
01390 monitor->status = "Error";
01391 return;
01392 }
01393 }
01394 #endif
01395
01396 if (shm_ptr == NULL)
01397 {
01398
01399 int shmid;
01400
01401 if ((shmid = shmget((m_shmKey & 0xffffff00) | monitor->mon_id,
01402 shared_data_size, SHM_R)) == -1)
01403 {
01404 cout << "Failed to shmget for monitor: " << monitor->mon_id << endl;
01405 monitor->status = "Error";
01406 switch(errno)
01407 {
01408 case EACCES: cout << "EACCES - no rights to access segment\n"; break;
01409 case EEXIST: cout << "EEXIST - segment already exists\n"; break;
01410 case EINVAL: cout << "EINVAL - size < SHMMIN or size > SHMMAX\n"; break;
01411 case ENFILE: cout << "ENFILE - limit on open files has been reached\n"; break;
01412 case ENOENT: cout << "ENOENT - no segment exists for the given key\n"; break;
01413 case ENOMEM: cout << "ENOMEM - couldn't reserve memory for segment\n"; break;
01414 case ENOSPC: cout << "ENOSPC - shmmni or shmall limit reached\n"; break;
01415 }
01416
01417 return;
01418 }
01419
01420 shm_ptr = shmat(shmid, 0, SHM_RDONLY);
01421
01422
01423 if (shm_ptr == NULL)
01424 {
01425 cout << "Failed to shmat for monitor: " << monitor->mon_id << endl;
01426 monitor->status = "Error";
01427 return;
01428 }
01429 }
01430
01431 monitor->shared_data = (SharedData*)shm_ptr;
01432
01433 if (g_zmversion == "1.22.2")
01434 monitor->shared_images = (unsigned char*) shm_ptr +
01435 sizeof(SharedData) +
01436 sizeof(TriggerData_old) +
01437 ((monitor->image_buffer_count) * sizeof(struct timeval));
01438 else
01439 monitor->shared_images = (unsigned char*) shm_ptr +
01440 sizeof(SharedData) +
01441 sizeof(TriggerData) +
01442 ((monitor->image_buffer_count) * sizeof(struct timeval));
01443 }
01444
01445 int ZMServer::getFrame(unsigned char *buffer, int bufferSize, MONITOR *monitor)
01446 {
01447 (void) bufferSize;
01448
01449
01450 if (monitor->shared_data->last_write_index == monitor->last_read)
01451 return 0;
01452
01453
01454 if (monitor->shared_data->last_write_index < 0 ||
01455 monitor->shared_data->last_write_index >= monitor->image_buffer_count)
01456 return 0;
01457
01458 monitor->last_read = monitor->shared_data->last_write_index;
01459
01460 switch (monitor->shared_data->state)
01461 {
01462 case IDLE:
01463 monitor->status = "Idle";
01464 break;
01465 case PREALARM:
01466 monitor->status = "Pre Alarm";
01467 break;
01468 case ALARM:
01469 monitor->status = "Alarm";
01470 break;
01471 case ALERT:
01472 monitor->status = "Alert";
01473 break;
01474 case TAPE:
01475 monitor->status = "Tape";
01476 break;
01477 default:
01478 monitor->status = "Unknown";
01479 break;
01480 }
01481
01482 unsigned char *data = monitor->shared_images +
01483 monitor->frame_size * monitor->last_read;
01484
01485
01486
01487 memcpy(buffer, data, monitor->frame_size);
01488
01489
01490 return monitor->frame_size;
01491 }
01492
01493 string ZMServer::getZMSetting(const string &setting)
01494 {
01495 string result;
01496 string sql("SELECT Name, Value FROM Config ");
01497 sql += "WHERE Name = '" + setting + "'";
01498
01499 MYSQL_RES *res;
01500 MYSQL_ROW row;
01501
01502 if (mysql_query(&g_dbConn, sql.c_str()))
01503 {
01504 fprintf(stderr, "%s\n", mysql_error(&g_dbConn));
01505 return "";
01506 }
01507
01508 res = mysql_store_result(&g_dbConn);
01509 row = mysql_fetch_row(res);
01510 if (row)
01511 {
01512 result = row[1];
01513 }
01514 else
01515 {
01516 cout << "Failed to get mysql row" << endl;
01517 result = "";
01518 }
01519
01520 if (m_debug)
01521 cout << "getZMSetting: " << setting << " Result: " << result << endl;
01522
01523 mysql_free_result(res);
01524
01525 return result;
01526 }
01527
01528 void ZMServer::handleSetMonitorFunction(vector<string> tokens)
01529 {
01530 string outStr("");
01531
01532 if (tokens.size() != 4)
01533 {
01534 sendError(ERROR_TOKEN_COUNT);
01535 return;
01536 }
01537
01538 string monitorID(tokens[1]);
01539 string function(tokens[2]);
01540 string enabled(tokens[3]);
01541
01542
01543 if (m_monitors.find(atoi(monitorID.c_str())) == m_monitors.end())
01544 {
01545 sendError(ERROR_INVALID_MONITOR);
01546 return;
01547 }
01548
01549 if (function != FUNCTION_NONE && function != FUNCTION_MONITOR &&
01550 function != FUNCTION_MODECT && function != FUNCTION_NODECT &&
01551 function != FUNCTION_RECORD && function != FUNCTION_MOCORD)
01552 {
01553 sendError(ERROR_INVALID_MONITOR_FUNCTION);
01554 return;
01555 }
01556
01557 if (enabled != "0" && enabled != "1")
01558 {
01559 sendError(ERROR_INVALID_MONITOR_ENABLE_VALUE);
01560 return;
01561 }
01562
01563 if (m_debug)
01564 cout << "User input validated OK" << endl;
01565
01566
01567
01568 MONITOR *monitor = m_monitors[atoi(monitorID.c_str())];
01569 string oldFunction = monitor->function;
01570 string newFunction = function;
01571 int oldEnabled = monitor->enabled;
01572 int newEnabled = atoi(enabled.c_str());
01573 monitor->function = newFunction;
01574 monitor->enabled = newEnabled;
01575
01576 if (m_debug)
01577 cout << "SetMonitorFunction MonitorId: " << monitorID << endl <<
01578 " oldEnabled: " << oldEnabled << endl <<
01579 " newEnabled: " << newEnabled << endl <<
01580 " oldFunction: " << oldFunction << endl <<
01581 " newFunction: " << newFunction << endl;
01582
01583 if ( newFunction != oldFunction || newEnabled != oldEnabled)
01584 {
01585 string sql("UPDATE Monitors ");
01586 sql += "SET Function = '" + function + "', ";
01587 sql += "Enabled = '" + enabled + "' ";
01588 sql += "WHERE Id = '" + monitorID + "'";
01589
01590 if (mysql_query(&g_dbConn, sql.c_str()))
01591 {
01592 fprintf(stderr, "%s\n", mysql_error(&g_dbConn));
01593 sendError(ERROR_MYSQL_QUERY);
01594 return;
01595 }
01596
01597 if (m_debug)
01598 cout << "Monitor function SQL update OK" << endl;
01599
01600 string status = runCommand(g_binPath + "/zmdc.pl check");
01601
01602
01603 if (RUNNING.compare(0, RUNNING.size(), status, 0, RUNNING.size()) == 0)
01604 {
01605 if (m_debug)
01606 cout << "Monitor function Refreshing daemons" << endl;
01607
01608 bool restart = (oldFunction == FUNCTION_NONE) ||
01609 (newFunction == FUNCTION_NONE) ||
01610 (newEnabled != oldEnabled);
01611
01612 if (restart)
01613 zmcControl(monitor, RESTART);
01614 else
01615 zmcControl(monitor, "");
01616 zmaControl(monitor, RELOAD);
01617 }
01618 else
01619 if (m_debug)
01620 cout << "zm daemons are not running" << endl;
01621 }
01622 else
01623 cout << "Not updating monitor function as identical to existing configuration" << endl;
01624
01625 ADD_STR(outStr, "OK")
01626 send(outStr);
01627 }
01628
01629 void ZMServer::zmcControl(MONITOR *monitor, const string &mode)
01630 {
01631 string zmcArgs = "";
01632 string sql = "";
01633 sql += "SELECT count(if(Function!='None',1,NULL)) as ActiveCount ";
01634 sql += "FROM Monitors ";
01635
01636 if (monitor->type == "Local" )
01637 {
01638 sql += "WHERE Device = '" + monitor->device + "'";
01639 zmcArgs = "-d " + monitor->device;
01640 }
01641 else
01642 {
01643 sql += "WHERE Id = '" + monitor->getIdStr() + "'";
01644 zmcArgs = "-m " + monitor->mon_id;
01645 }
01646
01647 if (mysql_query(&g_dbConn, sql.c_str()))
01648 {
01649 fprintf(stderr, "%s\n", mysql_error(&g_dbConn));
01650 sendError(ERROR_MYSQL_QUERY);
01651 return;
01652 }
01653
01654 MYSQL_RES *res;
01655 MYSQL_ROW row;
01656 int activeCount;
01657
01658 res = mysql_store_result(&g_dbConn);
01659 row = mysql_fetch_row(res);
01660
01661 if (row)
01662 activeCount = atoi(row[0]);
01663 else
01664 {
01665 sendError(ERROR_MYSQL_QUERY);
01666 return;
01667 }
01668
01669 if (!activeCount)
01670 runCommand(g_binPath + "/zmdc.pl stop zmc " + zmcArgs);
01671 else
01672 {
01673 if (mode == RESTART)
01674 runCommand(g_binPath + "/zmdc.pl stop zmc " + zmcArgs);
01675
01676 runCommand(g_binPath + "/zmdc.pl start zmc " + zmcArgs);
01677 }
01678 }
01679
01680 void ZMServer::zmaControl(MONITOR *monitor, const string &mode)
01681 {
01682 int zmOptControl = atoi(getZMSetting("ZM_OPT_CONTROL").c_str());
01683 int zmOptFrameServer = atoi(getZMSetting("ZM_OPT_FRAME_SERVER").c_str());
01684
01685 if (monitor->function == FUNCTION_MODECT ||
01686 monitor->function == FUNCTION_RECORD ||
01687 monitor->function == FUNCTION_MOCORD ||
01688 monitor->function == FUNCTION_NODECT)
01689 {
01690 if (mode == RESTART)
01691 {
01692 if (zmOptControl)
01693 runCommand(g_binPath + "/zmdc.pl stop zmtrack.pl -m " + monitor->getIdStr());
01694
01695 runCommand(g_binPath + "/zmdc.pl stop zma -m " + monitor->getIdStr());
01696
01697 if (zmOptFrameServer)
01698 runCommand(g_binPath + "/zmdc.pl stop zmf -m " + monitor->getIdStr());
01699 }
01700
01701 if (zmOptFrameServer)
01702 runCommand(g_binPath + "/zmdc.pl start zmf -m " + monitor->getIdStr());
01703
01704 runCommand(g_binPath + "/zmdc.pl start zma -m " + monitor->getIdStr());
01705
01706 if (zmOptControl && monitor->controllable && monitor->trackMotion &&
01707 ( monitor->function == FUNCTION_MODECT || monitor->function == FUNCTION_MOCORD) )
01708 runCommand(g_binPath + "/zmdc.pl start zmtrack.pl -m " + monitor->getIdStr());
01709
01710 if (mode == RELOAD)
01711 runCommand(g_binPath + "/zmdc.pl reload zma -m " + monitor->getIdStr());
01712 }
01713 else
01714 {
01715 if (zmOptControl)
01716 runCommand(g_binPath + "/zmdc.pl stop zmtrack.pl -m " + monitor->getIdStr());
01717
01718 runCommand(g_binPath + "/zmdc.pl stop zma -m " + monitor->getIdStr());
01719
01720 if (zmOptFrameServer)
01721 runCommand(g_binPath + "/zmdc.pl stop zmf -m " + monitor->getIdStr());
01722 }
01723 }