/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2007-2021 Free Software Foundation, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; If not, see
. */
#ifdef HAVE_CONFIG_H
# include
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
mu_server_t server;
int
echo_conn (int fd, struct sockaddr *s, int len,
void *server_data, void *call_data,
mu_ip_server_t srv)
{
pid_t pid;
char buf[512];
FILE *in, *out;
pid = fork ();
if (pid == -1)
{
mu_error ("fork failed: %s", mu_strerror (errno));
return 0;
}
if (pid)
{
struct mu_sockaddr *clt_addr;
int rc = mu_sockaddr_create (&clt_addr, s, len);
if (rc)
{
mu_error ("mu_sockaddr_create failed: %s", mu_strerror (rc));
return 0;
}
mu_diag_output (MU_DIAG_INFO, "%lu: opened connection %s => %s",
(unsigned long) pid,
mu_ip_server_addrstr (srv),
mu_sockaddr_str (clt_addr));
mu_sockaddr_free (clt_addr);
return 0;
}
mu_ip_server_shutdown (srv);
in = fdopen (fd, "r");
out = fdopen (fd, "w");
setvbuf (in, NULL, _IOLBF, 0);
setvbuf (out, NULL, _IOLBF, 0);
pid = getpid ();
while (fgets (buf, sizeof (buf), in) > 0)
{
int len = strlen (buf);
if (len > 0 && buf[len-1] == '\n')
{
buf[--len] = 0;
if (buf[len-1] == '\r')
buf[--len] = 0;
}
fprintf (out, "%lu: you said: \"%s\"\r\n", (unsigned long) pid, buf);
}
exit (0);
}
int
tcp_conn_handler (int fd, void *conn_data, void *server_data)
{
mu_ip_server_t tcpsrv = (mu_ip_server_t) conn_data;
int rc = mu_ip_server_accept (tcpsrv, server_data);
if (rc && rc != EINTR)
{
mu_ip_server_shutdown (tcpsrv);
return MU_SERVER_CLOSE_CONN;
}
return MU_SERVER_SUCCESS;
}
void
tcp_conn_free (void *conn_data, void *server_data)
{
mu_ip_server_t tcpsrv = (mu_ip_server_t) conn_data;
mu_ip_server_destroy (&tcpsrv);
}
void
create_server (char *arg)
{
struct mu_sockaddr *s;
mu_ip_server_t tcpsrv;
int rc;
mu_url_t url, url_hint;
struct mu_sockaddr_hints hints;
if (arg[0] == '/')
url_hint = NULL;
else
{
rc = mu_url_create (&url_hint, "inet://");
if (rc)
{
mu_error ("cannot create URL hints: %s", mu_strerror (rc));
exit (1);
}
}
rc = mu_url_create_hint (&url, arg, MU_URL_PARSE_DEFAULT, url_hint);
mu_url_destroy (&url_hint);
if (rc)
{
mu_error ("cannot parse URL `%s': %s", arg, mu_strerror (rc));
exit (1);
}
memset (&hints, 0, sizeof(hints));
hints.flags = MU_AH_PASSIVE;
hints.socktype = SOCK_STREAM;
hints.protocol = IPPROTO_TCP;
rc = mu_sockaddr_from_url (&s, url, &hints);
mu_url_destroy (&url);
if (rc)
{
mu_error ("cannot create sockaddr: %s", mu_strerror (rc));
exit (1);
}
MU_ASSERT (mu_ip_server_create (&tcpsrv, s, MU_IP_TCP));
MU_ASSERT (mu_ip_server_open (tcpsrv));
MU_ASSERT (mu_ip_server_set_conn (tcpsrv, echo_conn));
MU_ASSERT (mu_server_add_connection (server,
mu_ip_server_get_fd (tcpsrv),
tcpsrv,
tcp_conn_handler, tcp_conn_free));
}
static int cleanup_needed;
RETSIGTYPE
sig_child (int sig)
{
cleanup_needed = 1;
signal (sig, sig_child);
}
int
server_idle (void *server_data)
{
if (cleanup_needed)
{
int status;
pid_t pid;
cleanup_needed = 0;
while ((pid = waitpid (-1, &status, WNOHANG)) > 0)
{
if (WIFEXITED (status))
mu_diag_output (MU_DIAG_INFO, "%lu: finished with code %d",
(unsigned long) pid,
WEXITSTATUS (status));
else if (WIFSIGNALED (status))
mu_diag_output (MU_DIAG_ERR, "%lu: terminated on signal %d",
(unsigned long) pid,
WTERMSIG (status));
else
mu_diag_output (MU_DIAG_ERR, "%lu: terminated (cause unknown)",
(unsigned long) pid);
}
}
return 0;
}
int
run ()
{
int rc;
signal (SIGCHLD, sig_child);
rc = mu_server_run (server);
if (rc)
mu_error ("%s", mu_strerror (rc));
mu_server_destroy (&server);
return rc ? 1 : 0;
}
int
main (int argc, char **argv)
{
int rc;
mu_set_program_name (argv[0]);
while ((rc = getopt (argc, argv, "Dd:")) != EOF)
{
switch (rc)
{
case 'D':
mu_debug_line_info = 1;
break;
case 'd':
mu_debug_parse_spec (optarg);
break;
default:
exit (1);
}
}
argc -= optind;
argv += optind;
MU_ASSERT (mu_server_create (&server));
mu_server_set_idle (server, server_idle);
while (argc--)
create_server (*argv++);
return run ();
}