From e4f3e11a8e22db6fca08dba4290db39a2e1c0f4b Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Thu, 2 Nov 2017 10:52:53 +0100 Subject: [SERVER] Add --errormsg to only serve HTTP-JSON error code This could have been an external tool, but this didn't add much code and has the benefit of honoring the config file for port and bind address. --- src/server/rpc.c | 13 +++++++++ src/server/rpc.h | 1 + src/server/server.c | 80 ++++++++++++++++++++++++++++++++++------------------- 3 files changed, 65 insertions(+), 29 deletions(-) (limited to 'src/server') diff --git a/src/server/rpc.c b/src/server/rpc.c index 92aa249..ff4b0ab 100644 --- a/src/server/rpc.c +++ b/src/server/rpc.c @@ -233,6 +233,19 @@ func_return:; } while (0); } +void rpc_sendErrorMessage(int sock, const char* message) +{ + static const char *encoded = NULL; + static size_t len; + if ( encoded == NULL ) { + json_t *tmp = json_pack( "{ss}", "errorMsg", message ); + encoded = json_dumps( tmp, 0 ); + json_decref( tmp ); + len = strlen( encoded ); + } + sendReply( sock, "200 Somewhat OK", "application/json", encoded, len, HTTP_CLOSE ); +} + static bool handleStatus(int sock, int permissions, struct field *fields, size_t fields_num, int keepAlive) { bool ok; diff --git a/src/server/rpc.h b/src/server/rpc.h index f337067..285242c 100644 --- a/src/server/rpc.h +++ b/src/server/rpc.h @@ -5,5 +5,6 @@ struct dnbd3_host_t; void rpc_init(); void rpc_sendStatsJson(int sock, struct dnbd3_host_t* host, const void *data, const int dataLen); +void rpc_sendErrorMessage(int sock, const char* message); #endif diff --git a/src/server/server.c b/src/server/server.c index 075d9e7..28832e0 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -43,6 +43,7 @@ #define LONGOPT_CREATE 1002 #define LONGOPT_REVISION 1003 #define LONGOPT_SIZE 1004 +#define LONGOPT_ERRORMSG 1005 static poll_list_t *listeners = NULL; @@ -52,6 +53,8 @@ static poll_list_t *listeners = NULL; static ticks startupTime; static bool sigReload = false, sigLogCycle = false; +static poll_list_t* setupNetwork(char *bindAddress); + static dnbd3_client_t* dnbd3_prepareClient(struct sockaddr_storage *client, int fd); static void dnbd3_handleSignal(int signum); @@ -75,6 +78,7 @@ void dnbd3_printHelp(char *argv_0) printf( "--crc [image-file] Generate crc block list for given image\n" ); printf( "--create [image-name] --revision [rid] --size [filesize]\n" "\tCreate a local empty image file with a zeroed cache-map for the specified image\n" ); + printf( "--errormsg [text] Just serve given error message via HTTP, no service otherwise\n" ); printf( "\n" ); exit( 0 ); } @@ -144,6 +148,7 @@ int main(int argc, char *argv[]) int longIndex = 0; char *paramCreate = NULL; char *bindAddress = NULL; + char *errorMsg = NULL; int64_t paramSize = -1; int paramRevision = -1; static const char *optString = "b:c:d:hnv?"; @@ -159,6 +164,7 @@ int main(int argc, char *argv[]) { "create", required_argument, NULL, LONGOPT_CREATE }, { "revision", required_argument, NULL, LONGOPT_REVISION }, { "size", required_argument, NULL, LONGOPT_SIZE }, + { "errormsg", required_argument, NULL, LONGOPT_ERRORMSG }, { 0, 0, 0, 0 } }; @@ -172,18 +178,6 @@ int main(int argc, char *argv[]) case 'n': demonize = 0; break; - case 'r': - logadd( LOG_INFO, "Reloading configuration file..." ); - //dnbd3_rpc_send(RPC_RELOAD); - return EXIT_SUCCESS; - case 's': - logadd( LOG_INFO, "Stopping running server..." ); - //dnbd3_rpc_send(RPC_EXIT); - return EXIT_SUCCESS; - case 'i': - logadd( LOG_INFO, "Requesting information..." ); - //dnbd3_rpc_send(RPC_IMG_LIST); - return EXIT_SUCCESS; case 'h': case '?': dnbd3_printHelp( argv[0] ); @@ -210,6 +204,9 @@ int main(int argc, char *argv[]) case LONGOPT_SIZE: paramSize = strtoll( optarg, NULL, 10 ); break; + case LONGOPT_ERRORMSG: + errorMsg = strdup( optarg ); + break; } opt = getopt_long( argc, argv, optString, longOpts, &longIndex ); } @@ -218,8 +215,8 @@ int main(int argc, char *argv[]) if ( _configDir == NULL ) _configDir = strdup( "/etc/dnbd3-server" ); globals_loadConfig(); - if ( _basePath == NULL ) { - logadd( LOG_ERROR, "basePath not set in %s/%s", _configDir, CONFIG_FILENAME ); + if ( _basePath == NULL && errorMsg == NULL ) { + logadd( LOG_ERROR, "Aborting, set proper basePath in %s/%s", _configDir, CONFIG_FILENAME ); exit( EXIT_FAILURE ); } @@ -263,9 +260,27 @@ int main(int argc, char *argv[]) return image_create( paramCreate, paramRevision, paramSize ) ? 0 : EXIT_FAILURE; } - // No one-shot detected, normal server operation - - if ( demonize ) daemon( 1, 0 ); + // No one-shot detected, normal server operation or errormsg serving + if ( demonize ) { + logadd( LOG_INFO, "Forking into background, see log file for further information" ); + daemon( 1, 0 ); + } + if ( errorMsg != NULL ) { + setupNetwork( bindAddress ); + logadd( LOG_INFO, "Running errormsg server" ); + while ( true ) { + const int fd = sock_accept( listeners, NULL, NULL ); + if ( fd >= 0 ) { + rpc_sendErrorMessage( fd, errorMsg ); + } else { + const int err = errno; + if ( err == EINTR || err == EAGAIN ) continue; + logadd( LOG_ERROR, "Client accept failure (err=%d)", err ); + usleep( 10000 ); // 10ms + } + } + exit( 0 ); + } image_serverStartup(); altservers_init(); integrity_init(); @@ -302,18 +317,7 @@ int main(int argc, char *argv[]) sleep( 1 ); // setup network - listeners = sock_newPollList(); - if ( listeners == NULL ) { - logadd( LOG_ERROR, "Didnt get a poll list!" ); - exit( EXIT_FAILURE ); - } - if ( !sock_listen( listeners, bindAddress, (uint16_t)_listenPort ) ) { - logadd( LOG_ERROR, "Could not listen on any local interface." ); - exit( EXIT_FAILURE ); - } - struct sockaddr_storage client; - socklen_t len; - int fd; + listeners = setupNetwork( bindAddress ); // Initialize thread pool if ( !threadpool_init( 8 ) ) { @@ -324,6 +328,9 @@ int main(int argc, char *argv[]) logadd( LOG_INFO, "Server is ready. (%s)", VERSION_STRING ); // +++++++++++++++++++++++++++++++++++++++++++++++++++ main loop + struct sockaddr_storage client; + socklen_t len; + int fd; while ( !_shutdown ) { // Handle signals if ( sigReload ) { @@ -364,6 +371,21 @@ int main(int argc, char *argv[]) } free( bindAddress ); dnbd3_cleanup(); + return 0; +} + +static poll_list_t* setupNetwork(char *bindAddress) +{ + listeners = sock_newPollList(); + if ( listeners == NULL ) { + logadd( LOG_ERROR, "Didnt get a poll list!" ); + exit( EXIT_FAILURE ); + } + if ( !sock_listen( listeners, bindAddress, (uint16_t)_listenPort ) ) { + logadd( LOG_ERROR, "Could not listen on any local interface." ); + exit( EXIT_FAILURE ); + } + return listeners; } /** -- cgit v1.2.3-55-g7522