blob: 4c23c235109c986c2d10ee832e1317fec704ca85 [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 {
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. */
Dave Barachc3799992016-08-15 11:12:27 -0400219 else if (written == 0 && tx_len > 64 * 1024)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700220 {
221 vec_free (s->tx_buffer);
222 }
223
Dave Barachc3799992016-08-15 11:12:27 -0400224done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700225 return err;
226}
227
228static clib_error_t *
229default_socket_read (clib_socket_t * sock, int n_bytes)
230{
231 word fd, n_read;
Dave Barachc3799992016-08-15 11:12:27 -0400232 u8 *buf;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700233
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. */
Dave Barachc3799992016-08-15 11:12:27 -0400248 if (!unix_error_is_fatal (errno))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700249 goto non_fatal;
Dave Barachc3799992016-08-15 11:12:27 -0400250
Ed Warnickecb9cada2015-12-08 15:45:58 -0700251 return clib_error_return_unix (0, "read %d bytes", n_bytes);
252 }
Dave Barachc3799992016-08-15 11:12:27 -0400253
Ed Warnickecb9cada2015-12-08 15:45:58 -0700254 /* Other side closed the socket. */
255 if (n_read == 0)
256 sock->flags |= SOCKET_RX_END_OF_FILE;
257
Dave Barachc3799992016-08-15 11:12:27 -0400258non_fatal:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700259 _vec_len (sock->rx_buffer) += n_read - n_bytes;
260
261 return 0;
262}
263
Dave Barachc3799992016-08-15 11:12:27 -0400264static clib_error_t *
265default_socket_close (clib_socket_t * s)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700266{
267 if (close (s->fd) < 0)
268 return clib_error_return_unix (0, "close");
269 return 0;
270}
271
Dave Barachc3799992016-08-15 11:12:27 -0400272static void
273socket_init_funcs (clib_socket_t * s)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700274{
Dave Barachc3799992016-08-15 11:12:27 -0400275 if (!s->write_func)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700276 s->write_func = default_socket_write;
Dave Barachc3799992016-08-15 11:12:27 -0400277 if (!s->read_func)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700278 s->read_func = default_socket_read;
Dave Barachc3799992016-08-15 11:12:27 -0400279 if (!s->close_func)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700280 s->close_func = default_socket_close;
281}
282
283clib_error_t *
284clib_socket_init (clib_socket_t * s)
285{
Dave Barachc3799992016-08-15 11:12:27 -0400286 union
287 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700288 struct sockaddr sa;
289 struct sockaddr_un su;
290 } addr;
291 socklen_t addr_len = 0;
Dave Barachc3799992016-08-15 11:12:27 -0400292 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700293 word port;
294
295 error = socket_config (s->config, &addr.sa, &addr_len,
296 (s->flags & SOCKET_IS_SERVER
Dave Barachc3799992016-08-15 11:12:27 -0400297 ? INADDR_LOOPBACK : INADDR_ANY));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700298 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
Dave Barachc3799992016-08-15 11:12:27 -0400341 if (need_bind && bind (s->fd, &addr.sa, addr_len) < 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700342 {
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 }
Damjan Marionf6616382017-06-21 12:01:37 +0200352 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 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700360 }
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
Dave Barachc3799992016-08-15 11:12:27 -0400371 && !((s->flags & SOCKET_NON_BLOCKING_CONNECT) &&
372 errno == EINPROGRESS))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700373 {
374 error = clib_error_return_unix (0, "connect");
375 goto done;
376 }
377 }
378
379 return error;
380
Dave Barachc3799992016-08-15 11:12:27 -0400381done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700382 if (s->fd > 0)
383 close (s->fd);
384 return error;
385}
386
Dave Barachc3799992016-08-15 11:12:27 -0400387clib_error_t *
388clib_socket_accept (clib_socket_t * server, clib_socket_t * client)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700389{
Dave Barachc3799992016-08-15 11:12:27 -0400390 clib_error_t *err = 0;
391 socklen_t len = 0;
392
Ed Warnickecb9cada2015-12-08 15:45:58 -0700393 memset (client, 0, sizeof (client[0]));
394
395 /* Accept the new socket connection. */
396 client->fd = accept (server->fd, 0, 0);
Dave Barachc3799992016-08-15 11:12:27 -0400397 if (client->fd < 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700398 return clib_error_return_unix (0, "accept");
Dave Barachc3799992016-08-15 11:12:27 -0400399
Ed Warnickecb9cada2015-12-08 15:45:58 -0700400 /* 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 }
Dave Barachc3799992016-08-15 11:12:27 -0400406
Ed Warnickecb9cada2015-12-08 15:45:58 -0700407 /* 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
Dave Barachc3799992016-08-15 11:12:27 -0400420close_client:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700421 close (client->fd);
422 return err;
423}
Dave Barachc3799992016-08-15 11:12:27 -0400424
425/*
426 * fd.io coding-style-patch-verification: ON
427 *
428 * Local Variables:
429 * eval: (c-set-style "gnu")
430 * End:
431 */