blob: 37dcbbfd8c6638e250a04c20c54c759a3cf960f7 [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 };
Chris Lukeab7b8d92017-09-07 07:40:13 -0400362 if (stat (((struct sockaddr_un *) &addr)->sun_path, &st) < 0)
363 {
364 error = clib_error_return_unix (0, "stat (fd %d, '%s')",
365 s->fd, s->config);
366 goto done;
367 }
Damjan Marionf6616382017-06-21 12:01:37 +0200368 st.st_mode |= S_IWGRP;
Chris Lukeab7b8d92017-09-07 07:40:13 -0400369 if (chmod (((struct sockaddr_un *) &addr)->sun_path, st.st_mode) <
370 0)
371 {
372 error =
373 clib_error_return_unix (0, "chmod (fd %d, '%s', mode %o)",
374 s->fd, s->config, st.st_mode);
375 goto done;
376 }
Damjan Marionf6616382017-06-21 12:01:37 +0200377 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700378 }
379 else
380 {
381 if ((s->flags & SOCKET_NON_BLOCKING_CONNECT)
382 && fcntl (s->fd, F_SETFL, O_NONBLOCK) < 0)
383 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400384 error = clib_error_return_unix (0, "fcntl NONBLOCK (fd %d, '%s')",
385 s->fd, s->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700386 goto done;
387 }
388
389 if (connect (s->fd, &addr.sa, addr_len) < 0
Dave Barachc3799992016-08-15 11:12:27 -0400390 && !((s->flags & SOCKET_NON_BLOCKING_CONNECT) &&
391 errno == EINPROGRESS))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700392 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400393 error = clib_error_return_unix (0, "connect (fd %d, '%s')",
394 s->fd, s->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700395 goto done;
396 }
397 }
398
399 return error;
400
Dave Barachc3799992016-08-15 11:12:27 -0400401done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700402 if (s->fd > 0)
403 close (s->fd);
404 return error;
405}
406
Dave Barachc3799992016-08-15 11:12:27 -0400407clib_error_t *
408clib_socket_accept (clib_socket_t * server, clib_socket_t * client)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700409{
Dave Barachc3799992016-08-15 11:12:27 -0400410 clib_error_t *err = 0;
411 socklen_t len = 0;
412
Ed Warnickecb9cada2015-12-08 15:45:58 -0700413 memset (client, 0, sizeof (client[0]));
414
415 /* Accept the new socket connection. */
416 client->fd = accept (server->fd, 0, 0);
Dave Barachc3799992016-08-15 11:12:27 -0400417 if (client->fd < 0)
Dave Wallace70ec09d2017-09-06 16:45:04 -0400418 return clib_error_return_unix (0, "accept (fd %d, '%s')",
419 server->fd, server->config);
Dave Barachc3799992016-08-15 11:12:27 -0400420
Ed Warnickecb9cada2015-12-08 15:45:58 -0700421 /* Set the new socket to be non-blocking. */
422 if (fcntl (client->fd, F_SETFL, O_NONBLOCK) < 0)
423 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400424 err = clib_error_return_unix (0, "fcntl O_NONBLOCK (fd %d)",
425 client->fd);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700426 goto close_client;
427 }
Dave Barachc3799992016-08-15 11:12:27 -0400428
Ed Warnickecb9cada2015-12-08 15:45:58 -0700429 /* Get peer info. */
430 len = sizeof (client->peer);
431 if (getpeername (client->fd, (struct sockaddr *) &client->peer, &len) < 0)
432 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400433 err = clib_error_return_unix (0, "getpeername (fd %d)", client->fd);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700434 goto close_client;
435 }
436
437 client->flags = SOCKET_IS_CLIENT;
438
439 socket_init_funcs (client);
440 return 0;
441
Dave Barachc3799992016-08-15 11:12:27 -0400442close_client:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700443 close (client->fd);
444 return err;
445}
Dave Barachc3799992016-08-15 11:12:27 -0400446
447/*
448 * fd.io coding-style-patch-verification: ON
449 *
450 * Local Variables:
451 * eval: (c-set-style "gnu")
452 * End:
453 */