pass_fd.c
5b532c7f
 /*
  * $Id$
  *
  * Copyright (C) 2001-2003 Fhg Fokus
  *
  * This file is part of ser, a free SIP server.
  *
  * ser is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version
  *
  * For a license to use the ser software under conditions
  * other than those described here, or to purchase support for this
  * software, please contact iptel.org by e-mail at the following addresses:
  *    info@iptel.org
  *
  * ser is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
6c6659cb
  /*
   * History:
   * --------
   *  2002-11-29  created by andrei
   *  2003-02-20  added solaris support (! HAVE_MSGHDR_MSG_CONTROL) (andrei)
   */
5b532c7f
 
 #ifdef USE_TCP
 
 #include <sys/types.h>
 #include <sys/socket.h>
b988daef
 #include <sys/uio.h>
 #include <stdlib.h> /* for NULL definition on openbsd */
5b532c7f
 
b988daef
 #include "dprint.h"
5b532c7f
 
 
 /* at least 1 byte must be sent! */
 int send_fd(int unix_socket, void* data, int data_len, int fd)
 {
 	struct msghdr msg;
 	struct iovec iov[1];
 	int ret;
6c6659cb
 #ifdef HAVE_MSGHDR_MSG_CONTROL
 	struct cmsghdr* cmsg;
5b532c7f
 	union {
 		struct cmsghdr cm;
 		char control[CMSG_SPACE(sizeof(fd))];
 	}control_un;
 	
 	msg.msg_control=control_un.control;
 	msg.msg_controllen=sizeof(control_un.control);
 	
6c6659cb
 	cmsg=CMSG_FIRSTHDR(&msg);
 	cmsg->cmsg_level = SOL_SOCKET;
 	cmsg->cmsg_type = SCM_RIGHTS;
 	cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
 	*(int*)CMSG_DATA(cmsg)=fd;
 	msg.msg_flags=0;
 #else
 	msg.msg_accrights=(caddr_t) &fd;
 	msg.msg_accrightslen=sizeof(fd);
 #endif
 	
5b532c7f
 	msg.msg_name=0;
 	msg.msg_namelen=0;
 	
 	iov[0].iov_base=data;
 	iov[0].iov_len=data_len;
 	msg.msg_iov=iov;
 	msg.msg_iovlen=1;
 	
 	
 	ret=sendmsg(unix_socket, &msg, 0);
 	
 	return ret;
 }
 
 
 
 int receive_fd(int unix_socket, void* data, int data_len, int* fd)
 {
 	struct msghdr msg;
 	struct iovec iov[1];
 	int new_fd;
 	int ret;
6c6659cb
 #ifdef HAVE_MSGHDR_MSG_CONTROL
 	struct cmsghdr* cmsg;
5b532c7f
 	union{
 		struct cmsghdr cm;
 		char control[CMSG_SPACE(sizeof(new_fd))];
 	}control_un;
 	
 	msg.msg_control=control_un.control;
 	msg.msg_controllen=sizeof(control_un.control);
6c6659cb
 #else
 	msg.msg_accrights=(caddr_t) &new_fd;
 	msg.msg_accrightslen=sizeof(int);
 #endif
5b532c7f
 	
 	msg.msg_name=0;
 	msg.msg_namelen=0;
 	
 	iov[0].iov_base=data;
 	iov[0].iov_len=data_len;
 	msg.msg_iov=iov;
 	msg.msg_iovlen=1;
 	
 	ret=recvmsg(unix_socket, &msg, 0);
 	if (ret<=0) goto error;
 	
6c6659cb
 #ifdef HAVE_MSGHDR_MSG_CONTROL
5b532c7f
 	cmsg=CMSG_FIRSTHDR(&msg);
 	if ((cmsg!=0) && (cmsg->cmsg_len==CMSG_LEN(sizeof(new_fd)))){
 		if (cmsg->cmsg_type!= SCM_RIGHTS){
b988daef
 			LOG(L_ERR, "receive_fd: msg control type != SCM_RIGHTS\n");
5b532c7f
 			ret=-1;
 			goto error;
 		}
 		if (cmsg->cmsg_level!= SOL_SOCKET){
b988daef
 			LOG(L_ERR, "receive_fd: msg level != SOL_SOCKET\n");
5b532c7f
 			ret=-1;
 			goto error;
 		}
 		*fd=*((int*) CMSG_DATA(cmsg));
 	}else{
b988daef
 		LOG(L_ERR, "receive_fd: no descriptor passed, cmsg=%p, len=%d\n",
5b532c7f
 				cmsg, cmsg->cmsg_len);
 		*fd=-1;
 		/* it's not really an error */
 	}
6c6659cb
 #else
 	if (msg.msg_accrightslen==sizeof(int)){
 		*fd=new_fd;
 	}else{
 		LOG(L_ERR, "receive_fd: no descriptor passed, accrightslen=%d\n",
 				msg.msg_accrightslen);
 		*fd=-1;
 	}
 #endif
5b532c7f
 	
 error:
 	return ret;
 }
 
 #endif