2 * $Id: pass_fd.c,v 1.7.2.1 2005/08/31 13:18:29 andrei Exp $
4 * Copyright (C) 2001-2003 FhG Fokus
6 * This file is part of ser, a free SIP server.
8 * ser is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version
13 * For a license to use the ser software under conditions
14 * other than those described here, or to purchase support for this
15 * software, please contact iptel.org by e-mail at the following addresses:
18 * ser is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 * 2002-11-29 created by andrei
31 * 2003-02-20 added solaris support (! HAVE_MSGHDR_MSG_CONTROL) (andrei)
32 * 2003-11-03 added send_all, recv_all and updated send/get_fd
33 * to handle signals (andrei)
38 #include <sys/types.h>
39 #include <sys/socket.h>
41 #include <stdlib.h> /* for NULL definition on openbsd */
49 /* receive all the data or returns error (handles EINTR etc.)
50 * returns: bytes read or error (<0)
51 * can return < data_len if EOF */
52 int recv_all(int socket, void* data, int data_len)
59 n=recv(socket, (char*)data+b_read, data_len-b_read, MSG_WAITALL);
62 if (errno==EINTR) continue; /* signal, try again */
63 LOG(L_CRIT, "ERROR: recv_all: recv on %d failed: %s\n",
64 socket, strerror(errno));
68 }while( (b_read!=data_len) && (n));
73 /* sends all data (takes care of signals) (assumes blocking fd)
74 * returns number of bytes sent or < 0 for an error */
75 int send_all(int socket, void* data, int data_len)
80 n=send(socket, data, data_len, 0);
83 if (errno==EINTR) goto again; /* signal, try again */
84 LOG(L_CRIT, "ERROR: send_all: send on %d failed: %s\n",
85 socket, strerror(errno));
91 /* at least 1 byte must be sent! */
92 int send_fd(int unix_socket, void* data, int data_len, int fd)
97 #ifdef HAVE_MSGHDR_MSG_CONTROL
99 /* make sure msg_control will point to properly aligned data */
102 char control[CMSG_SPACE(sizeof(fd))];
105 msg.msg_control=control_un.control;
106 /* openbsd doesn't like "more space", msg_controllen must not
107 * include the end padding */
108 msg.msg_controllen=CMSG_LEN(sizeof(fd));
110 cmsg=CMSG_FIRSTHDR(&msg);
111 cmsg->cmsg_level = SOL_SOCKET;
112 cmsg->cmsg_type = SCM_RIGHTS;
113 cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
114 *(int*)CMSG_DATA(cmsg)=fd;
117 msg.msg_accrights=(caddr_t) &fd;
118 msg.msg_accrightslen=sizeof(fd);
124 iov[0].iov_base=data;
125 iov[0].iov_len=data_len;
130 ret=sendmsg(unix_socket, &msg, 0);
132 if (errno==EINTR) goto again;
133 LOG(L_CRIT, "ERROR: send_fd: sendmsg failed on %d: %s\n",
134 unix_socket, strerror(errno));
142 int receive_fd(int unix_socket, void* data, int data_len, int* fd)
149 #ifdef HAVE_MSGHDR_MSG_CONTROL
150 struct cmsghdr* cmsg;
153 char control[CMSG_SPACE(sizeof(new_fd))];
156 msg.msg_control=control_un.control;
157 msg.msg_controllen=sizeof(control_un.control);
159 msg.msg_accrights=(caddr_t) &new_fd;
160 msg.msg_accrightslen=sizeof(int);
166 iov[0].iov_base=data;
167 iov[0].iov_len=data_len;
172 ret=recvmsg(unix_socket, &msg, MSG_WAITALL);
174 if (errno==EINTR) goto again;
175 LOG(L_CRIT, "ERROR: receive_fd: recvmsg on %d failed: %s\n",
176 unix_socket, strerror(errno));
181 LOG(L_CRIT, "ERROR: receive_fd: EOF on %d\n", unix_socket);
185 LOG(L_WARN, "WARNING: receive_fd: too few bytes read (%d from %d)"
186 "trying to fix...\n", ret, data_len);
187 n=recv_all(unix_socket, (char*)data+ret, data_len-ret);
195 #ifdef HAVE_MSGHDR_MSG_CONTROL
196 cmsg=CMSG_FIRSTHDR(&msg);
197 if ((cmsg!=0) && (cmsg->cmsg_len==CMSG_LEN(sizeof(new_fd)))){
198 if (cmsg->cmsg_type!= SCM_RIGHTS){
199 LOG(L_ERR, "ERROR: receive_fd: msg control type != SCM_RIGHTS\n");
203 if (cmsg->cmsg_level!= SOL_SOCKET){
204 LOG(L_ERR, "ERROR: receive_fd: msg level != SOL_SOCKET\n");
208 *fd=*((int*) CMSG_DATA(cmsg));
210 LOG(L_ERR, "ERROR: receive_fd: no descriptor passed, cmsg=%p,"
211 "len=%d\n", cmsg, (unsigned)cmsg->cmsg_len);
213 /* it's not really an error */
216 if (msg.msg_accrightslen==sizeof(int)){
219 LOG(L_ERR, "ERROR: receive_fd: no descriptor passed,"
220 " accrightslen=%d\n", msg.msg_accrightslen);