667df229cb964c76e81bfd2b0e9792837158ec20
[sip-router] / pass_fd.c
1 /*
2  * $Id$
3  *
4  * Copyright (C) 2001-2003 FhG Fokus
5  *
6  * This file is part of ser, a free SIP server.
7  *
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
12  *
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:
16  *    info@iptel.org
17  *
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.
22  *
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
26  */
27  /*
28   * History:
29   * --------
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)
34   *  2005-06-13  added flags to recv_all & receive_fd, to allow full blocking
35   *              or semi-nonblocking mode (andrei)
36   */
37
38 #ifdef USE_TCP
39
40 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <sys/uio.h>
43 #include <stdlib.h> /* for NULL definition on openbsd */
44 #include <errno.h>
45 #include <string.h>
46
47 #include "dprint.h"
48
49
50
51 /* receive all the data or returns error (handles EINTR etc.)
52  * params: socket
53  *         data     - buffer for the results
54  *         data_len - 
55  *         flags    - recv flags for the first recv (see recv(2)), only
56  *                    0, MSG_WAITALL and MSG_DONTWAIT make sense
57  * if flags is set to MSG_DONWAIT (or to 0 and the socket fd is non-blocking),
58  * and if no data is queued on the fd, recv_all will not wait (it will 
59  * return error and set errno to EAGAIN/EWOULDBLOCK). However if even 1 byte
60  *  is queued, the call will block until the whole data_len was read or an
61  *  error or eof occured ("semi-nonblocking" behaviour,  some tcp code
62  *   counts on it).
63  * if flags is set to MSG_WAITALL it will block even if no byte is available.
64  *  
65  * returns: bytes read or error (<0)
66  * can return < data_len if EOF */
67 int recv_all(int socket, void* data, int data_len, int flags)
68 {
69         int b_read;
70         int n;
71         
72         b_read=0;
73 again:
74         n=recv(socket, (char*)data, data_len, flags);
75         if (n<0){
76                 /* error */
77                 if (errno==EINTR) goto again; /* signal, try again */
78                 /* on EAGAIN just return (let the caller know) */
79                 if ((errno==EAGAIN)||(errno==EWOULDBLOCK)) return n;
80                         LOG(L_CRIT, "ERROR: recv_all: 1st recv on %d failed: %s\n",
81                                         socket, strerror(errno));
82                         return n;
83         }
84         b_read+=n;
85         while( (b_read!=data_len) && (n)){
86                 n=recv(socket, (char*)data+b_read, data_len-b_read, MSG_WAITALL);
87                 if (n<0){
88                         /* error */
89                         if (errno==EINTR) continue; /* signal, try again */
90                         LOG(L_CRIT, "ERROR: recv_all: 2nd recv on %d failed: %s\n",
91                                         socket, strerror(errno));
92                         return n;
93                 }
94                 b_read+=n;
95         }
96         return b_read;
97 }
98
99
100
101 /* sends all data (takes care of signals) (assumes blocking fd)
102  * returns number of bytes sent or < 0 for an error */
103 int send_all(int socket, void* data, int data_len)
104 {
105         int n;
106         
107 again:
108         n=send(socket, data, data_len, 0);
109         if (n<0){
110                         /* error */
111                 if (errno==EINTR) goto again; /* signal, try again */
112                 if ((errno!=EAGAIN) &&(errno!=EWOULDBLOCK))
113                         LOG(L_CRIT, "ERROR: send_all: send on %d failed: %s\n",
114                                         socket, strerror(errno));
115         }
116         return n;
117 }
118
119
120 /* at least 1 byte must be sent! */
121 int send_fd(int unix_socket, void* data, int data_len, int fd)
122 {
123         struct msghdr msg;
124         struct iovec iov[1];
125         int ret;
126 #ifdef HAVE_MSGHDR_MSG_CONTROL
127         struct cmsghdr* cmsg;
128         /* make sure msg_control will point to properly aligned data */
129         union {
130                 struct cmsghdr cm;
131                 char control[CMSG_SPACE(sizeof(fd))];
132         }control_un;
133         
134         msg.msg_control=control_un.control;
135         /* openbsd doesn't like "more space", msg_controllen must not
136          * include the end padding */
137         msg.msg_controllen=CMSG_LEN(sizeof(fd));
138         
139         cmsg=CMSG_FIRSTHDR(&msg);
140         cmsg->cmsg_level = SOL_SOCKET;
141         cmsg->cmsg_type = SCM_RIGHTS;
142         cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
143         *(int*)CMSG_DATA(cmsg)=fd;
144         msg.msg_flags=0;
145 #else
146         msg.msg_accrights=(caddr_t) &fd;
147         msg.msg_accrightslen=sizeof(fd);
148 #endif
149         
150         msg.msg_name=0;
151         msg.msg_namelen=0;
152         
153         iov[0].iov_base=data;
154         iov[0].iov_len=data_len;
155         msg.msg_iov=iov;
156         msg.msg_iovlen=1;
157         
158 again:
159         ret=sendmsg(unix_socket, &msg, 0);
160         if (ret<0){
161                 if (errno==EINTR) goto again;
162                 if ((errno!=EAGAIN) && (errno!=EWOULDBLOCK))
163                         LOG(L_CRIT, "ERROR: send_fd: sendmsg failed on %d: %s\n",
164                                         unix_socket, strerror(errno));
165         }
166         
167         return ret;
168 }
169
170
171
172 /* receives a fd and data_len data
173  * params: unix_socket 
174  *         data
175  *         data_len
176  *         fd         - will be set to the passed fd value or -1 if no fd
177  *                      was passed
178  *         flags      - 0, MSG_DONTWAIT, MSG_WAITALL; same as recv_all flags
179  * returns: bytes read on success, -1 on error (and sets errno) */
180 int receive_fd(int unix_socket, void* data, int data_len, int* fd, int flags)
181 {
182         struct msghdr msg;
183         struct iovec iov[1];
184         int new_fd;
185         int ret;
186         int n;
187 #ifdef HAVE_MSGHDR_MSG_CONTROL
188         struct cmsghdr* cmsg;
189         union{
190                 struct cmsghdr cm;
191                 char control[CMSG_SPACE(sizeof(new_fd))];
192         }control_un;
193         
194         msg.msg_control=control_un.control;
195         msg.msg_controllen=sizeof(control_un.control);
196 #else
197         msg.msg_accrights=(caddr_t) &new_fd;
198         msg.msg_accrightslen=sizeof(int);
199 #endif
200         
201         msg.msg_name=0;
202         msg.msg_namelen=0;
203         
204         iov[0].iov_base=data;
205         iov[0].iov_len=data_len;
206         msg.msg_iov=iov;
207         msg.msg_iovlen=1;
208         
209 again:
210         ret=recvmsg(unix_socket, &msg, flags);
211         if (ret<0){
212                 if (errno==EINTR) goto again;
213                 if ((errno==EAGAIN)||(errno==EWOULDBLOCK)) goto error;
214                 LOG(L_CRIT, "ERROR: receive_fd: recvmsg on %d failed: %s\n",
215                                 unix_socket, strerror(errno));
216                 goto error;
217         }
218         if (ret==0){
219                 /* EOF */
220                 LOG(L_CRIT, "ERROR: receive_fd: EOF on %d\n", unix_socket);
221                 goto error;
222         }
223         if (ret<data_len){
224                 LOG(L_WARN, "WARNING: receive_fd: too few bytes read (%d from %d)"
225                                     "trying to fix...\n", ret, data_len);
226                 /* blocking recv_all */
227                 n=recv_all(unix_socket, (char*)data+ret, data_len-ret, MSG_WAITALL);
228                 if (n>=0) ret+=n;
229                 else{
230                         ret=n;
231                         goto error;
232                 }
233         }
234         
235 #ifdef HAVE_MSGHDR_MSG_CONTROL
236         cmsg=CMSG_FIRSTHDR(&msg);
237         if ((cmsg!=0) && (cmsg->cmsg_len==CMSG_LEN(sizeof(new_fd)))){
238                 if (cmsg->cmsg_type!= SCM_RIGHTS){
239                         LOG(L_ERR, "ERROR: receive_fd: msg control type != SCM_RIGHTS\n");
240                         ret=-1;
241                         goto error;
242                 }
243                 if (cmsg->cmsg_level!= SOL_SOCKET){
244                         LOG(L_ERR, "ERROR: receive_fd: msg level != SOL_SOCKET\n");
245                         ret=-1;
246                         goto error;
247                 }
248                 *fd=*((int*) CMSG_DATA(cmsg));
249         }else{
250                 /*
251                 LOG(L_ERR, "ERROR: receive_fd: no descriptor passed, cmsg=%p,"
252                                 "len=%d\n", cmsg, (unsigned)cmsg->cmsg_len); */
253                 *fd=-1;
254                 /* it's not really an error */
255         }
256 #else
257         if (msg.msg_accrightslen==sizeof(int)){
258                 *fd=new_fd;
259         }else{
260                 /*LOG(L_ERR, "ERROR: receive_fd: no descriptor passed,"
261                                 " accrightslen=%d\n", msg.msg_accrightslen); */
262                 *fd=-1;
263         }
264 #endif
265         
266 error:
267         return ret;
268 }
269 #endif