FD.io VPP  v16.06
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 clib_socket_tx_add_formatted (clib_socket_t * s, char * fmt, ...)
56 {
57  va_list va;
58  va_start (va, fmt);
59  clib_socket_tx_add_va_formatted (s, fmt, &va);
60  va_end (va);
61 }
62 
63 /* Return and bind to an unused port. */
64 static word find_free_port (word sock)
65 {
66  word port;
67 
68  for (port = IPPORT_USERRESERVED; port < 1 << 16; port++)
69  {
70  struct sockaddr_in a;
71 
72  memset(&a, 0, sizeof (a)); /* Warnings be gone */
73 
74  a.sin_family = PF_INET;
75  a.sin_addr.s_addr = INADDR_ANY;
76  a.sin_port = htons (port);
77 
78  if (bind (sock, (struct sockaddr *) &a, sizeof (a)) >= 0)
79  break;
80  }
81 
82  return port < 1 << 16 ? port : -1;
83 }
84 
85 /* Convert a config string to a struct sockaddr and length for use
86  with bind or connect. */
87 static clib_error_t *
88 socket_config (char * config,
89  void * addr,
90  socklen_t * addr_len,
91  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], host->h_length);
161  }
162 
163  else
164  sa->sin_addr.s_addr = htonl (ip4_default_address);
165 
166  vec_free (host_name);
167  if (error)
168  goto done;
169  }
170  }
171 
172  done:
173  return error;
174 }
175 
176 static clib_error_t *
178 {
179  clib_error_t * err = 0;
180  word written = 0;
181  word fd = 0;
182  word tx_len;
183 
184  fd = s->fd;
185 
186  /* Map standard input to standard output.
187  Typically, fd is a socket for which read/write both work. */
188  if (fd == 0)
189  fd = 1;
190 
191  tx_len = vec_len (s->tx_buffer);
192  written = write (fd, s->tx_buffer, tx_len);
193 
194  /* Ignore certain errors. */
195  if (written < 0 && ! unix_error_is_fatal (errno))
196  written = 0;
197 
198  /* A "real" error occurred. */
199  if (written < 0)
200  {
201  err = clib_error_return_unix (0, "write %wd bytes", tx_len);
202  vec_free (s->tx_buffer);
203  goto done;
204  }
205 
206  /* Reclaim the transmitted part of the tx buffer on successful writes. */
207  else if (written > 0)
208  {
209  if (written == tx_len)
210  _vec_len (s->tx_buffer) = 0;
211  else
212  vec_delete (s->tx_buffer, written, 0);
213  }
214 
215  /* If a non-fatal error occurred AND
216  the buffer is full, then we must free it. */
217  else if (written == 0 && tx_len > 64*1024)
218  {
219  vec_free (s->tx_buffer);
220  }
221 
222  done:
223  return err;
224 }
225 
226 static clib_error_t *
227 default_socket_read (clib_socket_t * sock, int n_bytes)
228 {
229  word fd, n_read;
230  u8 * buf;
231 
232  /* RX side of socket is down once end of file is reached. */
233  if (sock->flags & SOCKET_RX_END_OF_FILE)
234  return 0;
235 
236  fd = sock->fd;
237 
238  n_bytes = clib_max (n_bytes, 4096);
239  vec_add2 (sock->rx_buffer, buf, n_bytes);
240 
241  if ((n_read = read (fd, buf, n_bytes)) < 0)
242  {
243  n_read = 0;
244 
245  /* Ignore certain errors. */
246  if (! unix_error_is_fatal (errno))
247  goto non_fatal;
248 
249  return clib_error_return_unix (0, "read %d bytes", n_bytes);
250  }
251 
252  /* Other side closed the socket. */
253  if (n_read == 0)
254  sock->flags |= SOCKET_RX_END_OF_FILE;
255 
256  non_fatal:
257  _vec_len (sock->rx_buffer) += n_read - n_bytes;
258 
259  return 0;
260 }
261 
263 {
264  if (close (s->fd) < 0)
265  return clib_error_return_unix (0, "close");
266  return 0;
267 }
268 
270 {
271  if (! s->write_func)
272  s->write_func = default_socket_write;
273  if (! s->read_func)
274  s->read_func = default_socket_read;
275  if (! s->close_func)
276  s->close_func = default_socket_close;
277 }
278 
279 clib_error_t *
281 {
282  union {
283  struct sockaddr sa;
284  struct sockaddr_un su;
285  } addr;
286  socklen_t addr_len = 0;
287  clib_error_t * error = 0;
288  word port;
289 
290  error = socket_config (s->config, &addr.sa, &addr_len,
291  (s->flags & SOCKET_IS_SERVER
292  ? INADDR_LOOPBACK
293  : INADDR_ANY));
294  if (error)
295  goto done;
296 
297  socket_init_funcs (s);
298 
299  s->fd = socket (addr.sa.sa_family, SOCK_STREAM, 0);
300  if (s->fd < 0)
301  {
302  error = clib_error_return_unix (0, "socket");
303  goto done;
304  }
305 
306  port = 0;
307  if (addr.sa.sa_family == PF_INET)
308  port = ((struct sockaddr_in *) &addr)->sin_port;
309 
310  if (s->flags & SOCKET_IS_SERVER)
311  {
312  uword need_bind = 1;
313 
314  if (addr.sa.sa_family == PF_INET)
315  {
316  if (port == 0)
317  {
318  port = find_free_port (s->fd);
319  if (port < 0)
320  {
321  error = clib_error_return (0, "no free port");
322  goto done;
323  }
324  need_bind = 0;
325  }
326  }
327  if (addr.sa.sa_family == PF_LOCAL)
328  unlink (((struct sockaddr_un *) &addr)->sun_path);
329 
330  /* Make address available for multiple users. */
331  {
332  int v = 1;
333  if (setsockopt (s->fd, SOL_SOCKET, SO_REUSEADDR, &v, sizeof (v)) < 0)
334  clib_unix_warning ("setsockopt SO_REUSEADDR fails");
335  }
336 
337  if (need_bind
338  && bind (s->fd, &addr.sa, addr_len) < 0)
339  {
340  error = clib_error_return_unix (0, "bind");
341  goto done;
342  }
343 
344  if (listen (s->fd, 5) < 0)
345  {
346  error = clib_error_return_unix (0, "listen");
347  goto done;
348  }
349  }
350  else
351  {
352  if ((s->flags & SOCKET_NON_BLOCKING_CONNECT)
353  && fcntl (s->fd, F_SETFL, O_NONBLOCK) < 0)
354  {
355  error = clib_error_return_unix (0, "fcntl NONBLOCK");
356  goto done;
357  }
358 
359  if (connect (s->fd, &addr.sa, addr_len) < 0
360  && ! ((s->flags & SOCKET_NON_BLOCKING_CONNECT) &&
361  errno == EINPROGRESS))
362  {
363  error = clib_error_return_unix (0, "connect");
364  goto done;
365  }
366  }
367 
368  return error;
369 
370  done:
371  if (s->fd > 0)
372  close (s->fd);
373  return error;
374 }
375 
377 {
378  clib_error_t * err = 0;
379  socklen_t len = 0;
380 
381  memset (client, 0, sizeof (client[0]));
382 
383  /* Accept the new socket connection. */
384  client->fd = accept (server->fd, 0, 0);
385  if (client->fd < 0)
386  return clib_error_return_unix (0, "accept");
387 
388  /* Set the new socket to be non-blocking. */
389  if (fcntl (client->fd, F_SETFL, O_NONBLOCK) < 0)
390  {
391  err = clib_error_return_unix (0, "fcntl O_NONBLOCK");
392  goto close_client;
393  }
394 
395  /* Get peer info. */
396  len = sizeof (client->peer);
397  if (getpeername (client->fd, (struct sockaddr *) &client->peer, &len) < 0)
398  {
399  err = clib_error_return_unix (0, "getpeername");
400  goto close_client;
401  }
402 
403  client->flags = SOCKET_IS_CLIENT;
404 
405  socket_init_funcs (client);
406  return 0;
407 
408  close_client:
409  close (client->fd);
410  return err;
411 }
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:267
#define clib_min(x, y)
Definition: clib.h:295
uword unformat(unformat_input_t *i, char *fmt,...)
Definition: unformat.c:942
always_inline void unformat_free(unformat_input_t *i)
Definition: format.h:160
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:519
#define SOCKET_RX_END_OF_FILE
Definition: socket.h:62
clib_error_t * clib_socket_init(clib_socket_t *s)
Definition: socket.c:280
#define SOCKET_IS_SERVER
Definition: socket.h:57
static clib_error_t * default_socket_write(clib_socket_t *s)
Definition: socket.c:177
always_inline void clib_socket_tx_add_va_formatted(clib_socket_t *s, char *fmt, va_list *va)
Definition: socket.h:105
struct _socket_t clib_socket_t
void unformat_init_string(unformat_input_t *input, char *string, int string_len)
Definition: unformat.c:991
static word find_free_port(word sock)
Definition: socket.c:64
#define clib_error_return_unix(e, args...)
Definition: error.h:115
always_inline word unix_error_is_fatal(word error)
Definition: error.h:130
static clib_error_t * default_socket_close(clib_socket_t *s)
Definition: socket.c:262
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:298
static void socket_init_funcs(clib_socket_t *s)
Definition: socket.c:269
#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:376
#define clib_unix_warning(format, args...)
Definition: error.h:68
#define SOCKET_IS_CLIENT
Definition: socket.h:58
unsigned int u32
Definition: types.h:88
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:87
#define vec_delete(V, N, M)
Delete N elements starting at element M.
Definition: vec.h:743
#define clib_max(x, y)
Definition: clib.h:288
u64 uword
Definition: types.h:112
#define SOCKET_NON_BLOCKING_CONNECT
Definition: socket.h:59
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:88
void clib_socket_tx_add_formatted(clib_socket_t *s, char *fmt,...)
Definition: socket.c:55
vhost_vring_addr_t addr
Definition: vhost-user.h:78
#define clib_error_return(e, args...)
Definition: error.h:112
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:227