blob: 7ade440c51c9c0ffd326ff23e484f018ba9bfcce [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
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>
Damjan Marionf6616382017-06-21 12:01:37 +020041#include <sys/stat.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070042#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>
Dave Barachc3799992016-08-15 11:12:27 -040048#include <string.h> /* strchr */
Ed Warnickecb9cada2015-12-08 15:45:58 -070049
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
Dave Barachc3799992016-08-15 11:12:27 -040056void
57clib_socket_tx_add_formatted (clib_socket_t * s, char *fmt, ...)
Ed Warnickecb9cada2015-12-08 15:45:58 -070058{
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. */
Dave Barachc3799992016-08-15 11:12:27 -040066static word
67find_free_port (word sock)
Ed Warnickecb9cada2015-12-08 15:45:58 -070068{
69 word port;
70
71 for (port = IPPORT_USERRESERVED; port < 1 << 16; port++)
72 {
73 struct sockaddr_in a;
74
Dave Barachc3799992016-08-15 11:12:27 -040075 memset (&a, 0, sizeof (a)); /* Warnings be gone */
Ed Warnickecb9cada2015-12-08 15:45:58 -070076
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 }
Dave Barachc3799992016-08-15 11:12:27 -040084
Ed Warnickecb9cada2015-12-08 15:45:58 -070085 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. */
90static clib_error_t *
Dave Barachc3799992016-08-15 11:12:27 -040091socket_config (char *config,
92 void *addr, socklen_t * addr_len, u32 ip4_default_address)
Ed Warnickecb9cada2015-12-08 15:45:58 -070093{
Dave Barachc3799992016-08-15 11:12:27 -040094 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -070095
Dave Barachc3799992016-08-15 11:12:27 -040096 if (!config)
Ed Warnickecb9cada2015-12-08 15:45:58 -070097 config = "";
98
99 /* Anything that begins with a / is a local PF_LOCAL socket. */
100 if (config[0] == '/')
101 {
Dave Barachc3799992016-08-15 11:12:27 -0400102 struct sockaddr_un *su = addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700103 su->sun_family = PF_LOCAL;
Damjan Marionf1213b82016-03-13 02:22:06 +0100104 clib_memcpy (&su->sun_path, config,
Dave Barachc3799992016-08-15 11:12:27 -0400105 clib_min (sizeof (su->sun_path), 1 + strlen (config)));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700106 *addr_len = sizeof (su[0]);
107 }
108
109 /* Hostname or hostname:port or port. */
110 else
111 {
Dave Barachc3799992016-08-15 11:12:27 -0400112 char *host_name;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700113 int port = -1;
Dave Barachc3799992016-08-15 11:12:27 -0400114 struct sockaddr_in *sa = addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700115
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. */
Dave Barachc3799992016-08-15 11:12:27 -0400149 if (!strcmp (host_name, "localhost"))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700150 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 {
Dave Barachc3799992016-08-15 11:12:27 -0400157 struct hostent *host = gethostbyname (host_name);
158 if (!host)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700159 error = clib_error_return (0, "unknown host `%s'", config);
160 else
Dave Barachc3799992016-08-15 11:12:27 -0400161 clib_memcpy (&sa->sin_addr.s_addr, host->h_addr_list[0],
162 host->h_length);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700163 }
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
Dave Barachc3799992016-08-15 11:12:27 -0400174done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700175 return error;
176}
177
178static clib_error_t *
179default_socket_write (clib_socket_t * s)
180{
Dave Barachc3799992016-08-15 11:12:27 -0400181 clib_error_t *err = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700182 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. */
Dave Barachc3799992016-08-15 11:12:27 -0400197 if (written < 0 && !unix_error_is_fatal (errno))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700198 written = 0;
199
200 /* A "real" error occurred. */
201 if (written < 0)
202 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400203 err = clib_error_return_unix (0, "write %wd bytes (fd %d, '%s')",
204 tx_len, s->fd, s->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700205 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. */
Dave Barachc3799992016-08-15 11:12:27 -0400220 else if (written == 0 && tx_len > 64 * 1024)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700221 {
222 vec_free (s->tx_buffer);
223 }
224
Dave Barachc3799992016-08-15 11:12:27 -0400225done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700226 return err;
227}
228
229static clib_error_t *
230default_socket_read (clib_socket_t * sock, int n_bytes)
231{
232 word fd, n_read;
Dave Barachc3799992016-08-15 11:12:27 -0400233 u8 *buf;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700234
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. */
Dave Barachc3799992016-08-15 11:12:27 -0400249 if (!unix_error_is_fatal (errno))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700250 goto non_fatal;
Dave Barachc3799992016-08-15 11:12:27 -0400251
Dave Wallace70ec09d2017-09-06 16:45:04 -0400252 return clib_error_return_unix (0, "read %d bytes (fd %d, '%s')",
253 n_bytes, sock->fd, sock->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700254 }
Dave Barachc3799992016-08-15 11:12:27 -0400255
Ed Warnickecb9cada2015-12-08 15:45:58 -0700256 /* Other side closed the socket. */
257 if (n_read == 0)
258 sock->flags |= SOCKET_RX_END_OF_FILE;
259
Dave Barachc3799992016-08-15 11:12:27 -0400260non_fatal:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700261 _vec_len (sock->rx_buffer) += n_read - n_bytes;
262
263 return 0;
264}
265
Dave Barachc3799992016-08-15 11:12:27 -0400266static clib_error_t *
267default_socket_close (clib_socket_t * s)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700268{
269 if (close (s->fd) < 0)
Dave Wallace70ec09d2017-09-06 16:45:04 -0400270 return clib_error_return_unix (0, "close (fd %d, %s)", s->fd, s->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700271 return 0;
272}
273
Dave Barachc3799992016-08-15 11:12:27 -0400274static void
275socket_init_funcs (clib_socket_t * s)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700276{
Dave Barachc3799992016-08-15 11:12:27 -0400277 if (!s->write_func)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700278 s->write_func = default_socket_write;
Dave Barachc3799992016-08-15 11:12:27 -0400279 if (!s->read_func)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700280 s->read_func = default_socket_read;
Dave Barachc3799992016-08-15 11:12:27 -0400281 if (!s->close_func)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700282 s->close_func = default_socket_close;
283}
284
285clib_error_t *
286clib_socket_init (clib_socket_t * s)
287{
Dave Barachc3799992016-08-15 11:12:27 -0400288 union
289 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700290 struct sockaddr sa;
291 struct sockaddr_un su;
292 } addr;
293 socklen_t addr_len = 0;
Dave Barachc3799992016-08-15 11:12:27 -0400294 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700295 word port;
296
297 error = socket_config (s->config, &addr.sa, &addr_len,
298 (s->flags & SOCKET_IS_SERVER
Dave Barachc3799992016-08-15 11:12:27 -0400299 ? INADDR_LOOPBACK : INADDR_ANY));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700300 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 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400308 error = clib_error_return_unix (0, "socket (fd %d, '%s')",
309 s->fd, s->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700310 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 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400328 error = clib_error_return (0, "no free port (fd %d, '%s')",
329 s->fd, s->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700330 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
Dave Barachc3799992016-08-15 11:12:27 -0400345 if (need_bind && bind (s->fd, &addr.sa, addr_len) < 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700346 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400347 error = clib_error_return_unix (0, "bind (fd %d, '%s')",
348 s->fd, s->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700349 goto done;
350 }
351
352 if (listen (s->fd, 5) < 0)
353 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400354 error = clib_error_return_unix (0, "listen (fd %d, '%s')",
355 s->fd, s->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700356 goto done;
357 }
Damjan Marionf6616382017-06-21 12:01:37 +0200358 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 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700366 }
367 else
368 {
369 if ((s->flags & SOCKET_NON_BLOCKING_CONNECT)
370 && fcntl (s->fd, F_SETFL, O_NONBLOCK) < 0)
371 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400372 error = clib_error_return_unix (0, "fcntl NONBLOCK (fd %d, '%s')",
373 s->fd, s->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700374 goto done;
375 }
376
377 if (connect (s->fd, &addr.sa, addr_len) < 0
Dave Barachc3799992016-08-15 11:12:27 -0400378 && !((s->flags & SOCKET_NON_BLOCKING_CONNECT) &&
379 errno == EINPROGRESS))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700380 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400381 error = clib_error_return_unix (0, "connect (fd %d, '%s')",
382 s->fd, s->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700383 goto done;
384 }
385 }
386
387 return error;
388
Dave Barachc3799992016-08-15 11:12:27 -0400389done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700390 if (s->fd > 0)
391 close (s->fd);
392 return error;
393}
394
Dave Barachc3799992016-08-15 11:12:27 -0400395clib_error_t *
396clib_socket_accept (clib_socket_t * server, clib_socket_t * client)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700397{
Dave Barachc3799992016-08-15 11:12:27 -0400398 clib_error_t *err = 0;
399 socklen_t len = 0;
400
Ed Warnickecb9cada2015-12-08 15:45:58 -0700401 memset (client, 0, sizeof (client[0]));
402
403 /* Accept the new socket connection. */
404 client->fd = accept (server->fd, 0, 0);
Dave Barachc3799992016-08-15 11:12:27 -0400405 if (client->fd < 0)
Dave Wallace70ec09d2017-09-06 16:45:04 -0400406 return clib_error_return_unix (0, "accept (fd %d, '%s')",
407 server->fd, server->config);
Dave Barachc3799992016-08-15 11:12:27 -0400408
Ed Warnickecb9cada2015-12-08 15:45:58 -0700409 /* Set the new socket to be non-blocking. */
410 if (fcntl (client->fd, F_SETFL, O_NONBLOCK) < 0)
411 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400412 err = clib_error_return_unix (0, "fcntl O_NONBLOCK (fd %d)",
413 client->fd);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700414 goto close_client;
415 }
Dave Barachc3799992016-08-15 11:12:27 -0400416
Ed Warnickecb9cada2015-12-08 15:45:58 -0700417 /* Get peer info. */
418 len = sizeof (client->peer);
419 if (getpeername (client->fd, (struct sockaddr *) &client->peer, &len) < 0)
420 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400421 err = clib_error_return_unix (0, "getpeername (fd %d)", client->fd);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700422 goto close_client;
423 }
424
425 client->flags = SOCKET_IS_CLIENT;
426
427 socket_init_funcs (client);
428 return 0;
429
Dave Barachc3799992016-08-15 11:12:27 -0400430close_client:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700431 close (client->fd);
432 return err;
433}
Dave Barachc3799992016-08-15 11:12:27 -0400434
435/*
436 * fd.io coding-style-patch-verification: ON
437 *
438 * Local Variables:
439 * eval: (c-set-style "gnu")
440 * End:
441 */