37dcbbfd8c6638e250a04c20c54c759a3cf960f7
[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 <sys/un.h>
39 #include <sys/types.h>
40 #include <sys/socket.h>
41 #include <sys/stat.h>
42 #include <netinet/in.h>
43 #include <arpa/inet.h>
44 #include <netdb.h>
45 #include <unistd.h>
46 #include <stdio.h>
47 #include <fcntl.h>
48 #include <string.h>             /* strchr */
49
50 #include <vppinfra/mem.h>
51 #include <vppinfra/vec.h>
52 #include <vppinfra/socket.h>
53 #include <vppinfra/format.h>
54 #include <vppinfra/error.h>
55
56 void
57 clib_socket_tx_add_formatted (clib_socket_t * s, char *fmt, ...)
58 {
59   va_list va;
60   va_start (va, fmt);
61   clib_socket_tx_add_va_formatted (s, fmt, &va);
62   va_end (va);
63 }
64
65 /* Return and bind to an unused port. */
66 static word
67 find_free_port (word sock)
68 {
69   word port;
70
71   for (port = IPPORT_USERRESERVED; port < 1 << 16; port++)
72     {
73       struct sockaddr_in a;
74
75       memset (&a, 0, sizeof (a));       /* Warnings be gone */
76
77       a.sin_family = PF_INET;
78       a.sin_addr.s_addr = INADDR_ANY;
79       a.sin_port = htons (port);
80
81       if (bind (sock, (struct sockaddr *) &a, sizeof (a)) >= 0)
82         break;
83     }
84
85   return port < 1 << 16 ? port : -1;
86 }
87
88 /* Convert a config string to a struct sockaddr and length for use
89    with bind or connect. */
90 static clib_error_t *
91 socket_config (char *config,
92                void *addr, socklen_t * addr_len, u32 ip4_default_address)
93 {
94   clib_error_t *error = 0;
95
96   if (!config)
97     config = "";
98
99   /* Anything that begins with a / is a local PF_LOCAL socket. */
100   if (config[0] == '/')
101     {
102       struct sockaddr_un *su = addr;
103       su->sun_family = PF_LOCAL;
104       clib_memcpy (&su->sun_path, config,
105                    clib_min (sizeof (su->sun_path), 1 + strlen (config)));
106       *addr_len = sizeof (su[0]);
107     }
108
109   /* Hostname or hostname:port or port. */
110   else
111     {
112       char *host_name;
113       int port = -1;
114       struct sockaddr_in *sa = addr;
115
116       host_name = 0;
117       port = -1;
118       if (config[0] != 0)
119         {
120           unformat_input_t i;
121
122           unformat_init_string (&i, config, strlen (config));
123           if (unformat (&i, "%s:%d", &host_name, &port)
124               || unformat (&i, "%s:0x%x", &host_name, &port))
125             ;
126           else if (unformat (&i, "%s", &host_name))
127             ;
128           else
129             error = clib_error_return (0, "unknown input `%U'",
130                                        format_unformat_error, &i);
131           unformat_free (&i);
132
133           if (error)
134             goto done;
135         }
136
137       sa->sin_family = PF_INET;
138       *addr_len = sizeof (sa[0]);
139       if (port != -1)
140         sa->sin_port = htons (port);
141       else
142         sa->sin_port = 0;
143
144       if (host_name)
145         {
146           struct in_addr host_addr;
147
148           /* Recognize localhost to avoid host lookup in most common cast. */
149           if (!strcmp (host_name, "localhost"))
150             sa->sin_addr.s_addr = htonl (INADDR_LOOPBACK);
151
152           else if (inet_aton (host_name, &host_addr))
153             sa->sin_addr = host_addr;
154
155           else if (host_name && strlen (host_name) > 0)
156             {
157               struct hostent *host = gethostbyname (host_name);
158               if (!host)
159                 error = clib_error_return (0, "unknown host `%s'", config);
160               else
161                 clib_memcpy (&sa->sin_addr.s_addr, host->h_addr_list[0],
162                              host->h_length);
163             }
164
165           else
166             sa->sin_addr.s_addr = htonl (ip4_default_address);
167
168           vec_free (host_name);
169           if (error)
170             goto done;
171         }
172     }
173
174 done:
175   return error;
176 }
177
178 static clib_error_t *
179 default_socket_write (clib_socket_t * s)
180 {
181   clib_error_t *err = 0;
182   word written = 0;
183   word fd = 0;
184   word tx_len;
185
186   fd = s->fd;
187
188   /* Map standard input to standard output.
189      Typically, fd is a socket for which read/write both work. */
190   if (fd == 0)
191     fd = 1;
192
193   tx_len = vec_len (s->tx_buffer);
194   written = write (fd, s->tx_buffer, tx_len);
195
196   /* Ignore certain errors. */
197   if (written < 0 && !unix_error_is_fatal (errno))
198     written = 0;
199
200   /* A "real" error occurred. */
201   if (written < 0)
202     {
203       err = clib_error_return_unix (0, "write %wd bytes (fd %d, '%s')",
204                                     tx_len, s->fd, s->config);
205       vec_free (s->tx_buffer);
206       goto done;
207     }
208
209   /* Reclaim the transmitted part of the tx buffer on successful writes. */
210   else if (written > 0)
211     {
212       if (written == tx_len)
213         _vec_len (s->tx_buffer) = 0;
214       else
215         vec_delete (s->tx_buffer, written, 0);
216     }
217
218   /* If a non-fatal error occurred AND
219      the buffer is full, then we must free it. */
220   else if (written == 0 && tx_len > 64 * 1024)
221     {
222       vec_free (s->tx_buffer);
223     }
224
225 done:
226   return err;
227 }
228
229 static clib_error_t *
230 default_socket_read (clib_socket_t * sock, int n_bytes)
231 {
232   word fd, n_read;
233   u8 *buf;
234
235   /* RX side of socket is down once end of file is reached. */
236   if (sock->flags & SOCKET_RX_END_OF_FILE)
237     return 0;
238
239   fd = sock->fd;
240
241   n_bytes = clib_max (n_bytes, 4096);
242   vec_add2 (sock->rx_buffer, buf, n_bytes);
243
244   if ((n_read = read (fd, buf, n_bytes)) < 0)
245     {
246       n_read = 0;
247
248       /* Ignore certain errors. */
249       if (!unix_error_is_fatal (errno))
250         goto non_fatal;
251
252       return clib_error_return_unix (0, "read %d bytes (fd %d, '%s')",
253                                      n_bytes, sock->fd, sock->config);
254     }
255
256   /* Other side closed the socket. */
257   if (n_read == 0)
258     sock->flags |= SOCKET_RX_END_OF_FILE;
259
260 non_fatal:
261   _vec_len (sock->rx_buffer) += n_read - n_bytes;
262
263   return 0;
264 }
265
266 static clib_error_t *
267 default_socket_close (clib_socket_t * s)
268 {
269   if (close (s->fd) < 0)
270     return clib_error_return_unix (0, "close (fd %d, %s)", s->fd, s->config);
271   return 0;
272 }
273
274 static void
275 socket_init_funcs (clib_socket_t * s)
276 {
277   if (!s->write_func)
278     s->write_func = default_socket_write;
279   if (!s->read_func)
280     s->read_func = default_socket_read;
281   if (!s->close_func)
282     s->close_func = default_socket_close;
283 }
284
285 clib_error_t *
286 clib_socket_init (clib_socket_t * s)
287 {
288   union
289   {
290     struct sockaddr sa;
291     struct sockaddr_un su;
292   } addr;
293   socklen_t addr_len = 0;
294   clib_error_t *error = 0;
295   word port;
296
297   error = socket_config (s->config, &addr.sa, &addr_len,
298                          (s->flags & SOCKET_IS_SERVER
299                           ? INADDR_LOOPBACK : INADDR_ANY));
300   if (error)
301     goto done;
302
303   socket_init_funcs (s);
304
305   s->fd = socket (addr.sa.sa_family, SOCK_STREAM, 0);
306   if (s->fd < 0)
307     {
308       error = clib_error_return_unix (0, "socket (fd %d, '%s')",
309                                       s->fd, s->config);
310       goto done;
311     }
312
313   port = 0;
314   if (addr.sa.sa_family == PF_INET)
315     port = ((struct sockaddr_in *) &addr)->sin_port;
316
317   if (s->flags & SOCKET_IS_SERVER)
318     {
319       uword need_bind = 1;
320
321       if (addr.sa.sa_family == PF_INET)
322         {
323           if (port == 0)
324             {
325               port = find_free_port (s->fd);
326               if (port < 0)
327                 {
328                   error = clib_error_return (0, "no free port (fd %d, '%s')",
329                                              s->fd, s->config);
330                   goto done;
331                 }
332               need_bind = 0;
333             }
334         }
335       if (addr.sa.sa_family == PF_LOCAL)
336         unlink (((struct sockaddr_un *) &addr)->sun_path);
337
338       /* Make address available for multiple users. */
339       {
340         int v = 1;
341         if (setsockopt (s->fd, SOL_SOCKET, SO_REUSEADDR, &v, sizeof (v)) < 0)
342           clib_unix_warning ("setsockopt SO_REUSEADDR fails");
343       }
344
345       if (need_bind && bind (s->fd, &addr.sa, addr_len) < 0)
346         {
347           error = clib_error_return_unix (0, "bind (fd %d, '%s')",
348                                           s->fd, s->config);
349           goto done;
350         }
351
352       if (listen (s->fd, 5) < 0)
353         {
354           error = clib_error_return_unix (0, "listen (fd %d, '%s')",
355                                           s->fd, s->config);
356           goto done;
357         }
358       if (addr.sa.sa_family == PF_LOCAL
359           && s->flags & SOCKET_ALLOW_GROUP_WRITE)
360         {
361           struct stat st = { 0 };
362           if (stat (((struct sockaddr_un *) &addr)->sun_path, &st) < 0)
363             {
364               error = clib_error_return_unix (0, "stat (fd %d, '%s')",
365                                               s->fd, s->config);
366               goto done;
367             }
368           st.st_mode |= S_IWGRP;
369           if (chmod (((struct sockaddr_un *) &addr)->sun_path, st.st_mode) <
370               0)
371             {
372               error =
373                 clib_error_return_unix (0, "chmod (fd %d, '%s', mode %o)",
374                                         s->fd, s->config, st.st_mode);
375               goto done;
376             }
377         }
378     }
379   else
380     {
381       if ((s->flags & SOCKET_NON_BLOCKING_CONNECT)
382           && fcntl (s->fd, F_SETFL, O_NONBLOCK) < 0)
383         {
384           error = clib_error_return_unix (0, "fcntl NONBLOCK (fd %d, '%s')",
385                                           s->fd, s->config);
386           goto done;
387         }
388
389       if (connect (s->fd, &addr.sa, addr_len) < 0
390           && !((s->flags & SOCKET_NON_BLOCKING_CONNECT) &&
391                errno == EINPROGRESS))
392         {
393           error = clib_error_return_unix (0, "connect (fd %d, '%s')",
394                                           s->fd, s->config);
395           goto done;
396         }
397     }
398
399   return error;
400
401 done:
402   if (s->fd > 0)
403     close (s->fd);
404   return error;
405 }
406
407 clib_error_t *
408 clib_socket_accept (clib_socket_t * server, clib_socket_t * client)
409 {
410   clib_error_t *err = 0;
411   socklen_t len = 0;
412
413   memset (client, 0, sizeof (client[0]));
414
415   /* Accept the new socket connection. */
416   client->fd = accept (server->fd, 0, 0);
417   if (client->fd < 0)
418     return clib_error_return_unix (0, "accept (fd %d, '%s')",
419                                    server->fd, server->config);
420
421   /* Set the new socket to be non-blocking. */
422   if (fcntl (client->fd, F_SETFL, O_NONBLOCK) < 0)
423     {
424       err = clib_error_return_unix (0, "fcntl O_NONBLOCK (fd %d)",
425                                     client->fd);
426       goto close_client;
427     }
428
429   /* Get peer info. */
430   len = sizeof (client->peer);
431   if (getpeername (client->fd, (struct sockaddr *) &client->peer, &len) < 0)
432     {
433       err = clib_error_return_unix (0, "getpeername (fd %d)", client->fd);
434       goto close_client;
435     }
436
437   client->flags = SOCKET_IS_CLIENT;
438
439   socket_init_funcs (client);
440   return 0;
441
442 close_client:
443   close (client->fd);
444   return err;
445 }
446
447 /*
448  * fd.io coding-style-patch-verification: ON
449  *
450  * Local Variables:
451  * eval: (c-set-style "gnu")
452  * End:
453  */