diff options
Diffstat (limited to 'contrib/sendmail/libmilter/comm.c')
-rw-r--r-- | contrib/sendmail/libmilter/comm.c | 261 |
1 files changed, 261 insertions, 0 deletions
diff --git a/contrib/sendmail/libmilter/comm.c b/contrib/sendmail/libmilter/comm.c new file mode 100644 index 0000000..765b024 --- /dev/null +++ b/contrib/sendmail/libmilter/comm.c @@ -0,0 +1,261 @@ +/* + * Copyright (c) 1999-2000 Sendmail, Inc. and its suppliers. + * All rights reserved. + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the sendmail distribution. + * + */ + +#ifndef lint +static char id[] = "@(#)$Id: comm.c,v 8.30.4.3 2000/06/12 14:53:01 ca Exp $"; +#endif /* ! lint */ + +#if _FFR_MILTER +#include "libmilter.h" + +#define FD_Z FD_ZERO(&readset); \ + FD_SET((u_int) sd, &readset); \ + FD_ZERO(&excset); \ + FD_SET((u_int) sd, &excset) + +/* +** MI_RD_CMD -- read a command +** +** Parameters: +** sd -- socket descriptor +** timeout -- maximum time to wait +** cmd -- single character command read from sd +** rlen -- pointer to length of result +** name -- name of milter +** +** Returns: +** buffer with rest of command +** (malloc()ed here, should be free()d) +** hack: encode error in cmd +*/ + +char * +mi_rd_cmd(sd, timeout, cmd, rlen, name) + socket_t sd; + struct timeval *timeout; + char *cmd; + size_t *rlen; + char *name; +{ + ssize_t len; + mi_int32 expl; + ssize_t i; + fd_set readset, excset; + int ret; + int save_errno; + char *buf; + char data[MILTER_LEN_BYTES + 1]; + + *cmd = '\0'; + *rlen = 0; + if (sd >= FD_SETSIZE) + { + smi_log(SMI_LOG_ERR, "%s: fd %d is larger than FD_SETSIZE %d", + name, sd, FD_SETSIZE); + *cmd = SMFIC_SELECT; + return NULL; + } + FD_Z; + i = 0; + while ((ret = select(sd + 1, &readset, NULL, &excset, timeout)) >= 1) + { + if (FD_ISSET(sd, &excset)) + { + *cmd = SMFIC_SELECT; + return NULL; + } + if ((len = read(sd, data + i, sizeof data - i)) < 0) + { + smi_log(SMI_LOG_ERR, + "%s, mi_rd_cmd: read returned %d: %s", + name, len, strerror(errno)); + *cmd = SMFIC_RECVERR; + return NULL; + } + if (len == 0) + { + *cmd = SMFIC_EOF; + return NULL; + } + if (len >= (ssize_t) sizeof data - i) + break; + i += len; + FD_Z; + } + if (ret == 0) + { + *cmd = SMFIC_TIMEOUT; + return NULL; + } + else if (ret < 0) + { + smi_log(SMI_LOG_ERR, + "%s: mi_rd_cmd: select returned %d: %s", + name, ret, strerror(errno)); + *cmd = SMFIC_RECVERR; + return NULL; + } + + *cmd = data[MILTER_LEN_BYTES]; + data[MILTER_LEN_BYTES] = '\0'; + (void) memcpy((void *) &expl, (void *) &(data[0]), MILTER_LEN_BYTES); + expl = ntohl(expl) - 1; + if (expl <= 0) + return NULL; + if (expl > MILTER_CHUNK_SIZE) + { + *cmd = SMFIC_TOOBIG; + return NULL; + } + buf = malloc(expl); + if (buf == NULL) + { + *cmd = SMFIC_MALLOC; + return NULL; + } + + i = 0; + FD_Z; + while ((ret = select(sd + 1, &readset, NULL, &excset, timeout)) == 1) + { + if (FD_ISSET(sd, &excset)) + { + *cmd = SMFIC_SELECT; + free(buf); + return NULL; + } + if ((len = read(sd, buf + i, expl - i)) < 0) + { + smi_log(SMI_LOG_ERR, + "%s: mi_rd_cmd: read returned %d: %s", + name, len, strerror(errno)); + ret = -1; + break; + } + if (len == 0) + { + *cmd = SMFIC_EOF; + free(buf); + return NULL; + } + if (len > expl - i) + { + *cmd = SMFIC_RECVERR; + free(buf); + return NULL; + } + if (len >= expl - i) + { + *rlen = expl; + return buf; + } + i += len; + FD_Z; + } + + save_errno = errno; + free(buf); + + /* select returned 0 (timeout) or < 0 (error) */ + if (ret == 0) + { + *cmd = SMFIC_TIMEOUT; + return NULL; + } + if (ret < 0) + { + smi_log(SMI_LOG_ERR, + "%s: mi_rd_cmd: select returned %d: %s", + name, ret, strerror(save_errno)); + *cmd = SMFIC_RECVERR; + return NULL; + } + *cmd = SMFIC_UNKNERR; + return NULL; +} +/* +** MI_WR_CMD -- write a cmd to sd +** +** Parameters: +** sd -- socket descriptor +** timeout -- maximum time to wait (currently unused) +** cmd -- single character command to write +** buf -- buffer with further data +** len -- length of buffer (without cmd!) +** +** Returns: +** MI_SUCCESS/MI_FAILURE +*/ + +int +mi_wr_cmd(sd, timeout, cmd, buf, len) + socket_t sd; + struct timeval *timeout; + int cmd; + char *buf; + size_t len; +{ + size_t sl, i; + ssize_t l; + mi_int32 nl; + int ret; + fd_set wrtset; + char data[MILTER_LEN_BYTES + 1]; + + if (len > MILTER_CHUNK_SIZE) + return MI_FAILURE; + nl = htonl(len + 1); /* add 1 for the cmd char */ + (void) memcpy(data, (void *) &nl, MILTER_LEN_BYTES); + data[MILTER_LEN_BYTES] = (char) cmd; + i = 0; + sl = MILTER_LEN_BYTES + 1; + + do { + FD_ZERO(&wrtset); + FD_SET((u_int) sd, &wrtset); + if ((ret = select(sd + 1, NULL, &wrtset, NULL, timeout)) == 0) + return MI_FAILURE; + } while (ret < 0 && errno == EINTR); + if (ret < 0) + return MI_FAILURE; + + /* use writev() instead to send the whole stuff at once? */ + while ((l = write(sd, (void *) (data + i), sl - i)) < (ssize_t) sl) + { + if (l < 0) + return MI_FAILURE; + i += l; + sl -= l; + } + + if (len > 0 && buf == NULL) + return MI_FAILURE; + if (len == 0 || buf == NULL) + return MI_SUCCESS; + i = 0; + sl = len; + do { + FD_ZERO(&wrtset); + FD_SET((u_int) sd, &wrtset); + if ((ret = select(sd + 1, NULL, &wrtset, NULL, timeout)) == 0) + return MI_FAILURE; + } while (ret < 0 && errno == EINTR); + if (ret < 0) + return MI_FAILURE; + while ((l = write(sd, (void *) (buf + i), sl - i)) < (ssize_t) sl) + { + if (l < 0) + return MI_FAILURE; + i += l; + sl -= l; + } + return MI_SUCCESS; +} +#endif /* _FFR_MILTER */ |