/*
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 .
*/
#include "TcpLog.h"
#include "InetAddress.h"
#include
#include
#include
#include
#ifdef _WIN32
# include
#
# define vsnprintf _vsnprintf
# define MSG_NOSIGNAL 0
# define socklen_t int
#else
# include
# include
# include
# include
#endif
#include
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, "%s", 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, "%s", 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;
}