16 #include <arpa/inet.h>
24 #include <netinet/in.h>
26 #include <sys/socket.h>
28 #include <sys/types.h>
37 #define ZM_CONFIG "/etc/zm/zm.conf"
40 #define ZM_OVERRIDECONFIG "/etc/zm/conf.d/01-system-paths.conf"
46 #define EXIT_INVALID_CMDLINE 132
47 #define EXIT_OPENING_LOGFILE_ERROR 136 // mapped to _PERMISSIONS_ERROR
48 #define EXIT_DAEMONIZING_ERROR 145
49 #define EXIT_SOCKET_ERROR 135
50 #define EXIT_VERSION_ERROR 136
52 int main(
int argc,
char **argv)
56 struct sockaddr_in myaddr {};
57 struct sockaddr_in remoteaddr {};
61 std::array<char,4096> buf {};
66 bool daemon_mode =
false;
73 for (
int argpos = 1; argpos < argc; ++argpos)
75 if (strcmp(argv[argpos],
"-d") == 0 ||
76 strcmp(argv[argpos],
"--daemon") == 0)
80 else if (strcmp(argv[argpos],
"-n") == 0 ||
81 strcmp(argv[argpos],
"--nodaemon") == 0)
85 else if (strcmp(argv[argpos],
"-p") == 0 ||
86 strcmp(argv[argpos],
"--port") == 0)
90 port = atoi(argv[argpos+1]);
92 if (port < 1 || port > 65534)
94 std::cout <<
"Bad port number: " << port << std::endl;
101 std::cout <<
"Missing argument to -p/--port option\n";
105 else if (strcmp(argv[argpos],
"-l") == 0 ||
106 strcmp(argv[argpos],
"--logfile") == 0)
113 std::cerr <<
"Invalid or missing argument to -l/--logfile option\n";
121 std::cerr <<
"Missing argument to -l/--logfile option\n";
125 else if (strcmp(argv[argpos],
"-c") == 0 ||
126 strcmp(argv[argpos],
"--zmconfig") == 0)
130 zmconfig = argv[argpos+1];
131 if (zmconfig[0] ==
'-')
133 std::cerr <<
"Invalid or missing argument to -c/--zmconfig option\n";
141 std::cerr <<
"Missing argument to -c/--zmconfig option\n";
145 else if (strcmp(argv[argpos],
"-o") == 0 ||
146 strcmp(argv[argpos],
"--zmoverrideconfig") == 0)
150 zmconfig = argv[argpos+1];
151 if (zmconfig[0] ==
'-')
153 std::cerr <<
"Invalid or missing argument to -o/--zmoverrideconfig option\n";
161 std::cerr <<
"Missing argument to -o/--zmoverrideconfig option\n";
165 else if (strcmp(argv[argpos],
"-v") == 0 ||
166 strcmp(argv[argpos],
"--verbose") == 0)
172 std::cerr <<
"Invalid argument: " << argv[argpos] << std::endl <<
173 "Valid options are: " << std::endl <<
174 "-p or --port number A port number to listen on (default is 6548) " << std::endl <<
175 "-d or --daemon Runs mythzmserver as a daemon " << std::endl <<
176 "-n or --nodaemon Does not run mythzmserver as a daemon (default)" << std::endl <<
177 "-c or --zmconfig Location of zoneminders default config file (default is " <<
ZM_CONFIG <<
")" << std::endl <<
178 "-o or --zmoverrideconfig Location of zoneminders override config file (default is " <<
ZM_OVERRIDECONFIG <<
")" << std::endl <<
179 "-l or --logfile filename Writes STDERR and STDOUT messages to filename" << std::endl <<
180 "-v or --verbose Prints more debug output" << std::endl;
190 logfd = open(
logfile.c_str(), O_WRONLY|O_CREAT|O_APPEND, 0664);
194 perror(
"open(logfile)");
206 if (logfd != 1 && logfd != 2)
210 if (signal(
SIGPIPE, SIG_IGN) == SIG_ERR)
211 std::cout <<
"Unable to ignore SIGPIPE\n";
218 std::cout <<
"Failed to run as a daemon. Bailing out.\n";
221 std::cout << std::endl;
224 std::map<int, ZMServer*> serverList;
235 std::cout <<
"ZM version not found. Assuming at least v1.34.16 is installed" << std::endl;
247 std::cout <<
"ZM is version '" <<
g_zmversion <<
"'" << std::endl;
251 std::cout <<
"This version of ZM is to old you need 1.24.0 or later '" <<
g_zmversion <<
"'" << std::endl;
264 if ((listener = socket(AF_INET, SOCK_STREAM, 0)) == -1)
271 if (setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes,
274 perror(
"setsockopt");
279 myaddr.sin_family = AF_INET;
280 myaddr.sin_addr.s_addr = INADDR_ANY;
281 myaddr.sin_port = htons(port);
282 memset(&(myaddr.sin_zero),
'\0', 8);
283 if (::bind(listener, (
struct sockaddr *)&myaddr,
sizeof(myaddr)) == -1)
290 if (listen(listener, 10) == -1)
296 std::cout <<
"Listening on port: " << port << std::endl;
299 FD_SET(listener, &master);
311 int res = select(fdmax+1, &read_fds,
nullptr,
nullptr, &
timeout);
327 for (
int i = 0; i <= fdmax; i++)
329 if (FD_ISSET(i, &read_fds))
335 socklen_t addrlen =
sizeof(remoteaddr);
336 if ((newfd = accept(listener,
337 (
struct sockaddr *) &remoteaddr,
345 FD_SET(newfd, &master);
353 serverList[newfd] = server;
355 printf(
"new connection from %s on socket %d\n",
356 inet_ntoa(remoteaddr.sin_addr), newfd);
362 int nbytes = recv(i, buf.data(), buf.size(), 0);
369 printf(
"socket %d hung up\n", i);
397 for (
auto & server : serverList)
398 delete server.second;