/* GNU Mailutils -- a suite of utilities for electronic mail Copyright (C) 2007-2008, 2010-2012, 2014-2016 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 <http://www.gnu.org/licenses/>. */ #ifdef HAVE_CONFIG_H # include <config.h> #endif #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <sys/time.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <signal.h> #include <sys/wait.h> #include <mailutils/mailutils.h> #include <mailutils/server.h> 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 (); }