/*
 * Copyright (c) 2002-2005 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.
 */

#include "sm/generic.h"
SM_RCSID("@(#)$Id: read_fd.c,v 1.13 2005/03/21 22:56:24 ca Exp $")
#include "sm/assert.h"
#include "sm/error.h"
#include "sm/io.h"
#include "sm/varargs.h"
#include "sm/limits.h"
#include "sm/types.h"
#include "sm/socket.h"		/* struct msghdr */
#include "sm/uio.h"		/* struct iovec */
#include "sm/cmsg.h"

/*
**  READ_FD -- read filedescriptor recvfd over open file fd and some data
**
**	Parameters:
**		fd -- fd to use for communication
**		ptr -- buffer in which to store additional data
**		nbytes -- size of buffer
**		recvfd -- pointer to fd to receive (output)
**
**	Returns:
**		result of sendmsg()
*/

ssize_t
sm_read_fd(fd_T fd, void *ptr, size_t nbytes, int *recvfd)
{
	struct msghdr	msg;
	struct iovec	iov[1];
	ssize_t		n;
#if ! HAVE_MSGHDR_MSG_CONTROL
	int		newfd;
#endif

#if HAVE_MSGHDR_MSG_CONTROL
	char		control[CMSG_SPACE(sizeof(int))];
	struct cmsghdr	*cmptr;

	msg.msg_control = (caddr_t)control;
	msg.msg_controllen = CMSG_LEN(sizeof(int));
#else /* HAVE_MSGHDR_MSG_CONTROL */
	msg.msg_accrights = (caddr_t) &newfd;
	msg.msg_accrightslen = sizeof(int);
#endif /* HAVE_MSGHDR_MSG_CONTROL */

	msg.msg_name = NULL;
	msg.msg_namelen = 0;

	iov[0].iov_base = ptr;
	iov[0].iov_len = nbytes;
	msg.msg_iov = iov;
	msg.msg_iovlen = 1;

	n = sm_recvmsg(fd, &msg, 0);
	if (n <= 0)
		return n;

#if HAVE_MSGHDR_MSG_CONTROL
	if ((cmptr = CMSG_FIRSTHDR(&msg)) != NULL &&
	    cmptr->cmsg_len == CMSG_LEN(sizeof(int)))
	{
		if (cmptr->cmsg_level != SOL_SOCKET)
		{
#if 0
//			err_quit(smioerr, EX_SOFTWARE,
//				"control level != SOL_SOCKET");
#endif
			return -1;
		}
		if (cmptr->cmsg_type != SCM_RIGHTS)
		{
#if 0
//			err_quit(smioerr, EX_SOFTWARE,
//				"control type != SCM_RIGHTS");
#endif
			return -1;
		}
		*recvfd = *((int *) CMSG_DATA(cmptr));
	} else
		*recvfd = -1;		/* descriptor was not passed */
#else /* HAVE_MSGHDR_MSG_CONTROL */
	if (msg.msg_accrightslen == sizeof(int))
		*recvfd = newfd;
	else
		*recvfd = -1;		/* descriptor was not passed */
#endif /* HAVE_MSGHDR_MSG_CONTROL */

	return n;
}


syntax highlighted by Code2HTML, v. 0.9.1