2 * Copyright (c) 1999-2002 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.54 2002/03/06 16:03:26 ca Exp $")
14 #include "libmilter.h"
15 #include <sm/errstring.h>
17 #define FD_Z FD_ZERO(&readset); \
18 FD_SET((unsigned int) sd, &readset); \
20 FD_SET((unsigned int) sd, &excset)
23 ** MI_RD_CMD -- read a command
26 ** sd -- socket descriptor
27 ** timeout -- maximum time to wait
28 ** cmd -- single character command read from sd
29 ** rlen -- pointer to length of result
30 ** name -- name of milter
33 ** buffer with rest of command
34 ** (malloc()ed here, should be free()d)
35 ** hack: encode error in cmd
39 mi_rd_cmd(sd, timeout, cmd, rlen, name)
41 struct timeval *timeout;
49 fd_set readset, excset;
53 char data[MILTER_LEN_BYTES + 1];
60 smi_log(SMI_LOG_ERR, "%s: fd %d is larger than FD_SETSIZE %d",
61 name, sd, FD_SETSIZE);
68 while ((ret = select(sd + 1, &readset, NULL, &excset, timeout)) >= 1)
70 if (FD_ISSET(sd, &excset))
76 len = MI_SOCK_READ(sd, data + i, sizeof data - i);
77 if (MI_SOCK_READ_FAIL(len))
80 "%s, mi_rd_cmd: read returned %d: %s",
81 name, len, sm_errstring(errno));
90 if (len >= (ssize_t) sizeof data - i)
103 "%s: mi_rd_cmd: select returned %d: %s",
104 name, ret, sm_errstring(errno));
105 *cmd = SMFIC_RECVERR;
109 *cmd = data[MILTER_LEN_BYTES];
110 data[MILTER_LEN_BYTES] = '\0';
111 (void) memcpy((void *) &expl, (void *) &(data[0]), MILTER_LEN_BYTES);
112 expl = ntohl(expl) - 1;
115 if (expl > MILTER_CHUNK_SIZE)
121 buf = malloc(expl + 1);
122 #else /* _FFR_ADD_NULL */
124 #endif /* _FFR_ADD_NULL */
133 while ((ret = select(sd + 1, &readset, NULL, &excset, timeout)) == 1)
135 if (FD_ISSET(sd, &excset))
141 len = MI_SOCK_READ(sd, buf + i, expl - i);
142 if (MI_SOCK_READ_FAIL(len))
145 "%s: mi_rd_cmd: read returned %d: %s",
146 name, len, sm_errstring(errno));
158 *cmd = SMFIC_RECVERR;
166 /* makes life simpler for common string routines */
168 #endif /* _FFR_ADD_NULL */
178 /* select returned 0 (timeout) or < 0 (error) */
181 *cmd = SMFIC_TIMEOUT;
187 "%s: mi_rd_cmd: select returned %d: %s",
188 name, ret, sm_errstring(save_errno));
189 *cmd = SMFIC_RECVERR;
192 *cmd = SMFIC_UNKNERR;
196 ** MI_WR_CMD -- write a cmd to sd
199 ** sd -- socket descriptor
200 ** timeout -- maximum time to wait (currently unused)
201 ** cmd -- single character command to write
202 ** buf -- buffer with further data
203 ** len -- length of buffer (without cmd!)
206 ** MI_SUCCESS/MI_FAILURE
210 ** we don't care much about the timeout here, it's very long anyway
211 ** FD_SETSIZE is only checked in mi_rd_cmd.
215 #define MI_WR(data) \
219 FD_SET((unsigned int) sd, &wrtset); \
220 ret = select(sd + 1, NULL, &wrtset, NULL, timeout); \
225 if (errno == EINTR) \
230 l = MI_SOCK_WRITE(sd, (void *) ((data) + i), sl); \
233 if (errno == EINTR) \
243 mi_wr_cmd(sd, timeout, cmd, buf, len)
245 struct timeval *timeout;
255 char data[MILTER_LEN_BYTES + 1];
257 if (len > MILTER_CHUNK_SIZE)
259 nl = htonl(len + 1); /* add 1 for the cmd char */
260 (void) memcpy(data, (void *) &nl, MILTER_LEN_BYTES);
261 data[MILTER_LEN_BYTES] = (char) cmd;
263 sl = MILTER_LEN_BYTES + 1;
265 /* use writev() instead to send the whole stuff at once? */
268 if (len > 0 && buf == NULL)
270 if (len == 0 || buf == NULL)