diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2009-11-21 23:13:13 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2009-11-21 23:13:13 +0200 |
commit | 7f4dfb88f23a14f0b9603e648d4a1a459a6f26a3 (patch) | |
tree | 2beb9dee6a3a93130bd7f783a62afa20ed14e853 /mfd/savclt.c | |
parent | d20b648b02aa1f8caf9975a116c54e05d67d1c39 (diff) | |
download | mailfromd-7f4dfb88f23a14f0b9603e648d4a1a459a6f26a3.tar.gz mailfromd-7f4dfb88f23a14f0b9603e648d4a1a459a6f26a3.tar.bz2 |
Use callout resolver to handle timed-out callouts.mtax-cleanup
* mfd/savclt.c: New file.
* mfd/Makefile.am (mailfromd_SOURCES): Add savclt.c
* mfd/callout.c (transcript): Get ID as 1st arg.
Remove static qualifier. All callers updated.
* mfd/engine.c (method_strict)
(method_standard): If callout returned mf_temp_failure,
try to pass the task to the callout server, if one is
defined.
* mfd/mailfromd.h (transcript)
(schedule_callout): New protos.
(callout_server_sa, callout_server_sa_len): New externs.
* mfd/main.c (force_remove): Initialize to 0 (see srvman.c)
(server_config_stmt): New statements single-process and
reuseaddr.
(add_legacy_milter_port, server_section_parser): Pass
flags to mfd_server_new.
(mf_cfg_param): New statement `callout-url'.
* mfd/savsrv.c (MF_SOURCE_NAME): Fixed.
(verify, callout_session_server): Set proctitle.
(callout_session_server): Fix memory leak.
* mfd/srvman.c (struct mfd_server): New member `flags'.
(mfd_server_new): Take flags as 4th argument.
(server_run): Use flags to set single-user and reuseaddr
modes.
* mfd/srvman.h (SRV_SINGLE_PROCESS)
(SRV_KEEP_EXISTING): New defines.
(mfd_server_new): Change signature.
(srvman_url_to_sockaddr): New proto.
Diffstat (limited to 'mfd/savclt.c')
-rw-r--r-- | mfd/savclt.c | 275 |
1 files changed, 275 insertions, 0 deletions
diff --git a/mfd/savclt.c b/mfd/savclt.c new file mode 100644 index 00000000..447f6857 --- /dev/null +++ b/mfd/savclt.c | |||
@@ -0,0 +1,275 @@ | |||
1 | /* This file is part of Mailfromd. | ||
2 | Copyright (C) 2005, 2006, 2007, 2008, 2009 Sergey Poznyakoff | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 3, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program 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 | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | ||
16 | |||
17 | #define MF_SOURCE_NAME MF_SOURCE_SAVCLT | ||
18 | #ifdef HAVE_CONFIG_H | ||
19 | # include <config.h> | ||
20 | #endif | ||
21 | #include <sys/types.h> | ||
22 | #include <sys/stat.h> | ||
23 | #include <unistd.h> | ||
24 | #include <stdlib.h> | ||
25 | #include <stdio.h> | ||
26 | #include <sys/socket.h> | ||
27 | #include <netinet/in.h> | ||
28 | #include <arpa/inet.h> | ||
29 | #include <netdb.h> | ||
30 | |||
31 | #include "mailfromd.h" | ||
32 | |||
33 | struct sockaddr *callout_server_sa; | ||
34 | socklen_t callout_server_sa_len; | ||
35 | time_t savclt_timeout = 3; | ||
36 | |||
37 | /* Ideally, I'd want to use smtp_io functions here. But they are | ||
38 | based on Mailutils' TCP streams, which so far do not support | ||
39 | UNIX sockets. So, for the time being, I use the straightforward | ||
40 | I/O approach. */ | ||
41 | int | ||
42 | savclt_getline(int fd, char **pbuf, size_t *pbufsize) | ||
43 | { | ||
44 | char *buf = *pbuf; | ||
45 | size_t bufsize = *pbufsize; | ||
46 | int off = 0; | ||
47 | #define DELTA 128 | ||
48 | time_t start = time(NULL); | ||
49 | |||
50 | if (buf == NULL) { | ||
51 | bufsize = DELTA; | ||
52 | buf = xmalloc(bufsize); | ||
53 | } | ||
54 | |||
55 | do { | ||
56 | struct timeval tv; | ||
57 | int rc, flags; | ||
58 | time_t diff = time(NULL) - start; | ||
59 | |||
60 | if (diff > savclt_timeout) { | ||
61 | errno = ETIMEDOUT; | ||
62 | return -1; | ||
63 | } | ||
64 | |||
65 | tv.tv_sec = savclt_timeout - diff; | ||
66 | tv.tv_usec = 0; | ||
67 | flags = MU_STREAM_READY_RD; | ||
68 | rc = mu_fd_wait(fd, &flags, &tv); | ||
69 | if (rc) { | ||
70 | debug1(1, "mu_fd_wait: %s", mu_strerror(rc)); | ||
71 | errno = rc; | ||
72 | return -1; | ||
73 | } | ||
74 | if (!(flags & MU_STREAM_READY_RD)) { | ||
75 | errno = ETIMEDOUT; | ||
76 | return -1; | ||
77 | } | ||
78 | |||
79 | if (off + 1 == bufsize) { | ||
80 | bufsize += DELTA; | ||
81 | buf = xrealloc(buf, bufsize); | ||
82 | } | ||
83 | |||
84 | rc = read(fd, buf + off, 1); | ||
85 | if (rc == -1) | ||
86 | return -1; | ||
87 | if (rc == 0) | ||
88 | break; | ||
89 | off++; | ||
90 | } while (buf[off - 1] != '\n'); | ||
91 | |||
92 | if (off + 1 == bufsize) { | ||
93 | bufsize++; | ||
94 | buf = xrealloc(buf, bufsize); | ||
95 | } | ||
96 | buf[off] = 0; | ||
97 | *pbuf = buf; | ||
98 | *pbufsize = bufsize; | ||
99 | transcript("savclt", "RECV:", buf); | ||
100 | return off; | ||
101 | } | ||
102 | |||
103 | static int | ||
104 | send_line(int fd, const char *txt, size_t len) | ||
105 | { | ||
106 | time_t start = time(NULL); | ||
107 | |||
108 | while (len) { | ||
109 | struct timeval tv; | ||
110 | int rc, flags; | ||
111 | time_t diff = time(NULL) - start; | ||
112 | |||
113 | if (diff > savclt_timeout) { | ||
114 | errno = ETIMEDOUT; | ||
115 | return -1; | ||
116 | } | ||
117 | |||
118 | tv.tv_sec = savclt_timeout - diff; | ||
119 | tv.tv_usec = 0; | ||
120 | flags = MU_STREAM_READY_WR; | ||
121 | rc = mu_fd_wait(fd, &flags, &tv); | ||
122 | if (rc) { | ||
123 | debug1(1, "mu_fd_wait: %s", mu_strerror(rc)); | ||
124 | errno = rc; | ||
125 | return -1; | ||
126 | } | ||
127 | if (!(flags & MU_STREAM_READY_WR)) { | ||
128 | errno = ETIMEDOUT; | ||
129 | return -1; | ||
130 | } | ||
131 | |||
132 | rc = write(fd, txt, len); | ||
133 | if (rc <= 0) { | ||
134 | if (errno == EAGAIN) | ||
135 | continue; | ||
136 | return -1; | ||
137 | } | ||
138 | txt += rc; | ||
139 | len -= rc; | ||
140 | } | ||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | int | ||
145 | savclt_wrtline(int fd, char **pbuf, size_t *pbufsize, | ||
146 | const char *fmt, ...) | ||
147 | { | ||
148 | int rc; | ||
149 | va_list ap; | ||
150 | |||
151 | va_start(ap, fmt); | ||
152 | rc = mu_vasnprintf(pbuf, pbufsize, fmt, ap); | ||
153 | va_end(ap); | ||
154 | if (rc == 0) { | ||
155 | transcript("savclt", "SEND:", *pbuf); | ||
156 | rc = send_line(fd, *pbuf, strlen(*pbuf)); | ||
157 | } | ||
158 | return rc; | ||
159 | } | ||
160 | |||
161 | |||
162 | static int | ||
163 | connect_callout_server() | ||
164 | { | ||
165 | int fd; | ||
166 | int flags; | ||
167 | int rc; | ||
168 | |||
169 | if (!callout_server_sa) | ||
170 | return -1; | ||
171 | fd = socket(callout_server_sa->sa_family, SOCK_STREAM, 0); | ||
172 | if (fd == -1) { | ||
173 | mu_error("schedule_callout: socket: %s", | ||
174 | mu_strerror(errno)); | ||
175 | return -1; | ||
176 | } | ||
177 | |||
178 | flags = fcntl(fd, F_GETFL); | ||
179 | flags |= O_NONBLOCK; | ||
180 | fcntl(fd, F_SETFL, flags); | ||
181 | |||
182 | rc = connect(fd, callout_server_sa, callout_server_sa_len); | ||
183 | if (rc == -1) { | ||
184 | if (errno == EINPROGRESS) { | ||
185 | struct timeval tv; | ||
186 | |||
187 | tv.tv_sec = savclt_timeout; | ||
188 | tv.tv_usec = 0; | ||
189 | flags = MU_STREAM_READY_WR; | ||
190 | rc = mu_fd_wait(fd, &flags, &tv); | ||
191 | if (rc) { | ||
192 | debug1(1, "mu_fd_wait: %s", mu_strerror(rc)); | ||
193 | close(fd); | ||
194 | return -1; | ||
195 | } | ||
196 | |||
197 | if (flags & MU_STREAM_READY_WR) { | ||
198 | socklen_t len = sizeof(flags); | ||
199 | rc = getsockopt(fd, SOL_SOCKET, SO_ERROR, | ||
200 | &flags, &len); | ||
201 | if (rc) { | ||
202 | mu_error("getsockopt: %s", | ||
203 | mu_strerror(rc)); | ||
204 | close(fd); | ||
205 | return -1; | ||
206 | } | ||
207 | } else | ||
208 | flags = ETIMEDOUT; | ||
209 | } else | ||
210 | flags = errno; | ||
211 | |||
212 | if (flags) { | ||
213 | mu_error("connect: %s", mu_strerror(flags)); | ||
214 | close(fd); | ||
215 | return -1; | ||
216 | } | ||
217 | } | ||
218 | |||
219 | if (rc) { | ||
220 | close(fd); | ||
221 | return -1; | ||
222 | } | ||
223 | |||
224 | return fd; | ||
225 | } | ||
226 | |||
227 | enum callout_server_state { | ||