mdoc: Add NetBSD 6.0 (used in wbsio.4).
[dragonfly.git] / contrib / sendmail-8.14 / libmilter / comm.c
blobe04681c8d0ba56b52a1a6484ffab2f913276cba1
1 /*
2 * Copyright (c) 1999-2004, 2009 Sendmail, Inc. and its suppliers.
3 * All rights reserved.
5 * By using this file, you agree to the terms and conditions set
6 * forth in the LICENSE file which can be found at the top level of
7 * the sendmail distribution.
9 */
11 #include <sm/gen.h>
12 SM_RCSID("@(#)$Id: comm.c,v 8.70 2009/12/16 16:33:48 ca Exp $")
14 #include "libmilter.h"
15 #include <sm/errstring.h>
16 #include <sys/uio.h>
18 static ssize_t retry_writev __P((socket_t, struct iovec *, int, struct timeval *));
19 static size_t Maxdatasize = MILTER_MAX_DATA_SIZE;
22 ** SMFI_SETMAXDATASIZE -- set limit for milter data read/write.
24 ** Parameters:
25 ** sz -- new limit.
27 ** Returns:
28 ** old limit
31 size_t
32 smfi_setmaxdatasize(sz)
33 size_t sz;
35 size_t old;
37 old = Maxdatasize;
38 Maxdatasize = sz;
39 return old;
43 ** MI_RD_CMD -- read a command
45 ** Parameters:
46 ** sd -- socket descriptor
47 ** timeout -- maximum time to wait
48 ** cmd -- single character command read from sd
49 ** rlen -- pointer to length of result
50 ** name -- name of milter
52 ** Returns:
53 ** buffer with rest of command
54 ** (malloc()ed here, should be free()d)
55 ** hack: encode error in cmd
58 char *
59 mi_rd_cmd(sd, timeout, cmd, rlen, name)
60 socket_t sd;
61 struct timeval *timeout;
62 char *cmd;
63 size_t *rlen;
64 char *name;
66 ssize_t len;
67 mi_int32 expl;
68 ssize_t i;
69 FD_RD_VAR(rds, excs);
70 int ret;
71 int save_errno;
72 char *buf;
73 char data[MILTER_LEN_BYTES + 1];
75 *cmd = '\0';
76 *rlen = 0;
78 i = 0;
79 for (;;)
81 FD_RD_INIT(sd, rds, excs);
82 ret = FD_RD_READY(sd, rds, excs, timeout);
83 if (ret == 0)
84 break;
85 else if (ret < 0)
87 if (errno == EINTR)
88 continue;
89 break;
91 if (FD_IS_RD_EXC(sd, rds, excs))
93 *cmd = SMFIC_SELECT;
94 return NULL;
97 len = MI_SOCK_READ(sd, data + i, sizeof data - i);
98 if (MI_SOCK_READ_FAIL(len))
100 smi_log(SMI_LOG_ERR,
101 "%s, mi_rd_cmd: read returned %d: %s",
102 name, (int) len, sm_errstring(errno));
103 *cmd = SMFIC_RECVERR;
104 return NULL;
106 if (len == 0)
108 *cmd = SMFIC_EOF;
109 return NULL;
111 if (len >= (ssize_t) sizeof data - i)
112 break;
113 i += len;
115 if (ret == 0)
117 *cmd = SMFIC_TIMEOUT;
118 return NULL;
120 else if (ret < 0)
122 smi_log(SMI_LOG_ERR,
123 "%s: mi_rd_cmd: %s() returned %d: %s",
124 name, MI_POLLSELECT, ret, sm_errstring(errno));
125 *cmd = SMFIC_RECVERR;
126 return NULL;
129 *cmd = data[MILTER_LEN_BYTES];
130 data[MILTER_LEN_BYTES] = '\0';
131 (void) memcpy((void *) &expl, (void *) &(data[0]), MILTER_LEN_BYTES);
132 expl = ntohl(expl) - 1;
133 if (expl <= 0)
134 return NULL;
135 if (expl > Maxdatasize)
137 *cmd = SMFIC_TOOBIG;
138 return NULL;
140 #if _FFR_ADD_NULL
141 buf = malloc(expl + 1);
142 #else /* _FFR_ADD_NULL */
143 buf = malloc(expl);
144 #endif /* _FFR_ADD_NULL */
145 if (buf == NULL)
147 *cmd = SMFIC_MALLOC;
148 return NULL;
151 i = 0;
152 for (;;)
154 FD_RD_INIT(sd, rds, excs);
155 ret = FD_RD_READY(sd, rds, excs, timeout);
156 if (ret == 0)
157 break;
158 else if (ret < 0)
160 if (errno == EINTR)
161 continue;
162 break;
164 if (FD_IS_RD_EXC(sd, rds, excs))
166 *cmd = SMFIC_SELECT;
167 free(buf);
168 return NULL;
170 len = MI_SOCK_READ(sd, buf + i, expl - i);
171 if (MI_SOCK_READ_FAIL(len))
173 smi_log(SMI_LOG_ERR,
174 "%s: mi_rd_cmd: read returned %d: %s",
175 name, (int) len, sm_errstring(errno));
176 ret = -1;
177 break;
179 if (len == 0)
181 *cmd = SMFIC_EOF;
182 free(buf);
183 return NULL;
185 if (len > expl - i)
187 *cmd = SMFIC_RECVERR;
188 free(buf);
189 return NULL;
191 if (len >= expl - i)
193 *rlen = expl;
194 #if _FFR_ADD_NULL
195 /* makes life simpler for common string routines */
196 buf[expl] = '\0';
197 #endif /* _FFR_ADD_NULL */
198 return buf;
200 i += len;
203 save_errno = errno;
204 free(buf);
206 /* select returned 0 (timeout) or < 0 (error) */
207 if (ret == 0)
209 *cmd = SMFIC_TIMEOUT;
210 return NULL;
212 if (ret < 0)
214 smi_log(SMI_LOG_ERR,
215 "%s: mi_rd_cmd: %s() returned %d: %s",
216 name, MI_POLLSELECT, ret, sm_errstring(save_errno));
217 *cmd = SMFIC_RECVERR;
218 return NULL;
220 *cmd = SMFIC_UNKNERR;
221 return NULL;
225 ** RETRY_WRITEV -- Keep calling the writev() system call
226 ** until all the data is written out or an error occurs.
228 ** Parameters:
229 ** fd -- socket descriptor
230 ** iov -- io vector
231 ** iovcnt -- number of elements in io vector
232 ** must NOT exceed UIO_MAXIOV.
233 ** timeout -- maximum time to wait
235 ** Returns:
236 ** success: number of bytes written
237 ** otherwise: MI_FAILURE
240 static ssize_t
241 retry_writev(fd, iov, iovcnt, timeout)
242 socket_t fd;
243 struct iovec *iov;
244 int iovcnt;
245 struct timeval *timeout;
247 int i;
248 ssize_t n, written;
249 FD_WR_VAR(wrs);
251 written = 0;
252 for (;;)
254 while (iovcnt > 0 && iov[0].iov_len == 0)
256 iov++;
257 iovcnt--;
259 if (iovcnt <= 0)
260 return written;
263 ** We don't care much about the timeout here,
264 ** it's very long anyway; correct solution would be
265 ** to take the time before the loop and reduce the
266 ** timeout after each invocation.
267 ** FD_SETSIZE is checked when socket is created.
270 FD_WR_INIT(fd, wrs);
271 i = FD_WR_READY(fd, wrs, timeout);
272 if (i == 0)
273 return MI_FAILURE;
274 if (i < 0)
276 if (errno == EINTR || errno == EAGAIN)
277 continue;
278 return MI_FAILURE;
280 n = writev(fd, iov, iovcnt);
281 if (n == -1)
283 if (errno == EINTR || errno == EAGAIN)
284 continue;
285 return MI_FAILURE;
288 written += n;
289 for (i = 0; i < iovcnt; i++)
291 if (iov[i].iov_len > (unsigned int) n)
293 iov[i].iov_base = (char *)iov[i].iov_base + n;
294 iov[i].iov_len -= (unsigned int) n;
295 break;
297 n -= (int) iov[i].iov_len;
298 iov[i].iov_len = 0;
300 if (i == iovcnt)
301 return written;
306 ** MI_WR_CMD -- write a cmd to sd
308 ** Parameters:
309 ** sd -- socket descriptor
310 ** timeout -- maximum time to wait
311 ** cmd -- single character command to write
312 ** buf -- buffer with further data
313 ** len -- length of buffer (without cmd!)
315 ** Returns:
316 ** MI_SUCCESS/MI_FAILURE
320 mi_wr_cmd(sd, timeout, cmd, buf, len)
321 socket_t sd;
322 struct timeval *timeout;
323 int cmd;
324 char *buf;
325 size_t len;
327 size_t sl;
328 ssize_t l;
329 mi_int32 nl;
330 int iovcnt;
331 struct iovec iov[2];
332 char data[MILTER_LEN_BYTES + 1];
334 if (len > Maxdatasize || (len > 0 && buf == NULL))
335 return MI_FAILURE;
337 nl = htonl(len + 1); /* add 1 for the cmd char */
338 (void) memcpy(data, (void *) &nl, MILTER_LEN_BYTES);
339 data[MILTER_LEN_BYTES] = (char) cmd;
340 sl = MILTER_LEN_BYTES + 1;
342 /* set up the vector for the size / command */
343 iov[0].iov_base = (void *) data;
344 iov[0].iov_len = sl;
345 iovcnt = 1;
346 if (len >= 0 && buf != NULL)
348 iov[1].iov_base = (void *) buf;
349 iov[1].iov_len = len;
350 iovcnt = 2;
353 l = retry_writev(sd, iov, iovcnt, timeout);
354 if (l == MI_FAILURE)
355 return MI_FAILURE;
356 return MI_SUCCESS;