/* * Copyright (c) 2017-2024 OARC, Inc. * Copyright (c) 2011-2017, IIS - The Internet Foundation in Sweden * All rights reserved. * * This file is part of PacketQ. * * PacketQ is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * PacketQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with PacketQ. If not, see . */ #include "packetq.h" #include "pcap.h" #include "reader.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MAXHOSTNAME 256 namespace packetq { namespace httpd { class Socket; class Server; static char redirect[] = "HTTP/1.1 307 Temporary Redirect\r\n" "Location: /\r\n" "Connection: close\r\n" "Content-Type: text/html\r\n" "\r\nmoved

moved

this page has moved to /"; static char header[] = "HTTP/1.1 200 OK\r\n" "Server: PacketQ builtin\r\n" "Connection: close\r\n" "Access-Control-Allow-Origin: *\r\n" "Content-Type: %s\r\n" "\r\n"; static Server* g_server = 0; class SocketPool { public: SocketPool() { m_free = 0; for (int i = 0; i < FD_SETSIZE; i++) { m_sockets[i] = 0; } m_socket_count = 0; } int add(Socket* s) { if (m_free < FD_SETSIZE) m_sockets[m_free] = s; else return -1; int idx = m_free; while (m_free < FD_SETSIZE && m_sockets[m_free]) m_free++; m_socket_count++; return idx; } void remove(int s) { m_sockets[s] = 0; if (s < m_free) m_free = s; m_socket_count--; } int get_sockets() { return m_socket_count; } void select(); fd_set m_readset; fd_set m_writeset; int m_free; int m_socket_count; Socket* m_sockets[FD_SETSIZE]; }; SocketPool g_pool; class Stream { public: class Buffer { private: Buffer& operator=(const Buffer& other); Buffer const& operator=(Buffer&& other); public: Buffer(const unsigned char* buf, int len) { m_buf = new unsigned char[len]; memcpy(m_buf, buf, len); m_len = len; m_pos = 0; } Buffer(Buffer&& other) noexcept { m_buf = other.m_buf; m_len = other.m_len; m_pos = other.m_pos; other.m_buf = 0; other.m_len = 0; other.m_pos = 0; } ~Buffer() { m_len = 0; delete[] m_buf; } unsigned char* m_buf; int m_len; int m_pos; }; Stream() { m_len = 0; } void push_front(unsigned char* data, int len) { m_stream.push_front(Buffer(data, len)); m_len += len; } void write(unsigned char* data, int len) { m_stream.push_back(Buffer(data, len)); m_len += len; } int read(unsigned char* data, int maxlen) { int p = 0; while (p < maxlen && m_len > 0) { Buffer& buf = m_stream.front(); int l = maxlen - p; if (l > buf.m_len - buf.m_pos) l = buf.m_len - buf.m_pos; for (int i = 0; i < l; i++) { data[p++] = buf.m_buf[buf.m_pos++]; } m_len -= l; if (l == 0) { m_stream.pop_front(); } } return p; } int len() { return m_len; } int get() { unsigned char c = '@'; int r = read(&c, 1); if (r == 0) return -1; return c; } private: int m_len; std::list m_stream; }; class Socket { private: Socket& operator=(const Socket& other); Socket(Socket&& other) noexcept; Socket const& operator=(Socket&& other); public: Socket(int s, bool serv) : m_want_write(false) { int flags; // Add non-blocking flag if ((flags = fcntl(s, F_GETFL)) == -1) { syslog(LOG_ERR | LOG_USER, "fcntl(%d, F_GETFL) failed: %d\n", s, errno); exit(-1); } if (fcntl(s, F_SETFL, flags | O_NONBLOCK)) { syslog(LOG_ERR | LOG_USER, "fcntl(%d, F_SETFL, 0x%x) failed: %d\n", s, errno, flags | O_NONBLOCK); exit(-1); } m_bytes_written = 0; m_bytes_read = 0; m_serv = serv; m_socket = s; m_sidx = g_pool.add(this); m_close_when_empty = false; m_file = 0; } virtual ~Socket() { g_pool.remove(m_sidx); close(m_socket); } void process(bool read) { // m_serv means this is a listening socket if (m_serv) return; if (!read) { on_write(); unsigned char ptr[4096]; int len; while ((len = m_write.read(ptr, sizeof(ptr)))) { int res = write(m_socket, ptr, len); #if EAGAIN != EWOULDBLOCK if (res == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) { #else if (res == -1 && (errno == EAGAIN)) { #endif m_write.push_front(ptr, len); set_want_write(); return; } if (res < 0) { delete this; return; } m_bytes_written += res; if (res < len) { m_write.push_front(&ptr[res], len - res); set_want_write(); return; } } if (m_close_when_empty) { shutdown(m_socket, SHUT_WR); // fflush(m_socket); delete this; } } if (read) { int avail = read_sock(); if (avail) on_read(); } } virtual void file_write() { } virtual void file_read() { } void set_delete() { m_close_when_empty = true; m_want_write = false; } virtual void on_write() { } virtual void on_read() { } int read_sock() { unsigned char buf[2000]; int len = 0; if ((len = recv(m_socket, buf, sizeof(buf) - 1, 0)) > 0) { m_bytes_read += len; buf[len] = 0; m_read.write(buf, len); } if (len < 0) { delete this; return 0; } return len; } bool failed() { return m_sidx == -1; } bool has_data() { return m_want_write || m_write.len() > 0; } void set_want_write(bool set = true) { m_want_write = set; } int m_bytes_written; int m_bytes_read; int m_socket; int m_file; int m_sidx; bool m_serv; bool m_want_write; bool m_close_when_empty; char m_buffer[4096]; Stream m_read, m_write; }; void SocketPool::select() { FD_ZERO(&m_readset); FD_ZERO(&m_writeset); int max = 0; for (int i = 0; i < FD_SETSIZE; i++) { if (m_sockets[i]) { if (max < m_sockets[i]->m_socket) max = m_sockets[i]->m_socket; FD_SET(m_sockets[i]->m_socket, &m_readset); if (m_sockets[i]->has_data()) FD_SET(m_sockets[i]->m_socket, &m_writeset); if (max < m_sockets[i]->m_file) max = m_sockets[i]->m_file; FD_SET(m_sockets[i]->m_file, &m_readset); } } timeval timeout; timeout.tv_sec = 30; timeout.tv_usec = 0; int sel = ::select(max + 1, &m_readset, &m_writeset, 0, &timeout); if (sel < 0) { syslog(LOG_ERR | LOG_USER, "sel -1 errno = %d %s max:%d", errno, strerror(errno), max); exit(-1); } if (sel) { for (int i = 0; i < FD_SETSIZE; i++) { if (m_sockets[i] && m_sockets[i]->m_file) { if (FD_ISSET(m_sockets[i]->m_file, &m_readset)) { m_sockets[i]->file_read(); } if (m_sockets[i] && FD_ISSET(m_sockets[i]->m_file, &m_writeset)) { m_sockets[i]->file_write(); } } if (m_sockets[i] && FD_ISSET(m_sockets[i]->m_socket, &m_readset)) { m_sockets[i]->process(true); } if (m_sockets[i] && FD_ISSET(m_sockets[i]->m_socket, &m_writeset)) { m_sockets[i]->process(false); } } } } class Server { public: Socket m_socket; Server(int port, const std::string& pcaproot, const std::string& webroot) : m_socket(establish(port), true) , m_pcaproot(pcaproot) , m_webroot(webroot) { if (m_socket.m_socket < 0) { if (m_socket.m_socket == EADDRINUSE) syslog(LOG_ERR | LOG_USER, "Fail EADDRINUSE (%d)\n", m_socket.m_socket); else syslog(LOG_ERR | LOG_USER, "Fail %d port:%d\n", m_socket.m_socket, port); exit(-1); } } ~Server() { } int get_connection() { int s = m_socket.m_socket; int t; /* socket of connection */ if ((t = accept(s, NULL, NULL)) < 0) /* accept connection if there is one */ return (-1); return (t); } int establish(unsigned short portnum) { int s, res; sockaddr_in sa; memset(&sa, 0, sizeof(struct sockaddr_in)); sa.sin_family = AF_INET; sa.sin_addr.s_addr = htonl(INADDR_ANY); sa.sin_port = htons(portnum); if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) return (-2); int on = 1; res = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); if ((res = bind(s, (const sockaddr*)&sa, sizeof(struct sockaddr_in))) < 0) { close(s); return (res); /* bind address to socket */ } // Add non-blocking flag int flags; if ((flags = fcntl(s, F_GETFL)) == -1) { syslog(LOG_ERR | LOG_USER, "fcntl(%d, F_GETFL) failed: %d\n", s, errno); exit(-1); } if (fcntl(s, F_SETFL, flags | O_NONBLOCK)) { syslog(LOG_ERR | LOG_USER, "fcntl(%d, F_SETFL, 0x%x) failed: %d\n", s, errno, flags | O_NONBLOCK); exit(-1); } listen(s, 511); /* max # of queued connects */ return (s); } std::string m_pcaproot; std::string m_webroot; }; class Url { public: Url(const char* url) : m_full(url) { int i = 0; for (; i < m_full.length();) { char c = m_full.c_str()[i]; if (c == '?') { i++; break; } m_path += c; i++; } m_path = decode(m_path); if (m_path == "") m_path = "/"; decode_params(m_full.substr(i).c_str()); } void decode_params(const char* params) { if (!params) return; std::string str = params; for (int i = 0; i < str.length();) { std::string param = "", value = ""; for (; i < str.length();) { char c = str.c_str()[i]; if (c == '=' || c == '&') { i++; break; } param += c; i++; } for (; i < str.length();) { char c = str.c_str()[i]; if (c == '&') { i++; break; } value += c; i++; } add_param(decode(param), decode(value)); } } const char* get_param(const char* param) { auto it = m_params.find(std::string(param)); if (it == m_params.end()) return 0; return it->second.c_str(); } void add_param(std::string key, std::string val) { auto it = m_params.find(key); if (it == m_params.end()) { m_params[key] = val; m_counts[key] = 1; return; } char cnt[100]; int n = m_counts[key]; m_counts[key] = n + 1; snprintf(cnt, sizeof(cnt) - 1, "%d", n); cnt[99] = 0; std::string keyn = key; keyn += cnt; m_params[keyn] = val; } std::string decode(std::string str) { std::string dst; int percent_state = 0; int code = 0; for (int i = 0; i < str.length(); i++) { char c = str.c_str()[i]; if (percent_state) { int n = 0; if (c >= '0' && c <= '9') n = c - '0'; if (c >= 'a' && c <= 'f') n = c - 'a' + 10; if (c >= 'A' && c <= 'F') n = c - 'A' + 10; code = (code << 4) | n; percent_state--; if (!percent_state) { dst += char(code); code = 0; } } else { if (c == '%') { percent_state = 2; } else dst += c; } } return dst; } std::string get_full() { return m_full; } std::string get_path() { return m_path; } std::string m_full; std::string m_path; std::map m_params; std::map m_counts; }; class Page { public: Page(const char* url, const char* body) : m_url(url) { m_url.decode_params(body); } void process() { if (m_url.get_path().compare("/query") == 0) { if (!m_url.get_param("file")) { printf(header, "text/plain"); printf("no file selected\n"); return; } printf(header, "text/plain"); if (m_url.get_param("sql")) query(m_url.get_param("sql")); else printf("no query defined \n"); } else if (m_url.get_path().substr(0, 8).compare("/resolve") == 0) { resolve(); } else if (m_url.get_path().substr(0, 5).compare("/list") == 0) { serve_dir(); } else { serve_static(); } delete g_app; } static std::string join_path(const std::string& a, const std::string& b) { if (b.find("..") != std::string::npos) return a; if (a.length() == 0) return b; if (b.length() == 0) return a; if (a[a.length() - 1] != '/' && b[0] != '/') return a + std::string("/") + b; return a + b; } const char* get_mimetype(const std::string& file) { int p = file.find_last_of('.'); if (p == std::string::npos || p + 1 >= file.length()) return 0; std::string suff = file.substr(p + 1); if (suff.compare("js") == 0) return "application/x-javascript"; if (suff.compare("jpg") == 0) return "image/jpeg"; if (suff.compare("html") == 0) return "text/html"; if (suff.compare("htm") == 0) return "text/html"; if (suff.compare("txt") == 0) return "text/plain"; if (suff.compare("png") == 0) return "image/png"; if (suff.compare("gif") == 0) return "image/gif"; if (suff.compare("ico") == 0) return "image/x-icon"; if (suff.compare("json") == 0) return "application/json"; if (suff.compare("css") == 0) return "text/css"; return 0; } bool serve_file(const std::string& file) { const char* mimetype = get_mimetype(file); if (mimetype) { FILE* fp = fopen(file.c_str(), "rb"); if (fp) { printf(header, mimetype); char buffer[8192]; int len; while ((len = fread(buffer, 1, 200, fp)) > 0) { fwrite(buffer, 1, len, stdout); } fclose(fp); return true; } } return false; } void serve_static() { if (g_server->m_webroot == "") { printf(header, "text/html"); printf("

This server is not configured to serve static pages

"); printf("Start using the -w option to set a html directory"); return; } std::string file = join_path(g_server->m_webroot, m_url.get_path()); if (serve_file(file)) return; if (serve_file(join_path(file, "index.html"))) return; if (m_url.get_path().compare("/") != 0) { printf("%s", redirect); return; } printf(header, "text/html"); printf("

It works !


\n"); printf("%s", "Test query
\n"); printf("%s", "list available files
\n"); } void resolve() { const char* ip = m_url.get_param("ip"); const char* name = m_url.get_param("name"); if (ip) { printf(header, "application/json"); printf("["); struct addrinfo* result; struct addrinfo* res; int error; error = getaddrinfo(ip, NULL, NULL, &result); if (error == 0) { for (res = result; res != NULL; res = res->ai_next) { char hostname[NI_MAXHOST] = ""; error = getnameinfo(res->ai_addr, res->ai_addrlen, hostname, NI_MAXHOST, NULL, 0, 0); if (error != 0) { continue; } if (*hostname != '\0') { printf("\"%s\"", hostname); break; } } freeaddrinfo(result); } printf("]\n"); } else if (name) { char tmp[100]; printf(header, "application/json"); printf("["); struct addrinfo* result; struct addrinfo* res; int error; error = getaddrinfo(name, NULL, NULL, &result); char empty[] = "", line[] = ",\n"; char* sep = empty; if (error == 0) { for (res = result; res != NULL; res = res->ai_next) { void* ptr = &((struct sockaddr_in*)res->ai_addr)->sin_addr; if (res->ai_family == AF_INET6) ptr = &((struct sockaddr_in6*)res->ai_addr)->sin6_addr; tmp[0] = 0; inet_ntop(res->ai_family, ptr, tmp, sizeof(tmp)); printf("%s\"%s\"", sep, tmp); sep = line; } freeaddrinfo(result); } printf("]\n"); } else printf("[]\n"); } void serve_dir() { if (g_server->m_pcaproot == "") { printf(header, "text/html"); printf("

This server is not configured to list pcapfiles

"); printf("Start using the -r option to set a pcap directory"); return; } std::string directory = join_path(g_server->m_pcaproot, m_url.get_path().substr(5)); DIR* dir = opendir(directory.c_str()); if (!dir) { printf("%s", redirect); return; } printf(header, "application/json"); printf("[\n"); struct dirent* d; struct stat statbuf; char comma = ' '; while ((d = readdir(dir)) != 0) { std::string subject = join_path(directory, d->d_name); int fd = open(subject.c_str(), O_RDONLY); if (fd < 0) continue; if (fstat(fd, &statbuf) == -1) { close(fd); continue; } if (S_ISDIR(statbuf.st_mode)) { if ((strcmp(d->d_name, ".") != 0) && (strcmp(d->d_name, "..") != 0)) { printf(" %c{\n \"data\" : \"%s\",\n \"attr\" : { \"id\": \"%s\" },\n \"children\" : [], \"state\" : \"closed\" }\n", comma, d->d_name, join_path(m_url.get_path(), d->d_name).substr(5).c_str()); comma = ','; } } else { bool found = false; FILE* fp = fdopen(fd, "rb"); if (fp) { Pcap_file pfile(fp); if (pfile.get_header()) { unsigned char* data = 0; int s = 0, us, len; data = pfile.get_packet(len, s, us); if (data) { printf(" %c{\n \"data\" : \"%s\",\n \"attr\" : { \"id\" : \"%s\", \"size\": %d, \"time\": %d,\"type\": \"pcap\" },\n \"children\" : [] }\n", comma, d->d_name, join_path(m_url.get_path(), d->d_name).substr(5).c_str(), int(statbuf.st_size), s); comma = ','; found = true; } } fclose(fp); } if (!found) { std::string str = subject; transform(str.begin(), str.end(), str.begin(), tolower); if (str.rfind(".json") == str.length() - 5) { printf(" %c{\n \"data\" : \"%s\",\n \"attr\" : { \"id\" : \"%s\", \"size\": %d, \"type\": \"json\" },\n \"children\" : [] }\n", comma, d->d_name, join_path(m_url.get_path(), d->d_name).substr(5).c_str(), int(statbuf.st_size)); comma = ','; } } } close(fd); } printf("]\n"); closedir(dir); } void query(const char* sql) { Query query("result", sql); query.parse(); std::vector in_files; int i = 0; while (true) { char param[50] = "file"; std::string par = "file"; if (i > 0) { snprintf(param, sizeof(param) - 1, "file%d", i); param[49] = 0; } i++; const char* f = m_url.get_param(param); if (!f) break; std::string file = join_path(g_server->m_pcaproot, f); in_files.push_back(file); } Reader reader(in_files, g_app->get_limit()); query.execute(reader); query.m_result->json(false); } Url m_url; }; class Http_socket : public Socket { private: Http_socket& operator=(const Http_socket& other); Http_socket(Http_socket&& other) noexcept; Http_socket const& operator=(Http_socket&& other); public: enum State { get_post, header, body, error, wait_child, done }; Http_socket(int socket) : Socket(socket, false) , m_http_version(0) , m_emptyline(0) { m_state = get_post; m_nextc = -1; m_cr = false; m_line = ""; m_url = ""; m_child_fd = 0; m_child_pid = 0; m_child_read = 0; m_body_cnt = -1; m_content_len = 0; } ~Http_socket() { if (m_child_pid) { kill(m_child_pid, SIGHUP); int status; waitpid(m_child_pid, &status, 0); } if (m_child_fd) close(m_child_fd); m_file = 0; } inline void print(const char* fmt, ...) { char string[4096]; va_list ap; va_start(ap, fmt); vsnprintf(string, sizeof(string), fmt, ap); va_end(ap); m_write.write((unsigned char*)string, strlen(string)); } int peek() { if (m_nextc >= 0) return m_nextc; m_nextc = m_read.get(); return m_nextc; } int getc() { int c = peek(); m_nextc = -1; return c; } void on_read() { while (true) { int c = peek(); if (c == -1) return; if (m_body_cnt >= 0) { c = getc(); if (!(m_body_cnt == 0 && c == 10)) { m_line += char(c); m_content_len--; } m_body_cnt++; if (m_content_len == 0) parseline(); continue; } c = getc(); if (c != 13 && c != 10) { m_line += char(c); m_cr = false; } else { bool cr = m_cr; m_cr = false; if (c == 10 && cr) { continue; } if (c == 13) m_cr = true; parseline(); } } } virtual void file_read() { set_want_write(); } virtual void file_write() { } void on_write() { set_want_write(false); if (m_state == wait_child) { unsigned char buffer[4096]; int status; bool done = true; if (0 == waitpid(m_child_pid, &status, WNOHANG)) { done = false; } if (m_child_fd) { // Add non-blocking flag int flags; if ((flags = fcntl(m_child_fd, F_GETFL)) == -1) { syslog(LOG_ERR | LOG_USER, "fcntl(%d, F_GETFL) failed: %d\n", m_child_fd, errno); exit(-1); } if (fcntl(m_child_fd, F_SETFL, flags | O_NONBLOCK)) { syslog(LOG_ERR | LOG_USER, "fcntl(%d, F_SETFL, 0x%x) failed: %d\n", m_child_fd, errno, flags | O_NONBLOCK); exit(-1); } size_t res; pollfd pfd; pfd.fd = m_child_fd; pfd.events = POLLIN; pfd.revents = 0; if (1 == poll(&pfd, 1, 0) && (pfd.revents & POLLIN) != 0) { if ((res = read(m_child_fd, buffer, (int)sizeof(buffer))) > 0) { done = false; m_child_read += res; m_write.write(buffer, res); } } } if (done) { m_child_pid = 0; if (m_child_fd) { close(m_child_fd); m_child_fd = 0; m_file = 0; } set_delete(); } } } void parseline() { switch (m_state) { case (get_post): { m_state = error; syslog(LOG_INFO | LOG_USER, "%s\n", m_line.c_str()); int p = 0; if (m_line.find("GET ") != -1) { if ((p = m_line.find(" HTTP/1.1")) != -1) { m_http_version = 1; } else if ((p = m_line.find(" HTTP/1.0")) != -1) { m_http_version = 0; } else { return; } m_url = m_line.substr(4, p - 4); m_state = header; } else if (m_line.find("POST ") != -1) { if ((p = m_line.find(" HTTP/1.1")) != -1) { m_http_version = 1; } else if ((p = m_line.find(" HTTP/1.0")) != -1) { m_http_version = 0; } else { return; } m_url = m_line.substr(5, p - 5); m_state = header; } } break; case (header): if (m_line.length() == 0) { m_body_cnt = 0; m_state = body; } else { int colon = m_line.find(": "); std::string key = m_line.substr(0, colon); std::string val = m_line.substr(colon + 2); if (key == "Content-Length") { if (val.length() > 0) m_content_len = atoi(val.c_str()); } } break; case (body): m_body = m_line; header_done(); break; default: printf("error line: %s !\n", m_line.c_str()); break; } m_line = ""; } void header_done() { fflush(stdout); // required before fork or any unflushed output will go to the client int fd[2]; if (pipe(fd) < 0) return; // Add non-blocking flag int flags; if ((flags = fcntl(fd[0], F_GETFL)) == -1) { syslog(LOG_ERR | LOG_USER, "fcntl(%d, F_GETFL) failed: %d\n", fd[0], errno); exit(-1); } if (fcntl(fd[0], F_SETFL, flags | O_NONBLOCK)) { syslog(LOG_ERR | LOG_USER, "fcntl(%d, F_SETFL, 0x%x) failed: %d\n", fd[0], errno, flags | O_NONBLOCK); exit(-1); } m_child_pid = fork(); if (m_child_pid < 0) { print("Internal error"); set_delete(); return; } if (m_child_pid == 0) { ////////// child code ///////// dup2(fd[1], fileno(stdout)); dup2(fd[1], fileno(stderr)); close(fd[1]); Page page(m_url.c_str(), m_body.c_str()); page.process(); fflush(stdout); exit(0); ///////////// child exit() /////////////// } else { close(fd[1]); m_child_fd = fd[0]; m_file = m_child_fd; m_state = wait_child; } set_want_write(); } State m_state; bool m_cr; int m_body_cnt; int m_content_len; int m_nextc; int m_child_pid; int m_child_fd; int m_child_read; int m_http_version; // 0 = HTTP/1.0 1 = HTTP/1.1 int m_emptyline; std::string m_line; std::string m_url; std::string m_body; }; } // namespace httpd using namespace httpd; void start_server(int port, bool fork_me, const std::string& pcaproot, const std::string& webroot, int max_conn) { pid_t pid, sid; bool fg = !fork_me; printf("listening on port %d\n", port); if (!fg) { pid = fork(); if (pid < 0) { exit(EXIT_FAILURE); } else if (pid > 0) { exit(EXIT_SUCCESS); } sid = setsid(); if (sid < 0) { exit(EXIT_FAILURE); } } openlog("packetq", LOG_PID, LOG_USER); httpd::Server server(port, pcaproot, webroot); g_server = &server; while (true) { httpd::g_pool.select(); int cnt = g_pool.get_sockets(); if (cnt < max_conn) { int c = server.get_connection(); if (c > -1) { Http_socket* s = new (std::nothrow) Http_socket(c); if (s && s->failed()) { syslog(LOG_ERR | LOG_USER, "failed to create socket"); delete s; } } } usleep(1000); } // loop will never break // g_server = 0; // syslog(LOG_INFO | LOG_USER, "exiting"); // exit(EXIT_SUCCESS); } } // namespace packetq