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 */
recv_all(int socket,void * data,int data_len,int flags)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 */
send_all(int socket,void * data,int data_len)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! */
send_fd(int unix_socket,void * data,int data_len,int fd)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) */
receive_fd(int unix_socket,void * data,int data_len,int * fd,int flags)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
327