diff options
Diffstat (limited to 'src/TcpLog.cpp')
-rw-r--r-- | src/TcpLog.cpp | 330 |
1 files changed, 330 insertions, 0 deletions
diff --git a/src/TcpLog.cpp b/src/TcpLog.cpp new file mode 100644 index 0000000..7161c92 --- /dev/null +++ b/src/TcpLog.cpp @@ -0,0 +1,330 @@ +/* + Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Her Majesty the Queen in + Right of Canada (Communications Research Center Canada) + */ +/* + This file is part of CRC-DabMux. + + CRC-DabMux 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. + + CRC-DabMux 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 CRC-DabMux. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "TcpLog.h" +#include "InetAddress.h" +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> + +#ifdef _WIN32 +# include <io.h> +# +# define vsnprintf _vsnprintf +# define MSG_NOSIGNAL 0 +# define socklen_t int +#else +# include <sys/socket.h> +# include <netinet/in.h> +# include <arpa/inet.h> +# include <unistd.h> +#endif + +#include <sstream> + + +const int TcpLog::EMERG = 0; // system is unusable +const int TcpLog::ALERT = 1; // action must be taken immediately +const int TcpLog::CRIT = 2; // critical conditions +const int TcpLog::ERR = 3; // error conditions +const int TcpLog::WARNING = 4; // warning conditions +const int TcpLog::NOTICE = 5; // normal but significant condition +const int TcpLog::INFO = 6; // informational +const int TcpLog::DBG = 7; // debug-level messages + + +TcpLog::TcpLog() : listenPort(0), client(-1), name(NULL), serverThread(0), running(false) +{ + buffer = (char*)malloc(512); + bufferSize = 512; + headers = (char**)malloc(sizeof(char**)); + headers[0] = NULL; +} + + +TcpLog::~TcpLog() +{ + if (running) { + running = false; + } + if (client != -1) { + ::close(client); + } + if (headers != NULL) { + for (int count = 0; headers[count] != NULL; ++count) { + free(headers[count]); + } + free(headers); + } +} + + +//TcpLog::TcpLog(int port); + + +void TcpLog::open(const char *ident, const int option, const int port) +{ + listenPort = port; + + if (name != NULL) { + free(name); + } + name = strdup(ident); + + if (running) { + running = false; +#ifdef WIN32 + DWORD status; + for (int i = 0; i < 5; ++i) { + if (GetExitCodeThread(serverThread, &status)) { + break; + } + Sleep(100); + } + TerminateThread(serverThread, 1); +#else + pthread_join(serverThread, NULL); +#endif + } + running = true; +#ifdef _WIN32 + serverThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)listen, this, 0, NULL); + if (serverThread == NULL) { + fprintf(stderr, "Can't create TCP listen thread\n"); + } +#else + pthread_create(&serverThread, NULL, (void*(*)(void*))listen, this); +#endif +} + + +void TcpLog::printHeader(const int priority, const char *format, ...) +{ + static char last = '\n'; + std::string beginning; + std::string message; + int ret; + + + beginning = "<"; + beginning += '0' + (priority % 10); + beginning += "> "; + + va_list argp; + va_start(argp, format); + for (ret = vsnprintf(buffer, bufferSize, format, argp); + ret >= bufferSize || ret == -1; + ret = vsprintf(buffer, format, argp)) { + if (ret == -1) { + buffer = (char*)realloc(buffer, bufferSize * 2); + bufferSize *= 2; + } else { + buffer = (char*)realloc(buffer, ret + 1); + bufferSize = ret + 1; + } + } + va_end(argp); + + if (last == '\n') { + message += beginning; + } + message += buffer; + + last = buffer[ret - 1]; + + for (unsigned long pos = message.find('\n'); + pos != std::string::npos && ++pos != message.size(); + pos = message.find('\n', pos)) { + message.insert(pos, beginning); + } + + fprintf(stderr, message.c_str()); + if (client != -1) { + if (write(client, message.c_str(), message.size()) + != (int)message.size()) { + fprintf(stderr, "<6> Client closed\n"); + ::close(client); + client = -1; + } + } + + int count = 0; + while (headers[count++] != NULL) { + } + headers = (char**)realloc(headers, sizeof(char**) * (count + 1)); + headers[count - 1] = strdup(message.c_str()); + headers[count] = NULL; +} + + +void TcpLog::print(const int priority, const char *format, ...) +{ + static char last = '\n'; + std::string beginning; + std::string message; + int ret; + + + beginning = "<"; + beginning += '0' + (priority % 10); + beginning += "> "; + + va_list argp; + va_start(argp, format); + for (ret = vsnprintf(buffer, bufferSize, format, argp); + ret >= bufferSize || ret == -1; + ret = vsprintf(buffer, format, argp)) { + if (ret == -1) { + buffer = (char*)realloc(buffer, bufferSize * 2); + bufferSize *= 2; + } else { + buffer = (char*)realloc(buffer, ret + 1); + bufferSize = ret + 1; + } + } + va_end(argp); + + if (last == '\n') { + message += beginning; + } + message += buffer; + + last = buffer[ret - 1]; + + for (unsigned long pos = message.find('\n'); + pos != std::string::npos && ++pos != message.size(); + pos = message.find('\n', pos)) { + message.insert(pos, beginning); + } + + fprintf(stderr, message.c_str()); + if (client != -1) { + if (send(client, message.c_str(), message.size(), MSG_NOSIGNAL) + != (int)message.size()) { + fprintf(stderr, "<6> Client closed\n"); + ::close(client); + client = -1; + } + } +} + + +void TcpLog::close(void) +{ +} + + +void* TcpLog::listen(TcpLog* obj) +{ + int server; + struct sockaddr_in server_addr; + struct sockaddr_in client_addr; + socklen_t addrlen = sizeof(client_addr); + +#ifdef _WIN32 + WSADATA wsaData; + WORD wVersionRequested = wVersionRequested = MAKEWORD( 2, 2 ); + + int res = WSAStartup( wVersionRequested, &wsaData ); + if (res) { + fprintf(stderr, "Can't initialize winsock\n"); + ExitThread(1); + } +#endif + server = socket(PF_INET, SOCK_STREAM, 0); + if (server == INVALID_SOCKET) { +#ifdef _WIN32 + fprintf(stderr, "Can't create socket\n"); + ExitThread(1); +#else + perror("Can't create socket"); + pthread_exit(NULL); +#endif + } + + int reuse = 1; + if (setsockopt(server, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(reuse)) + == -1) { + perror("Can't set socket reusable"); + } + + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(obj->listenPort); + server_addr.sin_addr.s_addr = INADDR_ANY; + + if (bind(server, (struct sockaddr*)&server_addr, sizeof(server_addr)) + == -1) { + perror("Can't bind socket"); + fprintf(stderr, " port: %i\n", obj->listenPort); +#ifdef _WIN32 + ExitThread(1); +#else + pthread_exit(NULL); +#endif + } + + if (::listen(server, 1) == -1) { + perror("Can't listen on socket"); +#ifdef _WIN32 + ExitThread(1); +#else + pthread_exit(NULL); +#endif + } + + while (obj->running) { + int client = accept(server, (struct sockaddr*)&client_addr, &addrlen); + if (client == INVALID_SOCKET) { +#ifdef _WIN32 + if (WSAGetLastError() != WSAEINTR) { + setInetError("Can't accept client"); + fprintf(stderr, "%s: %s\n", inetErrDesc, inetErrMsg); + ExitThread(1); + } +#else + perror("Can't accept client"); + pthread_exit(NULL); +#endif + } + obj->print(INFO, "%s:%d connected\n", + inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); + if (obj->client != -1) { + ::close(obj->client); + } + obj->client = client; + for (int i = 0; obj->headers[i] != NULL; ++i) { + send(client, obj->headers[i], strlen(obj->headers[i]), MSG_NOSIGNAL); + } + } + if (obj->client != -1) { + ::close(obj->client); + obj->client = -1; + } + ::close(server); + +#ifdef _WIN32 + ExitThread(1); +#else + pthread_exit(NULL); +#endif + return NULL; +} |