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