Add fd/socket name to clib_socket_* error msgs.
[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           stat (((struct sockaddr_un *) &addr)->sun_path, &st);
363           st.st_mode |= S_IWGRP;
364           chmod (((struct sockaddr_un *) &addr)->sun_path, st.st_mode);
365         }
366     }
367   else
368     {
369       if ((s->flags & SOCKET_NON_BLOCKING_CONNECT)
370           && fcntl (s->fd, F_SETFL, O_NONBLOCK) < 0)
371         {
372           error = clib_error_return_unix (0, "fcntl NONBLOCK (fd %d, '%s')",
373                                           s->fd, s->config);
374           goto done;
375         }
376
377       if (connect (s->fd, &addr.sa, addr_len) < 0
378           && !((s->flags & SOCKET_NON_BLOCKING_CONNECT) &&
379                errno == EINPROGRESS))
380         {
381           error = clib_error_return_unix (0, "connect (fd %d, '%s')",
382                                           s->fd, s->config);
383           goto done;
384         }
385     }
386
387   return error;
388
389 done:
390   if (s->fd > 0)
391     close (s->fd);
392   return error;
393 }
394
395 clib_error_t *
396 clib_socket_accept (clib_socket_t * server, clib_socket_t * client)
397 {
398   clib_error_t *err = 0;
399   socklen_t len = 0;
400
401   memset (client, 0, sizeof (client[0]));
402
403   /* Accept the new socket connection. */
404   client->fd = accept (server->fd, 0, 0);
405   if (client->fd < 0)
406     return clib_error_return_unix (0, "accept (fd %d, '%s')",
407                                    server->fd, server->config);
408
409   /* Set the new socket to be non-blocking. */
410   if (fcntl (client->fd, F_SETFL, O_NONBLOCK) < 0)
411     {
412       err = clib_error_return_unix (0, "fcntl O_NONBLOCK (fd %d)",
413                                     client->fd);
414       goto close_client;
415     }
416
417   /* Get peer info. */
418   len = sizeof (client->peer);
419   if (getpeername (client->fd, (struct sockaddr *) &client->peer, &len) < 0)
420     {
421       err = clib_error_return_unix (0, "getpeername (fd %d)", client->fd);
422       goto close_client;
423     }
424
425   client->flags = SOCKET_IS_CLIENT;
426
427   socket_init_funcs (client);
428   return 0;
429
430 close_client:
431   close (client->fd);
432   return err;
433 }
434
435 /*
436  * fd.io coding-style-patch-verification: ON
437  *
438  * Local Variables:
439  * eval: (c-set-style "gnu")
440  * End:
441  */