xref: /illumos-gate/usr/src/cmd/sendmail/libmilter/comm.c (revision e9af4bc0b1cc30cea75d6ad4aa2fde97d985e9be)
17c478bd9Sstevel@tonic-gate /*
2*e9af4bc0SJohn Beck  *  Copyright (c) 1999-2004, 2009 Sendmail, Inc. and its suppliers.
37c478bd9Sstevel@tonic-gate  *	All rights reserved.
47c478bd9Sstevel@tonic-gate  *
57c478bd9Sstevel@tonic-gate  * By using this file, you agree to the terms and conditions set
67c478bd9Sstevel@tonic-gate  * forth in the LICENSE file which can be found at the top level of
77c478bd9Sstevel@tonic-gate  * the sendmail distribution.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  */
107c478bd9Sstevel@tonic-gate 
117c478bd9Sstevel@tonic-gate #include <sm/gen.h>
12*e9af4bc0SJohn Beck SM_RCSID("@(#)$Id: comm.c,v 8.70 2009/12/16 16:33:48 ca Exp $")
137c478bd9Sstevel@tonic-gate 
147c478bd9Sstevel@tonic-gate #include "libmilter.h"
157c478bd9Sstevel@tonic-gate #include <sm/errstring.h>
167c478bd9Sstevel@tonic-gate #include <sys/uio.h>
177c478bd9Sstevel@tonic-gate 
187c478bd9Sstevel@tonic-gate static ssize_t	retry_writev __P((socket_t, struct iovec *, int, struct timeval *));
197c478bd9Sstevel@tonic-gate static size_t Maxdatasize = MILTER_MAX_DATA_SIZE;
207c478bd9Sstevel@tonic-gate 
217c478bd9Sstevel@tonic-gate /*
227c478bd9Sstevel@tonic-gate **  SMFI_SETMAXDATASIZE -- set limit for milter data read/write.
237c478bd9Sstevel@tonic-gate **
247c478bd9Sstevel@tonic-gate **	Parameters:
257c478bd9Sstevel@tonic-gate **		sz -- new limit.
267c478bd9Sstevel@tonic-gate **
277c478bd9Sstevel@tonic-gate **	Returns:
287c478bd9Sstevel@tonic-gate **		old limit
297c478bd9Sstevel@tonic-gate */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate size_t
smfi_setmaxdatasize(sz)327c478bd9Sstevel@tonic-gate smfi_setmaxdatasize(sz)
337c478bd9Sstevel@tonic-gate 	size_t sz;
347c478bd9Sstevel@tonic-gate {
357c478bd9Sstevel@tonic-gate 	size_t old;
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate 	old = Maxdatasize;
387c478bd9Sstevel@tonic-gate 	Maxdatasize = sz;
397c478bd9Sstevel@tonic-gate 	return old;
407c478bd9Sstevel@tonic-gate }
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate /*
437c478bd9Sstevel@tonic-gate **  MI_RD_CMD -- read a command
447c478bd9Sstevel@tonic-gate **
457c478bd9Sstevel@tonic-gate **	Parameters:
467c478bd9Sstevel@tonic-gate **		sd -- socket descriptor
477c478bd9Sstevel@tonic-gate **		timeout -- maximum time to wait
487c478bd9Sstevel@tonic-gate **		cmd -- single character command read from sd
497c478bd9Sstevel@tonic-gate **		rlen -- pointer to length of result
507c478bd9Sstevel@tonic-gate **		name -- name of milter
517c478bd9Sstevel@tonic-gate **
527c478bd9Sstevel@tonic-gate **	Returns:
537c478bd9Sstevel@tonic-gate **		buffer with rest of command
547c478bd9Sstevel@tonic-gate **		(malloc()ed here, should be free()d)
557c478bd9Sstevel@tonic-gate **		hack: encode error in cmd
567c478bd9Sstevel@tonic-gate */
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate char *
mi_rd_cmd(sd,timeout,cmd,rlen,name)597c478bd9Sstevel@tonic-gate mi_rd_cmd(sd, timeout, cmd, rlen, name)
607c478bd9Sstevel@tonic-gate 	socket_t sd;
617c478bd9Sstevel@tonic-gate 	struct timeval *timeout;
627c478bd9Sstevel@tonic-gate 	char *cmd;
637c478bd9Sstevel@tonic-gate 	size_t *rlen;
647c478bd9Sstevel@tonic-gate 	char *name;
657c478bd9Sstevel@tonic-gate {
667c478bd9Sstevel@tonic-gate 	ssize_t len;
677c478bd9Sstevel@tonic-gate 	mi_int32 expl;
687c478bd9Sstevel@tonic-gate 	ssize_t i;
697c478bd9Sstevel@tonic-gate 	FD_RD_VAR(rds, excs);
707c478bd9Sstevel@tonic-gate 	int ret;
717c478bd9Sstevel@tonic-gate 	int save_errno;
727c478bd9Sstevel@tonic-gate 	char *buf;
737c478bd9Sstevel@tonic-gate 	char data[MILTER_LEN_BYTES + 1];
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate 	*cmd = '\0';
767c478bd9Sstevel@tonic-gate 	*rlen = 0;
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate 	i = 0;
797c478bd9Sstevel@tonic-gate 	for (;;)
807c478bd9Sstevel@tonic-gate 	{
817c478bd9Sstevel@tonic-gate 		FD_RD_INIT(sd, rds, excs);
827c478bd9Sstevel@tonic-gate 		ret = FD_RD_READY(sd, rds, excs, timeout);
837c478bd9Sstevel@tonic-gate 		if (ret == 0)
847c478bd9Sstevel@tonic-gate 			break;
857c478bd9Sstevel@tonic-gate 		else if (ret < 0)
867c478bd9Sstevel@tonic-gate 		{
877c478bd9Sstevel@tonic-gate 			if (errno == EINTR)
887c478bd9Sstevel@tonic-gate 				continue;
897c478bd9Sstevel@tonic-gate 			break;
907c478bd9Sstevel@tonic-gate 		}
917c478bd9Sstevel@tonic-gate 		if (FD_IS_RD_EXC(sd, rds, excs))
927c478bd9Sstevel@tonic-gate 		{
937c478bd9Sstevel@tonic-gate 			*cmd = SMFIC_SELECT;
947c478bd9Sstevel@tonic-gate 			return NULL;
957c478bd9Sstevel@tonic-gate 		}
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate 		len = MI_SOCK_READ(sd, data + i, sizeof data - i);
987c478bd9Sstevel@tonic-gate 		if (MI_SOCK_READ_FAIL(len))
997c478bd9Sstevel@tonic-gate 		{
1007c478bd9Sstevel@tonic-gate 			smi_log(SMI_LOG_ERR,
1017c478bd9Sstevel@tonic-gate 				"%s, mi_rd_cmd: read returned %d: %s",
1027c478bd9Sstevel@tonic-gate 				name, (int) len, sm_errstring(errno));
1037c478bd9Sstevel@tonic-gate 			*cmd = SMFIC_RECVERR;
1047c478bd9Sstevel@tonic-gate 			return NULL;
1057c478bd9Sstevel@tonic-gate 		}
1067c478bd9Sstevel@tonic-gate 		if (len == 0)
1077c478bd9Sstevel@tonic-gate 		{
1087c478bd9Sstevel@tonic-gate 			*cmd = SMFIC_EOF;
1097c478bd9Sstevel@tonic-gate 			return NULL;
1107c478bd9Sstevel@tonic-gate 		}
1117c478bd9Sstevel@tonic-gate 		if (len >= (ssize_t) sizeof data - i)
1127c478bd9Sstevel@tonic-gate 			break;
1137c478bd9Sstevel@tonic-gate 		i += len;
1147c478bd9Sstevel@tonic-gate 	}
1157c478bd9Sstevel@tonic-gate 	if (ret == 0)
1167c478bd9Sstevel@tonic-gate 	{
1177c478bd9Sstevel@tonic-gate 		*cmd = SMFIC_TIMEOUT;
1187c478bd9Sstevel@tonic-gate 		return NULL;
1197c478bd9Sstevel@tonic-gate 	}
1207c478bd9Sstevel@tonic-gate 	else if (ret < 0)
1217c478bd9Sstevel@tonic-gate 	{
1227c478bd9Sstevel@tonic-gate 		smi_log(SMI_LOG_ERR,
123*e9af4bc0SJohn Beck 			"%s: mi_rd_cmd: %s() returned %d: %s",
124*e9af4bc0SJohn Beck 			name, MI_POLLSELECT, ret, sm_errstring(errno));
1257c478bd9Sstevel@tonic-gate 		*cmd = SMFIC_RECVERR;
1267c478bd9Sstevel@tonic-gate 		return NULL;
1277c478bd9Sstevel@tonic-gate 	}
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 	*cmd = data[MILTER_LEN_BYTES];
1307c478bd9Sstevel@tonic-gate 	data[MILTER_LEN_BYTES] = '\0';
1317c478bd9Sstevel@tonic-gate 	(void) memcpy((void *) &expl, (void *) &(data[0]), MILTER_LEN_BYTES);
1327c478bd9Sstevel@tonic-gate 	expl = ntohl(expl) - 1;
1337c478bd9Sstevel@tonic-gate 	if (expl <= 0)
1347c478bd9Sstevel@tonic-gate 		return NULL;
1357c478bd9Sstevel@tonic-gate 	if (expl > Maxdatasize)
1367c478bd9Sstevel@tonic-gate 	{
1377c478bd9Sstevel@tonic-gate 		*cmd = SMFIC_TOOBIG;
1387c478bd9Sstevel@tonic-gate 		return NULL;
1397c478bd9Sstevel@tonic-gate 	}
1407c478bd9Sstevel@tonic-gate #if _FFR_ADD_NULL
1417c478bd9Sstevel@tonic-gate 	buf = malloc(expl + 1);
1427c478bd9Sstevel@tonic-gate #else /* _FFR_ADD_NULL */
1437c478bd9Sstevel@tonic-gate 	buf = malloc(expl);
1447c478bd9Sstevel@tonic-gate #endif /* _FFR_ADD_NULL */
1457c478bd9Sstevel@tonic-gate 	if (buf == NULL)
1467c478bd9Sstevel@tonic-gate 	{
1477c478bd9Sstevel@tonic-gate 		*cmd = SMFIC_MALLOC;
1487c478bd9Sstevel@tonic-gate 		return NULL;
1497c478bd9Sstevel@tonic-gate 	}
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 	i = 0;
1527c478bd9Sstevel@tonic-gate 	for (;;)
1537c478bd9Sstevel@tonic-gate 	{
1547c478bd9Sstevel@tonic-gate 		FD_RD_INIT(sd, rds, excs);
1557c478bd9Sstevel@tonic-gate 		ret = FD_RD_READY(sd, rds, excs, timeout);
1567c478bd9Sstevel@tonic-gate 		if (ret == 0)
1577c478bd9Sstevel@tonic-gate 			break;
1587c478bd9Sstevel@tonic-gate 		else if (ret < 0)
1597c478bd9Sstevel@tonic-gate 		{
1607c478bd9Sstevel@tonic-gate 			if (errno == EINTR)
1617c478bd9Sstevel@tonic-gate 				continue;
1627c478bd9Sstevel@tonic-gate 			break;
1637c478bd9Sstevel@tonic-gate 		}
1647c478bd9Sstevel@tonic-gate 		if (FD_IS_RD_EXC(sd, rds, excs))
1657c478bd9Sstevel@tonic-gate 		{
1667c478bd9Sstevel@tonic-gate 			*cmd = SMFIC_SELECT;
1677c478bd9Sstevel@tonic-gate 			free(buf);
1687c478bd9Sstevel@tonic-gate 			return NULL;
1697c478bd9Sstevel@tonic-gate 		}
1707c478bd9Sstevel@tonic-gate 		len = MI_SOCK_READ(sd, buf + i, expl - i);
1717c478bd9Sstevel@tonic-gate 		if (MI_SOCK_READ_FAIL(len))
1727c478bd9Sstevel@tonic-gate 		{
1737c478bd9Sstevel@tonic-gate 			smi_log(SMI_LOG_ERR,
1747c478bd9Sstevel@tonic-gate 				"%s: mi_rd_cmd: read returned %d: %s",
1757c478bd9Sstevel@tonic-gate 				name, (int) len, sm_errstring(errno));
1767c478bd9Sstevel@tonic-gate 			ret = -1;
1777c478bd9Sstevel@tonic-gate 			break;
1787c478bd9Sstevel@tonic-gate 		}
1797c478bd9Sstevel@tonic-gate 		if (len == 0)
1807c478bd9Sstevel@tonic-gate 		{
1817c478bd9Sstevel@tonic-gate 			*cmd = SMFIC_EOF;
1827c478bd9Sstevel@tonic-gate 			free(buf);
1837c478bd9Sstevel@tonic-gate 			return NULL;
1847c478bd9Sstevel@tonic-gate 		}
1857c478bd9Sstevel@tonic-gate 		if (len > expl - i)
1867c478bd9Sstevel@tonic-gate 		{
1877c478bd9Sstevel@tonic-gate 			*cmd = SMFIC_RECVERR;
1887c478bd9Sstevel@tonic-gate 			free(buf);
1897c478bd9Sstevel@tonic-gate 			return NULL;
1907c478bd9Sstevel@tonic-gate 		}
1917c478bd9Sstevel@tonic-gate 		if (len >= expl - i)
1927c478bd9Sstevel@tonic-gate 		{
1937c478bd9Sstevel@tonic-gate 			*rlen = expl;
1947c478bd9Sstevel@tonic-gate #if _FFR_ADD_NULL
1957c478bd9Sstevel@tonic-gate 			/* makes life simpler for common string routines */
1967c478bd9Sstevel@tonic-gate 			buf[expl] = '\0';
1977c478bd9Sstevel@tonic-gate #endif /* _FFR_ADD_NULL */
1987c478bd9Sstevel@tonic-gate 			return buf;
1997c478bd9Sstevel@tonic-gate 		}
2007c478bd9Sstevel@tonic-gate 		i += len;
2017c478bd9Sstevel@tonic-gate 	}
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate 	save_errno = errno;
2047c478bd9Sstevel@tonic-gate 	free(buf);
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 	/* select returned 0 (timeout) or < 0 (error) */
2077c478bd9Sstevel@tonic-gate 	if (ret == 0)
2087c478bd9Sstevel@tonic-gate 	{
2097c478bd9Sstevel@tonic-gate 		*cmd = SMFIC_TIMEOUT;
2107c478bd9Sstevel@tonic-gate 		return NULL;
2117c478bd9Sstevel@tonic-gate 	}
2127c478bd9Sstevel@tonic-gate 	if (ret < 0)
2137c478bd9Sstevel@tonic-gate 	{
2147c478bd9Sstevel@tonic-gate 		smi_log(SMI_LOG_ERR,
215*e9af4bc0SJohn Beck 			"%s: mi_rd_cmd: %s() returned %d: %s",
216*e9af4bc0SJohn Beck 			name, MI_POLLSELECT, ret, sm_errstring(save_errno));
2177c478bd9Sstevel@tonic-gate 		*cmd = SMFIC_RECVERR;
2187c478bd9Sstevel@tonic-gate 		return NULL;
2197c478bd9Sstevel@tonic-gate 	}
2207c478bd9Sstevel@tonic-gate 	*cmd = SMFIC_UNKNERR;
2217c478bd9Sstevel@tonic-gate 	return NULL;
2227c478bd9Sstevel@tonic-gate }
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate /*
2257c478bd9Sstevel@tonic-gate **  RETRY_WRITEV -- Keep calling the writev() system call
2267c478bd9Sstevel@tonic-gate **	until all the data is written out or an error occurs.
2277c478bd9Sstevel@tonic-gate **
2287c478bd9Sstevel@tonic-gate **	Parameters:
2297c478bd9Sstevel@tonic-gate **		fd -- socket descriptor
2307c478bd9Sstevel@tonic-gate **		iov -- io vector
2317c478bd9Sstevel@tonic-gate **		iovcnt -- number of elements in io vector
2327c478bd9Sstevel@tonic-gate **			must NOT exceed UIO_MAXIOV.
2337c478bd9Sstevel@tonic-gate **		timeout -- maximum time to wait
2347c478bd9Sstevel@tonic-gate **
2357c478bd9Sstevel@tonic-gate **	Returns:
2367c478bd9Sstevel@tonic-gate **		success: number of bytes written
2377c478bd9Sstevel@tonic-gate **		otherwise: MI_FAILURE
2387c478bd9Sstevel@tonic-gate */
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate static ssize_t
retry_writev(fd,iov,iovcnt,timeout)2417c478bd9Sstevel@tonic-gate retry_writev(fd, iov, iovcnt, timeout)
2427c478bd9Sstevel@tonic-gate 	socket_t fd;
2437c478bd9Sstevel@tonic-gate 	struct iovec *iov;
2447c478bd9Sstevel@tonic-gate 	int iovcnt;
2457c478bd9Sstevel@tonic-gate 	struct timeval *timeout;
2467c478bd9Sstevel@tonic-gate {
2477c478bd9Sstevel@tonic-gate 	int i;
2487c478bd9Sstevel@tonic-gate 	ssize_t n, written;
2497c478bd9Sstevel@tonic-gate 	FD_WR_VAR(wrs);
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 	written = 0;
2527c478bd9Sstevel@tonic-gate 	for (;;)
2537c478bd9Sstevel@tonic-gate 	{
2547c478bd9Sstevel@tonic-gate 		while (iovcnt > 0 && iov[0].iov_len == 0)
2557c478bd9Sstevel@tonic-gate 		{
2567c478bd9Sstevel@tonic-gate 			iov++;
2577c478bd9Sstevel@tonic-gate 			iovcnt--;
2587c478bd9Sstevel@tonic-gate 		}
2597c478bd9Sstevel@tonic-gate 		if (iovcnt <= 0)
2607c478bd9Sstevel@tonic-gate 			return written;
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 		/*
2637c478bd9Sstevel@tonic-gate 		**  We don't care much about the timeout here,
2647c478bd9Sstevel@tonic-gate 		**  it's very long anyway; correct solution would be
2657c478bd9Sstevel@tonic-gate 		**  to take the time before the loop and reduce the
2667c478bd9Sstevel@tonic-gate 		**  timeout after each invocation.
2677c478bd9Sstevel@tonic-gate 		**  FD_SETSIZE is checked when socket is created.
2687c478bd9Sstevel@tonic-gate 		*/
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate 		FD_WR_INIT(fd, wrs);
2717c478bd9Sstevel@tonic-gate 		i = FD_WR_READY(fd, wrs, timeout);
2727c478bd9Sstevel@tonic-gate 		if (i == 0)
2737c478bd9Sstevel@tonic-gate 			return MI_FAILURE;
2747c478bd9Sstevel@tonic-gate 		if (i < 0)
2757c478bd9Sstevel@tonic-gate 		{
2767c478bd9Sstevel@tonic-gate 			if (errno == EINTR || errno == EAGAIN)
2777c478bd9Sstevel@tonic-gate 				continue;
2787c478bd9Sstevel@tonic-gate 			return MI_FAILURE;
2797c478bd9Sstevel@tonic-gate 		}
2807c478bd9Sstevel@tonic-gate 		n = writev(fd, iov, iovcnt);
2817c478bd9Sstevel@tonic-gate 		if (n == -1)
2827c478bd9Sstevel@tonic-gate 		{
2837c478bd9Sstevel@tonic-gate 			if (errno == EINTR || errno == EAGAIN)
2847c478bd9Sstevel@tonic-gate 				continue;
2857c478bd9Sstevel@tonic-gate 			return MI_FAILURE;
2867c478bd9Sstevel@tonic-gate 		}
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 		written += n;
2897c478bd9Sstevel@tonic-gate 		for (i = 0; i < iovcnt; i++)
2907c478bd9Sstevel@tonic-gate 		{
2917c478bd9Sstevel@tonic-gate 			if (iov[i].iov_len > (unsigned int) n)
2927c478bd9Sstevel@tonic-gate 			{
2937c478bd9Sstevel@tonic-gate 				iov[i].iov_base = (char *)iov[i].iov_base + n;
2947c478bd9Sstevel@tonic-gate 				iov[i].iov_len -= (unsigned int) n;
2957c478bd9Sstevel@tonic-gate 				break;
2967c478bd9Sstevel@tonic-gate 			}
2977c478bd9Sstevel@tonic-gate 			n -= (int) iov[i].iov_len;
2987c478bd9Sstevel@tonic-gate 			iov[i].iov_len = 0;
2997c478bd9Sstevel@tonic-gate 		}
3007c478bd9Sstevel@tonic-gate 		if (i == iovcnt)
3017c478bd9Sstevel@tonic-gate 			return written;
3027c478bd9Sstevel@tonic-gate 	}
3037c478bd9Sstevel@tonic-gate }
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate /*
3067c478bd9Sstevel@tonic-gate **  MI_WR_CMD -- write a cmd to sd
3077c478bd9Sstevel@tonic-gate **
3087c478bd9Sstevel@tonic-gate **	Parameters:
3097c478bd9Sstevel@tonic-gate **		sd -- socket descriptor
3107c478bd9Sstevel@tonic-gate **		timeout -- maximum time to wait
3117c478bd9Sstevel@tonic-gate **		cmd -- single character command to write
3127c478bd9Sstevel@tonic-gate **		buf -- buffer with further data
3137c478bd9Sstevel@tonic-gate **		len -- length of buffer (without cmd!)
3147c478bd9Sstevel@tonic-gate **
3157c478bd9Sstevel@tonic-gate **	Returns:
3167c478bd9Sstevel@tonic-gate **		MI_SUCCESS/MI_FAILURE
3177c478bd9Sstevel@tonic-gate */
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate int
mi_wr_cmd(sd,timeout,cmd,buf,len)3207c478bd9Sstevel@tonic-gate mi_wr_cmd(sd, timeout, cmd, buf, len)
3217c478bd9Sstevel@tonic-gate 	socket_t sd;
3227c478bd9Sstevel@tonic-gate 	struct timeval *timeout;
3237c478bd9Sstevel@tonic-gate 	int cmd;
3247c478bd9Sstevel@tonic-gate 	char *buf;
3257c478bd9Sstevel@tonic-gate 	size_t len;
3267c478bd9Sstevel@tonic-gate {
327*e9af4bc0SJohn Beck 	size_t sl;
3287c478bd9Sstevel@tonic-gate 	ssize_t l;
3297c478bd9Sstevel@tonic-gate 	mi_int32 nl;
3307c478bd9Sstevel@tonic-gate 	int iovcnt;
3317c478bd9Sstevel@tonic-gate 	struct iovec iov[2];
3327c478bd9Sstevel@tonic-gate 	char data[MILTER_LEN_BYTES + 1];
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 	if (len > Maxdatasize || (len > 0 && buf == NULL))
3357c478bd9Sstevel@tonic-gate 		return MI_FAILURE;
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate 	nl = htonl(len + 1);	/* add 1 for the cmd char */
3387c478bd9Sstevel@tonic-gate 	(void) memcpy(data, (void *) &nl, MILTER_LEN_BYTES);
3397c478bd9Sstevel@tonic-gate 	data[MILTER_LEN_BYTES] = (char) cmd;
3407c478bd9Sstevel@tonic-gate 	sl = MILTER_LEN_BYTES + 1;
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 	/* set up the vector for the size / command */
3437c478bd9Sstevel@tonic-gate 	iov[0].iov_base = (void *) data;
3447c478bd9Sstevel@tonic-gate 	iov[0].iov_len  = sl;
3457c478bd9Sstevel@tonic-gate 	iovcnt = 1;
3467c478bd9Sstevel@tonic-gate 	if (len >= 0 && buf != NULL)
3477c478bd9Sstevel@tonic-gate 	{
3487c478bd9Sstevel@tonic-gate 		iov[1].iov_base = (void *) buf;
3497c478bd9Sstevel@tonic-gate 		iov[1].iov_len  = len;
3507c478bd9Sstevel@tonic-gate 		iovcnt = 2;
3517c478bd9Sstevel@tonic-gate 	}
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 	l = retry_writev(sd, iov, iovcnt, timeout);
3547c478bd9Sstevel@tonic-gate 	if (l == MI_FAILURE)
3557c478bd9Sstevel@tonic-gate 		return MI_FAILURE;
3567c478bd9Sstevel@tonic-gate 	return MI_SUCCESS;
3577c478bd9Sstevel@tonic-gate }
358