Bug 542207 - ssltunnel: clean up and update logging and make it optional, r=ted, a=test-only-change

This commit is contained in:
Honza Bambas 2010-10-25 18:47:23 +02:00
Родитель 2ae655ca5e
Коммит 5df1da2ced
1 изменённых файлов: 164 добавлений и 95 удалений

Просмотреть файл

@ -51,8 +51,10 @@
#include <string>
#include <vector>
#include <algorithm>
#include <stdarg.h>
#include "prinit.h"
#include "prerror.h"
#include "prenv.h"
#include "prio.h"
#include "prnetdb.h"
#include "prtpool.h"
@ -71,6 +73,68 @@ using std::vector;
#define SET_DELIM(m, c) ((m)[(c) >> 3] |= (1 << ((c) & 7)))
#define DELIM_TABLE_SIZE 32
// You can set the level of logging by env var SSLTUNNEL_LOG_LEVEL=n, where n
// is 0 through 3. The default is 1, INFO level logging.
enum LogLevel {
LEVEL_DEBUG = 0,
LEVEL_INFO = 1,
LEVEL_ERROR = 2,
LEVEL_SILENT = 3
} gLogLevel, gLastLogLevel;
#define _LOG_OUTPUT(level, func, params) \
PR_BEGIN_MACRO \
if (level >= gLogLevel) { \
gLastLogLevel = level; \
func params;\
} \
PR_END_MACRO
// The most verbose output
#define LOG_DEBUG(params) \
_LOG_OUTPUT(LEVEL_DEBUG, printf, params)
// Top level informative messages
#define LOG_INFO(params) \
_LOG_OUTPUT(LEVEL_INFO, printf, params)
// Serious errors that must be logged always until completely gag
#define LOG_ERROR(params) \
_LOG_OUTPUT(LEVEL_ERROR, eprintf, params)
// Same as LOG_ERROR, but when logging is set to LEVEL_DEBUG, the message
// will be put to the stdout instead of stderr to keep continuity with other
// LOG_DEBUG message output
#define LOG_ERRORD(params) \
PR_BEGIN_MACRO \
if (gLogLevel == LEVEL_DEBUG) \
_LOG_OUTPUT(LEVEL_ERROR, printf, params); \
else \
_LOG_OUTPUT(LEVEL_ERROR, eprintf, params); \
PR_END_MACRO
// If there is any output written between LOG_BEGIN_BLOCK() and
// LOG_END_BLOCK() then a new line will be put to the proper output (out/err)
#define LOG_BEGIN_BLOCK() \
gLastLogLevel = LEVEL_SILENT;
#define LOG_END_BLOCK() \
PR_BEGIN_MACRO \
if (gLastLogLevel == LEVEL_ERROR) \
LOG_ERROR(("\n")); \
if (gLastLogLevel < LEVEL_ERROR) \
_LOG_OUTPUT(gLastLogLevel, printf, ("\n")); \
PR_END_MACRO
int eprintf(const char* str, ...)
{
va_list ap;
va_start(ap, str);
int result = vfprintf(stderr, str, ap);
va_end(ap);
return result;
}
// Copied from nsCRT
char* strtok2(char* string, const char* delims, char* *newStr)
{
@ -264,19 +328,19 @@ bool ReadConnectRequest(server_info_t* server_info,
client_auth_option* clientauth, string& host)
{
if (buffer.present() < 4) {
printf(" !! only %d bytes present in the buffer", (int)buffer.present());
LOG_DEBUG((" !! only %d bytes present in the buffer", (int)buffer.present()));
return false;
}
if (strncmp(buffer.buffertail-4, "\r\n\r\n", 4)) {
printf(" !! request is not tailed with CRLFCRLF but with %x %x %x %x",
*(buffer.buffertail-4),
*(buffer.buffertail-3),
*(buffer.buffertail-2),
*(buffer.buffertail-1));
LOG_ERRORD((" !! request is not tailed with CRLFCRLF but with %x %x %x %x",
*(buffer.buffertail-4),
*(buffer.buffertail-3),
*(buffer.buffertail-2),
*(buffer.buffertail-1)));
return false;
}
printf(" parsing initial connect request, dump:\n%.*s\n", (int)buffer.present(), buffer.bufferhead);
LOG_DEBUG((" parsing initial connect request, dump:\n%.*s\n", (int)buffer.present(), buffer.bufferhead));
*result = 400;
@ -284,11 +348,11 @@ bool ReadConnectRequest(server_info_t* server_info,
char* _caret;
token = strtok2(buffer.bufferhead, " ", &_caret);
if (!token) {
printf(" no space found");
LOG_ERRORD((" no space found"));
return true;
}
if (strcmp(token, "CONNECT")) {
printf(" not CONNECT request but %s", token);
LOG_ERRORD((" not CONNECT request but %s", token));
return true;
}
@ -308,7 +372,7 @@ bool ReadConnectRequest(server_info_t* server_info,
token = strtok2(_caret, "/", &_caret);
if (strcmp(token, "HTTP")) {
printf(" not tailed with HTTP but with %s", token);
LOG_ERRORD((" not tailed with HTTP but with %s", token));
return true;
}
@ -324,26 +388,26 @@ bool ConfigureSSLServerSocket(PRFileDesc* socket, server_info_t* si, string &cer
AutoCert cert(PK11_FindCertFromNickname(
certnick, NULL));
if (!cert) {
fprintf(stderr, "Failed to find cert %s\n", certnick);
LOG_ERROR(("Failed to find cert %s\n", certnick));
return false;
}
AutoKey privKey(PK11_FindKeyByAnyCert(cert, NULL));
if (!privKey) {
fprintf(stderr, "Failed to find private key\n");
LOG_ERROR(("Failed to find private key\n"));
return false;
}
PRFileDesc* ssl_socket = SSL_ImportFD(NULL, socket);
if (!ssl_socket) {
fprintf(stderr, "Error importing SSL socket\n");
LOG_ERROR(("Error importing SSL socket\n"));
return false;
}
SSLKEAType certKEA = NSS_FindCertKEAType(cert);
if (SSL_ConfigSecureServer(ssl_socket, cert, privKey, certKEA)
!= SECSuccess) {
fprintf(stderr, "Error configuring SSL server socket\n");
LOG_ERROR(("Error configuring SSL server socket\n"));
return false;
}
@ -480,7 +544,7 @@ bool AdjustRequestURI(relayBuffer& buffer, string *host)
// Cannot use strnchr so add a null char at the end. There is always some space left
// because we preserve a margin.
buffer.buffertail[1] = '\0';
printf(" incoming request to adjust:\n%s\n", buffer.bufferhead);
LOG_DEBUG((" incoming request to adjust:\n%s\n", buffer.bufferhead));
char *token, *path;
path = strchr(buffer.bufferhead, ' ') + 1;
@ -545,10 +609,10 @@ void HandleConnection(void* data)
client_auth_option clientAuth;
string fullHost;
printf("SSLTUNNEL(%p): incoming connection csock(0)=%p, ssock(1)=%p\n",
LOG_DEBUG(("SSLTUNNEL(%p)): incoming connection csock(0)=%p, ssock(1)=%p\n",
static_cast<void*>(data),
static_cast<void*>(ci->client_sock),
static_cast<void*>(other_sock));
static_cast<void*>(other_sock)));
if (other_sock)
{
PRInt32 numberOfSockets = 1;
@ -577,17 +641,17 @@ void HandleConnection(void* data)
{
sockets[0].in_flags |= PR_POLL_EXCEPT;
sockets[1].in_flags |= PR_POLL_EXCEPT;
printf("SSLTUNNEL(%p): polling flags csock(0)=%c%c, ssock(1)=%c%c\n",
static_cast<void*>(data),
sockets[0].in_flags & PR_POLL_READ ? 'R' : '-',
sockets[0].in_flags & PR_POLL_WRITE ? 'W' : '-',
sockets[1].in_flags & PR_POLL_READ ? 'R' : '-',
sockets[1].in_flags & PR_POLL_WRITE ? 'W' : '-');
LOG_DEBUG(("SSLTUNNEL(%p)): polling flags csock(0)=%c%c, ssock(1)=%c%c\n",
static_cast<void*>(data),
sockets[0].in_flags & PR_POLL_READ ? 'R' : '-',
sockets[0].in_flags & PR_POLL_WRITE ? 'W' : '-',
sockets[1].in_flags & PR_POLL_READ ? 'R' : '-',
sockets[1].in_flags & PR_POLL_WRITE ? 'W' : '-'));
PRInt32 pollStatus = PR_Poll(sockets, numberOfSockets, PR_MillisecondsToInterval(1000));
if (pollStatus < 0)
{
printf("SSLTUNNEL(%p): pollStatus=%d, exiting\n",
static_cast<void*>(data), pollStatus);
LOG_DEBUG(("SSLTUNNEL(%p)): pollStatus=%d, exiting\n",
static_cast<void*>(data), pollStatus));
client_error = true;
break;
}
@ -595,8 +659,8 @@ void HandleConnection(void* data)
if (pollStatus == 0)
{
// timeout
printf("SSLTUNNEL(%p): poll timeout, looping\n",
static_cast<void*>(data));
LOG_DEBUG(("SSLTUNNEL(%p)): poll timeout, looping\n",
static_cast<void*>(data)));
continue;
}
@ -608,15 +672,16 @@ void HandleConnection(void* data)
PRInt16 &in_flags2 = sockets[s2].in_flags;
sockets[s].out_flags = 0;
printf("SSLTUNNEL(%p): %csock(%d)=%p out_flags=%d",
static_cast<void*>(data),
s == 0 ? 'c' : 's',
s,
static_cast<void*>(sockets[s].fd),
out_flags);
LOG_BEGIN_BLOCK();
LOG_DEBUG(("SSLTUNNEL(%p)): %csock(%d)=%p out_flags=%d",
static_cast<void*>(data),
s == 0 ? 'c' : 's',
s,
static_cast<void*>(sockets[s].fd),
out_flags));
if (out_flags & (PR_POLL_EXCEPT | PR_POLL_ERR | PR_POLL_HUP))
{
printf(" :exception\n");
LOG_DEBUG((" :exception\n"));
client_error = true;
socketErrorState[s] = PR_TRUE;
// We got a fatal error state on the socket. Clear the output buffer
@ -628,19 +693,19 @@ void HandleConnection(void* data)
if (out_flags & PR_POLL_READ && !buffers[s].free())
{
printf(" no place in read buffer but got read flag, dropping it now!");
LOG_DEBUG((" no place in read buffer but got read flag, dropping it now!"));
in_flags &= ~PR_POLL_READ;
}
if (out_flags & PR_POLL_READ && buffers[s].free())
{
printf(" :reading");
LOG_DEBUG((" :reading"));
PRInt32 bytesRead = PR_Recv(sockets[s].fd, buffers[s].buffertail,
buffers[s].free(), 0, PR_INTERVAL_NO_TIMEOUT);
if (bytesRead == 0)
{
printf(" socket gracefully closed");
LOG_DEBUG((" socket gracefully closed"));
client_done = true;
in_flags &= ~PR_POLL_READ;
}
@ -648,7 +713,7 @@ void HandleConnection(void* data)
{
if (PR_GetError() != PR_WOULD_BLOCK_ERROR)
{
printf(" error=%d", PR_GetError());
LOG_DEBUG((" error=%d", PR_GetError()));
// We are in error state, indicate that the connection was
// not closed gracefully
client_error = true;
@ -657,7 +722,7 @@ void HandleConnection(void* data)
buffers[s2].bufferhead = buffers[s2].buffertail = buffers[s2].buffer;
}
else
printf(" would block");
LOG_DEBUG((" would block"));
}
else
{
@ -665,12 +730,12 @@ void HandleConnection(void* data)
// throw this data away and continue loop
if (socketErrorState[s2])
{
printf(" have read but other socket is in error state\n");
LOG_DEBUG((" have read but other socket is in error state\n"));
continue;
}
buffers[s].buffertail += bytesRead;
printf(", read %d bytes", bytesRead);
LOG_DEBUG((", read %d bytes", bytesRead));
// We have to accept and handle the initial CONNECT request here
PRInt32 response;
@ -706,7 +771,7 @@ void HandleConnection(void* data)
// Store response to the oposite buffer
if (response != 200)
{
printf(" could not read the connect request, closing connection with %d", response);
LOG_ERRORD((" could not read the connect request, closing connection with %d", response));
client_done = true;
sprintf(buffers[s2].buffer, "HTTP/1.1 %d ERROR\r\nConnection: close\r\n\r\n", response);
buffers[s2].buffertail = buffers[s2].buffer + strlen(buffers[s2].buffer);
@ -716,7 +781,7 @@ void HandleConnection(void* data)
strcpy(buffers[s2].buffer, "HTTP/1.1 200 Connected\r\nConnection: keep-alive\r\n\r\n");
buffers[s2].buffertail = buffers[s2].buffer + strlen(buffers[s2].buffer);
printf(" accepted CONNECT request, connected to the server, sending OK to the client\n");
LOG_DEBUG((" accepted CONNECT request, connected to the server, sending OK to the client\n"));
// Send the response to the client socket
break;
} // end of CONNECT handling
@ -724,7 +789,7 @@ void HandleConnection(void* data)
if (!buffers[s].free())
{
// Do not poll for read when the buffer is full
printf(" no place in our read buffer, stop reading");
LOG_DEBUG((" no place in our read buffer, stop reading"));
in_flags &= ~PR_POLL_READ;
}
@ -747,11 +812,11 @@ void HandleConnection(void* data)
addr = &websocket_server;
if (!ConnectSocket(other_sock, addr, connect_timeout))
{
printf(" could not open connection to the real server\n");
LOG_ERRORD((" could not open connection to the real server\n"));
client_error = true;
break;
}
printf("\n connected to remote server\n");
LOG_DEBUG(("\n connected to remote server\n"));
numberOfSockets = 2;
}
}
@ -762,23 +827,23 @@ void HandleConnection(void* data)
}
in_flags2 |= PR_POLL_WRITE;
printf(" telling the other socket to write");
LOG_DEBUG((" telling the other socket to write"));
}
else
printf(" we have something for the other socket to write, but ssl has not been administered on it");
LOG_DEBUG((" we have something for the other socket to write, but ssl has not been administered on it"));
}
} // PR_POLL_READ handling
if (out_flags & PR_POLL_WRITE)
{
printf(" :writing");
LOG_DEBUG((" :writing"));
PRInt32 bytesWrite = PR_Send(sockets[s].fd, buffers[s2].bufferhead,
buffers[s2].present(), 0, PR_INTERVAL_NO_TIMEOUT);
if (bytesWrite < 0)
{
if (PR_GetError() != PR_WOULD_BLOCK_ERROR) {
printf(" error=%d", PR_GetError());
LOG_DEBUG((" error=%d", PR_GetError()));
client_error = true;
socketErrorState[s] = PR_TRUE;
// We got a fatal error while writting the buffer. Clear it to break
@ -786,56 +851,56 @@ void HandleConnection(void* data)
buffers[s2].bufferhead = buffers[s2].buffertail = buffers[s2].buffer;
}
else
printf(" would block");
LOG_DEBUG((" would block"));
}
else
{
printf(", written %d bytes", bytesWrite);
LOG_DEBUG((", written %d bytes", bytesWrite));
buffers[s2].buffertail[1] = '\0';
printf(" dump:\n%.*s\n", bytesWrite, buffers[s2].bufferhead);
LOG_DEBUG((" dump:\n%.*s\n", bytesWrite, buffers[s2].bufferhead));
buffers[s2].bufferhead += bytesWrite;
if (buffers[s2].present())
{
printf(" still have to write %d bytes", (int)buffers[s2].present());
LOG_DEBUG((" still have to write %d bytes", (int)buffers[s2].present()));
in_flags |= PR_POLL_WRITE;
}
else
{
if (!ssl_updated)
{
printf(" proxy response sent to the client");
LOG_DEBUG((" proxy response sent to the client"));
// Proxy response has just been writen, update to ssl
ssl_updated = true;
if (!ci->http_proxy_only &&
!ConfigureSSLServerSocket(ci->client_sock, ci->server_info, certificateToUse, clientAuth))
{
printf(" but failed to config server socket\n");
LOG_ERRORD((" failed to config server socket\n"));
client_error = true;
break;
}
printf(" client socket updated to SSL");
LOG_DEBUG((" client socket updated to SSL"));
} // sslUpdate
printf(" dropping our write flag and setting other socket read flag");
LOG_DEBUG((" dropping our write flag and setting other socket read flag"));
in_flags &= ~PR_POLL_WRITE;
in_flags2 |= PR_POLL_READ;
buffers[s2].compact();
}
}
} // PR_POLL_WRITE handling
printf("\n"); // end the log
LOG_END_BLOCK(); // end the log
} // for...
} // while, poll
}
else
client_error = true;
printf("SSLTUNNEL(%p): exiting root function for csock=%p, ssock=%p\n",
static_cast<void*>(data),
static_cast<void*>(ci->client_sock),
static_cast<void*>(other_sock));
LOG_DEBUG(("SSLTUNNEL(%p)): exiting root function for csock=%p, ssock=%p\n",
static_cast<void*>(data),
static_cast<void*>(ci->client_sock),
static_cast<void*>(other_sock)));
if (!client_error)
PR_Shutdown(ci->client_sock, PR_SHUTDOWN_SEND);
PR_Close(ci->client_sock);
@ -856,7 +921,7 @@ void StartServer(void* data)
//TODO: select ciphers?
AutoFD listen_socket(PR_NewTCPSocket());
if (!listen_socket) {
fprintf(stderr, "failed to create socket\n");
LOG_ERROR(("failed to create socket\n"));
SignalShutdown();
return;
}
@ -871,19 +936,19 @@ void StartServer(void* data)
PRNetAddr server_addr;
PR_InitializeNetAddr(PR_IpAddrAny, si->listen_port, &server_addr);
if (PR_Bind(listen_socket, &server_addr) != PR_SUCCESS) {
fprintf(stderr, "failed to bind socket\n");
LOG_ERROR(("failed to bind socket\n"));
SignalShutdown();
return;
}
if (PR_Listen(listen_socket, 1) != PR_SUCCESS) {
fprintf(stderr, "failed to listen on socket\n");
LOG_ERROR(("failed to listen on socket\n"));
SignalShutdown();
return;
}
printf("Server listening on port %d with cert %s\n", si->listen_port,
si->cert_nickname.c_str());
LOG_INFO(("Server listening on port %d with cert %s\n", si->listen_port,
si->cert_nickname.c_str()));
while (!shutdown_server) {
connection_info_t* ci = new connection_info_t();
@ -949,13 +1014,13 @@ int processConfigLine(char* configLine)
{
char* ipstring = strtok2(_caret, ":", &_caret);
if (PR_StringToNetAddr(ipstring, &websocket_server) != PR_SUCCESS) {
fprintf(stderr, "Invalid IP address in proxy config: %s\n", ipstring);
LOG_ERROR(("Invalid IP address in proxy config: %s\n", ipstring));
return 1;
}
char* remoteport = strtok2(_caret, ":", &_caret);
int port = atoi(remoteport);
if (port <= 0) {
fprintf(stderr, "Invalid remote port in proxy config: %s\n", remoteport);
LOG_ERROR(("Invalid remote port in proxy config: %s\n", remoteport));
return 1;
}
websocket_server.inet.port = PR_htons(port);
@ -967,13 +1032,13 @@ int processConfigLine(char* configLine)
{
char* ipstring = strtok2(_caret, ":", &_caret);
if (PR_StringToNetAddr(ipstring, &remote_addr) != PR_SUCCESS) {
fprintf(stderr, "Invalid remote IP address: %s\n", ipstring);
LOG_ERROR(("Invalid remote IP address: %s\n", ipstring));
return 1;
}
char* serverportstring = strtok2(_caret, ":", &_caret);
int port = atoi(serverportstring);
if (port <= 0) {
fprintf(stderr, "Invalid remote port: %s\n", serverportstring);
LOG_ERROR(("Invalid remote port: %s\n", serverportstring));
return 1;
}
remote_addr.inet.port = PR_htons(port);
@ -997,7 +1062,7 @@ int processConfigLine(char* configLine)
int port = atoi(serverportstring);
if (port <= 0) {
fprintf(stderr, "Invalid port specified: %s\n", serverportstring);
LOG_ERROR(("Invalid port specified: %s\n", serverportstring));
return 1;
}
@ -1013,7 +1078,7 @@ int processConfigLine(char* configLine)
PLHashEntry* entry = PL_HashTableAdd(existingServer->host_cert_table, hostname_copy, certnick_copy);
if (!entry) {
fprintf(stderr, "Out of memory");
LOG_ERROR(("Out of memory"));
return 1;
}
}
@ -1025,13 +1090,13 @@ int processConfigLine(char* configLine)
server.host_cert_table = PL_NewHashTable(0, PL_HashString, PL_CompareStrings, PL_CompareStrings, NULL, NULL);
if (!server.host_cert_table)
{
fprintf(stderr, "Internal, could not create hash table\n");
LOG_ERROR(("Internal, could not create hash table\n"));
return 1;
}
server.host_clientauth_table = PL_NewHashTable(0, PL_HashString, PL_CompareStrings, ClientAuthValueComparator, NULL, NULL);
if (!server.host_clientauth_table)
{
fprintf(stderr, "Internal, could not create hash table\n");
LOG_ERROR(("Internal, could not create hash table\n"));
return 1;
}
servers.push_back(server);
@ -1048,7 +1113,7 @@ int processConfigLine(char* configLine)
int port = atoi(serverportstring);
if (port <= 0) {
fprintf(stderr, "Invalid port specified: %s\n", serverportstring);
LOG_ERROR(("Invalid port specified: %s\n", serverportstring));
return 1;
}
@ -1057,7 +1122,7 @@ int processConfigLine(char* configLine)
char* authoptionstring = strtok2(_caret, ":", &_caret);
client_auth_option* authoption = new client_auth_option;
if (!authoption) {
fprintf(stderr, "Out of memory");
LOG_ERROR(("Out of memory"));
return 1;
}
@ -1069,7 +1134,7 @@ int processConfigLine(char* configLine)
*authoption = caNone;
else
{
fprintf(stderr, "Incorrect client auth option modifier for host '%s'", hostname);
LOG_ERROR(("Incorrect client auth option modifier for host '%s'", hostname));
return 1;
}
@ -1077,7 +1142,7 @@ int processConfigLine(char* configLine)
char *hostname_copy = new char[strlen(hostname)+strlen(hostportstring)+2];
if (!hostname_copy) {
fprintf(stderr, "Out of memory");
LOG_ERROR(("Out of memory"));
return 1;
}
@ -1087,13 +1152,13 @@ int processConfigLine(char* configLine)
PLHashEntry* entry = PL_HashTableAdd(existingServer->host_clientauth_table, hostname_copy, authoption);
if (!entry) {
fprintf(stderr, "Out of memory");
LOG_ERROR(("Out of memory"));
return 1;
}
}
else
{
fprintf(stderr, "Server on port %d for client authentication option is not defined, use 'listen' option first", port);
LOG_ERROR(("Server on port %d for client authentication option is not defined, use 'listen' option first", port));
return 1;
}
@ -1107,7 +1172,7 @@ int processConfigLine(char* configLine)
return 0;
}
printf("Error: keyword \"%s\" unexpected\n", keyword);
LOG_ERROR(("Error: keyword \"%s\" unexpected\n", keyword));
return 1;
}
@ -1141,13 +1206,13 @@ int parseConfigFile(const char* filePath)
// Check mandatory items
if (nssconfigdir.empty())
{
printf("Error: missing path to NSS certification database\n,use certdbdir:<path> in the config file\n");
LOG_ERROR(("Error: missing path to NSS certification database\n,use certdbdir:<path> in the config file\n"));
return 1;
}
if (any_host_spec_config && !do_http_proxy)
{
printf("Warning: any host-specific configurations are ignored, add httpproxy:1 to allow them\n");
LOG_ERROR(("Warning: any host-specific configurations are ignored, add httpproxy:1 to allow them\n"));
}
return 0;
@ -1170,6 +1235,10 @@ PRIntn freeClientAuthHashItems(PLHashEntry *he, PRIntn i, void *arg)
int main(int argc, char** argv)
{
const char* configFilePath;
const char* logLevelEnv = PR_GetEnv("SSLTUNNEL_LOG_LEVEL");
gLogLevel = logLevelEnv ? (LogLevel)atoi(logLevelEnv) : LEVEL_INFO;
if (argc == 1)
configFilePath = "ssltunnel.cfg";
else
@ -1178,7 +1247,7 @@ int main(int argc, char** argv)
memset(&websocket_server, 0, sizeof(PRNetAddr));
if (parseConfigFile(configFilePath)) {
fprintf(stderr, "Error: config file \"%s\" missing or formating incorrect\n"
LOG_ERROR(("Error: config file \"%s\" missing or formating incorrect\n"
"Specify path to the config file as parameter to ssltunnel or \n"
"create ssltunnel.cfg in the working directory.\n\n"
"Example format of the config file:\n\n"
@ -1207,7 +1276,7 @@ int main(int argc, char** argv)
" # Proxy WebSocket traffic to the server at 127.0.0.1:9999,\n"
" # instead of the server specified in the 'forward' option.\n"
" websocketserver:127.0.0.1:9999\n",
configFilePath);
configFilePath));
return 1;
}
@ -1216,19 +1285,19 @@ int main(int argc, char** argv)
PR_MAX(MAX_THREADS, servers.size()*2),
DEFAULT_STACKSIZE);
if (!threads) {
fprintf(stderr, "Failed to create thread pool\n");
LOG_ERROR(("Failed to create thread pool\n"));
return 1;
}
shutdown_lock = PR_NewLock();
if (!shutdown_lock) {
fprintf(stderr, "Failed to create lock\n");
LOG_ERROR(("Failed to create lock\n"));
PR_ShutdownThreadPool(threads);
return 1;
}
shutdown_condvar = PR_NewCondVar(shutdown_lock);
if (!shutdown_condvar) {
fprintf(stderr, "Failed to create condvar\n");
LOG_ERROR(("Failed to create condvar\n"));
PR_ShutdownThreadPool(threads);
PR_DestroyLock(shutdown_lock);
return 1;
@ -1241,7 +1310,7 @@ int main(int argc, char** argv)
PRInt32 errorlen = PR_GetErrorTextLength();
char* err = new char[errorlen+1];
PR_GetErrorText(err);
fprintf(stderr, "Failed to init NSS: %s", err);
LOG_ERROR(("Failed to init NSS: %s", err));
delete[] err;
PR_ShutdownThreadPool(threads);
PR_DestroyCondVar(shutdown_condvar);
@ -1250,7 +1319,7 @@ int main(int argc, char** argv)
}
if (NSS_SetDomesticPolicy() != SECSuccess) {
fprintf(stderr, "NSS_SetDomesticPolicy failed\n");
LOG_ERROR(("NSS_SetDomesticPolicy failed\n"));
PR_ShutdownThreadPool(threads);
PR_DestroyCondVar(shutdown_condvar);
PR_DestroyLock(shutdown_lock);
@ -1260,7 +1329,7 @@ int main(int argc, char** argv)
// these values should make NSS use the defaults
if (SSL_ConfigServerSessionIDCache(0, 0, 0, NULL) != SECSuccess) {
fprintf(stderr, "SSL_ConfigServerSessionIDCache failed\n");
LOG_ERROR(("SSL_ConfigServerSessionIDCache failed\n"));
PR_ShutdownThreadPool(threads);
PR_DestroyCondVar(shutdown_condvar);
PR_DestroyLock(shutdown_lock);
@ -1279,14 +1348,14 @@ int main(int argc, char** argv)
PR_WaitCondVar(shutdown_condvar, PR_INTERVAL_NO_TIMEOUT);
PR_Unlock(shutdown_lock);
shutdown_server = true;
printf("Shutting down...\n");
LOG_INFO(("Shutting down...\n"));
// cleanup
PR_ShutdownThreadPool(threads);
PR_JoinThreadPool(threads);
PR_DestroyCondVar(shutdown_condvar);
PR_DestroyLock(shutdown_lock);
if (NSS_Shutdown() == SECFailure) {
fprintf(stderr, "Leaked NSS objects!\n");
LOG_DEBUG(("Leaked NSS objects!\n"));
}
for (vector<server_info_t>::iterator it = servers.begin();