comm.c revision 111823
164562Sgshapiro/*
2111823Sgshapiro *  Copyright (c) 1999-2003 Sendmail, Inc. and its suppliers.
364562Sgshapiro *	All rights reserved.
464562Sgshapiro *
564562Sgshapiro * By using this file, you agree to the terms and conditions set
664562Sgshapiro * forth in the LICENSE file which can be found at the top level of
764562Sgshapiro * the sendmail distribution.
864562Sgshapiro *
964562Sgshapiro */
1064562Sgshapiro
1190792Sgshapiro#include <sm/gen.h>
12111823SgshapiroSM_RCSID("@(#)$Id: comm.c,v 8.54.2.6 2003/01/03 22:14:40 ca Exp $")
1364562Sgshapiro
1464562Sgshapiro#include "libmilter.h"
1590792Sgshapiro#include <sm/errstring.h>
1664562Sgshapiro
1764562Sgshapiro/*
1864562Sgshapiro**  MI_RD_CMD -- read a command
1964562Sgshapiro**
2064562Sgshapiro**	Parameters:
2164562Sgshapiro**		sd -- socket descriptor
2264562Sgshapiro**		timeout -- maximum time to wait
2364562Sgshapiro**		cmd -- single character command read from sd
2464562Sgshapiro**		rlen -- pointer to length of result
2564562Sgshapiro**		name -- name of milter
2664562Sgshapiro**
2764562Sgshapiro**	Returns:
2864562Sgshapiro**		buffer with rest of command
2964562Sgshapiro**		(malloc()ed here, should be free()d)
3064562Sgshapiro**		hack: encode error in cmd
3164562Sgshapiro*/
3264562Sgshapiro
3364562Sgshapirochar *
3464562Sgshapiromi_rd_cmd(sd, timeout, cmd, rlen, name)
3564562Sgshapiro	socket_t sd;
3664562Sgshapiro	struct timeval *timeout;
3764562Sgshapiro	char *cmd;
3864562Sgshapiro	size_t *rlen;
3964562Sgshapiro	char *name;
4064562Sgshapiro{
4164562Sgshapiro	ssize_t len;
4264562Sgshapiro	mi_int32 expl;
4364562Sgshapiro	ssize_t i;
44111823Sgshapiro	FD_RD_VAR(rds, excs);
4564562Sgshapiro	int ret;
4664562Sgshapiro	int save_errno;
4764562Sgshapiro	char *buf;
4864562Sgshapiro	char data[MILTER_LEN_BYTES + 1];
4964562Sgshapiro
5064562Sgshapiro	*cmd = '\0';
5164562Sgshapiro	*rlen = 0;
5271345Sgshapiro
5364562Sgshapiro	i = 0;
54102528Sgshapiro	for (;;)
5564562Sgshapiro	{
56111823Sgshapiro		FD_RD_INIT(sd, rds, excs);
57111823Sgshapiro		ret = FD_RD_READY(sd, rds, excs, timeout);
58102528Sgshapiro		if (ret == 0)
59102528Sgshapiro			break;
60102528Sgshapiro		else if (ret < 0)
61102528Sgshapiro		{
62102528Sgshapiro			if (errno == EINTR)
63102528Sgshapiro				continue;
64102528Sgshapiro			break;
65102528Sgshapiro		}
66111823Sgshapiro		if (FD_IS_RD_EXC(sd, rds, excs))
6764562Sgshapiro		{
6864562Sgshapiro			*cmd = SMFIC_SELECT;
6964562Sgshapiro			return NULL;
7064562Sgshapiro		}
7190792Sgshapiro
7290792Sgshapiro		len = MI_SOCK_READ(sd, data + i, sizeof data - i);
7390792Sgshapiro		if (MI_SOCK_READ_FAIL(len))
7464562Sgshapiro		{
7564562Sgshapiro			smi_log(SMI_LOG_ERR,
7664562Sgshapiro				"%s, mi_rd_cmd: read returned %d: %s",
77110560Sgshapiro				name, (int) len, sm_errstring(errno));
7864562Sgshapiro			*cmd = SMFIC_RECVERR;
7964562Sgshapiro			return NULL;
8064562Sgshapiro		}
8164562Sgshapiro		if (len == 0)
8264562Sgshapiro		{
8364562Sgshapiro			*cmd = SMFIC_EOF;
8464562Sgshapiro			return NULL;
8564562Sgshapiro		}
8664562Sgshapiro		if (len >= (ssize_t) sizeof data - i)
8764562Sgshapiro			break;
8864562Sgshapiro		i += len;
8964562Sgshapiro	}
9064562Sgshapiro	if (ret == 0)
9164562Sgshapiro	{
9264562Sgshapiro		*cmd = SMFIC_TIMEOUT;
9364562Sgshapiro		return NULL;
9464562Sgshapiro	}
9564562Sgshapiro	else if (ret < 0)
9664562Sgshapiro	{
9764562Sgshapiro		smi_log(SMI_LOG_ERR,
9864562Sgshapiro			"%s: mi_rd_cmd: select returned %d: %s",
9990792Sgshapiro			name, ret, sm_errstring(errno));
10064562Sgshapiro		*cmd = SMFIC_RECVERR;
10164562Sgshapiro		return NULL;
10264562Sgshapiro	}
10364562Sgshapiro
10464562Sgshapiro	*cmd = data[MILTER_LEN_BYTES];
10564562Sgshapiro	data[MILTER_LEN_BYTES] = '\0';
10664562Sgshapiro	(void) memcpy((void *) &expl, (void *) &(data[0]), MILTER_LEN_BYTES);
10764562Sgshapiro	expl = ntohl(expl) - 1;
10864562Sgshapiro	if (expl <= 0)
10964562Sgshapiro		return NULL;
11064562Sgshapiro	if (expl > MILTER_CHUNK_SIZE)
11164562Sgshapiro	{
11264562Sgshapiro		*cmd = SMFIC_TOOBIG;
11364562Sgshapiro		return NULL;
11464562Sgshapiro	}
11590792Sgshapiro#if _FFR_ADD_NULL
11690792Sgshapiro	buf = malloc(expl + 1);
11790792Sgshapiro#else /* _FFR_ADD_NULL */
11864562Sgshapiro	buf = malloc(expl);
11990792Sgshapiro#endif /* _FFR_ADD_NULL */
12064562Sgshapiro	if (buf == NULL)
12164562Sgshapiro	{
12264562Sgshapiro		*cmd = SMFIC_MALLOC;
12364562Sgshapiro		return NULL;
12464562Sgshapiro	}
12564562Sgshapiro
12664562Sgshapiro	i = 0;
127102528Sgshapiro	for (;;)
12864562Sgshapiro	{
129111823Sgshapiro		FD_RD_INIT(sd, rds, excs);
130111823Sgshapiro		ret = FD_RD_READY(sd, rds, excs, timeout);
131102528Sgshapiro		if (ret == 0)
132102528Sgshapiro			break;
133102528Sgshapiro		else if (ret < 0)
134102528Sgshapiro		{
135102528Sgshapiro			if (errno == EINTR)
136102528Sgshapiro				continue;
137102528Sgshapiro			break;
138102528Sgshapiro		}
139111823Sgshapiro		if (FD_IS_RD_EXC(sd, rds, excs))
14064562Sgshapiro		{
14164562Sgshapiro			*cmd = SMFIC_SELECT;
14264562Sgshapiro			free(buf);
14364562Sgshapiro			return NULL;
14464562Sgshapiro		}
14590792Sgshapiro		len = MI_SOCK_READ(sd, buf + i, expl - i);
14690792Sgshapiro		if (MI_SOCK_READ_FAIL(len))
14764562Sgshapiro		{
14864562Sgshapiro			smi_log(SMI_LOG_ERR,
14964562Sgshapiro				"%s: mi_rd_cmd: read returned %d: %s",
150110560Sgshapiro				name, (int) len, sm_errstring(errno));
15164562Sgshapiro			ret = -1;
15264562Sgshapiro			break;
15364562Sgshapiro		}
15464562Sgshapiro		if (len == 0)
15564562Sgshapiro		{
15664562Sgshapiro			*cmd = SMFIC_EOF;
15764562Sgshapiro			free(buf);
15864562Sgshapiro			return NULL;
15964562Sgshapiro		}
16064562Sgshapiro		if (len > expl - i)
16164562Sgshapiro		{
16264562Sgshapiro			*cmd = SMFIC_RECVERR;
16364562Sgshapiro			free(buf);
16464562Sgshapiro			return NULL;
16564562Sgshapiro		}
16664562Sgshapiro		if (len >= expl - i)
16764562Sgshapiro		{
16864562Sgshapiro			*rlen = expl;
16990792Sgshapiro#if _FFR_ADD_NULL
17090792Sgshapiro			/* makes life simpler for common string routines */
17190792Sgshapiro			buf[expl] = '\0';
17290792Sgshapiro#endif /* _FFR_ADD_NULL */
17364562Sgshapiro			return buf;
17464562Sgshapiro		}
17564562Sgshapiro		i += len;
17664562Sgshapiro	}
17764562Sgshapiro
17864562Sgshapiro	save_errno = errno;
17964562Sgshapiro	free(buf);
18064562Sgshapiro
18164562Sgshapiro	/* select returned 0 (timeout) or < 0 (error) */
18264562Sgshapiro	if (ret == 0)
18364562Sgshapiro	{
18464562Sgshapiro		*cmd = SMFIC_TIMEOUT;
18564562Sgshapiro		return NULL;
18664562Sgshapiro	}
18764562Sgshapiro	if (ret < 0)
18864562Sgshapiro	{
18964562Sgshapiro		smi_log(SMI_LOG_ERR,
19064562Sgshapiro			"%s: mi_rd_cmd: select returned %d: %s",
19190792Sgshapiro			name, ret, sm_errstring(save_errno));
19264562Sgshapiro		*cmd = SMFIC_RECVERR;
19364562Sgshapiro		return NULL;
19464562Sgshapiro	}
19564562Sgshapiro	*cmd = SMFIC_UNKNERR;
19664562Sgshapiro	return NULL;
19764562Sgshapiro}
19890792Sgshapiro/*
19964562Sgshapiro**  MI_WR_CMD -- write a cmd to sd
20064562Sgshapiro**
20164562Sgshapiro**	Parameters:
20264562Sgshapiro**		sd -- socket descriptor
20364562Sgshapiro**		timeout -- maximum time to wait (currently unused)
20464562Sgshapiro**		cmd -- single character command to write
20564562Sgshapiro**		buf -- buffer with further data
20664562Sgshapiro**		len -- length of buffer (without cmd!)
20764562Sgshapiro**
20864562Sgshapiro**	Returns:
20964562Sgshapiro**		MI_SUCCESS/MI_FAILURE
21064562Sgshapiro*/
21164562Sgshapiro
21294334Sgshapiro/*
21394334Sgshapiro**  we don't care much about the timeout here, it's very long anyway
214110560Sgshapiro**  FD_SETSIZE is checked when socket is created.
21594334Sgshapiro**  XXX l == 0 ?
21694334Sgshapiro*/
21794334Sgshapiro
21894334Sgshapiro#define MI_WR(data)	\
21994334Sgshapiro	while (sl > 0)							\
22094334Sgshapiro	{								\
221111823Sgshapiro		FD_WR_INIT(sd, wrs);					\
222111823Sgshapiro		ret = FD_WR_READY(sd, wrs, timeout);			\
22394334Sgshapiro		if (ret == 0)						\
22494334Sgshapiro			return MI_FAILURE;				\
22594334Sgshapiro		if (ret < 0)						\
22694334Sgshapiro		{							\
22794334Sgshapiro			if (errno == EINTR)				\
22894334Sgshapiro				continue;				\
22994334Sgshapiro			else						\
23094334Sgshapiro				return MI_FAILURE;			\
23194334Sgshapiro		}							\
23294334Sgshapiro		l = MI_SOCK_WRITE(sd, (void *) ((data) + i), sl);	\
23394334Sgshapiro		if (l < 0)						\
23494334Sgshapiro		{							\
23594334Sgshapiro			if (errno == EINTR)				\
23694334Sgshapiro				continue;				\
23794334Sgshapiro			else						\
23894334Sgshapiro				return MI_FAILURE;			\
23994334Sgshapiro		}							\
24094334Sgshapiro		i += l;							\
24194334Sgshapiro		sl -= l;						\
24294334Sgshapiro	}
24394334Sgshapiro
24464562Sgshapiroint
24564562Sgshapiromi_wr_cmd(sd, timeout, cmd, buf, len)
24664562Sgshapiro	socket_t sd;
24764562Sgshapiro	struct timeval *timeout;
24864562Sgshapiro	int cmd;
24964562Sgshapiro	char *buf;
25064562Sgshapiro	size_t len;
25164562Sgshapiro{
25264562Sgshapiro	size_t sl, i;
25364562Sgshapiro	ssize_t l;
25464562Sgshapiro	mi_int32 nl;
25564562Sgshapiro	int ret;
256111823Sgshapiro	FD_WR_VAR(wrs);
25764562Sgshapiro	char data[MILTER_LEN_BYTES + 1];
25864562Sgshapiro
25964562Sgshapiro	if (len > MILTER_CHUNK_SIZE)
26064562Sgshapiro		return MI_FAILURE;
26164562Sgshapiro	nl = htonl(len + 1);	/* add 1 for the cmd char */
26264562Sgshapiro	(void) memcpy(data, (void *) &nl, MILTER_LEN_BYTES);
26364562Sgshapiro	data[MILTER_LEN_BYTES] = (char) cmd;
26464562Sgshapiro	i = 0;
26564562Sgshapiro	sl = MILTER_LEN_BYTES + 1;
26664562Sgshapiro
26764562Sgshapiro	/* use writev() instead to send the whole stuff at once? */
26864562Sgshapiro
26994334Sgshapiro	MI_WR(data);
27064562Sgshapiro	if (len > 0 && buf == NULL)
27164562Sgshapiro		return MI_FAILURE;
27264562Sgshapiro	if (len == 0 || buf == NULL)
27364562Sgshapiro		return MI_SUCCESS;
27464562Sgshapiro	i = 0;
27564562Sgshapiro	sl = len;
27694334Sgshapiro	MI_WR(buf);
27764562Sgshapiro	return MI_SUCCESS;
27864562Sgshapiro}
279