Commit 797a5462 797a5462a89c41ffe944a10746a4b5b29ee077c0 by Sergey Poznyakoff

* examples/Makefile.am: add echosrv.c.

* examples/echosrv.c: New file.
* include/mailutils/Makefile.am: Add server.h.
* include/mailutils/server.h: New file.
* include/mailutils/acl.h (mu_acl_t): Move to types.hin
* include/mailutils/types.hin (mu_acl_t,mu_server_t)
(mu_tcp_server_t): New types.
* mailbox/Makefile.am: Add server.c and tcpsrv.c.
* mailbox/server.c: New file.
* mailbox/tcpsrv.c: New file.
* mailbox/acl.c: Include <sys/wait.h>
Rename all `sin' and `sun' to avoid name clashes.
* mailbox/errors (MU_ERR_LOCK_EXT_FAIL): Do not abbreviate
anything in error description.
1 parent c119cfbf
2007-12-09 Sergey Poznyakoff <gray@gnu.org.ua>
* examples/Makefile.am: add echosrv.c.
* examples/echosrv.c: New file.
* include/mailutils/Makefile.am: Add server.h.
* include/mailutils/server.h: New file.
* include/mailutils/acl.h (mu_acl_t): Move to types.hin
* include/mailutils/types.hin (mu_acl_t,mu_server_t)
(mu_tcp_server_t): New types.
* mailbox/Makefile.am: Add server.c and tcpsrv.c.
* mailbox/server.c: New file.
* mailbox/tcpsrv.c: New file.
* mailbox/acl.c: Include <sys/wait.h>
Rename all `sin' and `sun' to avoid name clashes.
* mailbox/errors (MU_ERR_LOCK_EXT_FAIL): Do not abbreviate
anything in error description.
* auth/ldap.c (_construct_attr_array): Use mu_vartab_* to expand
filter.
* imap4d/preauth.c: Fix misleading comment.
......
......@@ -25,6 +25,7 @@ noinst_PROGRAMS = \
argcv\
base64\
decode2047\
echosrv\
encode2047\
header\
http\
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2007 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 "getopt.h"
#include <mailutils/mailutils.h>
#include <mailutils/server.h>
#define MU_ASSERT(expr) \
do \
{ \
int rc = expr; \
if (rc) \
{ \
mu_error (#expr " failed: %s", mu_strerror (rc)); \
abort (); \
} \
} \
while (0);
mu_server_t server;
int
echo_conn (int fd, struct sockaddr_in *s, void *server_data, void *call_data,
mu_tcp_server_t srv)
{
struct sockaddr_in srv_addr;
pid_t pid;
char *buf = NULL;
size_t size = 0;
FILE *in, *out;
mu_tcp_server_get_sockaddr (srv, &srv_addr);
pid = fork ();
if (pid == -1)
{
mu_error ("fork failed: %s", mu_strerror (errno));
return 0;
}
if (pid)
{
mu_diag_output (MU_DIAG_INFO, "%lu: opened connection %s:%d => %s:%d",
(unsigned long) pid,
inet_ntoa (srv_addr.sin_addr), ntohs (srv_addr.sin_port),
inet_ntoa (s->sin_addr), ntohs (s->sin_port));
return 0;
}
mu_tcp_server_shutdown (srv);
in = fdopen (fd, "r");
out = fdopen (fd, "w");
setvbuf (in, NULL, _IOLBF, 0);
setvbuf (out, NULL, _IOLBF, 0);
pid = getpid ();
while (getline (&buf, &size, in) > 0)
{
int len = strlen (buf);
if (len > 0)
{
buf[--len] = 0;
if (buf[len-1] == '\r')
buf[--len] = 0;
}
fprintf (out, "%lu: you said: \"%s\"\r\n", (unsigned long) pid, buf);
}
free (buf);
exit (0);
}
int
tcp_conn_handler (int fd, void *conn_data, void *server_data)
{
mu_tcp_server_t tcpsrv = (mu_tcp_server_t) conn_data;
int rc = mu_tcp_server_accept (tcpsrv, server_data);
if (rc && rc != EINTR)
{
mu_tcp_server_shutdown (tcpsrv);
return MU_SERVER_CLOSE_CONN;
}
return MU_SERVER_SUCCESS;
}
void
tcp_conn_free (void *conn_data, void *server_data)
{
mu_tcp_server_t tcpsrv = (mu_tcp_server_t) conn_data;
mu_tcp_server_destroy (&tcpsrv);
}
void
create_server (char *arg)
{
char *p, *q;
struct sockaddr_in s;
mu_tcp_server_t tcpsrv;
unsigned n;
p = strchr (arg, ':');
if (!*p)
{
mu_error ("invalid specification: %s\n", arg);
exit (1);
}
*p++ = 0;
s.sin_family = AF_INET;
if (inet_aton (arg, &s.sin_addr) == 0)
{
mu_error ("invalid IP address: %s\n", arg);
exit (1);
}
n = strtoul (p, &q, 0);
if (*q)
{
mu_error ("invalid port number: %s\n", p);
exit (1);
}
s.sin_port = htons (n);
MU_ASSERT (mu_tcp_server_create (&tcpsrv, &s));
MU_ASSERT (mu_tcp_server_open (tcpsrv));
MU_ASSERT (mu_tcp_server_set_conn (tcpsrv, echo_conn));
MU_ASSERT (mu_server_add_connection (server,
mu_tcp_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)");
}
}
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_global_debug_from_string (optarg, "command line");
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 ();
}
......@@ -81,6 +81,7 @@ pkginclude_HEADERS = \
refcount.h\
registrar.h\
sha1.h\
server.h\
stream.h\
syslog.h\
sql.h\
......
......@@ -21,8 +21,6 @@
#include <mailutils/types.h>
#include <mailutils/iterator.h>
typedef struct _mu_acl *mu_acl_t;
typedef enum mu_acl_action
{
mu_acl_accept,
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2007 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/>. */
#ifndef _MAILUTILS_SERVER_H
#define _MAILUTILS_SERVER_H
#include <mailutils/types.h>
typedef int (*mu_conn_loop_fp) (int fd, void *conn_data, void *server_data);
typedef void (*mu_conn_free_fp) (void *conn_data, void *server_data);
typedef int (*mu_server_idle_fp) (void *server_data);
typedef void (*mu_server_free_fp) (void *server_data);
#define MU_SERVER_SUCCESS 0
#define MU_SERVER_CLOSE_CONN 1
#define MU_SERVER_SHUTDOWN 2
int mu_server_run (mu_server_t srv);
int mu_server_create (mu_server_t *psrv);
int mu_server_destroy (mu_server_t *psrv);
int mu_server_set_idle (mu_server_t srv, mu_server_idle_fp fp);
int mu_server_set_data (mu_server_t srv, void *data, mu_server_free_fp fp);
int mu_server_add_connection (mu_server_t srv,
int fd, void *data,
mu_conn_loop_fp loop, mu_conn_free_fp free);
struct timeval;
int mu_server_set_timeout (mu_server_t srv, struct timeval *to);
int mu_server_count (mu_server_t srv, size_t *pcount);
/* TCP server */
struct sockaddr_in;
typedef int (*mu_tcp_server_conn_fp) (int fd, struct sockaddr_in *s,
void *server_data, void *call_data,
mu_tcp_server_t srv);
typedef int (*mu_tcp_server_intr_fp) (void *data, void *call_data);
typedef void (*mu_tcp_server_free_fp) (void *data);
int mu_tcp_server_create (mu_tcp_server_t *psrv, struct sockaddr_in *addr);
int mu_tcp_server_destroy (mu_tcp_server_t *psrv);
int mu_tcp_server_set_debug (mu_tcp_server_t srv, mu_debug_t debug);
int mu_tcp_server_get_debug (mu_tcp_server_t srv, mu_debug_t *pdebug);
int mu_tcp_server_set_backlog (mu_tcp_server_t srv, int backlog);
int mu_tcp_server_set_ident (mu_tcp_server_t srv, const char *ident);
int mu_tcp_server_set_acl (mu_tcp_server_t srv, mu_acl_t acl);
int mu_tcp_server_set_conn (mu_tcp_server_t srv, mu_tcp_server_conn_fp conn);
int mu_tcp_server_set_intr (mu_tcp_server_t srv, mu_tcp_server_intr_fp intr);
int mu_tcp_server_set_data (mu_tcp_server_t srv,
void *data, mu_tcp_server_free_fp free);
int mu_tcp_server_open (mu_tcp_server_t srv);
int mu_tcp_server_shutdown (mu_tcp_server_t srv);
int mu_tcp_server_accept (mu_tcp_server_t srv, void *call_data);
int mu_tcp_server_loop (mu_tcp_server_t srv, void *call_data);
int mu_tcp_server_get_fd (mu_tcp_server_t srv);
int mu_tcp_server_get_sockaddr (mu_tcp_server_t srv, struct sockaddr_in *s);
#endif
......@@ -66,7 +66,10 @@ struct _mu_ticket;
struct _mu_url;
struct _mu_wicket;
struct _mu_assoc;
struct _mu_acl;
struct _mu_server;
struct _mu_tcp_server;
typedef MU_OFF_TYPE mu_off_t;
typedef struct _mu_address *mu_address_t;
......@@ -102,6 +105,9 @@ typedef void *mu_transport_t;
typedef struct _mu_assoc *mu_assoc_t;
typedef char *mu_message_qid_t;
typedef int mu_log_level_t;
typedef struct _mu_acl *mu_acl_t;
typedef struct _mu_server *mu_server_t;
typedef struct _mu_tcp_server *mu_tcp_server_t;
#define MU_FOLDER_ATTRIBUTE_DIRECTORY 0x001
#define MU_FOLDER_ATTRIBUTE_FILE 0x002
......
......@@ -97,12 +97,14 @@ libmailutils_la_SOURCES = \
refcount.c\
rfc2047.c\
sha1.c\
server.c\
socket_stream.c\
stream.c\
syslog.c\
system.c\
tcp.c\
ticket.c\
tcp.c\
tcpsrv.c\
url.c\
vartab.c\
version.c\
......
......@@ -24,6 +24,7 @@
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
......@@ -74,8 +75,8 @@ prepare_sa (struct sockaddr *sa)
{
case AF_INET:
{
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
sin->sin_addr.s_addr = ntohl (sin->sin_addr.s_addr);
struct sockaddr_in *s_in = (struct sockaddr_in *)sa;
s_in->sin_addr.s_addr = ntohl (s_in->sin_addr.s_addr);
break;
}
......@@ -313,16 +314,16 @@ debug_sockaddr (mu_debug_t dbg, mu_log_level_t lvl, struct sockaddr *sa)
{
case AF_INET:
{
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
struct sockaddr_in *s_in = (struct sockaddr_in *)sa;
mu_debug_printf (dbg, lvl, "{AF_INET %s:%d}",
inet_ntoa (sin->sin_addr), ntohs (sin->sin_port));
inet_ntoa (s_in->sin_addr), ntohs (s_in->sin_port));
break;
}
case AF_UNIX:
{
struct sockaddr_un *sun = (struct sockaddr_un *)sa;
mu_debug_printf (dbg, lvl, "{AF_UNIX %s}", sun->sun_path);
struct sockaddr_un *s_un = (struct sockaddr_un *)sa;
mu_debug_printf (dbg, lvl, "{AF_UNIX %s}", s_un->sun_path);
break;
}
......@@ -439,25 +440,25 @@ spawn_prog (const char *cmdline, int *pstatus, struct run_closure *rp)
{
case AF_INET:
{
struct sockaddr_in *sin = (struct sockaddr_in *)rp->sa;
struct in_addr addr = sin->sin_addr;
struct sockaddr_in *s_in = (struct sockaddr_in *)rp->sa;
struct in_addr addr = s_in->sin_addr;
char buf[UINTMAX_STRSIZE_BOUND];
unsigned n;
mu_vartab_define (vtab, "family", "AF_INET", 1);
addr.s_addr = htonl (addr.s_addr);
mu_vartab_define (vtab, "address", inet_ntoa (addr), 0);
n = ntohs (sin->sin_port);
n = ntohs (s_in->sin_port);
mu_vartab_define (vtab, "port", umaxtostr (n, buf), 0);
}
break;
case AF_UNIX:
{
struct sockaddr_un *sun = (struct sockaddr_un *)rp->sa;
struct sockaddr_un *s_un = (struct sockaddr_un *)rp->sa;
mu_vartab_define (vtab, "family", "AF_UNIX", 1);
mu_vartab_define (vtab, "address", sun->sun_path, 1);
mu_vartab_define (vtab, "address", s_un->sun_path, 1);
}
break;
}
......
......@@ -35,7 +35,7 @@ MU_ERR_LOCK_CONFLICT _("Conflict with previous locker")
MU_ERR_LOCK_BAD_LOCK _("Lock file check failed")
MU_ERR_LOCK_BAD_FILE _("File check failed")
MU_ERR_LOCK_NOT_HELD _("Lock not held on file")
MU_ERR_LOCK_EXT_FAIL _("Failed to exec external locker")
MU_ERR_LOCK_EXT_FAIL _("Failed to execute external locker")
MU_ERR_LOCK_EXT_ERR _("External locker failed")
MU_ERR_LOCK_EXT_KILLED _("External locker killed")
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2007 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 <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <mailutils/server.h>
#include <mailutils/errno.h>
struct _mu_connection
{
struct _mu_connection *next, *prev;
int fd;
mu_conn_loop_fp f_loop;
mu_conn_free_fp f_free;
void *data;
};
#define MU_SERVER_TIMEOUT 0x1
struct _mu_server
{
int nfd;
fd_set fdset;
int flags;
struct timeval timeout;
struct _mu_connection *head, *tail;
mu_server_idle_fp f_idle;
mu_server_free_fp f_free;
void *server_data;
};
void
recompute_nfd (mu_server_t srv)
{
struct _mu_connection *p;
int nfd = 0;
for (p = srv->head; p; p = p->next)
if (p->fd > nfd)
nfd = p->fd;
srv->nfd = nfd + 1;
}
void
destroy_connection (mu_server_t srv, struct _mu_connection *conn)
{
if (conn->f_free)
conn->f_free (conn->data, srv->server_data);
free (conn);
}
void
remove_connection (mu_server_t srv, struct _mu_connection *conn)
{
struct _mu_connection *p;
close (conn->fd);
FD_CLR (conn->fd, &srv->fdset);
p = conn->prev;
if (p)
p->next = conn->next;
else /* we're at head */
srv->head = conn->next;
p = conn->next;
if (p)
p->prev = conn->prev;
else /* we're at tail */
srv->tail = conn->prev;
if (conn->fd == srv->nfd - 1)
recompute_nfd (srv);
destroy_connection (srv, conn);
}
int
connection_loop (mu_server_t srv, fd_set *fdset)
{
struct _mu_connection *conn;
for (conn = srv->head; conn;)
{
struct _mu_connection *next = conn->next;
if (FD_ISSET (conn->fd, fdset))
{
int rc = conn->f_loop (conn->fd, conn->data, srv->server_data);
switch (rc)
{
case 0:
break;
case MU_SERVER_CLOSE_CONN:
default:
remove_connection (srv, conn);
break;
case MU_SERVER_SHUTDOWN:
return 1;
}
}
conn = next;
}
return 0;
}
void
make_fdset (mu_server_t srv)
{
struct _mu_connection *p;
int nfd = 0;
FD_ZERO (&srv->fdset);
for (p = srv->head; p; p = p->next)
{
FD_SET (p->fd, &srv->fdset);
if (p->fd > nfd)
nfd = p->fd;
}
srv->nfd = nfd + 1;
}
int
mu_server_run (mu_server_t srv)
{
int status = 0;
if (!srv)
return EINVAL;
if (!srv->head)
return MU_ERR_NOENT;
make_fdset (srv);
while (1)
{
int rc;
fd_set rdset;
struct timeval *to;
rdset = srv->fdset;
to = (srv->flags & MU_SERVER_TIMEOUT) ? &srv->timeout : NULL;
rc = select (srv->nfd, &rdset, NULL, NULL, to);
if (rc == -1 && errno == EINTR)
{
if (srv->f_idle && srv->f_idle (srv->server_data))
break;
continue;
}
if (rc < 0)
return errno;
if (connection_loop (srv, &rdset))
{
status = MU_ERR_FAILURE;
break;
}
}
return status;
}
int
mu_server_create (mu_server_t *psrv)
{
mu_server_t srv = calloc (1, sizeof (*srv));
if (!srv)
return ENOMEM;
*psrv = srv;
return 0;
}
int
mu_server_destroy (mu_server_t *psrv)
{
mu_server_t srv;
struct _mu_connection *p;
if (!psrv)
return EINVAL;
srv = *psrv;
if (!srv)
return 0;
for (p = srv->head; p; p = p->next)
destroy_connection (srv, p);
if (srv->f_free)
srv->f_free (srv->server_data);
free (srv);
*psrv = NULL;
return 0;
}
int
mu_server_count (mu_server_t srv, size_t *pcount)
{
size_t n = 0;
struct _mu_connection *p;
if (!srv)
return EINVAL;
for (p = srv->head; p; p = p->next)
n++;
*pcount = n;
return 0;
}
int
mu_server_set_idle (mu_server_t srv, mu_server_idle_fp fp)
{
if (!srv)
return EINVAL;
srv->f_idle = fp;
return 0;
}
int
mu_server_set_data (mu_server_t srv, void *data, mu_server_free_fp fp)
{
if (!srv)
return EINVAL;
srv->server_data = data;
srv->f_free = fp;
return 0;
}
int
mu_server_set_timeout (mu_server_t srv, struct timeval *to)
{
if (!srv)
return EINVAL;
if (!to)
srv->flags &= ~MU_SERVER_TIMEOUT;
else
{
srv->timeout = *to;
srv->flags |= MU_SERVER_TIMEOUT;
}
return 0;
}
int
mu_server_add_connection (mu_server_t srv,
int fd, void *data,
mu_conn_loop_fp loop, mu_conn_free_fp free)
{
struct _mu_connection *p;
if (!srv || !loop)
return EINVAL;
p = malloc (sizeof (*p));
if (!p)
return ENOMEM;
p->fd = fd;
p->f_loop = loop;
p->f_free = free;
p->data = data;
p->next = NULL;
p->prev = srv->tail;
if (srv->tail)
srv->tail->next = p;
else
srv->head = p;
srv->tail = p;
return 0;
}
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2007 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 <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <mailutils/acl.h>
#include <mailutils/server.h>
#include <mailutils/debug.h>
#include <mailutils/diag.h>
#include <mailutils/errno.h>
struct _mu_tcp_server
{
char *ident;
struct sockaddr_in addr;
int backlog;
int fd;
mu_debug_t debug;
mu_acl_t acl;
mu_tcp_server_conn_fp f_conn;
mu_tcp_server_intr_fp f_intr;
mu_tcp_server_free_fp f_free;
void *data;
};
#define IDENTSTR(s) ((s)->ident ? (s)->ident : "default")
int
mu_tcp_server_create (mu_tcp_server_t *psrv,
struct sockaddr_in *addr)
{
struct _mu_tcp_server *srv;
mu_log_level_t level;
srv = calloc (1, sizeof *srv);
if (!srv)
return ENOMEM;
srv->addr = *addr;
level = mu_global_debug_level ("mailbox");
if (level)
{
mu_debug_create (&srv->debug, NULL);
mu_debug_set_level (srv->debug, level);
}
srv->fd = -1;
srv->backlog = 4;
*psrv = srv;
return 0;
}
int
mu_tcp_server_destroy (mu_tcp_server_t *psrv)
{
mu_tcp_server_t srv;
if (!psrv)
return EINVAL;
srv = *psrv;
if (!srv)
return 0;
if (srv->f_free)
srv->f_free (srv->data);
close (srv->fd);
free (srv->ident);
free (srv);
*psrv = NULL;
return 0;
}
int
mu_tcp_server_set_debug (mu_tcp_server_t srv, mu_debug_t debug)
{
if (!srv)
return EINVAL;
mu_debug_destroy (&srv->debug, NULL);
srv->debug = debug;
return 0;
}
int
mu_tcp_server_get_debug (mu_tcp_server_t srv, mu_debug_t *pdebug)
{
if (!srv)
return EINVAL;
*pdebug = srv->debug;
return 0;
}
int
mu_tcp_server_set_backlog (mu_tcp_server_t srv, int backlog)
{
if (!srv)
return EINVAL;
srv->backlog = backlog;
return 0;
}
int
mu_tcp_server_set_ident (mu_tcp_server_t srv, const char *ident)
{
if (!srv)
return EINVAL;
if (srv->ident)
free (srv->ident);
srv->ident = strdup (ident);
if (!srv->ident)
return ENOMEM;
return 0;
}
int
mu_tcp_server_set_acl (mu_tcp_server_t srv, mu_acl_t acl)
{
if (!srv)
return EINVAL;
srv->acl = acl;
return 0;
}
int
mu_tcp_server_set_conn (mu_tcp_server_t srv, mu_tcp_server_conn_fp conn)
{
if (!srv)
return EINVAL;
srv->f_conn = conn;
return 0;
}
int
mu_tcp_server_set_intr (mu_tcp_server_t srv, mu_tcp_server_intr_fp intr)
{
if (!srv)
return EINVAL;
srv->f_intr = intr;
return 0;
}
int
mu_tcp_server_set_data (mu_tcp_server_t srv,
void *data, mu_tcp_server_free_fp free)
{
if (!srv)
return EINVAL;
srv->data = data;
srv->f_free = free;
return 0;
}
int
mu_tcp_server_open (mu_tcp_server_t srv)
{
int fd;
int t;
if (!srv || srv->fd != -1)
return EINVAL;
MU_DEBUG3 (srv->debug, MU_DEBUG_TRACE0,
"opening server \"%s\" %s:%d\n", IDENTSTR (srv),
inet_ntoa (srv->addr.sin_addr), ntohs (srv->addr.sin_port));
fd = socket (PF_INET, SOCK_STREAM, 0);
if (fd == -1)
{
MU_DEBUG2 (srv->debug, MU_DEBUG_ERROR,
"%s: socket: %s\n", IDENTSTR (srv), mu_strerror (errno));
return errno;
}
t = 1;
setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &t, sizeof (t));
if (bind (fd, (struct sockaddr *) &srv->addr, sizeof (srv->addr)) == -1)
{
MU_DEBUG2 (srv->debug, MU_DEBUG_ERROR,
"%s: bind: %s\n", IDENTSTR (srv), mu_strerror (errno));
close (fd);
return errno;
}
if (listen (fd, srv->backlog) == -1)
{
MU_DEBUG2 (srv->debug, MU_DEBUG_ERROR,
"%s: listen: %s\n", IDENTSTR (srv), mu_strerror (errno));
close (fd);
return errno;
}
srv->fd = fd;
return 0;
}
int
mu_tcp_server_shutdown (mu_tcp_server_t srv)
{
if (!srv || srv->fd != -1)
return EINVAL;
MU_DEBUG4 (srv->debug, MU_DEBUG_TRACE0,
"closing server \"%s\" %s:%d, fd %d\n", IDENTSTR (srv),
inet_ntoa (srv->addr.sin_addr), ntohs (srv->addr.sin_port),
srv->fd);
close (srv->fd);
return 0;
}
int
mu_tcp_server_accept (mu_tcp_server_t srv, void *call_data)
{
int rc;
int connfd;
struct sockaddr_in client;
socklen_t size = sizeof (client);
if (!srv || srv->fd == -1)
return EINVAL;
connfd = accept (srv->fd, (struct sockaddr *) &client, &size);
if (connfd == -1)
{
int ec = errno;
if (ec == EINTR)
{
if (srv->f_intr && srv->f_intr (srv->data, call_data))
mu_tcp_server_shutdown (srv);
}
return ec;
}
if (srv->acl)
{
mu_acl_result_t res;
int rc = mu_acl_check_sockaddr (srv->acl, (struct sockaddr *) &client,
size, &res);
if (rc)
MU_DEBUG2 (srv->debug, MU_DEBUG_ERROR,
"%s: mu_acl_check_sockaddr: %s\n",
IDENTSTR (srv), strerror (rc));
if (res == mu_acl_result_deny)
{
mu_diag_output (MU_DIAG_INFO, "Denying connection from %s:%d",
inet_ntoa (client.sin_addr),
ntohs (client.sin_port));
close (connfd);
return 0;
}
}
rc = srv->f_conn (connfd, &client, srv->data, call_data, srv);
if (rc)
mu_tcp_server_shutdown (srv);
close (connfd);
return 0;
}
int
mu_tcp_server_loop (mu_tcp_server_t srv, void *call_data)
{
if (!srv)
return EINVAL;
while (srv->fd != -1)
{
int rc = mu_tcp_server_accept (srv, call_data);
if (rc && rc != EINTR)
{
mu_tcp_server_shutdown (srv);
return rc;
}
}
return 0;
}
int
mu_tcp_server_get_fd (mu_tcp_server_t srv)
{
return srv->fd;
}
int
mu_tcp_server_get_sockaddr (mu_tcp_server_t srv, struct sockaddr_in *s)
{
if (!srv || !s)
return EINVAL;
memcpy (s, &srv->addr, sizeof (*s));
return 0;
}