aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2009-11-25 10:08:33 +0200
committerSergey Poznyakoff <gray@gnu.org.ua>2009-11-25 10:08:33 +0200
commit849e60108f8df449367f4a05eb489017bea35281 (patch)
treecd54057a69e19b9adc1364639a4dac9a37088a6b /src
parent534098c3d35f36ab9d333fb0ee800c7ffaf0dcbd (diff)
downloadpies-849e60108f8df449367f4a05eb489017bea35281.tar.gz
pies-849e60108f8df449367f4a05eb489017bea35281.tar.bz2
Implement TCPMUX internal service.
* src/pies.h (CF_TCPMUX, CF_TCPMUXPLUS): New flags. (struct component): New member: service. (progman_lookup_service, progman_run_comp) (progman_iterate_comp): New protos. * src/progman.c (progman_iterate_comp) (prog_lookup_by_service) (progman_lookup_service): New functions (prog_start_prologue, prog_execute): New functions, extracted from prog_start. (progman_run_comp): New function. (prog_start): Replace extracted parts of code with calls to prog_start_prologue and prog_execute. * src/inetd-bi.c: Implement TCPMUX * src/inetd.c (inetd_conf_file): Handle tcpmux extries.
Diffstat (limited to 'src')
-rw-r--r--src/inetd-bi.c116
-rw-r--r--src/inetd.c66
-rw-r--r--src/pies.h10
-rw-r--r--src/progman.c166
4 files changed, 270 insertions, 88 deletions
diff --git a/src/inetd-bi.c b/src/inetd-bi.c
index f86f373..60e6fb5 100644
--- a/src/inetd-bi.c
+++ b/src/inetd-bi.c
@@ -20,7 +20,7 @@
#define INTBUFSIZE 8192
/* Echo protocol, RFC 862 */
-void
+static void
echo_stream (int fd)
{
int rc;
@@ -31,7 +31,7 @@ echo_stream (int fd)
;
}
-void
+static void
echo_dg (int fd)
{
int rc;
@@ -46,7 +46,7 @@ echo_dg (int fd)
}
/* Discard protocol, RFC 863 */
-void
+static void
discard_stream (int fd)
{
int rc;
@@ -61,7 +61,7 @@ discard_stream (int fd)
}
}
-void
+static void
discard_dg (int fd)
{
char buffer[INTBUFSIZE];
@@ -76,7 +76,7 @@ discard_dg (int fd)
#define SEVENTY_YEARS ((unsigned long)25567 * 24 * 60 * 60)
-unsigned long
+static unsigned long
time_since_1900 (void)
{
struct timeval tv;
@@ -89,14 +89,14 @@ time_since_1900 (void)
return htonl ((long) (tv.tv_sec + SEVENTY_YEARS));
}
-void
+static void
time_stream (int fd)
{
unsigned long result = time_since_1900 ();
write (fd, (char *) &result, sizeof result);
}
-void
+static void
time_dg (int fd)
{
unsigned long result;
@@ -110,7 +110,7 @@ time_dg (int fd)
}
/* Daytime Protocol, RFC 867 */
-void
+static void
daytime_stream (int fd)
{
char buffer[27];
@@ -121,7 +121,7 @@ daytime_stream (int fd)
write (fd, buffer, strlen (buffer));
}
-void
+static void
daytime_dg (int fd)
{
char buffer[27];
@@ -159,7 +159,7 @@ chargen_next_line (char *text)
}
}
-void
+static void
chargen_stream (int fd)
{
char text[LINESIZ + 2];
@@ -175,7 +175,7 @@ chargen_stream (int fd)
}
}
-void
+static void
chargen_dg (int fd)
{
struct sockaddr sa;
@@ -218,7 +218,7 @@ trnl (char *text, size_t size)
return size;
}
-size_t
+static size_t
qotd_read (char *text)
{
ssize_t rc;
@@ -246,7 +246,7 @@ qotd_read (char *text)
return rc;
}
-void
+static void
qotd_stream (int fd)
{
char text[QOTD_MAX];
@@ -254,7 +254,7 @@ qotd_stream (int fd)
write (fd, text, len);
}
-void
+static void
qotd_dg (int fd)
{
char text[QOTD_MAX];
@@ -267,7 +267,90 @@ qotd_dg (int fd)
sendto (fd, text, len, 0, &sa, sizeof sa);
}
+
+/* TCPMUX service, RFC 1078 */
+#define MAX_SERV_LEN (256+2)
+
+static int
+fd_getline (int fd, char *buf, int len)
+{
+ int count = 0, n;
+
+ do
+ {
+ n = read (fd, buf, len - count);
+ if (n == 0)
+ return count;
+ if (n < 0)
+ return -1;
+ while (--n >= 0)
+ {
+ if (*buf == '\r' || *buf == '\n' || *buf == '\0')
+ return count;
+ count++;
+ buf++;
+ }
+ }
+ while (count < len);
+ return count;
+}
+
+static int
+fd_write (int fd, const char *text)
+{
+ return write (fd, text, strlen (text));
+}
+
+static int
+tcpmux_help (struct component *comp, void *data)
+{
+ int *pfd = data;
+
+ if (comp->flags & (CF_TCPMUXPLUS | CF_TCPMUX))
+ {
+ fd_write (*pfd, comp->service);
+ fd_write (*pfd, "\r\n");
+ }
+ return 0;
+}
+static void
+tcpmux (int fd)
+{
+ char service[MAX_SERV_LEN + 1];
+ size_t len;
+ struct component *comp;
+
+ /* Read service name */
+ if ((len = fd_getline (fd, service, MAX_SERV_LEN)) < 0)
+ {
+ fd_write (fd, "-Error reading service name\r\n");
+ return;
+ }
+ service[len] = 0;
+
+ debug (2, ("tcpmux: someone wants %s", service));
+
+ if (!strcasecmp (service, "help"))
+ {
+ progman_iterate_comp (tcpmux_help, &fd);
+ return;
+ }
+
+ comp = progman_lookup_service (service);
+ if (!comp)
+ {
+ fd_write (fd, "-Service not available\r\n");
+ return;
+ }
+
+ if (comp->flags & CF_TCPMUXPLUS)
+ fd_write (fd, "+Go\r\n");
+
+ progman_run_comp (comp, fd);
+}
+
+
struct inetd_builtin inetd_builtin_tab[] = {
/* Echo received data */
{"echo", SOCK_STREAM, 0, 0, echo_stream},
@@ -287,9 +370,8 @@ struct inetd_builtin inetd_builtin_tab[] = {
/* Quote of the Day */
{"qotd", SOCK_STREAM, 0, 0, qotd_stream},
{"qotd", SOCK_DGRAM, 1, 0, qotd_dg},
-#if 0
- {"tcpmux", SOCK_STREAM, 0, 0, tcpmux},
-#endif
+ /* TCPMUX */
+ {"tcpmux", SOCK_STREAM, 0, 0, tcpmux},
{NULL, 0, 0, 0, NULL}
};
diff --git a/src/inetd.c b/src/inetd.c
index f6c8276..f356512 100644
--- a/src/inetd.c
+++ b/src/inetd.c
@@ -35,6 +35,9 @@ listel_dispose(const void *el)
free((void*)el);
}
+#define TCPMUX_PREFIX_STR "tcpmux/"
+#define TCPMUX_PREFIX_LEN (sizeof(TCPMUX_PREFIX_STR)-1)
+
static int
inetd_conf_file (const char *file)
{
@@ -69,6 +72,7 @@ inetd_conf_file (const char *file)
char *service;
size_t len;
struct inetd_builtin *builtin;
+ char *tag;
if (line_no)
wordsplit_free (&ws);
@@ -135,21 +139,50 @@ inetd_conf_file (const char *file)
continue;
}
- /* Create URL from protocol and service fields. */
- str = xasprintf ("inet+%s://%s:%s",
- ws.ws_wordv[IFLD_PROTOCOL],
- address ? address : "0.0.0.0",
- service);
- if (pies_url_create (&url, str))
+ tag = service;
+ /* Handle eventual "tcpmux/" */
+ if (strncmp (service, TCPMUX_PREFIX_STR, TCPMUX_PREFIX_LEN) == 0)
{
- /* FIXME: Better error message */
- logmsg (LOG_ERR, "%s:%lu: %s",
- file, line_no, _("invalid socket address"));
- continue;
- }
-
- free (str);
+ service += TCPMUX_PREFIX_LEN;
+ if (*service == '+')
+ {
+ flags |= CF_TCPMUXPLUS;
+ service++;
+ }
+ else
+ flags |= CF_TCPMUX;
+ if (strncmp (ws.ws_wordv[IFLD_PROTOCOL], "tcp", 3))
+ {
+ logmsg (LOG_ERR, "%s:%lu: %s",
+ file, line_no, _("bad protocol for tcpmux service"));
+ continue;
+ }
+ if (socket_type != SOCK_STREAM)
+ {
+ logmsg (LOG_ERR, "%s:%lu: %s",
+ file, line_no, _("bad socket type for tcpmux service"));
+ continue;
+ }
+ url = NULL;
+ }
+ else
+ {
+ /* Create URL from protocol and service fields. */
+ str = xasprintf ("inet+%s://%s:%s",
+ ws.ws_wordv[IFLD_PROTOCOL],
+ address ? address : "0.0.0.0",
+ service);
+ if (pies_url_create (&url, str))
+ {
+ /* FIXME: Better error message */
+ logmsg (LOG_ERR, "%s:%lu: %s",
+ file, line_no, _("invalid socket address"));
+ continue;
+ }
+ free (str);
+ }
+
/* Parse wait/nowait field */
str = strchr (ws.ws_wordv[IFLD_WAIT], '.');
if (str)
@@ -201,15 +234,15 @@ inetd_conf_file (const char *file)
/* Create the component */
if (address)
{
- str = xmalloc (strlen (address) + 1 + strlen (service) + 1);
+ str = xmalloc (strlen (address) + 1 + strlen (tag) + 1);
strcpy (str, address);
strcat (str, ":");
- strcat (str, service);
+ strcat (str, tag);
comp = component_create (str);
free (str);
}
else
- comp = component_create (service);
+ comp = component_create (tag);
comp->mode = pies_comp_inetd;
comp->socket_type = socket_type;
@@ -222,6 +255,7 @@ inetd_conf_file (const char *file)
}
else
comp->flags = flags;
+ comp->service = xstrdup (service);
comp->privs.user = xstrdup (user); /* FIXME: memory leak */
if (group)
{
diff --git a/src/pies.h b/src/pies.h
index d9c1a3c..9ec1410 100644
--- a/src/pies.h
+++ b/src/pies.h
@@ -140,6 +140,8 @@ enum pies_comp_mode
#define CF_PRECIOUS 0x02 /* The component is precious (should not
be disabled) */
#define CF_WAIT 0x04
+#define CF_TCPMUX 0x08
+#define CF_TCPMUXPLUS 0x10
struct component
{
@@ -159,6 +161,7 @@ struct component
(inetd) */
int socket_type; /* Socket type */
struct inetd_builtin *builtin; /* Builtin function (inetd) */
+ char *service;
char *rmfile; /* Try to remove this file before starting */
struct pies_privs privs; /* UID/GIDS+groups to run under */
mode_t umask; /* Umask to install before starting */
@@ -205,6 +208,12 @@ int progman_accept (int socket);
int progman_build_depmap (void);
void progman_create_sockets (void);
struct component *progman_lookup_component (const char *tag);
+struct component *progman_lookup_service (const char *service);
+void progman_run_comp (struct component *comp, int fd);
+
+void progman_iterate_comp (int (*fun) (struct component *, void *),
+ void *data);
+
void log_setup (int want_stderr);
void signal_setup (RETSIGTYPE (*sf)(int));
@@ -232,6 +241,7 @@ int assert_grecs_value_type (grecs_locus_t *locus,
int str_to_socket_type (const char *str, int *pret);
struct component *component_create (const char *name);
+
void component_finish (struct component *comp, grecs_locus_t *locus);
struct grecs_keyword *find_component_keyword (const char *ident);
diff --git a/src/progman.c b/src/progman.c
index 35fc876..1235d81 100644
--- a/src/progman.c
+++ b/src/progman.c
@@ -78,6 +78,19 @@ static struct prog *proghead, *progtail;
static pies_depmap_t depmap;
static int recompute_alarm;
+void
+progman_iterate_comp (int (*fun) (struct component *, void *), void *data)
+{
+ struct prog *prog;
+
+ for (prog = proghead; prog; prog = prog->next)
+ if (IS_COMPONENT (prog)
+ && !(prog->v.p.comp->mode == pies_comp_inetd
+ && prog->v.p.listener)
+ && fun (prog->v.p.comp, data))
+ break;
+}
+
static struct prog *
prog_lookup_by_pid (pid_t pid)
{
@@ -110,6 +123,18 @@ prog_lookup_by_tag (const char *tag)
return prog;
}
+struct prog *
+prog_lookup_by_service (const char *service)
+{
+ struct prog *prog;
+ for (prog = proghead; prog; prog = prog->next)
+ if (IS_COMPONENT (prog)
+ && prog->v.p.comp->service
+ && strcmp (prog->v.p.comp->service, service) == 0)
+ break;
+ return prog;
+}
+
struct component *
progman_lookup_component (const char *tag)
{
@@ -120,6 +145,15 @@ progman_lookup_component (const char *tag)
return NULL;
}
+struct component *
+progman_lookup_service (const char *service)
+{
+ struct prog *prog = prog_lookup_by_service (service);
+ if (!prog)
+ return NULL;
+ return prog->v.p.comp;
+}
+
struct prog *
prog_lookup_by_idx (unsigned idx)
{
@@ -693,6 +727,77 @@ prog_open_socket (struct prog *prog)
}
static void
+prog_start_prologue (struct prog *prog)
+{
+ if (prog->v.p.comp->dir)
+ {
+ debug (1, (_("chdir %s"), prog->v.p.comp->dir));
+ if (chdir (prog->v.p.comp->dir))
+ logmsg (LOG_ERR, _("%s: cannot change to directory %s: %s"),
+ prog->tag, prog->v.p.comp->dir, strerror (errno));
+ }
+
+ environ = env_setup (prog->v.p.comp->env);
+ if (debug_level >= 4)
+ {
+ int i;
+ logmsg_printf (LOG_DEBUG, "environment: ");
+ for (i = 0; environ[i]; i++)
+ logmsg_printf (LOG_DEBUG, "%s ", environ[i]);
+ logmsg_printf (LOG_DEBUG, "\n");
+ }
+
+ pies_priv_setup (&prog->v.p.comp->privs);
+ if (prog->v.p.comp->umask)
+ umask (prog->v.p.comp->umask);
+
+ set_limits (prog->tag,
+ prog->v.p.comp->limits ?
+ prog->v.p.comp->limits : pies_limits);
+
+ if (debug_level >= 1)
+ {
+ int i;
+ struct component *comp = prog->v.p.comp;
+
+ logmsg_printf (LOG_DEBUG, "executing");
+ for (i = 0; i < comp->argc; i++)
+ logmsg_printf (LOG_DEBUG, " %s",
+ quotearg (comp->argv[i]));
+ logmsg_printf (LOG_DEBUG, "\n");
+ }
+}
+
+static void
+prog_execute (struct prog *prog)
+{
+ if (prog->v.p.comp->builtin)
+ {
+ mf_proctitle_format ("inetd %s",
+ prog->v.p.comp->builtin->service);
+ prog->v.p.comp->builtin->fun (0);
+ _exit (0);
+ }
+
+ execvp (prog->v.p.comp->program ?
+ prog->v.p.comp->program : prog->v.p.comp->argv[0],
+ prog->v.p.comp->argv);
+ openlog (log_tag, LOG_PID, prog->v.p.comp->facility);
+ syslog (LOG_CRIT, _("cannot start `%s': %s"), prog->tag,
+ strerror (errno));
+ _exit (EX_SOFTWARE);
+}
+
+void
+progman_run_comp (struct component *comp, int fd)
+{
+ struct prog *prog = register_prog0 (comp, -1);
+ prog->v.p.socket = fd;
+ prog_start_prologue (prog);
+ prog_execute (prog);
+}
+
+static void
prog_start (struct prog *prog)
{
pid_t pid;
@@ -769,52 +874,7 @@ prog_start (struct prog *prog)
/* The child branch. */
case 0:
signal_setup (SIG_DFL);
- if (prog->v.p.comp->dir)
- {
- debug (1, (_("chdir %s"), prog->v.p.comp->dir));
- if (chdir (prog->v.p.comp->dir))
- logmsg (LOG_ERR, _("%s: cannot change to directory %s: %s"),
- prog->tag, prog->v.p.comp->dir, strerror (errno));
- }
-
- environ = env_setup (prog->v.p.comp->env);
- if (debug_level >= 4)
- {
- int i;
- logmsg_printf (LOG_DEBUG, "environment: ");
- for (i = 0; environ[i]; i++)
- logmsg_printf (LOG_DEBUG, "%s ", environ[i]);
- logmsg_printf (LOG_DEBUG, "\n");
- }
-
- pies_priv_setup (&prog->v.p.comp->privs);
- if (prog->v.p.comp->umask)
- umask (prog->v.p.comp->umask);
-
- set_limits (prog->tag,
- prog->v.p.comp->limits ?
- prog->v.p.comp->limits : pies_limits);
-
- if (prog->v.p.comp->builtin)
- {
- mf_proctitle_format ("inetd %s",
- prog->v.p.comp->builtin->service);
- prog->v.p.comp->builtin->fun (prog->v.p.socket);
- _exit (0);
- }
-
- if (debug_level >= 1)
- {
- int i;
- struct component *comp = prog->v.p.comp;
-
- logmsg_printf (LOG_DEBUG, "executing");
- for (i = 0; i < comp->argc; i++)
- logmsg_printf (LOG_DEBUG, " %s",
- quotearg (comp->argv[i]));
- logmsg_printf (LOG_DEBUG, "\n");
- }
-
+ prog_start_prologue (prog);
switch (prog->v.p.comp->mode)
{
case pies_comp_pass_fd:
@@ -858,14 +918,9 @@ prog_start (struct prog *prog)
FD_SET (prog->v.p.socket, &fdset);
close_fds (&fdset);
- execvp (prog->v.p.comp->program ?
- prog->v.p.comp->program : prog->v.p.comp->argv[0],
- prog->v.p.comp->argv);
- openlog (log_tag, LOG_PID, prog->v.p.comp->facility);
- syslog (LOG_CRIT, _("cannot start `%s': %s"), prog->tag,
- strerror (errno));
- _exit (EX_SOFTWARE);
-
+ prog_execute (prog);
+
+
case -1:
logmsg (LOG_CRIT,
_("cannot run `%s': fork failed: %s"),
@@ -1199,7 +1254,8 @@ progman_create_sockets ()
if (IS_COMPONENT (prog))
{
struct component *comp = prog->v.p.comp;
- if (comp->mode == pies_comp_inetd)
+ if (comp->mode == pies_comp_inetd
+ && !(comp->flags & (CF_TCPMUXPLUS | CF_TCPMUX)))
{
int fd = create_socket (comp->socket_url,
comp->socket_type,

Return to:

Send suggestions and report system problems to the System administrator.