summaryrefslogtreecommitdiffstats
path: root/contrib/sendmail/libmilter/comm.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/sendmail/libmilter/comm.c')
-rw-r--r--contrib/sendmail/libmilter/comm.c261
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 */
OpenPOWER on IntegriCloud