version 1.4, 2015/04/20 18:20:13
|
version 1.5, 2015/09/25 20:24:20
|
|
|
#include <base/multiplex.h> | #include <base/multiplex.h> |
#include <base/Strand.h> | #include <base/Strand.h> |
#include <pal/format.h> | #include <pal/format.h> |
|
#include <pal/lock.h> |
| |
#if defined(CONFIG_POSIX) | #if defined(CONFIG_POSIX) |
# include <signal.h> | # include <signal.h> |
|
|
Disp disp; | Disp disp; |
MuxIn mux; | MuxIn mux; |
ProtocolBase* protocol; | ProtocolBase* protocol; |
WSMAN* wsman; |
WSMAN** wsman; |
|
int wsman_size; |
Selector selector; | Selector selector; |
MI_Boolean selectorInitialized; | MI_Boolean selectorInitialized; |
|
MI_Boolean reloadDispFlag; |
MI_Boolean terminated; | MI_Boolean terminated; |
| |
/* pointers to self with different types - one per supported transport */ | /* pointers to self with different types - one per supported transport */ |
|
|
MI_Boolean daemonize; | MI_Boolean daemonize; |
MI_Boolean stop; | MI_Boolean stop; |
MI_Boolean reloadConfig; | MI_Boolean reloadConfig; |
|
MI_Boolean reloadDispatcher; |
#endif | #endif |
/* mostly for unittesting in non-root env */ | /* mostly for unittesting in non-root env */ |
MI_Boolean ignoreAuthentication; | MI_Boolean ignoreAuthentication; |
MI_Boolean locations; | MI_Boolean locations; |
MI_Boolean logstderr; | MI_Boolean logstderr; |
unsigned short httpport; |
unsigned short *httpport; |
unsigned short httpsport; |
int httpport_size; |
|
unsigned short *httpsport; |
|
int httpsport_size; |
char* sslCipherSuite; | char* sslCipherSuite; |
Server_SSL_Options sslOptions; | Server_SSL_Options sslOptions; |
MI_Uint64 idletimeout; | MI_Uint64 idletimeout; |
|
|
} | } |
Options; | Options; |
| |
|
static Lock s_disp_mutex = LOCK_INITIALIZER; |
|
|
static Options s_opts; | static Options s_opts; |
| |
static ServerData s_data; | static ServerData s_data; |
|
|
-d Daemonize the server process (POSIX only).\n\ | -d Daemonize the server process (POSIX only).\n\ |
-s Stop the server process (POSIX only).\n\ | -s Stop the server process (POSIX only).\n\ |
-r Re-read configuration by the running server (POSIX only).\n\ | -r Re-read configuration by the running server (POSIX only).\n\ |
|
--reload-dispatcher Re-read configuration by the running server (POSIX only), but don't unload providers.\n\ |
--httpport PORT HTTP protocol listener port.\n\ | --httpport PORT HTTP protocol listener port.\n\ |
--httpsport PORT HTTPS protocol listener port.\n\ | --httpsport PORT HTTPS protocol listener port.\n\ |
--idletimeout TIMEOUT Idle providers unload timeout (in seconds).\n\ | --idletimeout TIMEOUT Idle providers unload timeout (in seconds).\n\ |
|
|
} | } |
#endif | #endif |
| |
|
Lock_Acquire(&s_disp_mutex); |
result = Disp_HandleInteractionRequest( | result = Disp_HandleInteractionRequest( |
&self->data->disp, | &self->data->disp, |
interactionParams ); | interactionParams ); |
|
Lock_Release(&s_disp_mutex); |
if( result != MI_RESULT_OK ) | if( result != MI_RESULT_OK ) |
{ | { |
Strand_FailOpenWithResult(interactionParams, result, PostResultMsg_NewAndSerialize); | Strand_FailOpenWithResult(interactionParams, result, PostResultMsg_NewAndSerialize); |
|
|
*argc_ = argc; | *argc_ = argc; |
} | } |
| |
|
/* |
|
* Parse an HTTP or HTTPS port specification: |
|
* |
|
* "1270" would simply place 1270 in the list, |
|
* "1270,5599" would place port 1270 and port 5599 to the list |
|
* |
|
* Returns 0 if parameter was good, non-zero if parameter was bad |
|
*/ |
|
static int ParseHttpPortSpecification(unsigned short **ports, int *size, const char *spec, unsigned short defport) |
|
{ |
|
// defport is unused (no longer support "+" to add default port |
|
(void) defport; |
|
|
|
// Ignore anything that is already stored |
|
*size = 0; |
|
|
|
// Skip leading spaces |
|
char *saveptr; |
|
char *ptr = (char *) spec; |
|
while (*ptr == ' ') |
|
{ |
|
ptr++; |
|
} |
|
|
|
while ( 1 ) |
|
{ |
|
unsigned long x; |
|
char *end = NULL; |
|
|
|
char *token = Strtok(ptr, ",", &saveptr); |
|
ptr = NULL; |
|
if (NULL == token) |
|
{ |
|
break; |
|
} |
|
|
|
x = Strtoul(token, &end, 10); |
|
if (*end != '\0' || x > USHRT_MAX) |
|
{ |
|
return 1; |
|
} |
|
|
|
/* Don't add a port of '0' */ |
|
if ( x != 0 ) |
|
{ |
|
/* Don't add duplicate ports; just ignore second port */ |
|
int found = 0, i; |
|
for (i = 0; i < (*size); ++i) |
|
{ |
|
if ( (*ports)[i] == x ) |
|
{ |
|
found = 1; |
|
break; |
|
} |
|
} |
|
|
|
if ( ! found ) |
|
{ |
|
int bytes = ++(*size) * sizeof(unsigned int); |
|
*ports = PAL_Realloc(*ports, bytes); |
|
if ( (*ports) == 0 ) |
|
{ |
|
err(ZT("memory allocation failure allocating %d bytes"), bytes); |
|
} |
|
|
|
(*ports)[(*size) - 1] = x; |
|
} |
|
} |
|
} |
|
|
|
return 0; |
|
} |
|
|
static void GetCommandLineOptions( | static void GetCommandLineOptions( |
int* argc_, | int* argc_, |
const char* argv[]) | const char* argv[]) |
|
|
"--loglevel:", | "--loglevel:", |
"-l", | "-l", |
"--testopts", | "--testopts", |
|
"--reload-dispatcher", |
NULL, | NULL, |
}; | }; |
| |
|
|
{ | { |
s_opts.reloadConfig = MI_TRUE; | s_opts.reloadConfig = MI_TRUE; |
} | } |
|
else if (strcmp(state.opt, "--reload-dispatcher") == 0) |
|
{ |
|
s_opts.reloadDispatcher = MI_TRUE; |
|
} |
#endif | #endif |
else if (strcmp(state.opt, "--httpport") == 0) | else if (strcmp(state.opt, "--httpport") == 0) |
{ | { |
unsigned long x; |
if ( ParseHttpPortSpecification(&s_opts.httpport, &s_opts.httpport_size, state.arg, CONFIG_HTTPPORT) ) |
char* end = 0; |
|
|
|
x = Strtoul(state.arg, &end, 10); |
|
|
|
if (*end != '\0' || x > USHRT_MAX) |
|
{ | { |
err(ZT("bad option argument for --httpport: %s"), | err(ZT("bad option argument for --httpport: %s"), |
scs(state.arg)); | scs(state.arg)); |
} | } |
|
|
s_opts.httpport = (unsigned short)x; |
|
} | } |
else if (strcmp(state.opt, "--httpsport") == 0) | else if (strcmp(state.opt, "--httpsport") == 0) |
{ | { |
unsigned long x; |
if ( ParseHttpPortSpecification(&s_opts.httpsport, &s_opts.httpsport_size, state.arg, CONFIG_HTTPSPORT) ) |
char* end; |
|
|
|
x = Strtoul(state.arg, &end, 10); |
|
|
|
if (*end != '\0' || x > USHRT_MAX) |
|
{ | { |
err(ZT("bad option argument for --httpsport: %s"), | err(ZT("bad option argument for --httpsport: %s"), |
scs(state.arg)); | scs(state.arg)); |
} | } |
|
|
s_opts.httpsport = (unsigned short)x; |
|
} | } |
else if (strcmp(state.opt, "--idletimeout") == 0) | else if (strcmp(state.opt, "--idletimeout") == 0) |
{ | { |
|
|
} | } |
} | } |
| |
|
// We reload the ProvReg structure in the Dispatcher when this signal is received. |
|
// This gives us access to providers that are installed after the omiserver is running without terminating current providers that are running. |
|
static void _HandleSIGUSR1(int sig) |
|
{ |
|
if (sig == SIGUSR1) |
|
{ |
|
s_data.reloadDispFlag = MI_TRUE; |
|
} |
|
} |
|
|
/* An array of PIDS that abnormally exited */ | /* An array of PIDS that abnormally exited */ |
#define NPIDS 16 | #define NPIDS 16 |
static pid_t _pids[NPIDS]; | static pid_t _pids[NPIDS]; |
|
|
| |
if (strcmp(key, "httpport") == 0) | if (strcmp(key, "httpport") == 0) |
{ | { |
char* end; |
if ( ParseHttpPortSpecification(&s_opts.httpport, &s_opts.httpport_size, value, CONFIG_HTTPPORT) ) |
unsigned long x = Strtoul(value, &end, 10); |
|
|
|
if (*end != '\0' || x > USHRT_MAX) |
|
{ | { |
err(ZT("%s(%u): invalid value for '%s': %s"), scs(path), | err(ZT("%s(%u): invalid value for '%s': %s"), scs(path), |
Conf_Line(conf), scs(key), scs(value)); | Conf_Line(conf), scs(key), scs(value)); |
} | } |
|
|
s_opts.httpport = (unsigned short)x; |
|
} | } |
else if (strcmp(key, "httpsport") == 0) | else if (strcmp(key, "httpsport") == 0) |
{ | { |
char* end; |
if ( ParseHttpPortSpecification(&s_opts.httpsport, &s_opts.httpsport_size, value, CONFIG_HTTPSPORT) ) |
unsigned long x = Strtoul(value, &end, 10); |
|
|
|
if (*end != '\0' || x > USHRT_MAX) |
|
{ | { |
err(ZT("%s(%u): invalid value for '%s': %s"), scs(path), | err(ZT("%s(%u): invalid value for '%s': %s"), scs(path), |
Conf_Line(conf), scs(key), scs(value)); | Conf_Line(conf), scs(key), scs(value)); |
} | } |
|
|
s_opts.httpsport = (unsigned short)x; |
|
} | } |
else if (strcmp(key, "idletimeout") == 0) | else if (strcmp(key, "idletimeout") == 0) |
{ | { |
|
|
Strlcpy(s_opts.sslCipherSuite, value, valueLength+1); | Strlcpy(s_opts.sslCipherSuite, value, valueLength+1); |
s_opts.sslCipherSuite[valueLength] = '\0'; | s_opts.sslCipherSuite[valueLength] = '\0'; |
} | } |
else if (Strcasecmp(key, "NoSSLv2") == 0) |
else if (strcmp(key, "NoSSLv2") == 0) |
{ | { |
if (Strcasecmp(value, "true") == 0) | if (Strcasecmp(value, "true") == 0) |
{ | { |
s_opts.sslOptions |= DISABLE_SSL_V2; | s_opts.sslOptions |= DISABLE_SSL_V2; |
} | } |
else if (Strcasecmp(value, "false") != 0) |
else if (Strcasecmp(value, "false") == 0) |
|
{ |
|
s_opts.sslOptions &= ~DISABLE_SSL_V2; |
|
} |
|
else |
{ | { |
err(ZT("%s(%u): invalid value for '%s': %s"), scs(path), | err(ZT("%s(%u): invalid value for '%s': %s"), scs(path), |
Conf_Line(conf), scs(key), scs(value)); | Conf_Line(conf), scs(key), scs(value)); |
} | } |
} | } |
else if (Strcasecmp(key, "NoSSLv3") == 0) |
else if (strcmp(key, "NoSSLv3") == 0) |
{ | { |
if (Strcasecmp(value, "true") == 0) | if (Strcasecmp(value, "true") == 0) |
{ | { |
s_opts.sslOptions |= DISABLE_SSL_V3; | s_opts.sslOptions |= DISABLE_SSL_V3; |
} | } |
else if (Strcasecmp(value, "false") != 0) |
else if (Strcasecmp(value, "false") == 0) |
|
{ |
|
s_opts.sslOptions &= ~DISABLE_SSL_V3; |
|
} |
|
else |
{ | { |
err(ZT("%s(%u): invalid value for '%s': %s"), scs(path), | err(ZT("%s(%u): invalid value for '%s': %s"), scs(path), |
Conf_Line(conf), scs(key), scs(value)); | Conf_Line(conf), scs(key), scs(value)); |
|
|
memset(&s_data, 0, sizeof(s_data)); | memset(&s_data, 0, sizeof(s_data)); |
| |
/* Set default options */ | /* Set default options */ |
s_opts.httpport = CONFIG_HTTPPORT; |
s_opts.httpport = PAL_Malloc(sizeof(unsigned short)); |
s_opts.httpsport = CONFIG_HTTPSPORT; |
s_opts.httpport[0] = CONFIG_HTTPPORT; |
|
s_opts.httpport_size = 1; |
|
|
|
s_opts.httpsport = PAL_Malloc(sizeof(unsigned short)); |
|
s_opts.httpsport[0] = CONFIG_HTTPSPORT; |
|
s_opts.httpsport_size = 1; |
|
|
|
s_opts.sslOptions = DISABLE_SSL_V2; |
s_opts.idletimeout = 0; | s_opts.idletimeout = 0; |
s_opts.livetime = 0; | s_opts.livetime = 0; |
| |
|
|
| |
exit(0); | exit(0); |
} | } |
|
if (s_opts.reloadDispatcher) |
|
{ |
|
if (PIDFile_IsRunning() != 0) |
|
info_exit(ZT("server is not running\n")); |
|
|
|
if (PIDFile_Signal(SIGUSR1) != 0) |
|
err(ZT("failed to reload dispatcher on the server\n")); |
|
|
|
Tprintf(ZT("%s: server has reloaded its dispatcher\n"), scs(arg0)); |
|
|
|
exit(0); |
|
} |
#endif | #endif |
| |
#if defined(CONFIG_POSIX) | #if defined(CONFIG_POSIX) |
|
|
| |
/* Watch for SIGTERM signals */ | /* Watch for SIGTERM signals */ |
if (0 != SetSignalHandler(SIGTERM, _HandleSIGTERM) || | if (0 != SetSignalHandler(SIGTERM, _HandleSIGTERM) || |
0 != SetSignalHandler(SIGHUP, _HandleSIGHUP)) |
0 != SetSignalHandler(SIGHUP, _HandleSIGHUP) || |
err(ZT("cannot set sighanlder, erron %d"), errno); |
0 != SetSignalHandler(SIGUSR1, _HandleSIGUSR1)) |
|
err(ZT("cannot set sighandler, errno %d"), errno); |
| |
| |
/* Watch for SIGCHLD signals */ | /* Watch for SIGCHLD signals */ |
|
|
} | } |
| |
/* Set WSMAN options and create WSMAN server */ | /* Set WSMAN options and create WSMAN server */ |
|
s_data.wsman_size = s_opts.httpport_size + s_opts.httpsport_size; |
|
if ( s_data.wsman_size > 0 ) |
|
{ |
|
s_data.wsman = PAL_Calloc(s_data.wsman_size, sizeof(WSMAN*)); |
|
if ( s_data.wsman == NULL ) |
{ | { |
|
err(ZT("memory allocation failure allocating %d bytes"), s_data.wsman_size * sizeof(WSMAN*)); |
|
} |
|
} |
|
|
|
{ |
|
int wsman_count = 0; |
WSMAN_Options options = DEFAULT_WSMAN_OPTIONS; | WSMAN_Options options = DEFAULT_WSMAN_OPTIONS; |
#if !defined(CONFIG_FAVORSIZE) | #if !defined(CONFIG_FAVORSIZE) |
options.enableTracing = s_opts.trace; | options.enableTracing = s_opts.trace; |
#endif | #endif |
options.enableHTTPTracing = s_opts.httptrace; | options.enableHTTPTracing = s_opts.httptrace; |
| |
|
/* Start up the non-encrypted listeners */ |
|
int count; |
|
for ( count = 0; count < s_opts.httpport_size; ++count ) |
|
{ |
|
r = WSMAN_New_Listener( |
|
&s_data.wsman[wsman_count++], |
|
&s_data.selector, |
|
s_opts.httpport[count], |
|
0, |
|
s_opts.sslCipherSuite, |
|
s_opts.sslOptions, |
|
_RequestCallback, |
|
&s_data.wsmanData, |
|
&options); |
|
|
|
if (r != MI_RESULT_OK) |
|
{ |
|
err(ZT("WSMAN_New_Listener() failed for port %u"), s_opts.httpport[count]); |
|
} |
|
|
|
/* Log start up message */ |
|
trace_ListeningOnPort(s_opts.httpport[count]); |
|
} |
|
|
|
/* Start up the encrypted listeners */ |
|
for ( count = 0; count < s_opts.httpsport_size; ++count ) |
|
{ |
r = WSMAN_New_Listener( | r = WSMAN_New_Listener( |
&s_data.wsman, |
&s_data.wsman[wsman_count++], |
&s_data.selector, | &s_data.selector, |
s_opts.httpport, |
0, |
s_opts.httpsport, |
s_opts.httpsport[count], |
s_opts.sslCipherSuite, | s_opts.sslCipherSuite, |
s_opts.sslOptions, | s_opts.sslOptions, |
_RequestCallback, | _RequestCallback, |
|
|
&options); | &options); |
| |
if (r != MI_RESULT_OK) | if (r != MI_RESULT_OK) |
err(ZT("WSMAN_New_Listener() failed")); |
{ |
|
err(ZT("WSMAN_New_Listener() failed for encrypted port %u"), s_opts.httpsport[count]); |
|
} |
|
|
|
/* Log start up message */ |
|
trace_ListeningOnEncryptedPort(s_opts.httpsport[count]); |
|
} |
} | } |
| |
/* mux */ | /* mux */ |
|
|
err(ZT("Protocol_New_Listener() failed")); | err(ZT("Protocol_New_Listener() failed")); |
} | } |
| |
/* Log start up message */ |
|
trace_ListeningOnPorts(s_opts.httpport, s_opts.httpsport); |
|
|
|
/* Run the protocol object (waiting for new messages) */ | /* Run the protocol object (waiting for new messages) */ |
{ | { |
const PAL_Uint64 ONE_SECOND_USEC = 1000 * 1000; | const PAL_Uint64 ONE_SECOND_USEC = 1000 * 1000; |
|
|
{ | { |
PAL_Uint64 now; | PAL_Uint64 now; |
| |
|
if (s_data.reloadDispFlag) |
|
{ |
|
Lock_Acquire(&s_disp_mutex); |
|
Disp_Reload(&s_data.disp); |
|
s_data.reloadDispFlag = MI_FALSE; |
|
Lock_Release(&s_disp_mutex); |
|
} |
|
|
r = Protocol_Run(s_data.protocol, ONE_SECOND_USEC); | r = Protocol_Run(s_data.protocol, ONE_SECOND_USEC); |
| |
if (r != MI_RESULT_TIME_OUT) | if (r != MI_RESULT_TIME_OUT) |
|
|
// Destroy the dispatcher. | // Destroy the dispatcher. |
Selector_RemoveAllHandlers(&s_data.selector); | Selector_RemoveAllHandlers(&s_data.selector); |
Disp_Destroy(&s_data.disp); | Disp_Destroy(&s_data.disp); |
WSMAN_Delete(s_data.wsman); |
|
|
{ |
|
int i; |
|
for (i = 0; i < s_data.wsman_size; ++i) |
|
{ |
|
WSMAN_Delete(s_data.wsman[i]); |
|
} |
|
} |
|
|
ProtocolBase_Delete(s_data.protocol); | ProtocolBase_Delete(s_data.protocol); |
Selector_Destroy(&s_data.selector); | Selector_Destroy(&s_data.selector); |
| |
|
|
Sock_Stop(); | Sock_Stop(); |
} | } |
| |
|
/* Done with WSMAN* array; free it */ |
|
PAL_Free(s_data.wsman); |
|
s_data.wsman_size = 0; |
|
|
|
/* Done with pointers to ports; free them now */ |
|
PAL_Free(s_opts.httpport); |
|
PAL_Free(s_opts.httpsport); |
|
s_opts.httpport_size = s_opts.httpsport_size = 0; |
|
|
#if defined(CONFIG_POSIX) | #if defined(CONFIG_POSIX) |
/* Close PID file */ | /* Close PID file */ |
close(pidfile); | close(pidfile); |