From c96c03a9e0fa1fbc08ec3f31f7e93b12fc29f9b3 Mon Sep 17 00:00:00 2001 From: short <> Date: Mon, 8 Aug 2005 08:34:21 +0000 Subject: [PATCH] Untested draft of xinetd(8) interface for on-demand standalone servers. --- inetdmx.c | 290 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 290 insertions(+) create mode 100644 inetdmx.c diff --git a/inetdmx.c b/inetdmx.c new file mode 100644 index 0000000..e3c4d96 --- /dev/null +++ b/inetdmx.c @@ -0,0 +1,290 @@ +/* $Id$ */ + + +#define _GNU_SOURCE 1 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define CONNECT_RETRY_MSEC 100 + +static long opt_start_timeout=60; +static int opt_port; +static int opt_syslog; +static int opt_stderr; + + +/* /usr/include/glib-2.0/glib/gmacros.h */ +#ifndef G_GNUC_PRINTF +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4) +#define G_GNUC_PRINTF( format_idx, arg_idx ) \ + __attribute__((__format__ (__printf__, format_idx, arg_idx))) +#else /* !__GNUC__ */ +#define G_GNUC_PRINTF( format_idx, arg_idx ) +#endif /* !__GNUC__ */ +#endif /* !G_GNUC_PRINTF */ + +/* /usr/include/glib-2.0/glib/gmacros.h */ +#ifndef G_GNUC_NORETURN +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4) +#define G_GNUC_NORETURN \ + __attribute__((__noreturn__)) +#else /* !__GNUC__ */ +#define G_GNUC_NORETURN +#endif /* !__GNUC__ */ +#endif /* !G_GNUC_NORETURN */ + +/* /usr/include/glib-2.0/glib/gmacros.h */ +/* Count the number of elements in an array. The array must be defined + * as such; using this with a dynamically allocated array will give + * incorrect results. + */ +#define G_N_ELEMENTS(arr) (sizeof (arr) / sizeof ((arr)[0])) + + +static const char *program_name; + +static void fatal(const char *fmt,...) G_GNUC_PRINTF(1,2) G_GNUC_NORETURN; +static void fatal(const char *fmt,...) +{ +int use_syslog=opt_syslog,use_stderr=opt_stderr; +va_list ap; +char *string; +const char *const error_error="Error printing error message"; + + if (!use_syslog && !use_stderr) + use_stderr=1; + va_start(ap,fmt); + if (-1==vasprintf(&string,fmt,ap)) { + if (fmt==error_error) + exit(EXIT_FAILURE); + fatal(error_error); + } + if (use_stderr) + fprintf(stderr,"%s: %s!\n",program_name,string); + if (use_syslog) { + openlog(program_name,LOG_PID,LOG_DAEMON); + syslog(LOG_DAEMON|LOG_ERR,"%s!",string); + closelog(); + } + va_end(ap); + exit(EXIT_FAILURE); +} + +static void usage(void) +{ + fprintf(stderr,"\ +Syntax: %s [{-T|--start-timeout} \n\ +\n\ +Error messages out to stderr by default, -S|--syslog omits stderr output,\n\ +both -S|--syslog and -e|--stderr output the errors by both methods.\n\ +\n",program_name); + exit(EXIT_FAILURE); +} + +static const struct option longopts[]={ + {"start-timeout",1,0,'T'}, + {"syslog" ,0,0,'S'}, + {"stderr" ,0,0,'e'}, + {"port" ,1,0,'p'}, + {NULL ,0,0,0 }, + }; + +static int connect_try(void) +{ +int fdtcp; +struct sockaddr_in sockaddr_tcp; + + if (-1==(fdtcp=socket(PF_INET,SOCK_STREAM,0))) + fatal("socket(PF_INET,SOCK_STREAM,0)=%d: %m",fdtcp); + memset(&sockaddr_tcp,0,sizeof(sockaddr_tcp)); + sockaddr_tcp.sin_family=AF_INET; + sockaddr_tcp.sin_addr.s_addr=htonl(INADDR_LOOPBACK); + sockaddr_tcp.sin_port=htons(opt_port); + if (connect(fdtcp,(const struct sockaddr *)&sockaddr_tcp,sizeof(sockaddr_tcp))) { + if (errno==ECONNREFUSED) + return -1; + fatal("connect(TCP socket,127.0.0.1:%d): %m",opt_port); + } + return fdtcp; +} + +static void session_transfer( + const char *conn0_name,int conn0_fdin,int conn0_fdout, + const char *conn1_name,int conn1_fdin,int conn1_fdout) + G_GNUC_NORETURN; +static void session_transfer( + const char *conn0_name,int conn0_fdin,int conn0_fdout, + const char *conn1_name,int conn1_fdin,int conn1_fdout) +{ +struct pollfd pollfdi[2]; +int pollfdo[2]; +const char *pollfdi_name[2]; +int fdi,fdo; + + pollfdi[0].fd=conn0_fdin; + pollfdi[0].events=POLLIN; + pollfdi[1].fd=conn1_fdin; + pollfdi[1].events=POLLIN; + pollfdo[0]=conn0_fdout; + pollfdo[1]=conn1_fdout; + pollfdi_name[0]=conn0_name; + pollfdi_name[1]=conn1_name; + for (;;) { + for (fdi=0;fdi=G_N_ELEMENTS(pollfdi)) + exit(EXIT_SUCCESS); + if (0>=poll(pollfdi,G_N_ELEMENTS(pollfdi),-1)) + fatal("poll(%s socket,%s socket): %m",pollfdi_name[0],pollfdi_name[1]); + for (fdi=0;fdi=LONG_MAX || (endptr && *endptr)) + fatal("Invalid -T|--start-timeout values: %s",optarg); + opt_start_timeout=l; + break; + + case 'p': /* -p|--port */ + l=strtol(optarg,&endptr,0); + if (l<=0 || l>=0x10000 || (endptr && *endptr)) + fatal("Invalid -p|--port value: %s",optarg); + opt_port=l; + break; + + default: + if (optc!='h') + fatal("Error parsing commandline!"); + usage(); + break; + } + + if (!opt_port) + fatal("-p|--port is a required argument!"); + if (optind>=argc) + fatal(" is a required argument!"); + if (optind+1 needs quoting?"); + command=argv[optind]; + + session_try(); + system_checked(command); + + for (retry=0;retry*CONNECT_RETRY_MSEC/1000