2 * Copyright (c) 1999-2004, 2009 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.70 2009/12/16 16:33:48 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
;
22 ** SMFI_SETMAXDATASIZE -- set limit for milter data read/write.
32 smfi_setmaxdatasize(sz
)
43 ** MI_RD_CMD -- read a command
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
53 ** buffer with rest of command
54 ** (malloc()ed here, should be free()d)
55 ** hack: encode error in cmd
59 mi_rd_cmd(sd
, timeout
, cmd
, rlen
, name
)
61 struct timeval
*timeout
;
73 char data
[MILTER_LEN_BYTES
+ 1];
81 FD_RD_INIT(sd
, rds
, excs
);
82 ret
= FD_RD_READY(sd
, rds
, excs
, timeout
);
91 if (FD_IS_RD_EXC(sd
, rds
, excs
))
97 len
= MI_SOCK_READ(sd
, data
+ i
, sizeof data
- i
);
98 if (MI_SOCK_READ_FAIL(len
))
101 "%s, mi_rd_cmd: read returned %d: %s",
102 name
, (int) len
, sm_errstring(errno
));
103 *cmd
= SMFIC_RECVERR
;
111 if (len
>= (ssize_t
) sizeof data
- i
)
117 *cmd
= SMFIC_TIMEOUT
;
123 "%s: mi_rd_cmd: %s() returned %d: %s",
124 name
, MI_POLLSELECT
, ret
, sm_errstring(errno
));
125 *cmd
= SMFIC_RECVERR
;
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;
135 if (expl
> Maxdatasize
)
141 buf
= malloc(expl
+ 1);
142 #else /* _FFR_ADD_NULL */
144 #endif /* _FFR_ADD_NULL */
154 FD_RD_INIT(sd
, rds
, excs
);
155 ret
= FD_RD_READY(sd
, rds
, excs
, timeout
);
164 if (FD_IS_RD_EXC(sd
, rds
, excs
))
170 len
= MI_SOCK_READ(sd
, buf
+ i
, expl
- i
);
171 if (MI_SOCK_READ_FAIL(len
))
174 "%s: mi_rd_cmd: read returned %d: %s",
175 name
, (int) len
, sm_errstring(errno
));
187 *cmd
= SMFIC_RECVERR
;
195 /* makes life simpler for common string routines */
197 #endif /* _FFR_ADD_NULL */
206 /* select returned 0 (timeout) or < 0 (error) */
209 *cmd
= SMFIC_TIMEOUT
;
215 "%s: mi_rd_cmd: %s() returned %d: %s",
216 name
, MI_POLLSELECT
, ret
, sm_errstring(save_errno
));
217 *cmd
= SMFIC_RECVERR
;
220 *cmd
= SMFIC_UNKNERR
;
225 ** RETRY_WRITEV -- Keep calling the writev() system call
226 ** until all the data is written out or an error occurs.
229 ** fd -- socket descriptor
231 ** iovcnt -- number of elements in io vector
232 ** must NOT exceed UIO_MAXIOV.
233 ** timeout -- maximum time to wait
236 ** success: number of bytes written
237 ** otherwise: MI_FAILURE
241 retry_writev(fd
, iov
, iovcnt
, timeout
)
245 struct timeval
*timeout
;
254 while (iovcnt
> 0 && iov
[0].iov_len
== 0)
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.
271 i
= FD_WR_READY(fd
, wrs
, timeout
);
276 if (errno
== EINTR
|| errno
== EAGAIN
)
280 n
= writev(fd
, iov
, iovcnt
);
283 if (errno
== EINTR
|| errno
== EAGAIN
)
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
;
297 n
-= (int) iov
[i
].iov_len
;
306 ** MI_WR_CMD -- write a cmd to sd
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!)
316 ** MI_SUCCESS/MI_FAILURE
320 mi_wr_cmd(sd
, timeout
, cmd
, buf
, len
)
322 struct timeval
*timeout
;
332 char data
[MILTER_LEN_BYTES
+ 1];
334 if (len
> Maxdatasize
|| (len
> 0 && buf
== NULL
))
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
;
346 if (len
>= 0 && buf
!= NULL
)
348 iov
[1].iov_base
= (void *) buf
;
349 iov
[1].iov_len
= len
;
353 l
= retry_writev(sd
, iov
, iovcnt
, timeout
);