diff --git a/README.md b/README.md index 16a6e1c..38583ed 100644 --- a/README.md +++ b/README.md @@ -19,3 +19,9 @@ Usage takes up to 3 command line options: * `-p port` Server port to connect to * `-l port` Listening port for clients to connect to, HTTP status port will be equal to this plus one +* `-d` Connect to server only when first client arrives and exit when last disconnects +* `-r` Close connection with the server and restart it when last client disconnects + +Note: For standby use (for example, when running as a daemon), use both flags `-d -r`. + When running in this way the RTL_TCP is only active (reading samples) when some client is connected. + In any order case, the RTL_TCP and RTLMUX processes are in standby (idle). diff --git a/cmdline.c b/cmdline.c index c9d38ba..8be16f4 100644 --- a/cmdline.c +++ b/cmdline.c @@ -39,10 +39,13 @@ const char *gengetopt_args_info_help[] = { " -p, --port=port rtl_tcp port (default=`1234')", " -h, --host=address rtl_tcp host address (default=`localhost')", " -l, --listen=port Listening port for client connections (default=`7878')", + " -d, --delayed Delayed \n connection to the server (default=off)", + " -r, --restart Restart server's connection when last \n client disconnects (default=off)", 0 }; typedef enum {ARG_NO + , ARG_FLAG , ARG_STRING , ARG_INT } cmdline_c_arg_type; @@ -92,6 +95,8 @@ void clear_given (struct gengetopt_args_info *args_info) args_info->port_given = 0 ; args_info->host_given = 0 ; args_info->listen_given = 0 ; + args_info->delayed_given = 0 ; + args_info->restart_given = 0 ; } static @@ -104,6 +109,8 @@ void clear_args (struct gengetopt_args_info *args_info) args_info->host_orig = NULL; args_info->listen_arg = 7878; args_info->listen_orig = NULL; + args_info->delayed_flag = 0; + args_info->restart_flag = 0; } @@ -117,6 +124,8 @@ void init_args_info(struct gengetopt_args_info *args_info) args_info->port_help = gengetopt_args_info_help[2] ; args_info->host_help = gengetopt_args_info_help[3] ; args_info->listen_help = gengetopt_args_info_help[4] ; + args_info->delayed_help = gengetopt_args_info_help[5] ; + args_info->restart_help = gengetopt_args_info_help[6] ; } @@ -244,6 +253,10 @@ cmdline_c_dump(FILE *outfile, struct gengetopt_args_info *args_info) write_into_file(outfile, "host", args_info->host_orig, 0); if (args_info->listen_given) write_into_file(outfile, "listen", args_info->listen_orig, 0); + if (args_info->delayed_given) + write_into_file(outfile, "delayed", 0, 0 ); + if (args_info->restart_given) + write_into_file(outfile, "restart", 0, 0 ); i = EXIT_SUCCESS; @@ -410,6 +423,9 @@ int update_arg(void *field, char **orig_field, val = possible_values[found]; switch(arg_type) { + case ARG_FLAG: + *((int *)field) = !*((int *)field); + break; case ARG_INT: if (val) *((int *)field) = strtol (val, &stop_char, 0); break; @@ -440,6 +456,7 @@ int update_arg(void *field, char **orig_field, /* store the original value */ switch(arg_type) { case ARG_NO: + case ARG_FLAG: break; default: if (value && orig_field) { @@ -499,10 +516,12 @@ cmdline_c_internal ( { "port", 1, NULL, 'p' }, { "host", 1, NULL, 'h' }, { "listen", 1, NULL, 'l' }, + { "delayed", 0, NULL, 'd' }, + { "restart", 0, NULL, 'r' }, { 0, 0, 0, 0 } }; - c = getopt_long (argc, argv, "Vp:h:l:", long_options, &option_index); + c = getopt_long (argc, argv, "Vp:h:l:dr", long_options, &option_index); if (c == -1) break; /* Exit from `while (1)' loop. */ @@ -549,6 +568,28 @@ cmdline_c_internal ( goto failure; break; + case 'd': /* Delayed + connection to the server. */ + + + if (update_arg((void *)&(args_info->delayed_flag), 0, &(args_info->delayed_given), + &(local_args_info.delayed_given), optarg, 0, 0, ARG_FLAG, + check_ambiguity, override, 1, 0, "delayed", 'd', + additional_error)) + goto failure; + + break; + case 'r': /* Restart server's connection when last + client disconnects. */ + + + if (update_arg((void *)&(args_info->restart_flag), 0, &(args_info->restart_given), + &(local_args_info.restart_given), optarg, 0, 0, ARG_FLAG, + check_ambiguity, override, 1, 0, "restart", 'r', + additional_error)) + goto failure; + + break; case 0: /* Long option with no short option */ if (strcmp (long_options[option_index].name, "help") == 0) { diff --git a/cmdline.h b/cmdline.h index b7f6710..da82935 100644 --- a/cmdline.h +++ b/cmdline.h @@ -48,12 +48,22 @@ struct gengetopt_args_info int listen_arg; /**< @brief Listening port for client connections (default='7878'). */ char * listen_orig; /**< @brief Listening port for client connections original value given at command line. */ const char *listen_help; /**< @brief Listening port for client connections help description. */ + int delayed_flag; /**< @brief Delayed + connection to the server (default=off). */ + const char *delayed_help; /**< @brief Delayed + connection to the server help description. */ + int restart_flag; /**< @brief Restart server's connection when last + client disconnects (default=off). */ + const char *restart_help; /**< @brief Restart server's connection when last + client disconnects help description. */ unsigned int help_given ; /**< @brief Whether help was given. */ unsigned int version_given ; /**< @brief Whether version was given. */ unsigned int port_given ; /**< @brief Whether port was given. */ unsigned int host_given ; /**< @brief Whether host was given. */ unsigned int listen_given ; /**< @brief Whether listen was given. */ + unsigned int delayed_given ; /**< @brief Whether delayed was given. */ + unsigned int restart_given ; /**< @brief Whether restart was given. */ } ; diff --git a/config.c b/config.c index ac3baf3..34b8d56 100644 --- a/config.c +++ b/config.c @@ -19,7 +19,9 @@ int convertConfig(struct gengetopt_args_info *args) { config.host = args->host_arg; config.port = args->port_arg; config.clientPort = args->listen_arg; - + config.delayed = args->delayed_flag; + config.restart = args->restart_flag; + return 1; } diff --git a/config.h b/config.h index f26505a..5d52471 100644 --- a/config.h +++ b/config.h @@ -8,6 +8,8 @@ struct config { char *host; uint16_t port; uint16_t clientPort; + int delayed; + int restart; }; extern struct config config; diff --git a/main.c b/main.c index 69fe582..b387a65 100644 --- a/main.c +++ b/main.c @@ -22,8 +22,14 @@ int main(int argc, char **argv) { sigact.sa_flags = 0; sigaction(SIGTERM, &sigact, NULL); sigaction(SIGINT, &sigact, NULL); - +restart: pthread_create(&threadServer, NULL, serverThread, NULL); - + pthread_join(threadServer, NULL); + + if (timeToExit == 2) { + slog(LOG_INFO, SLOG_INFO, "Restarting."); + timeToExit = 0; + goto restart; + } } diff --git a/options.ggo b/options.ggo index a0bfc0e..ba9cf0d 100644 --- a/options.ggo +++ b/options.ggo @@ -10,4 +10,8 @@ option "port" p "rtl_tcp port" option "host" h "rtl_tcp host address" string typestr="address" default="localhost" optional option "listen" l "Listening port for client connections" - int typestr="port" default="7878" optional + int typestr="port" default="7878" optional option "delayed" d "Delayed +connection to the server" + flag off option "restart" r "Restart server's connection when last +client disconnects" + flag off diff --git a/rtlmux.c b/rtlmux.c index 1db4edf..6d760ae 100644 --- a/rtlmux.c +++ b/rtlmux.c @@ -215,9 +215,10 @@ static void serverReadCB(struct bufferevent *bev, void *ctx) { slog(LOG_INFO, SLOG_INFO, "Connected to server."); } else { // Failed to receive the magic header slog(LOG_ERROR, SLOG_ERROR, "Failed to receive magic header from server."); - bufferevent_free(bev); - connectToServerSoon(ctx); - return; + //bufferevent_free(bev); + //connectToServerSoon(ctx); + //return; + serverInfo.state = SERVER_CONNECTED; } // Send stored and set parameters on reconnect int i; @@ -251,6 +252,10 @@ static void serverReadCB(struct bufferevent *bev, void *ctx) { if(sendDataToAllClients(data) == 0) { // No one was listening free(data); + if (config.delayed) { + slog(LOG_INFO, SLOG_INFO, "Last user disconnected."); + if (config.restart) timeToExit = 2; else timeToExit = 1; + } } else { dataBlocks++; dataBlocksSize += data->len; @@ -388,6 +393,11 @@ static void connectCB(struct evconnlistener *listener, base, sock, BEV_OPT_CLOSE_ON_FREE); #endif + if (config.delayed && (serverConnection == NULL || LIST_FIRST(&clients) == NULL)) { + slog(LOG_INFO, SLOG_INFO, "Connection to server triggered."); + connectToServer(&serverConnection); + } + struct client *client = addClient(bev, ptr); memcpy(&client->sa, addr, len); char ipBuf[128]; @@ -397,7 +407,7 @@ static void connectCB(struct evconnlistener *listener, evutil_inet_ntop(client->sa.sa_family, &client->sin6.sin6_addr, ipBuf, 128); else snprintf(ipBuf, 128, "from unknown address"); - slog(LOG_INFO, SLOG_INFO, "Connection from client %s", ipBuf); + slog(LOG_INFO, SLOG_INFO, "Connection from client %s%s", ipBuf, LIST_NEXT(client,peer) == NULL ? " (first!)" : ""); bufferevent_setcb(bev, clientReadCB, NULL, errorEventCB, client); bufferevent_setwatermark(bev, EV_WRITE, 0, 4*1024*1024); // Limit output to 4MB? bufferevent_enable(bev, EV_READ|EV_WRITE); @@ -483,8 +493,12 @@ void *serverThread(void *arg) { } slog(LOG_INFO, SLOG_INFO, "Listening for clients on port %d", config.clientPort); - - connectToServer(&serverConnection); + + if (!config.delayed) { + connectToServer(&serverConnection); + } else { + slog(LOG_INFO, SLOG_INFO, "connection to server delayed."); + } struct evhttp *http; struct evhttp_bound_socket *handle; @@ -539,6 +553,12 @@ void *serverThread(void *arg) { evhttp_free(http); event_base_free(event_base); - + if (serverConnection != NULL) { + bufferevent_free(serverConnection); + serverInfo.state = SERVER_DISCONNECTED; + slog(LOG_INFO, SLOG_INFO, "Disconnecting from server."); + } + + slog(LOG_INFO, SLOG_INFO, "End of server thread."); return NULL; }