vppinfra: explicit blocking mode for sock connects
[vpp.git] / src / vppinfra / socket.c
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /*
16   Copyright (c) 2001, 2002, 2003, 2005 Eliot Dresselhaus
17
18   Permission is hereby granted, free of charge, to any person obtaining
19   a copy of this software and associated documentation files (the
20   "Software"), to deal in the Software without restriction, including
21   without limitation the rights to use, copy, modify, merge, publish,
22   distribute, sublicense, and/or sell copies of the Software, and to
23   permit persons to whom the Software is furnished to do so, subject to
24   the following conditions:
25
26   The above copyright notice and this permission notice shall be
27   included in all copies or substantial portions of the Software.
28
29   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
33   LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
34   OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
35   WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 */
37
38 #include <stdio.h>
39 #include <string.h>             /* strchr */
40 #define __USE_GNU
41 #define _GNU_SOURCE
42 #include <sys/types.h>
43 #include <sys/socket.h>
44 #include <sys/un.h>
45 #include <sys/stat.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
48 #include <netdb.h>
49 #include <unistd.h>
50 #include <fcntl.h>
51
52 #include <vppinfra/mem.h>
53 #include <vppinfra/vec.h>
54 #include <vppinfra/socket.h>
55 #include <vppinfra/format.h>
56 #include <vppinfra/error.h>
57
58 #ifndef __GLIBC__
59 /* IPPORT_USERRESERVED is not part of musl libc. */
60 #define IPPORT_USERRESERVED 5000
61 #endif
62
63 __clib_export void
64 clib_socket_tx_add_formatted (clib_socket_t * s, char *fmt, ...)
65 {
66   va_list va;
67   va_start (va, fmt);
68   clib_socket_tx_add_va_formatted (s, fmt, &va);
69   va_end (va);
70 }
71
72 /* Return and bind to an unused port. */
73 static word
74 find_free_port (word sock)
75 {
76   word port;
77
78   for (port = IPPORT_USERRESERVED; port < 1 << 16; port++)
79     {
80       struct sockaddr_in a;
81
82       clib_memset (&a, 0, sizeof (a));  /* Warnings be gone */
83
84       a.sin_family = PF_INET;
85       a.sin_addr.s_addr = INADDR_ANY;
86       a.sin_port = htons (port);
87
88       if (bind (sock, (struct sockaddr *) &a, sizeof (a)) >= 0)
89         break;
90     }
91
92   return port < 1 << 16 ? port : -1;
93 }
94
95 /* Convert a config string to a struct sockaddr and length for use
96    with bind or connect. */
97 static clib_error_t *
98 socket_config (char *config,
99                void *addr, socklen_t * addr_len, u32 ip4_default_address)
100 {
101   clib_error_t *error = 0;
102
103   if (!config)
104     config = "";
105
106   /* Anything that begins with a / is a local PF_LOCAL socket. */
107   if (config[0] == '/')
108     {
109       struct sockaddr_un *su = addr;
110       su->sun_family = PF_LOCAL;
111       clib_memcpy (&su->sun_path, config,
112                    clib_min (sizeof (su->sun_path), 1 + strlen (config)));
113       *addr_len = sizeof (su[0]);
114     }
115
116   /* Hostname or hostname:port or port. */
117   else
118     {
119       char *host_name;
120       int port = -1;
121       struct sockaddr_in *sa = addr;
122
123       host_name = 0;
124       port = -1;
125       if (config[0] != 0)
126         {
127           unformat_input_t i;
128
129           unformat_init_string (&i, config, strlen (config));
130           if (unformat (&i, "%s:%d", &host_name, &port)
131               || unformat (&i, "%s:0x%x", &host_name, &port))
132             ;
133           else if (unformat (&i, "%s", &host_name))
134             ;
135           else
136             error = clib_error_return (0, "unknown input `%U'",
137                                        format_unformat_error, &i);
138           unformat_free (&i);
139
140           if (error)
141             goto done;
142         }
143
144       sa->sin_family = PF_INET;
145       *addr_len = sizeof (sa[0]);
146       if (port != -1)
147         sa->sin_port = htons (port);
148       else
149         sa->sin_port = 0;
150
151       if (host_name)
152         {
153           struct in_addr host_addr;
154
155           /* Recognize localhost to avoid host lookup in most common cast. */
156           if (!strcmp (host_name, "localhost"))
157             sa->sin_addr.s_addr = htonl (INADDR_LOOPBACK);
158
159           else if (inet_aton (host_name, &host_addr))
160             sa->sin_addr = host_addr;
161
162           else if (host_name && strlen (host_name) > 0)
163             {
164               struct hostent *host = gethostbyname (host_name);
165               if (!host)
166                 error = clib_error_return (0, "unknown host `%s'", config);
167               else
168                 clib_memcpy (&sa->sin_addr.s_addr, host->h_addr_list[0],
169                              host->h_length);
170             }
171
172           else
173             sa->sin_addr.s_addr = htonl (ip4_default_address);
174
175           vec_free (host_name);
176           if (error)
177             goto done;
178         }
179     }
180
181 done:
182   return error;
183 }
184
185 static clib_error_t *
186 default_socket_write (clib_socket_t * s)
187 {
188   clib_error_t *err = 0;
189   word written = 0;
190   word fd = 0;
191   word tx_len;
192
193   fd = s->fd;
194
195   /* Map standard input to standard output.
196      Typically, fd is a socket for which read/write both work. */
197   if (fd == 0)
198     fd = 1;
199
200   tx_len = vec_len (s->tx_buffer);
201   written = write (fd, s->tx_buffer, tx_len);
202
203   /* Ignore certain errors. */
204   if (written < 0 && !unix_error_is_fatal (errno))
205     written = 0;
206
207   /* A "real" error occurred. */
208   if (written < 0)
209     {
210       err = clib_error_return_unix (0, "write %wd bytes (fd %d, '%s')",
211                                     tx_len, s->fd, s->config);
212       vec_free (s->tx_buffer);
213       goto done;
214     }
215
216   /* Reclaim the transmitted part of the tx buffer on successful writes. */
217   else if (written > 0)
218     {
219       if (written == tx_len)
220         _vec_len (s->tx_buffer) = 0;
221       else
222         vec_delete (s->tx_buffer, written, 0);
223     }
224
225   /* If a non-fatal error occurred AND
226      the buffer is full, then we must free it. */
227   else if (written == 0 && tx_len > 64 * 1024)
228     {
229       vec_free (s->tx_buffer);
230     }
231
232 done:
233   return err;
234 }
235
236 static clib_error_t *
237 default_socket_read (clib_socket_t * sock, int n_bytes)
238 {
239   word fd, n_read;
240   u8 *buf;
241
242   /* RX side of socket is down once end of file is reached. */
243   if (sock->flags & CLIB_SOCKET_F_RX_END_OF_FILE)
244     return 0;
245
246   fd = sock->fd;
247
248   n_bytes = clib_max (n_bytes, 4096);
249   vec_add2 (sock->rx_buffer, buf, n_bytes);
250
251   if ((n_read = read (fd, buf, n_bytes)) < 0)
252     {
253       n_read = 0;
254
255       /* Ignore certain errors. */
256       if (!unix_error_is_fatal (errno))
257         goto non_fatal;
258
259       return clib_error_return_unix (0, "read %d bytes (fd %d, '%s')",
260                                      n_bytes, sock->fd, sock->config);
261     }
262
263   /* Other side closed the socket. */
264   if (n_read == 0)
265     sock->flags |= CLIB_SOCKET_F_RX_END_OF_FILE;
266
267 non_fatal:
268   _vec_len (sock->rx_buffer) += n_read - n_bytes;
269
270   return 0;
271 }
272
273 static clib_error_t *
274 default_socket_close (clib_socket_t * s)
275 {
276   if (close (s->fd) < 0)
277     return clib_error_return_unix (0, "close (fd %d, %s)", s->fd, s->config);
278   return 0;
279 }
280
281 static clib_error_t *
282 default_socket_sendmsg (clib_socket_t * s, void *msg, int msglen,
283                         int fds[], int num_fds)
284 {
285   struct msghdr mh = { 0 };
286   struct iovec iov[1];
287   char ctl[CMSG_SPACE (sizeof (int) * num_fds)];
288   int rv;
289
290   iov[0].iov_base = msg;
291   iov[0].iov_len = msglen;
292   mh.msg_iov = iov;
293   mh.msg_iovlen = 1;
294
295   if (num_fds > 0)
296     {
297       struct cmsghdr *cmsg;
298       clib_memset (&ctl, 0, sizeof (ctl));
299       mh.msg_control = ctl;
300       mh.msg_controllen = sizeof (ctl);
301       cmsg = CMSG_FIRSTHDR (&mh);
302       cmsg->cmsg_len = CMSG_LEN (sizeof (int) * num_fds);
303       cmsg->cmsg_level = SOL_SOCKET;
304       cmsg->cmsg_type = SCM_RIGHTS;
305       memcpy (CMSG_DATA (cmsg), fds, sizeof (int) * num_fds);
306     }
307   rv = sendmsg (s->fd, &mh, 0);
308   if (rv < 0)
309     return clib_error_return_unix (0, "sendmsg");
310   return 0;
311 }
312
313
314 static clib_error_t *
315 default_socket_recvmsg (clib_socket_t * s, void *msg, int msglen,
316                         int fds[], int num_fds)
317 {
318 #ifdef __linux__
319   char ctl[CMSG_SPACE (sizeof (int) * num_fds) +
320            CMSG_SPACE (sizeof (struct ucred))];
321   struct ucred *cr = 0;
322 #else
323   char ctl[CMSG_SPACE (sizeof (int) * num_fds)];
324 #endif
325   struct msghdr mh = { 0 };
326   struct iovec iov[1];
327   ssize_t size;
328   struct cmsghdr *cmsg;
329
330   iov[0].iov_base = msg;
331   iov[0].iov_len = msglen;
332   mh.msg_iov = iov;
333   mh.msg_iovlen = 1;
334   mh.msg_control = ctl;
335   mh.msg_controllen = sizeof (ctl);
336
337   clib_memset (ctl, 0, sizeof (ctl));
338
339   /* receive the incoming message */
340   size = recvmsg (s->fd, &mh, 0);
341   if (size != msglen)
342     {
343       return (size == 0) ? clib_error_return (0, "disconnected") :
344         clib_error_return_unix (0, "recvmsg: malformed message (fd %d, '%s')",
345                                 s->fd, s->config);
346     }
347
348   cmsg = CMSG_FIRSTHDR (&mh);
349   while (cmsg)
350     {
351       if (cmsg->cmsg_level == SOL_SOCKET)
352         {
353 #ifdef __linux__
354           if (cmsg->cmsg_type == SCM_CREDENTIALS)
355             {
356               cr = (struct ucred *) CMSG_DATA (cmsg);
357               s->uid = cr->uid;
358               s->gid = cr->gid;
359               s->pid = cr->pid;
360             }
361           else
362 #endif
363           if (cmsg->cmsg_type == SCM_RIGHTS)
364             {
365               clib_memcpy_fast (fds, CMSG_DATA (cmsg),
366                                 num_fds * sizeof (int));
367             }
368         }
369       cmsg = CMSG_NXTHDR (&mh, cmsg);
370     }
371   return 0;
372 }
373
374 static void
375 socket_init_funcs (clib_socket_t * s)
376 {
377   if (!s->write_func)
378     s->write_func = default_socket_write;
379   if (!s->read_func)
380     s->read_func = default_socket_read;
381   if (!s->close_func)
382     s->close_func = default_socket_close;
383   if (!s->sendmsg_func)
384     s->sendmsg_func = default_socket_sendmsg;
385   if (!s->recvmsg_func)
386     s->recvmsg_func = default_socket_recvmsg;
387 }
388
389 __clib_export clib_error_t *
390 clib_socket_init (clib_socket_t * s)
391 {
392   union
393   {
394     struct sockaddr sa;
395     struct sockaddr_un su;
396   } addr;
397   socklen_t addr_len = 0;
398   int socket_type, rv;
399   clib_error_t *error = 0;
400   word port;
401
402   error = socket_config (s->config, &addr.sa, &addr_len,
403                          (s->flags & CLIB_SOCKET_F_IS_SERVER
404                           ? INADDR_LOOPBACK : INADDR_ANY));
405   if (error)
406     goto done;
407
408   socket_init_funcs (s);
409
410   socket_type = s->flags & CLIB_SOCKET_F_SEQPACKET ?
411     SOCK_SEQPACKET : SOCK_STREAM;
412
413   s->fd = socket (addr.sa.sa_family, socket_type, 0);
414   if (s->fd < 0)
415     {
416       error = clib_error_return_unix (0, "socket (fd %d, '%s')",
417                                       s->fd, s->config);
418       goto done;
419     }
420
421   port = 0;
422   if (addr.sa.sa_family == PF_INET)
423     port = ((struct sockaddr_in *) &addr)->sin_port;
424
425   if (s->flags & CLIB_SOCKET_F_IS_SERVER)
426     {
427       uword need_bind = 1;
428
429       if (addr.sa.sa_family == PF_INET)
430         {
431           if (port == 0)
432             {
433               port = find_free_port (s->fd);
434               if (port < 0)
435                 {
436                   error = clib_error_return (0, "no free port (fd %d, '%s')",
437                                              s->fd, s->config);
438                   goto done;
439                 }
440               need_bind = 0;
441             }
442         }
443       if (addr.sa.sa_family == PF_LOCAL)
444         unlink (((struct sockaddr_un *) &addr)->sun_path);
445
446       /* Make address available for multiple users. */
447       {
448         int v = 1;
449         if (setsockopt (s->fd, SOL_SOCKET, SO_REUSEADDR, &v, sizeof (v)) < 0)
450           clib_unix_warning ("setsockopt SO_REUSEADDR fails");
451       }
452
453 #if __linux__
454       if (addr.sa.sa_family == PF_LOCAL && s->flags & CLIB_SOCKET_F_PASSCRED)
455         {
456           int x = 1;
457           if (setsockopt (s->fd, SOL_SOCKET, SO_PASSCRED, &x, sizeof (x)) < 0)
458             {
459               error = clib_error_return_unix (0, "setsockopt (SO_PASSCRED, "
460                                               "fd %d, '%s')", s->fd,
461                                               s->config);
462               goto done;
463             }
464         }
465 #endif
466
467       if (need_bind && bind (s->fd, &addr.sa, addr_len) < 0)
468         {
469           error = clib_error_return_unix (0, "bind (fd %d, '%s')",
470                                           s->fd, s->config);
471           goto done;
472         }
473
474       if (listen (s->fd, 5) < 0)
475         {
476           error = clib_error_return_unix (0, "listen (fd %d, '%s')",
477                                           s->fd, s->config);
478           goto done;
479         }
480       if (addr.sa.sa_family == PF_LOCAL
481           && s->flags & CLIB_SOCKET_F_ALLOW_GROUP_WRITE)
482         {
483           struct stat st = { 0 };
484           if (stat (((struct sockaddr_un *) &addr)->sun_path, &st) < 0)
485             {
486               error = clib_error_return_unix (0, "stat (fd %d, '%s')",
487                                               s->fd, s->config);
488               goto done;
489             }
490           st.st_mode |= S_IWGRP;
491           if (chmod (((struct sockaddr_un *) &addr)->sun_path, st.st_mode) <
492               0)
493             {
494               error =
495                 clib_error_return_unix (0, "chmod (fd %d, '%s', mode %o)",
496                                         s->fd, s->config, st.st_mode);
497               goto done;
498             }
499         }
500     }
501   else
502     {
503       if ((s->flags & CLIB_SOCKET_F_NON_BLOCKING_CONNECT)
504           && fcntl (s->fd, F_SETFL, O_NONBLOCK) < 0)
505         {
506           error = clib_error_return_unix (0, "fcntl NONBLOCK (fd %d, '%s')",
507                                           s->fd, s->config);
508           goto done;
509         }
510
511       while ((rv = connect (s->fd, &addr.sa, addr_len)) < 0
512              && errno == EAGAIN)
513         ;
514       if (rv < 0 && !((s->flags & CLIB_SOCKET_F_NON_BLOCKING_CONNECT) &&
515                       errno == EINPROGRESS))
516         {
517           error = clib_error_return_unix (0, "connect (fd %d, '%s')",
518                                           s->fd, s->config);
519           goto done;
520         }
521       /* Connect was blocking so set fd to non-blocking now unless
522        * blocking mode explicitly requested. */
523       if (!(s->flags & CLIB_SOCKET_F_NON_BLOCKING_CONNECT) &&
524           !(s->flags & CLIB_SOCKET_F_BLOCKING) &&
525           fcntl (s->fd, F_SETFL, O_NONBLOCK) < 0)
526         {
527           error = clib_error_return_unix (0, "fcntl NONBLOCK2 (fd %d, '%s')",
528                                           s->fd, s->config);
529           goto done;
530         }
531     }
532
533   return error;
534
535 done:
536   if (s->fd > 0)
537     close (s->fd);
538   return error;
539 }
540
541 __clib_export clib_error_t *
542 clib_socket_accept (clib_socket_t * server, clib_socket_t * client)
543 {
544   clib_error_t *err = 0;
545   socklen_t len = 0;
546
547   clib_memset (client, 0, sizeof (client[0]));
548
549   /* Accept the new socket connection. */
550   client->fd = accept (server->fd, 0, 0);
551   if (client->fd < 0)
552     return clib_error_return_unix (0, "accept (fd %d, '%s')",
553                                    server->fd, server->config);
554
555   /* Set the new socket to be non-blocking. */
556   if (fcntl (client->fd, F_SETFL, O_NONBLOCK) < 0)
557     {
558       err = clib_error_return_unix (0, "fcntl O_NONBLOCK (fd %d)",
559                                     client->fd);
560       goto close_client;
561     }
562
563   /* Get peer info. */
564   len = sizeof (client->peer);
565   if (getpeername (client->fd, (struct sockaddr *) &client->peer, &len) < 0)
566     {
567       err = clib_error_return_unix (0, "getpeername (fd %d)", client->fd);
568       goto close_client;
569     }
570
571   client->flags = CLIB_SOCKET_F_IS_CLIENT;
572
573   socket_init_funcs (client);
574   return 0;
575
576 close_client:
577   close (client->fd);
578   return err;
579 }
580
581 /*
582  * fd.io coding-style-patch-verification: ON
583  *
584  * Local Variables:
585  * eval: (c-set-style "gnu")
586  * End:
587  */