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
1 2007-12-09 Sergey Poznyakoff <gray@gnu.org.ua> 1 2007-12-09 Sergey Poznyakoff <gray@gnu.org.ua>
2 2
3 * examples/Makefile.am: add echosrv.c.
4 * examples/echosrv.c: New file.
5 * include/mailutils/Makefile.am: Add server.h.
6 * include/mailutils/server.h: New file.
7 * include/mailutils/acl.h (mu_acl_t): Move to types.hin
8 * include/mailutils/types.hin (mu_acl_t,mu_server_t)
9 (mu_tcp_server_t): New types.
10 * mailbox/Makefile.am: Add server.c and tcpsrv.c.
11 * mailbox/server.c: New file.
12 * mailbox/tcpsrv.c: New file.
13 * mailbox/acl.c: Include <sys/wait.h>
14 Rename all `sin' and `sun' to avoid name clashes.
15 * mailbox/errors (MU_ERR_LOCK_EXT_FAIL): Do not abbreviate
16 anything in error description.
17
3 * auth/ldap.c (_construct_attr_array): Use mu_vartab_* to expand 18 * auth/ldap.c (_construct_attr_array): Use mu_vartab_* to expand
4 filter. 19 filter.
5 * imap4d/preauth.c: Fix misleading comment. 20 * imap4d/preauth.c: Fix misleading comment.
......
...@@ -25,6 +25,7 @@ noinst_PROGRAMS = \ ...@@ -25,6 +25,7 @@ noinst_PROGRAMS = \
25 argcv\ 25 argcv\
26 base64\ 26 base64\
27 decode2047\ 27 decode2047\
28 echosrv\
28 encode2047\ 29 encode2047\
29 header\ 30 header\
30 http\ 31 http\
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2007 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 3 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General
15 Public License along with this library; If not, see
16 <http://www.gnu.org/licenses/>. */
17
18 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <unistd.h>
24 #include <sys/time.h>
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
29 #include <signal.h>
30 #include <sys/wait.h>
31 #include "getopt.h"
32
33 #include <mailutils/mailutils.h>
34 #include <mailutils/server.h>
35
36 #define MU_ASSERT(expr) \
37 do \
38 { \
39 int rc = expr; \
40 if (rc) \
41 { \
42 mu_error (#expr " failed: %s", mu_strerror (rc)); \
43 abort (); \
44 } \
45 } \
46 while (0);
47
48 mu_server_t server;
49
50 int
51 echo_conn (int fd, struct sockaddr_in *s, void *server_data, void *call_data,
52 mu_tcp_server_t srv)
53 {
54 struct sockaddr_in srv_addr;
55 pid_t pid;
56 char *buf = NULL;
57 size_t size = 0;
58 FILE *in, *out;
59
60 mu_tcp_server_get_sockaddr (srv, &srv_addr);
61
62 pid = fork ();
63 if (pid == -1)
64 {
65 mu_error ("fork failed: %s", mu_strerror (errno));
66 return 0;
67 }
68
69 if (pid)
70 {
71 mu_diag_output (MU_DIAG_INFO, "%lu: opened connection %s:%d => %s:%d",
72 (unsigned long) pid,
73 inet_ntoa (srv_addr.sin_addr), ntohs (srv_addr.sin_port),
74 inet_ntoa (s->sin_addr), ntohs (s->sin_port));
75 return 0;
76 }
77
78 mu_tcp_server_shutdown (srv);
79
80 in = fdopen (fd, "r");
81 out = fdopen (fd, "w");
82 setvbuf (in, NULL, _IOLBF, 0);
83 setvbuf (out, NULL, _IOLBF, 0);
84
85 pid = getpid ();
86 while (getline (&buf, &size, in) > 0)
87 {
88 int len = strlen (buf);
89 if (len > 0)
90 {
91 buf[--len] = 0;
92 if (buf[len-1] == '\r')
93 buf[--len] = 0;
94 }
95 fprintf (out, "%lu: you said: \"%s\"\r\n", (unsigned long) pid, buf);
96 }
97 free (buf);
98 exit (0);
99 }
100
101 int
102 tcp_conn_handler (int fd, void *conn_data, void *server_data)
103 {
104 mu_tcp_server_t tcpsrv = (mu_tcp_server_t) conn_data;
105 int rc = mu_tcp_server_accept (tcpsrv, server_data);
106 if (rc && rc != EINTR)
107 {
108 mu_tcp_server_shutdown (tcpsrv);
109 return MU_SERVER_CLOSE_CONN;
110 }
111 return MU_SERVER_SUCCESS;
112 }
113
114 void
115 tcp_conn_free (void *conn_data, void *server_data)
116 {
117 mu_tcp_server_t tcpsrv = (mu_tcp_server_t) conn_data;
118 mu_tcp_server_destroy (&tcpsrv);
119 }
120
121 void
122 create_server (char *arg)
123 {
124 char *p, *q;
125 struct sockaddr_in s;
126 mu_tcp_server_t tcpsrv;
127 unsigned n;
128
129 p = strchr (arg, ':');
130 if (!*p)
131 {
132 mu_error ("invalid specification: %s\n", arg);
133 exit (1);
134 }
135 *p++ = 0;
136 s.sin_family = AF_INET;
137 if (inet_aton (arg, &s.sin_addr) == 0)
138 {
139 mu_error ("invalid IP address: %s\n", arg);
140 exit (1);
141 }
142 n = strtoul (p, &q, 0);
143 if (*q)
144 {
145 mu_error ("invalid port number: %s\n", p);
146 exit (1);
147 }
148 s.sin_port = htons (n);
149
150 MU_ASSERT (mu_tcp_server_create (&tcpsrv, &s));
151 MU_ASSERT (mu_tcp_server_open (tcpsrv));
152 MU_ASSERT (mu_tcp_server_set_conn (tcpsrv, echo_conn));
153 MU_ASSERT (mu_server_add_connection (server,
154 mu_tcp_server_get_fd (tcpsrv),
155 tcpsrv,
156 tcp_conn_handler, tcp_conn_free));
157 }
158
159 static int cleanup_needed;
160
161 RETSIGTYPE
162 sig_child (int sig)
163 {
164 cleanup_needed = 1;
165 signal (sig, sig_child);
166 }
167
168 int
169 server_idle (void *server_data)
170 {
171 if (cleanup_needed)
172 {
173 int status;
174 pid_t pid;
175
176 cleanup_needed = 0;
177 while ((pid = waitpid (-1, &status, WNOHANG)) > 0)
178 {
179 if (WIFEXITED (status))
180 mu_diag_output (MU_DIAG_INFO, "%lu: finished with code %d",
181 (unsigned long) pid,
182 WEXITSTATUS (status));
183 else if (WIFSIGNALED (status))
184 mu_diag_output (MU_DIAG_ERR, "%lu: terminated on signal %d",
185 (unsigned long) pid,
186 WTERMSIG (status));
187 else
188 mu_diag_output (MU_DIAG_ERR, "%lu: terminated (cause unknown)");
189 }
190 }
191 return 0;
192 }
193
194 int
195 run ()
196 {
197 int rc;
198 signal (SIGCHLD, sig_child);
199 rc = mu_server_run (server);
200 if (rc)
201 mu_error ("%s", mu_strerror (rc));
202 mu_server_destroy (&server);
203 return rc ? 1 : 0;
204 }
205
206 int
207 main (int argc, char **argv)
208 {
209 int rc;
210
211 mu_set_program_name (argv[0]);
212 while ((rc = getopt (argc, argv, "Dd:")) != EOF)
213 {
214 switch (rc)
215 {
216 case 'D':
217 mu_debug_line_info = 1;
218 break;
219
220 case 'd':
221 mu_global_debug_from_string (optarg, "command line");
222 break;
223
224 default:
225 exit (1);
226 }
227 }
228
229 argc -= optind;
230 argv += optind;
231
232 MU_ASSERT (mu_server_create (&server));
233 mu_server_set_idle (server, server_idle);
234 while (argc--)
235 create_server (*argv++);
236 return run ();
237 }
238
...@@ -81,6 +81,7 @@ pkginclude_HEADERS = \ ...@@ -81,6 +81,7 @@ pkginclude_HEADERS = \
81 refcount.h\ 81 refcount.h\
82 registrar.h\ 82 registrar.h\
83 sha1.h\ 83 sha1.h\
84 server.h\
84 stream.h\ 85 stream.h\
85 syslog.h\ 86 syslog.h\
86 sql.h\ 87 sql.h\
......
...@@ -21,8 +21,6 @@ ...@@ -21,8 +21,6 @@
21 #include <mailutils/types.h> 21 #include <mailutils/types.h>
22 #include <mailutils/iterator.h> 22 #include <mailutils/iterator.h>
23 23
24 typedef struct _mu_acl *mu_acl_t;
25
26 typedef enum mu_acl_action 24 typedef enum mu_acl_action
27 { 25 {
28 mu_acl_accept, 26 mu_acl_accept,
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2007 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 3 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General
15 Public License along with this library; If not, see
16 <http://www.gnu.org/licenses/>. */
17
18 #ifndef _MAILUTILS_SERVER_H
19 #define _MAILUTILS_SERVER_H
20
21 #include <mailutils/types.h>
22
23 typedef int (*mu_conn_loop_fp) (int fd, void *conn_data, void *server_data);
24 typedef void (*mu_conn_free_fp) (void *conn_data, void *server_data);
25 typedef int (*mu_server_idle_fp) (void *server_data);
26 typedef void (*mu_server_free_fp) (void *server_data);
27
28 #define MU_SERVER_SUCCESS 0
29 #define MU_SERVER_CLOSE_CONN 1
30 #define MU_SERVER_SHUTDOWN 2
31
32 int mu_server_run (mu_server_t srv);
33 int mu_server_create (mu_server_t *psrv);
34 int mu_server_destroy (mu_server_t *psrv);
35 int mu_server_set_idle (mu_server_t srv, mu_server_idle_fp fp);
36 int mu_server_set_data (mu_server_t srv, void *data, mu_server_free_fp fp);
37 int mu_server_add_connection (mu_server_t srv,
38 int fd, void *data,
39 mu_conn_loop_fp loop, mu_conn_free_fp free);
40 struct timeval;
41 int mu_server_set_timeout (mu_server_t srv, struct timeval *to);
42 int mu_server_count (mu_server_t srv, size_t *pcount);
43
44
45 /* TCP server */
46 struct sockaddr_in;
47 typedef int (*mu_tcp_server_conn_fp) (int fd, struct sockaddr_in *s,
48 void *server_data, void *call_data,
49 mu_tcp_server_t srv);
50 typedef int (*mu_tcp_server_intr_fp) (void *data, void *call_data);
51 typedef void (*mu_tcp_server_free_fp) (void *data);
52
53
54 int mu_tcp_server_create (mu_tcp_server_t *psrv, struct sockaddr_in *addr);
55 int mu_tcp_server_destroy (mu_tcp_server_t *psrv);
56 int mu_tcp_server_set_debug (mu_tcp_server_t srv, mu_debug_t debug);
57 int mu_tcp_server_get_debug (mu_tcp_server_t srv, mu_debug_t *pdebug);
58 int mu_tcp_server_set_backlog (mu_tcp_server_t srv, int backlog);
59 int mu_tcp_server_set_ident (mu_tcp_server_t srv, const char *ident);
60 int mu_tcp_server_set_acl (mu_tcp_server_t srv, mu_acl_t acl);
61 int mu_tcp_server_set_conn (mu_tcp_server_t srv, mu_tcp_server_conn_fp conn);
62 int mu_tcp_server_set_intr (mu_tcp_server_t srv, mu_tcp_server_intr_fp intr);
63 int mu_tcp_server_set_data (mu_tcp_server_t srv,
64 void *data, mu_tcp_server_free_fp free);
65 int mu_tcp_server_open (mu_tcp_server_t srv);
66 int mu_tcp_server_shutdown (mu_tcp_server_t srv);
67 int mu_tcp_server_accept (mu_tcp_server_t srv, void *call_data);
68 int mu_tcp_server_loop (mu_tcp_server_t srv, void *call_data);
69 int mu_tcp_server_get_fd (mu_tcp_server_t srv);
70 int mu_tcp_server_get_sockaddr (mu_tcp_server_t srv, struct sockaddr_in *s);
71
72 #endif
...@@ -66,6 +66,9 @@ struct _mu_ticket; ...@@ -66,6 +66,9 @@ struct _mu_ticket;
66 struct _mu_url; 66 struct _mu_url;
67 struct _mu_wicket; 67 struct _mu_wicket;
68 struct _mu_assoc; 68 struct _mu_assoc;
69 struct _mu_acl;
70 struct _mu_server;
71 struct _mu_tcp_server;
69 72
70 typedef MU_OFF_TYPE mu_off_t; 73 typedef MU_OFF_TYPE mu_off_t;
71 74
...@@ -102,6 +105,9 @@ typedef void *mu_transport_t; ...@@ -102,6 +105,9 @@ typedef void *mu_transport_t;
102 typedef struct _mu_assoc *mu_assoc_t; 105 typedef struct _mu_assoc *mu_assoc_t;
103 typedef char *mu_message_qid_t; 106 typedef char *mu_message_qid_t;
104 typedef int mu_log_level_t; 107 typedef int mu_log_level_t;
108 typedef struct _mu_acl *mu_acl_t;
109 typedef struct _mu_server *mu_server_t;
110 typedef struct _mu_tcp_server *mu_tcp_server_t;
105 111
106 #define MU_FOLDER_ATTRIBUTE_DIRECTORY 0x001 112 #define MU_FOLDER_ATTRIBUTE_DIRECTORY 0x001
107 #define MU_FOLDER_ATTRIBUTE_FILE 0x002 113 #define MU_FOLDER_ATTRIBUTE_FILE 0x002
......
...@@ -97,12 +97,14 @@ libmailutils_la_SOURCES = \ ...@@ -97,12 +97,14 @@ libmailutils_la_SOURCES = \
97 refcount.c\ 97 refcount.c\
98 rfc2047.c\ 98 rfc2047.c\
99 sha1.c\ 99 sha1.c\
100 server.c\
100 socket_stream.c\ 101 socket_stream.c\
101 stream.c\ 102 stream.c\
102 syslog.c\ 103 syslog.c\
103 system.c\ 104 system.c\
104 tcp.c\
105 ticket.c\ 105 ticket.c\
106 tcp.c\
107 tcpsrv.c\
106 url.c\ 108 url.c\
107 vartab.c\ 109 vartab.c\
108 version.c\ 110 version.c\
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
24 #include <arpa/inet.h> 24 #include <arpa/inet.h>
25 25
26 #include <sys/types.h> 26 #include <sys/types.h>
27 #include <sys/wait.h>
27 #include <unistd.h> 28 #include <unistd.h>
28 #include <stdlib.h> 29 #include <stdlib.h>
29 #include <string.h> 30 #include <string.h>
...@@ -74,8 +75,8 @@ prepare_sa (struct sockaddr *sa) ...@@ -74,8 +75,8 @@ prepare_sa (struct sockaddr *sa)
74 { 75 {
75 case AF_INET: 76 case AF_INET:
76 { 77 {
77 struct sockaddr_in *sin = (struct sockaddr_in *)sa; 78 struct sockaddr_in *s_in = (struct sockaddr_in *)sa;
78 sin->sin_addr.s_addr = ntohl (sin->sin_addr.s_addr); 79 s_in->sin_addr.s_addr = ntohl (s_in->sin_addr.s_addr);
79 break; 80 break;
80 } 81 }
81 82
...@@ -313,16 +314,16 @@ debug_sockaddr (mu_debug_t dbg, mu_log_level_t lvl, struct sockaddr *sa) ...@@ -313,16 +314,16 @@ debug_sockaddr (mu_debug_t dbg, mu_log_level_t lvl, struct sockaddr *sa)
313 { 314 {
314 case AF_INET: 315 case AF_INET:
315 { 316 {
316 struct sockaddr_in *sin = (struct sockaddr_in *)sa; 317 struct sockaddr_in *s_in = (struct sockaddr_in *)sa;
317 mu_debug_printf (dbg, lvl, "{AF_INET %s:%d}", 318 mu_debug_printf (dbg, lvl, "{AF_INET %s:%d}",
318 inet_ntoa (sin->sin_addr), ntohs (sin->sin_port)); 319 inet_ntoa (s_in->sin_addr), ntohs (s_in->sin_port));
319 break; 320 break;
320 } 321 }
321 322
322 case AF_UNIX: 323 case AF_UNIX:
323 { 324 {
324 struct sockaddr_un *sun = (struct sockaddr_un *)sa; 325 struct sockaddr_un *s_un = (struct sockaddr_un *)sa;
325 mu_debug_printf (dbg, lvl, "{AF_UNIX %s}", sun->sun_path); 326 mu_debug_printf (dbg, lvl, "{AF_UNIX %s}", s_un->sun_path);
326 break; 327 break;
327 } 328 }
328 329
...@@ -439,25 +440,25 @@ spawn_prog (const char *cmdline, int *pstatus, struct run_closure *rp) ...@@ -439,25 +440,25 @@ spawn_prog (const char *cmdline, int *pstatus, struct run_closure *rp)
439 { 440 {
440 case AF_INET: 441 case AF_INET:
441 { 442 {
442 struct sockaddr_in *sin = (struct sockaddr_in *)rp->sa; 443 struct sockaddr_in *s_in = (struct sockaddr_in *)rp->sa;
443 struct in_addr addr = sin->sin_addr; 444 struct in_addr addr = s_in->sin_addr;
444 char buf[UINTMAX_STRSIZE_BOUND]; 445 char buf[UINTMAX_STRSIZE_BOUND];
445 unsigned n; 446 unsigned n;
446 447
447 mu_vartab_define (vtab, "family", "AF_INET", 1); 448 mu_vartab_define (vtab, "family", "AF_INET", 1);
448 addr.s_addr = htonl (addr.s_addr); 449 addr.s_addr = htonl (addr.s_addr);
449 mu_vartab_define (vtab, "address", inet_ntoa (addr), 0); 450 mu_vartab_define (vtab, "address", inet_ntoa (addr), 0);
450 n = ntohs (sin->sin_port); 451 n = ntohs (s_in->sin_port);
451 mu_vartab_define (vtab, "port", umaxtostr (n, buf), 0); 452 mu_vartab_define (vtab, "port", umaxtostr (n, buf), 0);
452 } 453 }
453 break; 454 break;
454 455
455 case AF_UNIX: 456 case AF_UNIX:
456 { 457 {
457 struct sockaddr_un *sun = (struct sockaddr_un *)rp->sa; 458 struct sockaddr_un *s_un = (struct sockaddr_un *)rp->sa;
458 459
459 mu_vartab_define (vtab, "family", "AF_UNIX", 1); 460 mu_vartab_define (vtab, "family", "AF_UNIX", 1);
460 mu_vartab_define (vtab, "address", sun->sun_path, 1); 461 mu_vartab_define (vtab, "address", s_un->sun_path, 1);
461 } 462 }
462 break; 463 break;
463 } 464 }
......
...@@ -35,7 +35,7 @@ MU_ERR_LOCK_CONFLICT _("Conflict with previous locker") ...@@ -35,7 +35,7 @@ MU_ERR_LOCK_CONFLICT _("Conflict with previous locker")
35 MU_ERR_LOCK_BAD_LOCK _("Lock file check failed") 35 MU_ERR_LOCK_BAD_LOCK _("Lock file check failed")
36 MU_ERR_LOCK_BAD_FILE _("File check failed") 36 MU_ERR_LOCK_BAD_FILE _("File check failed")
37 MU_ERR_LOCK_NOT_HELD _("Lock not held on file") 37 MU_ERR_LOCK_NOT_HELD _("Lock not held on file")
38 MU_ERR_LOCK_EXT_FAIL _("Failed to exec external locker") 38 MU_ERR_LOCK_EXT_FAIL _("Failed to execute external locker")
39 MU_ERR_LOCK_EXT_ERR _("External locker failed") 39 MU_ERR_LOCK_EXT_ERR _("External locker failed")
40 MU_ERR_LOCK_EXT_KILLED _("External locker killed") 40 MU_ERR_LOCK_EXT_KILLED _("External locker killed")
41 41
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2007 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 3 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General
15 Public License along with this library; If not, see
16 <http://www.gnu.org/licenses/>. */
17
18 #ifdef HAVE_CONFIG_H
19 #include <config.h>
20 #endif
21 #include <sys/select.h>
22 #include <sys/time.h>
23 #include <sys/types.h>
24 #include <unistd.h>
25 #include <stdlib.h>
26 #include <mailutils/server.h>
27 #include <mailutils/errno.h>
28
29
30 struct _mu_connection
31 {
32 struct _mu_connection *next, *prev;
33 int fd;
34 mu_conn_loop_fp f_loop;
35 mu_conn_free_fp f_free;
36 void *data;
37 };
38
39 #define MU_SERVER_TIMEOUT 0x1
40
41 struct _mu_server
42 {
43 int nfd;
44 fd_set fdset;
45 int flags;
46 struct timeval timeout;
47 struct _mu_connection *head, *tail;
48 mu_server_idle_fp f_idle;
49 mu_server_free_fp f_free;
50 void *server_data;
51 };
52
53 void
54 recompute_nfd (mu_server_t srv)
55 {
56 struct _mu_connection *p;
57 int nfd = 0;
58 for (p = srv->head; p; p = p->next)
59 if (p->fd > nfd)
60 nfd = p->fd;
61 srv->nfd = nfd + 1;
62 }
63
64 void
65 destroy_connection (mu_server_t srv, struct _mu_connection *conn)
66 {
67 if (conn->f_free)
68 conn->f_free (conn->data, srv->server_data);
69 free (conn);
70 }
71
72 void
73 remove_connection (mu_server_t srv, struct _mu_connection *conn)
74 {
75 struct _mu_connection *p;
76
77 close (conn->fd);
78 FD_CLR (conn->fd, &srv->fdset);
79
80 p = conn->prev;
81 if (p)
82 p->next = conn->next;
83 else /* we're at head */
84 srv->head = conn->next;
85
86 p = conn->next;
87 if (p)
88 p->prev = conn->prev;
89 else /* we're at tail */
90 srv->tail = conn->prev;
91
92 if (conn->fd == srv->nfd - 1)
93 recompute_nfd (srv);
94
95 destroy_connection (srv, conn);
96 }
97
98 int
99 connection_loop (mu_server_t srv, fd_set *fdset)
100 {
101 struct _mu_connection *conn;
102 for (conn = srv->head; conn;)
103 {
104 struct _mu_connection *next = conn->next;
105 if (FD_ISSET (conn->fd, fdset))
106 {
107 int rc = conn->f_loop (conn->fd, conn->data, srv->server_data);
108 switch (rc)
109 {
110 case 0:
111 break;
112
113 case MU_SERVER_CLOSE_CONN:
114 default:
115 remove_connection (srv, conn);
116 break;
117
118 case MU_SERVER_SHUTDOWN:
119 return 1;
120 }
121 }
122 conn = next;
123 }
124 return 0;
125 }
126
127 void
128 make_fdset (mu_server_t srv)
129 {
130 struct _mu_connection *p;
131 int nfd = 0;
132
133 FD_ZERO (&srv->fdset);
134 for (p = srv->head; p; p = p->next)
135 {
136 FD_SET (p->fd, &srv->fdset);
137 if (p->fd > nfd)
138 nfd = p->fd;
139 }
140 srv->nfd = nfd + 1;
141 }
142
143 int
144 mu_server_run (mu_server_t srv)
145 {
146 int status = 0;
147
148 if (!srv)
149 return EINVAL;
150 if (!srv->head)
151 return MU_ERR_NOENT;
152
153 make_fdset (srv);
154
155 while (1)
156 {
157 int rc;
158 fd_set rdset;
159 struct timeval *to;
160
161 rdset = srv->fdset;
162 to = (srv->flags & MU_SERVER_TIMEOUT) ? &srv->timeout : NULL;
163 rc = select (srv->nfd, &rdset, NULL, NULL, to);
164 if (rc == -1 && errno == EINTR)
165 {
166 if (srv->f_idle && srv->f_idle (srv->server_data))
167 break;
168 continue;
169 }
170 if (rc < 0)
171 return errno;
172
173 if (connection_loop (srv, &rdset))
174 {
175 status = MU_ERR_FAILURE;
176 break;
177 }
178 }
179 return status;
180 }
181
182 int
183 mu_server_create (mu_server_t *psrv)
184 {
185 mu_server_t srv = calloc (1, sizeof (*srv));
186 if (!srv)
187 return ENOMEM;
188 *psrv = srv;
189 return 0;
190 }
191
192 int
193 mu_server_destroy (mu_server_t *psrv)
194 {
195 mu_server_t srv;
196 struct _mu_connection *p;
197
198 if (!psrv)
199 return EINVAL;
200 srv = *psrv;
201 if (!srv)
202 return 0;
203
204 for (p = srv->head; p; p = p->next)
205 destroy_connection (srv, p);
206
207 if (srv->f_free)
208 srv->f_free (srv->server_data);
209
210 free (srv);
211 *psrv = NULL;
212 return 0;
213 }
214
215 int
216 mu_server_count (mu_server_t srv, size_t *pcount)
217 {
218 size_t n = 0;
219 struct _mu_connection *p;
220
221 if (!srv)
222 return EINVAL;
223 for (p = srv->head; p; p = p->next)
224 n++;
225 *pcount = n;
226 return 0;
227 }
228
229 int
230 mu_server_set_idle (mu_server_t srv, mu_server_idle_fp fp)
231 {
232 if (!srv)
233 return EINVAL;
234 srv->f_idle = fp;
235 return 0;
236 }
237
238 int
239 mu_server_set_data (mu_server_t srv, void *data, mu_server_free_fp fp)
240 {
241 if (!srv)
242 return EINVAL;
243 srv->server_data = data;
244 srv->f_free = fp;
245 return 0;
246 }
247
248 int
249 mu_server_set_timeout (mu_server_t srv, struct timeval *to)
250 {
251 if (!srv)
252 return EINVAL;
253 if (!to)
254 srv->flags &= ~MU_SERVER_TIMEOUT;
255 else
256 {
257 srv->timeout = *to;
258 srv->flags |= MU_SERVER_TIMEOUT;
259 }
260 return 0;
261 }
262
263 int
264 mu_server_add_connection (mu_server_t srv,
265 int fd, void *data,
266 mu_conn_loop_fp loop, mu_conn_free_fp free)
267 {
268 struct _mu_connection *p;
269
270 if (!srv || !loop)
271 return EINVAL;
272
273 p = malloc (sizeof (*p));
274 if (!p)
275 return ENOMEM;
276 p->fd = fd;
277 p->f_loop = loop;
278 p->f_free = free;
279 p->data = data;
280
281 p->next = NULL;
282 p->prev = srv->tail;
283 if (srv->tail)
284 srv->tail->next = p;
285 else
286 srv->head = p;
287 srv->tail = p;
288 return 0;
289 }
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2007 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 3 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General
15 Public License along with this library; If not, see
16 <http://www.gnu.org/licenses/>. */
17
18 #ifdef HAVE_CONFIG_H
19 #include <config.h>
20 #endif
21 #include <sys/time.h>
22 #include <sys/types.h>
23 #include <sys/socket.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
26 #include <unistd.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <mailutils/acl.h>
30 #include <mailutils/server.h>
31 #include <mailutils/debug.h>
32 #include <mailutils/diag.h>
33 #include <mailutils/errno.h>
34
35
36 struct _mu_tcp_server
37 {
38 char *ident;
39 struct sockaddr_in addr;
40 int backlog;
41 int fd;
42 mu_debug_t debug;
43 mu_acl_t acl;
44 mu_tcp_server_conn_fp f_conn;
45 mu_tcp_server_intr_fp f_intr;
46 mu_tcp_server_free_fp f_free;
47 void *data;
48 };
49
50 #define IDENTSTR(s) ((s)->ident ? (s)->ident : "default")
51
52 int
53 mu_tcp_server_create (mu_tcp_server_t *psrv,
54 struct sockaddr_in *addr)
55 {
56 struct _mu_tcp_server *srv;
57 mu_log_level_t level;
58
59 srv = calloc (1, sizeof *srv);
60 if (!srv)
61 return ENOMEM;
62 srv->addr = *addr;
63 level = mu_global_debug_level ("mailbox");
64 if (level)
65 {
66 mu_debug_create (&srv->debug, NULL);
67 mu_debug_set_level (srv->debug, level);
68 }
69 srv->fd = -1;
70 srv->backlog = 4;
71 *psrv = srv;
72 return 0;
73 }
74
75 int
76 mu_tcp_server_destroy (mu_tcp_server_t *psrv)
77 {
78 mu_tcp_server_t srv;
79 if (!psrv)
80 return EINVAL;
81 srv = *psrv;
82 if (!srv)
83 return 0;
84 if (srv->f_free)
85 srv->f_free (srv->data);
86 close (srv->fd);
87 free (srv->ident);
88 free (srv);
89 *psrv = NULL;
90 return 0;
91 }
92
93 int
94 mu_tcp_server_set_debug (mu_tcp_server_t srv, mu_debug_t debug)
95 {
96 if (!srv)
97 return EINVAL;
98 mu_debug_destroy (&srv->debug, NULL);
99 srv->debug = debug;
100 return 0;
101 }
102
103 int
104 mu_tcp_server_get_debug (mu_tcp_server_t srv, mu_debug_t *pdebug)
105 {
106 if (!srv)
107 return EINVAL;
108 *pdebug = srv->debug;
109 return 0;
110 }
111
112 int
113 mu_tcp_server_set_backlog (mu_tcp_server_t srv, int backlog)
114 {
115 if (!srv)
116 return EINVAL;
117 srv->backlog = backlog;
118 return 0;
119 }
120
121 int
122 mu_tcp_server_set_ident (mu_tcp_server_t srv, const char *ident)
123 {
124 if (!srv)
125 return EINVAL;
126 if (srv->ident)
127 free (srv->ident);
128 srv->ident = strdup (ident);
129 if (!srv->ident)
130 return ENOMEM;
131 return 0;
132 }
133
134 int
135 mu_tcp_server_set_acl (mu_tcp_server_t srv, mu_acl_t acl)
136 {
137 if (!srv)
138 return EINVAL;
139 srv->acl = acl;
140 return 0;
141 }
142
143 int
144 mu_tcp_server_set_conn (mu_tcp_server_t srv, mu_tcp_server_conn_fp conn)
145 {
146 if (!srv)
147 return EINVAL;
148 srv->f_conn = conn;
149 return 0;
150 }
151
152 int
153 mu_tcp_server_set_intr (mu_tcp_server_t srv, mu_tcp_server_intr_fp intr)
154 {
155 if (!srv)
156 return EINVAL;
157 srv->f_intr = intr;
158 return 0;
159 }
160
161 int
162 mu_tcp_server_set_data (mu_tcp_server_t srv,
163 void *data, mu_tcp_server_free_fp free)
164 {
165 if (!srv)
166 return EINVAL;
167 srv->data = data;
168 srv->f_free = free;
169 return 0;
170 }
171
172 int
173 mu_tcp_server_open (mu_tcp_server_t srv)
174 {
175 int fd;
176 int t;
177
178 if (!srv || srv->fd != -1)
179 return EINVAL;
180
181 MU_DEBUG3 (srv->debug, MU_DEBUG_TRACE0,
182 "opening server \"%s\" %s:%d\n", IDENTSTR (srv),
183 inet_ntoa (srv->addr.sin_addr), ntohs (srv->addr.sin_port));
184
185 fd = socket (PF_INET, SOCK_STREAM, 0);
186 if (fd == -1)
187 {
188 MU_DEBUG2 (srv->debug, MU_DEBUG_ERROR,
189 "%s: socket: %s\n", IDENTSTR (srv), mu_strerror (errno));
190 return errno;
191 }
192
193 t = 1;
194 setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &t, sizeof (t));
195
196 if (bind (fd, (struct sockaddr *) &srv->addr, sizeof (srv->addr)) == -1)
197 {
198 MU_DEBUG2 (srv->debug, MU_DEBUG_ERROR,
199 "%s: bind: %s\n", IDENTSTR (srv), mu_strerror (errno));
200 close (fd);
201 return errno;
202 }
203
204 if (listen (fd, srv->backlog) == -1)
205 {
206 MU_DEBUG2 (srv->debug, MU_DEBUG_ERROR,
207 "%s: listen: %s\n", IDENTSTR (srv), mu_strerror (errno));
208 close (fd);
209 return errno;
210 }
211
212 srv->fd = fd;
213 return 0;
214 }
215
216 int
217 mu_tcp_server_shutdown (mu_tcp_server_t srv)
218 {
219 if (!srv || srv->fd != -1)
220 return EINVAL;
221 MU_DEBUG4 (srv->debug, MU_DEBUG_TRACE0,
222 "closing server \"%s\" %s:%d, fd %d\n", IDENTSTR (srv),
223 inet_ntoa (srv->addr.sin_addr), ntohs (srv->addr.sin_port),
224 srv->fd);
225 close (srv->fd);
226 return 0;
227 }
228
229 int
230 mu_tcp_server_accept (mu_tcp_server_t srv, void *call_data)
231 {
232 int rc;
233 int connfd;
234 struct sockaddr_in client;
235 socklen_t size = sizeof (client);
236
237 if (!srv || srv->fd == -1)
238 return EINVAL;
239
240 connfd = accept (srv->fd, (struct sockaddr *) &client, &size);
241 if (connfd == -1)
242 {
243 int ec = errno;
244 if (ec == EINTR)
245 {
246 if (srv->f_intr && srv->f_intr (srv->data, call_data))
247 mu_tcp_server_shutdown (srv);
248 }
249 return ec;
250 }
251
252 if (srv->acl)
253 {
254 mu_acl_result_t res;
255 int rc = mu_acl_check_sockaddr (srv->acl, (struct sockaddr *) &client,
256 size, &res);
257 if (rc)
258 MU_DEBUG2 (srv->debug, MU_DEBUG_ERROR,
259 "%s: mu_acl_check_sockaddr: %s\n",
260 IDENTSTR (srv), strerror (rc));
261 if (res == mu_acl_result_deny)
262 {
263 mu_diag_output (MU_DIAG_INFO, "Denying connection from %s:%d",
264 inet_ntoa (client.sin_addr),
265 ntohs (client.sin_port));
266 close (connfd);
267 return 0;
268 }
269 }
270 rc = srv->f_conn (connfd, &client, srv->data, call_data, srv);
271 if (rc)
272 mu_tcp_server_shutdown (srv);
273 close (connfd);
274 return 0;
275 }
276
277 int
278 mu_tcp_server_loop (mu_tcp_server_t srv, void *call_data)
279 {
280 if (!srv)
281 return EINVAL;
282 while (srv->fd != -1)
283 {
284 int rc = mu_tcp_server_accept (srv, call_data);
285 if (rc && rc != EINTR)
286 {
287 mu_tcp_server_shutdown (srv);
288 return rc;
289 }
290 }
291 return 0;
292 }
293
294 int
295 mu_tcp_server_get_fd (mu_tcp_server_t srv)
296 {
297 return srv->fd;
298 }
299
300 int
301 mu_tcp_server_get_sockaddr (mu_tcp_server_t srv, struct sockaddr_in *s)
302 {
303 if (!srv || !s)
304 return EINVAL;
305 memcpy (s, &srv->addr, sizeof (*s));
306 return 0;
307 }
308