blob: 99b353fcd52deebfd729e0fb2cb498d3b384f371 [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>
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>
Dave Barachc3799992016-08-15 11:12:27 -040047#include <string.h> /* strchr */
Ed Warnickecb9cada2015-12-08 15:45:58 -070048
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
Dave Barachc3799992016-08-15 11:12:27 -040055void
56clib_socket_tx_add_formatted (clib_socket_t * s, char *fmt, ...)
Ed Warnickecb9cada2015-12-08 15:45:58 -070057{
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. */
Dave Barachc3799992016-08-15 11:12:27 -040065static word
66find_free_port (word sock)
Ed Warnickecb9cada2015-12-08 15:45:58 -070067{
68 word port;
69
70 for (port = IPPORT_USERRESERVED; port < 1 << 16; port++)
71 {
72 struct sockaddr_in a;
73
Dave Barachc3799992016-08-15 11:12:27 -040074 memset (&a, 0, sizeof (a)); /* Warnings be gone */
Ed Warnickecb9cada2015-12-08 15:45:58 -070075
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 }
Dave Barachc3799992016-08-15 11:12:27 -040083
Ed Warnickecb9cada2015-12-08 15:45:58 -070084 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. */
89static clib_error_t *
Dave Barachc3799992016-08-15 11:12:27 -040090socket_config (char *config,
91 void *addr, socklen_t * addr_len, u32 ip4_default_address)
Ed Warnickecb9cada2015-12-08 15:45:58 -070092{
Dave Barachc3799992016-08-15 11:12:27 -040093 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -070094
Dave Barachc3799992016-08-15 11:12:27 -040095 if (!config)
Ed Warnickecb9cada2015-12-08 15:45:58 -070096 config = "";
97
98 /* Anything that begins with a / is a local PF_LOCAL socket. */
99 if (config[0] == '/')
100 {
Dave Barachc3799992016-08-15 11:12:27 -0400101 struct sockaddr_un *su = addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700102 su->sun_family = PF_LOCAL;
Damjan Marionf1213b82016-03-13 02:22:06 +0100103 clib_memcpy (&su->sun_path, config,
Dave Barachc3799992016-08-15 11:12:27 -0400104 clib_min (sizeof (su->sun_path), 1 + strlen (config)));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700105 *addr_len = sizeof (su[0]);
106 }
107
108 /* Hostname or hostname:port or port. */
109 else
110 {
Dave Barachc3799992016-08-15 11:12:27 -0400111 char *host_name;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700112 int port = -1;
Dave Barachc3799992016-08-15 11:12:27 -0400113 struct sockaddr_in *sa = addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700114
115 host_name = 0;
116 port = -1;
117 if (config[0] != 0)
118 {
119 unformat_input_t i;
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'",
129 format_unformat_error, &i);
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. */
Dave Barachc3799992016-08-15 11:12:27 -0400148 if (!strcmp (host_name, "localhost"))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700149 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 {
Dave Barachc3799992016-08-15 11:12:27 -0400156 struct hostent *host = gethostbyname (host_name);
157 if (!host)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700158 error = clib_error_return (0, "unknown host `%s'", config);
159 else
Dave Barachc3799992016-08-15 11:12:27 -0400160 clib_memcpy (&sa->sin_addr.s_addr, host->h_addr_list[0],
161 host->h_length);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700162 }
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
Dave Barachc3799992016-08-15 11:12:27 -0400173done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700174 return error;
175}
176
177static clib_error_t *
178default_socket_write (clib_socket_t * s)
179{
Dave Barachc3799992016-08-15 11:12:27 -0400180 clib_error_t *err = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700181 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. */
Dave Barachc3799992016-08-15 11:12:27 -0400196 if (written < 0 && !unix_error_is_fatal (errno))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700197 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. */
Dave Barachc3799992016-08-15 11:12:27 -0400218 else if (written == 0 && tx_len > 64 * 1024)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700219 {
220 vec_free (s->tx_buffer);
221 }
222
Dave Barachc3799992016-08-15 11:12:27 -0400223done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700224 return err;
225}
226
227static clib_error_t *
228default_socket_read (clib_socket_t * sock, int n_bytes)
229{
230 word fd, n_read;
Dave Barachc3799992016-08-15 11:12:27 -0400231 u8 *buf;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700232
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. */
Dave Barachc3799992016-08-15 11:12:27 -0400247 if (!unix_error_is_fatal (errno))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700248 goto non_fatal;
Dave Barachc3799992016-08-15 11:12:27 -0400249
Ed Warnickecb9cada2015-12-08 15:45:58 -0700250 return clib_error_return_unix (0, "read %d bytes", n_bytes);
251 }
Dave Barachc3799992016-08-15 11:12:27 -0400252
Ed Warnickecb9cada2015-12-08 15:45:58 -0700253 /* Other side closed the socket. */
254 if (n_read == 0)
255 sock->flags |= SOCKET_RX_END_OF_FILE;
256
Dave Barachc3799992016-08-15 11:12:27 -0400257non_fatal:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700258 _vec_len (sock->rx_buffer) += n_read - n_bytes;
259
260 return 0;
261}
262
Dave Barachc3799992016-08-15 11:12:27 -0400263static clib_error_t *
264default_socket_close (clib_socket_t * s)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700265{
266 if (close (s->fd) < 0)
267 return clib_error_return_unix (0, "close");
268 return 0;
269}
270
Dave Barachc3799992016-08-15 11:12:27 -0400271static void
272socket_init_funcs (clib_socket_t * s)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700273{
Dave Barachc3799992016-08-15 11:12:27 -0400274 if (!s->write_func)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700275 s->write_func = default_socket_write;
Dave Barachc3799992016-08-15 11:12:27 -0400276 if (!s->read_func)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700277 s->read_func = default_socket_read;
Dave Barachc3799992016-08-15 11:12:27 -0400278 if (!s->close_func)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700279 s->close_func = default_socket_close;
280}
281
282clib_error_t *
283clib_socket_init (clib_socket_t * s)
284{
Dave Barachc3799992016-08-15 11:12:27 -0400285 union
286 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700287 struct sockaddr sa;
288 struct sockaddr_un su;
289 } addr;
290 socklen_t addr_len = 0;
Dave Barachc3799992016-08-15 11:12:27 -0400291 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700292 word port;
293
294 error = socket_config (s->config, &addr.sa, &addr_len,
295 (s->flags & SOCKET_IS_SERVER
Dave Barachc3799992016-08-15 11:12:27 -0400296 ? INADDR_LOOPBACK : INADDR_ANY));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700297 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
Dave Barachc3799992016-08-15 11:12:27 -0400340 if (need_bind && bind (s->fd, &addr.sa, addr_len) < 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700341 {
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
Dave Barachc3799992016-08-15 11:12:27 -0400362 && !((s->flags & SOCKET_NON_BLOCKING_CONNECT) &&
363 errno == EINPROGRESS))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700364 {
365 error = clib_error_return_unix (0, "connect");
366 goto done;
367 }
368 }
369
370 return error;
371
Dave Barachc3799992016-08-15 11:12:27 -0400372done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700373 if (s->fd > 0)
374 close (s->fd);
375 return error;
376}
377
Dave Barachc3799992016-08-15 11:12:27 -0400378clib_error_t *
379clib_socket_accept (clib_socket_t * server, clib_socket_t * client)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700380{
Dave Barachc3799992016-08-15 11:12:27 -0400381 clib_error_t *err = 0;
382 socklen_t len = 0;
383
Ed Warnickecb9cada2015-12-08 15:45:58 -0700384 memset (client, 0, sizeof (client[0]));
385
386 /* Accept the new socket connection. */
387 client->fd = accept (server->fd, 0, 0);
Dave Barachc3799992016-08-15 11:12:27 -0400388 if (client->fd < 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700389 return clib_error_return_unix (0, "accept");
Dave Barachc3799992016-08-15 11:12:27 -0400390
Ed Warnickecb9cada2015-12-08 15:45:58 -0700391 /* 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 }
Dave Barachc3799992016-08-15 11:12:27 -0400397
Ed Warnickecb9cada2015-12-08 15:45:58 -0700398 /* 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
Dave Barachc3799992016-08-15 11:12:27 -0400411close_client:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700412 close (client->fd);
413 return err;
414}
Dave Barachc3799992016-08-15 11:12:27 -0400415
416/*
417 * fd.io coding-style-patch-verification: ON
418 *
419 * Local Variables:
420 * eval: (c-set-style "gnu")
421 * End:
422 */