4c23c235109c986c2d10ee832e1317fec704ca85
[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", tx_len);
204       vec_free (s->tx_buffer);
205       goto done;
206     }
207
208   /* Reclaim the transmitted part of the tx buffer on successful writes. */
209   else if (written > 0)
210     {
211       if (written == tx_len)
212         _vec_len (s->tx_buffer) = 0;
213       else
214         vec_delete (s->tx_buffer, written, 0);
215     }
216
217   /* If a non-fatal error occurred AND
218      the buffer is full, then we must free it. */
219   else if (written == 0 && tx_len > 64 * 1024)
220     {
221       vec_free (s->tx_buffer);
222     }
223
224 done:
225   return err;
226 }
227
228 static clib_error_t *
229 default_socket_read (clib_socket_t * sock, int n_bytes)
230 {
231   word fd, n_read;
232   u8 *buf;
233
234   /* RX side of socket is down once end of file is reached. */
235   if (sock->flags & SOCKET_RX_END_OF_FILE)
236     return 0;
237
238   fd = sock->fd;
239
240   n_bytes = clib_max (n_bytes, 4096);
241   vec_add2 (sock->rx_buffer, buf, n_bytes);
242
243   if ((n_read = read (fd, buf, n_bytes)) < 0)
244     {
245       n_read = 0;
246
247       /* Ignore certain errors. */
248       if (!unix_error_is_fatal (errno))
249         goto non_fatal;
250
251       return clib_error_return_unix (0, "read %d bytes", n_bytes);
252     }
253
254   /* Other side closed the socket. */
255   if (n_read == 0)
256     sock->flags |= SOCKET_RX_END_OF_FILE;
257
258 non_fatal:
259   _vec_len (sock->rx_buffer) += n_read - n_bytes;
260
261   return 0;
262 }
263
264 static clib_error_t *
265 default_socket_close (clib_socket_t * s)
266 {
267   if (close (s->fd) < 0)
268     return clib_error_return_unix (0, "close");
269   return 0;
270 }
271
272 static void
273 socket_init_funcs (clib_socket_t * s)
274 {
275   if (!s->write_func)
276     s->write_func = default_socket_write;
277   if (!s->read_func)
278     s->read_func = default_socket_read;
279   if (!s->close_func)
280     s->close_func = default_socket_close;
281 }
282
283 clib_error_t *
284 clib_socket_init (clib_socket_t * s)
285 {
286   union
287   {
288     struct sockaddr sa;
289     struct sockaddr_un su;
290   } addr;
291   socklen_t addr_len = 0;
292   clib_error_t *error = 0;
293   word port;
294
295   error = socket_config (s->config, &addr.sa, &addr_len,
296                          (s->flags & SOCKET_IS_SERVER
297                           ? INADDR_LOOPBACK : INADDR_ANY));
298   if (error)
299     goto done;
300
301   socket_init_funcs (s);
302
303   s->fd = socket (addr.sa.sa_family, SOCK_STREAM, 0);
304   if (s->fd < 0)
305     {
306       error = clib_error_return_unix (0, "socket");
307       goto done;
308     }
309
310   port = 0;
311   if (addr.sa.sa_family == PF_INET)
312     port = ((struct sockaddr_in *) &addr)->sin_port;
313
314   if (s->flags & SOCKET_IS_SERVER)
315     {
316       uword need_bind = 1;
317
318       if (addr.sa.sa_family == PF_INET)
319         {
320           if (port == 0)
321             {
322               port = find_free_port (s->fd);
323               if (port < 0)
324                 {
325                   error = clib_error_return (0, "no free port");
326                   goto done;
327                 }
328               need_bind = 0;
329             }
330         }
331       if (addr.sa.sa_family == PF_LOCAL)
332         unlink (((struct sockaddr_un *) &addr)->sun_path);
333
334       /* Make address available for multiple users. */
335       {
336         int v = 1;
337         if (setsockopt (s->fd, SOL_SOCKET, SO_REUSEADDR, &v, sizeof (v)) < 0)
338           clib_unix_warning ("setsockopt SO_REUSEADDR fails");
339       }
340
341       if (need_bind && bind (s->fd, &addr.sa, addr_len) < 0)
342         {
343           error = clib_error_return_unix (0, "bind");
344           goto done;
345         }
346
347       if (listen (s->fd, 5) < 0)
348         {
349           error = clib_error_return_unix (0, "listen");
350           goto done;
351         }
352       if (addr.sa.sa_family == PF_LOCAL
353           && s->flags & SOCKET_ALLOW_GROUP_WRITE)
354         {
355           struct stat st = { 0 };
356           stat (((struct sockaddr_un *) &addr)->sun_path, &st);
357           st.st_mode |= S_IWGRP;
358           chmod (((struct sockaddr_un *) &addr)->sun_path, st.st_mode);
359         }
360     }
361   else
362     {
363       if ((s->flags & SOCKET_NON_BLOCKING_CONNECT)
364           && fcntl (s->fd, F_SETFL, O_NONBLOCK) < 0)
365         {
366           error = clib_error_return_unix (0, "fcntl NONBLOCK");
367           goto done;
368         }
369
370       if (connect (s->fd, &addr.sa, addr_len) < 0
371           && !((s->flags & SOCKET_NON_BLOCKING_CONNECT) &&
372                errno == EINPROGRESS))
373         {
374           error = clib_error_return_unix (0, "connect");
375           goto done;
376         }
377     }
378
379   return error;
380
381 done:
382   if (s->fd > 0)
383     close (s->fd);
384   return error;
385 }
386
387 clib_error_t *
388 clib_socket_accept (clib_socket_t * server, clib_socket_t * client)
389 {
390   clib_error_t *err = 0;
391   socklen_t len = 0;
392
393   memset (client, 0, sizeof (client[0]));
394
395   /* Accept the new socket connection. */
396   client->fd = accept (server->fd, 0, 0);
397   if (client->fd < 0)
398     return clib_error_return_unix (0, "accept");
399
400   /* Set the new socket to be non-blocking. */
401   if (fcntl (client->fd, F_SETFL, O_NONBLOCK) < 0)
402     {
403       err = clib_error_return_unix (0, "fcntl O_NONBLOCK");
404       goto close_client;
405     }
406
407   /* Get peer info. */
408   len = sizeof (client->peer);
409   if (getpeername (client->fd, (struct sockaddr *) &client->peer, &len) < 0)
410     {
411       err = clib_error_return_unix (0, "getpeername");
412       goto close_client;
413     }
414
415   client->flags = SOCKET_IS_CLIENT;
416
417   socket_init_funcs (client);
418   return 0;
419
420 close_client:
421   close (client->fd);
422   return err;
423 }
424
425 /*
426  * fd.io coding-style-patch-verification: ON
427  *
428  * Local Variables:
429  * eval: (c-set-style "gnu")
430  * End:
431  */