core: init structure to 0 for pass fd operations
[sip-router] / pass_fd.c
1 /*
2  * Copyright (C) 2001-2003 FhG Fokus
3  *
4  * This file is part of Kamailio, a free SIP server.
5  *
6  * Kamailio is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version
10  *
11  * Kamailio is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20
21 /*!
22  * \file
23  * \brief Kamailio core ::
24  * \ingroup core
25  * Module: \ref core
26  */
27
28 #ifdef USE_TCP
29
30 #include "pass_fd.h"
31
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <sys/uio.h>
35 #include <stdlib.h> /* for NULL definition on openbsd */
36 #include <errno.h>
37 #include <string.h>
38 #ifdef NO_MSG_WAITALL
39 #include <poll.h>
40 #endif /* NO_MSG_WAITALL */
41
42 #include "dprint.h"
43
44
45
46 /** receive all the data or returns error (handles EINTR etc.)
47  * params: socket
48  *         data     - buffer for the results
49  *         data_len -
50  *         flags    - recv flags for the first recv (see recv(2)), only
51  *                    0, MSG_WAITALL and MSG_DONTWAIT make sense
52  * if flags is set to MSG_DONWAIT (or to 0 and the socket fd is non-blocking),
53  * and if no data is queued on the fd, recv_all will not wait (it will
54  * return error and set errno to EAGAIN/EWOULDBLOCK). However if even 1 byte
55  *  is queued, the call will block until the whole data_len was read or an
56  *  error or eof occurred ("semi-nonblocking" behaviour,  some tcp code
57  *   counts on it).
58  * if flags is set to MSG_WAITALL it will block even if no byte is available.
59  *
60  * returns: bytes read or error (<0)
61  * can return < data_len if EOF */
62 int recv_all(int socket, void* data, int data_len, int flags)
63 {
64         int b_read;
65         int n;
66 #ifdef NO_MSG_WAITALL
67         struct pollfd pfd;
68 #endif /* NO_MSG_WAITALL */
69
70         b_read=0;
71 again:
72 #ifdef NO_MSG_WAITALL
73         if (flags & MSG_WAITALL){
74                 n=-1;
75                 goto poll_recv; /* simulate MSG_WAITALL */
76         }
77 #endif /* NO_MSG_WAITALL */
78         n=recv(socket, (char*)data, data_len, flags);
79         if (n<0){
80                 /* error */
81                 if (errno==EINTR) goto again; /* signal, try again */
82                 /* on EAGAIN just return (let the caller know) */
83                 if ((errno==EAGAIN)||(errno==EWOULDBLOCK)) return n;
84                         LM_CRIT("1st recv on %d failed: %s\n",
85                                         socket, strerror(errno));
86                         return n;
87         }
88         b_read+=n;
89         while( (b_read!=data_len) && (n)){
90 #ifdef NO_MSG_WAITALL
91                 /* cygwin & win do not support MSG_WAITALL => workaround using poll */
92 poll_recv:
93                 n=recv(socket, (char*)data+b_read, data_len-b_read, 0);
94 #else /* NO_MSG_WAITALL */
95                 n=recv(socket, (char*)data+b_read, data_len-b_read, MSG_WAITALL);
96 #endif /* NO_MSG_WAITALL */
97                 if (n<0){
98                         /* error */
99                         if (errno==EINTR) continue; /* signal, try again */
100 #ifdef NO_MSG_WAITALL
101                         if (errno==EAGAIN || errno==EWOULDBLOCK){
102                                 /* emulate MSG_WAITALL using poll */
103                                 pfd.fd=socket;
104                                 pfd.events=POLLIN;
105 poll_retry:
106                                 n=poll(&pfd, 1, -1);
107                                 if (n<0){
108                                         if (errno==EINTR) goto poll_retry;
109                                         LM_CRIT("poll on %d failed: %s\n",
110                                                 socket, strerror(errno));
111                                         return n;
112                                 } else continue; /* try recv again */
113                         }
114 #endif /* NO_MSG_WAITALL */
115                         LM_CRIT("2nd recv on %d failed: %s\n",
116                                         socket, strerror(errno));
117                         return n;
118                 }
119                 b_read+=n;
120         }
121         return b_read;
122 }
123
124
125
126 /** sends all data (takes care of signals) (assumes blocking fd)
127  * returns number of bytes sent or < 0 for an error */
128 int send_all(int socket, void* data, int data_len)
129 {
130         int n;
131
132 again:
133         n=send(socket, data, data_len, 0);
134         if (n<0){
135                         /* error */
136                 if (errno==EINTR) goto again; /* signal, try again */
137                 if ((errno!=EAGAIN) &&(errno!=EWOULDBLOCK))
138                         LM_CRIT("send on %d failed: %s\n",
139                                         socket, strerror(errno));
140         }
141         return n;
142 }
143
144
145 /** at least 1 byte must be sent! */
146 int send_fd(int unix_socket, void* data, int data_len, int fd)
147 {
148         struct msghdr msg;
149         struct iovec iov[1];
150         int ret;
151 #ifdef HAVE_MSGHDR_MSG_CONTROL
152         int* pi;
153         struct cmsghdr* cmsg;
154         /* make sure msg_control will point to properly aligned data */
155         union {
156                 struct cmsghdr cm;
157                 char control[CMSG_SPACE(sizeof(fd))];
158         }control_un;
159
160         memset(&msg, 0, sizeof(struct msghdr));
161         msg.msg_control=control_un.control;
162         /* openbsd doesn't like "more space", msg_controllen must not
163          * include the end padding */
164         msg.msg_controllen=CMSG_LEN(sizeof(fd));
165
166         cmsg=CMSG_FIRSTHDR(&msg);
167         cmsg->cmsg_level = SOL_SOCKET;
168         cmsg->cmsg_type = SCM_RIGHTS;
169         cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
170         pi=(int*)CMSG_DATA(cmsg);
171         *pi=fd;
172         msg.msg_flags=0;
173 #else
174         msg.msg_accrights=(caddr_t) &fd;
175         msg.msg_accrightslen=sizeof(fd);
176 #endif
177
178         msg.msg_name=0;
179         msg.msg_namelen=0;
180
181         iov[0].iov_base=data;
182         iov[0].iov_len=data_len;
183         msg.msg_iov=iov;
184         msg.msg_iovlen=1;
185
186 again:
187         ret=sendmsg(unix_socket, &msg, 0);
188         if (ret<0){
189                 if (errno==EINTR) goto again;
190                 if ((errno!=EAGAIN) && (errno!=EWOULDBLOCK))
191                         LM_CRIT("sendmsg failed sending %d on %d: %s (%d)\n",
192                                 fd, unix_socket, strerror(errno), errno);
193         }
194
195         return ret;
196 }
197
198
199
200 /** receives a fd and data_len data
201  * params: unix_socket
202  *         data
203  *         data_len
204  *         fd         - will be set to the passed fd value or -1 if no fd
205  *                      was passed
206  *         flags      - 0, MSG_DONTWAIT, MSG_WAITALL; same as recv_all flags
207  * returns: bytes read on success, -1 on error (and sets errno) */
208 int receive_fd(int unix_socket, void* data, int data_len, int* fd, int flags)
209 {
210         struct msghdr msg;
211         struct iovec iov[1];
212         int new_fd;
213         int ret;
214         int n;
215 #ifdef NO_MSG_WAITALL
216         struct pollfd pfd;
217         int f;
218 #endif /*NO_MSG_WAITALL */
219 #ifdef HAVE_MSGHDR_MSG_CONTROL
220         int* pi;
221         struct cmsghdr* cmsg;
222         union{
223                 struct cmsghdr cm;
224                 char control[CMSG_SPACE(sizeof(new_fd))];
225         }control_un;
226
227         memset(&msg, 0, sizeof(struct msghdr));
228         msg.msg_control=control_un.control;
229         msg.msg_controllen=sizeof(control_un.control);
230 #else
231         msg.msg_accrights=(caddr_t) &new_fd;
232         msg.msg_accrightslen=sizeof(int);
233 #endif
234
235         msg.msg_name=0;
236         msg.msg_namelen=0;
237
238         iov[0].iov_base=data;
239         iov[0].iov_len=data_len;
240         msg.msg_iov=iov;
241         msg.msg_iovlen=1;
242
243 #ifdef NO_MSG_WAITALL
244         f=flags & ~MSG_WAITALL;
245 #endif /* NO_MSG_WAITALL */
246
247 again:
248 #ifdef NO_MSG_WAITALL
249                 ret=recvmsg(unix_socket, &msg, f);
250 #else /* NO_MSG_WAITALL */
251                 ret=recvmsg(unix_socket, &msg, flags);
252 #endif /* NO_MSG_WAITALL */
253         if (ret<0){
254                 if (errno==EINTR) goto again;
255                 if ((errno==EAGAIN)||(errno==EWOULDBLOCK)){
256 #ifdef NO_MSG_WAITALL
257                         if (flags & MSG_WAITALL){
258                                 /* emulate MSG_WAITALL using poll */
259                                 pfd.fd=unix_socket;
260                                 pfd.events=POLLIN;
261 poll_again:
262                                 ret=poll(&pfd, 1, -1);
263                                 if (ret>=0) goto again;
264                                 else if (errno==EINTR) goto poll_again;
265                                 LM_CRIT("poll on %d failed: %s\n",
266                                         unix_socket, strerror(errno));
267                         }
268 #endif /* NO_MSG_WAITALL */
269                         goto error;
270                 }
271                 LM_CRIT("recvmsg on %d failed: %s\n",
272                                 unix_socket, strerror(errno));
273                 goto error;
274         }
275         if (ret==0){
276                 /* EOF */
277                 LM_CRIT("EOF on %d\n", unix_socket);
278                 goto error;
279         }
280         if (ret<data_len){
281                 LM_WARN("too few bytes read (%d from %d) trying to fix...\n",
282                                 ret, data_len);
283                 /* blocking recv_all */
284                 n=recv_all(unix_socket, (char*)data+ret, data_len-ret, MSG_WAITALL);
285                 if (n>=0) ret+=n;
286                 else{
287                         ret=n;
288                         goto error;
289                 }
290         }
291
292 #ifdef HAVE_MSGHDR_MSG_CONTROL
293         cmsg=CMSG_FIRSTHDR(&msg);
294         if ((cmsg!=0) && (cmsg->cmsg_len==CMSG_LEN(sizeof(new_fd)))){
295                 if (cmsg->cmsg_type!= SCM_RIGHTS){
296                         LM_ERR("msg control type != SCM_RIGHTS\n");
297                         ret=-1;
298                         goto error;
299                 }
300                 if (cmsg->cmsg_level!= SOL_SOCKET){
301                         LM_ERR("msg level != SOL_SOCKET\n");
302                         ret=-1;
303                         goto error;
304                 }
305                 pi=(int*) CMSG_DATA(cmsg);
306                 *fd=*pi;
307         }else{
308                 /*LM_ERR("no descriptor passed, cmsg=%p, len=%d\n",
309                         cmsg, (unsigned)cmsg->cmsg_len); */
310                 *fd=-1;
311                 /* it's not really an error */
312         }
313 #else
314         if (msg.msg_accrightslen==sizeof(int)){
315                 *fd=new_fd;
316         }else{
317                 /*LM_ERR("no descriptor passed, accrightslen=%d\n",
318                         msg.msg_accrightslen); */
319                 *fd=-1;
320         }
321 #endif
322
323 error:
324         return ret;
325 }
326 #endif