2 * Copyright (c) 1999-2004 Sendmail, Inc. and its suppliers.
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.
12 SM_RCSID("@(#)$Id: comm.c,v 8.67 2006/11/02 17:54:44 ca Exp $")
14 #include "libmilter.h"
15 #include <sm/errstring.h>
18 static ssize_t retry_writev __P((socket_t, struct iovec *, int, struct timeval *));
19 static size_t Maxdatasize = MILTER_MAX_DATA_SIZE;
23 ** SMFI_SETMAXDATASIZE -- set limit for milter data read/write.
33 smfi_setmaxdatasize(sz)
42 #endif /* _FFR_MAXDATASIZE */
45 ** MI_RD_CMD -- read a command
48 ** sd -- socket descriptor
49 ** timeout -- maximum time to wait
50 ** cmd -- single character command read from sd
51 ** rlen -- pointer to length of result
52 ** name -- name of milter
55 ** buffer with rest of command
56 ** (malloc()ed here, should be free()d)
57 ** hack: encode error in cmd
61 mi_rd_cmd(sd, timeout, cmd, rlen, name)
63 struct timeval *timeout;
75 char data[MILTER_LEN_BYTES + 1];
83 FD_RD_INIT(sd, rds, excs);
84 ret = FD_RD_READY(sd, rds, excs, timeout);
93 if (FD_IS_RD_EXC(sd, rds, excs))
99 len = MI_SOCK_READ(sd, data + i, sizeof data - i);
100 if (MI_SOCK_READ_FAIL(len))
103 "%s, mi_rd_cmd: read returned %d: %s",
104 name, (int) len, sm_errstring(errno));
105 *cmd = SMFIC_RECVERR;
113 if (len >= (ssize_t) sizeof data - i)
119 *cmd = SMFIC_TIMEOUT;
125 "%s: mi_rd_cmd: select returned %d: %s",
126 name, ret, sm_errstring(errno));
127 *cmd = SMFIC_RECVERR;
131 *cmd = data[MILTER_LEN_BYTES];
132 data[MILTER_LEN_BYTES] = '\0';
133 (void) memcpy((void *) &expl, (void *) &(data[0]), MILTER_LEN_BYTES);
134 expl = ntohl(expl) - 1;
137 if (expl > Maxdatasize)
143 buf = malloc(expl + 1);
144 #else /* _FFR_ADD_NULL */
146 #endif /* _FFR_ADD_NULL */
156 FD_RD_INIT(sd, rds, excs);
157 ret = FD_RD_READY(sd, rds, excs, timeout);
166 if (FD_IS_RD_EXC(sd, rds, excs))
172 len = MI_SOCK_READ(sd, buf + i, expl - i);
173 if (MI_SOCK_READ_FAIL(len))
176 "%s: mi_rd_cmd: read returned %d: %s",
177 name, (int) len, sm_errstring(errno));
189 *cmd = SMFIC_RECVERR;
197 /* makes life simpler for common string routines */
199 #endif /* _FFR_ADD_NULL */
208 /* select returned 0 (timeout) or < 0 (error) */
211 *cmd = SMFIC_TIMEOUT;
217 "%s: mi_rd_cmd: select returned %d: %s",
218 name, ret, sm_errstring(save_errno));
219 *cmd = SMFIC_RECVERR;
222 *cmd = SMFIC_UNKNERR;
227 ** RETRY_WRITEV -- Keep calling the writev() system call
228 ** until all the data is written out or an error occurs.
231 ** fd -- socket descriptor
233 ** iovcnt -- number of elements in io vector
234 ** must NOT exceed UIO_MAXIOV.
235 ** timeout -- maximum time to wait
238 ** success: number of bytes written
239 ** otherwise: MI_FAILURE
243 retry_writev(fd, iov, iovcnt, timeout)
247 struct timeval *timeout;
256 while (iovcnt > 0 && iov[0].iov_len == 0)
265 ** We don't care much about the timeout here,
266 ** it's very long anyway; correct solution would be
267 ** to take the time before the loop and reduce the
268 ** timeout after each invocation.
269 ** FD_SETSIZE is checked when socket is created.
273 i = FD_WR_READY(fd, wrs, timeout);
278 if (errno == EINTR || errno == EAGAIN)
282 n = writev(fd, iov, iovcnt);
285 if (errno == EINTR || errno == EAGAIN)
291 for (i = 0; i < iovcnt; i++)
293 if (iov[i].iov_len > (unsigned int) n)
295 iov[i].iov_base = (char *)iov[i].iov_base + n;
296 iov[i].iov_len -= (unsigned int) n;
299 n -= (int) iov[i].iov_len;
308 ** MI_WR_CMD -- write a cmd to sd
311 ** sd -- socket descriptor
312 ** timeout -- maximum time to wait
313 ** cmd -- single character command to write
314 ** buf -- buffer with further data
315 ** len -- length of buffer (without cmd!)
318 ** MI_SUCCESS/MI_FAILURE
322 mi_wr_cmd(sd, timeout, cmd, buf, len)
324 struct timeval *timeout;
334 char data[MILTER_LEN_BYTES + 1];
336 if (len > Maxdatasize || (len > 0 && buf == NULL))
339 nl = htonl(len + 1); /* add 1 for the cmd char */
340 (void) memcpy(data, (void *) &nl, MILTER_LEN_BYTES);
341 data[MILTER_LEN_BYTES] = (char) cmd;
343 sl = MILTER_LEN_BYTES + 1;
345 /* set up the vector for the size / command */
346 iov[0].iov_base = (void *) data;
349 if (len >= 0 && buf != NULL)
351 iov[1].iov_base = (void *) buf;
352 iov[1].iov_len = len;
356 l = retry_writev(sd, iov, iovcnt, timeout);