FD.io VPP  v17.07.01-10-g3be13f0
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 <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
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
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  {
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'",
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 *
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 *
266 {
267  if (close (s->fd) < 0)
268  return clib_error_return_unix (0, "close");
269  return 0;
270 }
271 
272 static void
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 *
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 *
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  */
static word find_free_port(word sock)
Definition: socket.c:67
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:337
#define clib_min(x, y)
Definition: clib.h:332
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:561
static clib_error_t * default_socket_close(clib_socket_t *s)
Definition: socket.c:265
#define SOCKET_RX_END_OF_FILE
Definition: socket.h:64
static clib_error_t * default_socket_write(clib_socket_t *s)
Definition: socket.c:179
#define SOCKET_IS_SERVER
Definition: socket.h:58
struct _socket_t clib_socket_t
clib_error_t * clib_socket_accept(clib_socket_t *server, clib_socket_t *client)
Definition: socket.c:388
#define clib_error_return(e, args...)
Definition: error.h:99
void unformat_init_string(unformat_input_t *input, char *string, int string_len)
Definition: unformat.c:1023
clib_error_t * clib_socket_init(clib_socket_t *s)
Definition: socket.c:284
static void socket_init_funcs(clib_socket_t *s)
Definition: socket.c:273
#define v
Definition: acl.c:320
struct _unformat_input_t unformat_input_t
#define clib_error_return_unix(e, args...)
Definition: error.h:102
static clib_error_t * socket_config(char *config, void *addr, socklen_t *addr_len, u32 ip4_default_address)
Definition: socket.c:91
static void clib_socket_tx_add_va_formatted(clib_socket_t *s, char *fmt, va_list *va)
Definition: socket.h:116
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:340
static clib_error_t * default_socket_read(clib_socket_t *sock, int n_bytes)
Definition: socket.c:229
#define clib_memcpy(a, b, c)
Definition: string.h:69
#define SOCKET_IS_CLIENT
Definition: socket.h:59
unsigned int u32
Definition: types.h:88
#define vec_delete(V, N, M)
Delete N elements starting at element M.
Definition: vec.h:785
static word unix_error_is_fatal(word error)
Definition: error.h:118
#define SOCKET_ALLOW_GROUP_WRITE
Definition: socket.h:61
#define clib_max(x, y)
Definition: clib.h:325
void clib_socket_tx_add_formatted(clib_socket_t *s, char *fmt,...)
Definition: socket.c:57
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 void unformat_free(unformat_input_t *i)
Definition: format.h:161
#define clib_unix_warning(format, args...)
Definition: error.h:68
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
vhost_vring_addr_t addr
Definition: vhost-user.h:82
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:972
CLIB vectors are ubiquitous dynamically resized arrays with by user defined "headers".