#include #include #include #include "mode.h" #include "util.h" #include "proxy.h" static struct option proxy_options[] = { GETOPT_HELP, GETOPT_ADDR, GETOPT_PORT, GETOPT_CONNECT_ADDR, GETOPT_CONNECT_PORT, GETOPT_BIND, GETOPT_CACHE, GETOPT_QUIET, GETOPT_VERBOSE, {0} }; static char proxy_short_options[] = "hl:p:C:P:b:" SOPT_QUIET SOPT_VERBOSE; static char proxy_help_text[] = "Usage: flexnbd-proxy \n\n" "Resiliently proxy an NBD connection between client and server\n" "We can listen on TCP or UNIX socket, but only connect to TCP servers.\n\n" HELP_LINE "\t--" OPT_ADDR ",-l \tThe address we will bind to as a proxy.\n" "\t--" OPT_PORT ",-p \tThe port we will bind to as a proxy, if required.\n" "\t--" OPT_CONNECT_ADDR ",-C \tAddress of the proxied server.\n" "\t--" OPT_CONNECT_PORT ",-P \tPort of the proxied server.\n" "\t--" OPT_BIND ",-b \tThe address we connect from, as a proxy.\n" "\t--" OPT_CACHE ",-c[=]\tUse a RAM read cache of the given size.\n" QUIET_LINE VERBOSE_LINE; static char proxy_default_cache_size[] = "4096"; void read_proxy_param( int c, char **downstream_addr, char **downstream_port, char **upstream_addr, char **upstream_port, char **bind_addr, char **cache_bytes) { switch( c ) { case 'h' : fprintf( stdout, "%s\n", proxy_help_text ); exit( 0 ); case 'l': *downstream_addr = optarg; break; case 'p': *downstream_port = optarg; break; case 'C': *upstream_addr = optarg; break; case 'P': *upstream_port = optarg; break; case 'b': *bind_addr = optarg; break; case 'c': *cache_bytes = optarg ? optarg : proxy_default_cache_size; break; case 'q': log_level = QUIET_LOG_LEVEL; break; case 'v': log_level = VERBOSE_LOG_LEVEL; break; default: exit_err( proxy_help_text ); break; } } struct proxier * proxy = NULL; void my_exit(int signum) { info( "Exit signalled (%i)", signum ); if ( NULL != proxy ) { proxy_cleanup( proxy ); }; exit( 0 ); } int main( int argc, char *argv[] ) { int c; char *downstream_addr = NULL; char *downstream_port = NULL; char *upstream_addr = NULL; char *upstream_port = NULL; char *bind_addr = NULL; char *cache_bytes = NULL; int success; sigset_t mask; struct sigaction exit_action; sigemptyset( &mask ); sigaddset( &mask, SIGTERM ); sigaddset( &mask, SIGQUIT ); sigaddset( &mask, SIGINT ); exit_action.sa_handler = my_exit; exit_action.sa_mask = mask; exit_action.sa_flags = 0; srand(time(NULL)); while (1) { c = getopt_long( argc, argv, proxy_short_options, proxy_options, NULL ); if ( -1 == c ) { break; } read_proxy_param( c, &downstream_addr, &downstream_port, &upstream_addr, &upstream_port, &bind_addr, &cache_bytes ); } if ( NULL == downstream_addr ){ fprintf( stderr, "--addr is required.\n" ); exit_err( proxy_help_text ); } else if ( NULL == upstream_addr || NULL == upstream_port ){ fprintf( stderr, "both --conn-addr and --conn-port are required.\n" ); exit_err( proxy_help_text ); } proxy = proxy_create( downstream_addr, downstream_port, upstream_addr, upstream_port, bind_addr, cache_bytes ); /* Set these *after* proxy has been assigned to */ sigaction(SIGTERM, &exit_action, NULL); sigaction(SIGQUIT, &exit_action, NULL); sigaction(SIGINT, &exit_action, NULL); signal(SIGPIPE, SIG_IGN); /* calls to splice() unhelpfully throw this */ if ( NULL != downstream_port ) { info( "Proxying between %s %s (downstream) and %s %s (upstream)", downstream_addr, downstream_port, upstream_addr, upstream_port ); } else { info( "Proxying between %s (downstream) and %s %s (upstream)", downstream_addr, upstream_addr, upstream_port ); } success = do_proxy( proxy ); proxy_destroy( proxy ); return success ? 0 : 1; }