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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 Copyright (c) 2001, 2002, 2003, 2005 Eliot Dresselhaus
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:
26 The above copyright notice and this permission notice shall be
27 included in all copies or substantial portions of the Software.
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.
39 #include <sys/types.h>
40 #include <sys/socket.h>
42 #include <netinet/in.h>
43 #include <arpa/inet.h>
48 #include <string.h> /* strchr */
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>
57 clib_socket_tx_add_formatted (clib_socket_t * s, char *fmt, ...)
61 clib_socket_tx_add_va_formatted (s, fmt, &va);
65 /* Return and bind to an unused port. */
67 find_free_port (word sock)
71 for (port = IPPORT_USERRESERVED; port < 1 << 16; port++)
75 memset (&a, 0, sizeof (a)); /* Warnings be gone */
77 a.sin_family = PF_INET;
78 a.sin_addr.s_addr = INADDR_ANY;
79 a.sin_port = htons (port);
81 if (bind (sock, (struct sockaddr *) &a, sizeof (a)) >= 0)
85 return port < 1 << 16 ? port : -1;
88 /* Convert a config string to a struct sockaddr and length for use
89 with bind or connect. */
91 socket_config (char *config,
92 void *addr, socklen_t * addr_len, u32 ip4_default_address)
94 clib_error_t *error = 0;
99 /* Anything that begins with a / is a local PF_LOCAL socket. */
100 if (config[0] == '/')
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]);
109 /* Hostname or hostname:port or port. */
114 struct sockaddr_in *sa = addr;
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))
126 else if (unformat (&i, "%s", &host_name))
129 error = clib_error_return (0, "unknown input `%U'",
130 format_unformat_error, &i);
137 sa->sin_family = PF_INET;
138 *addr_len = sizeof (sa[0]);
140 sa->sin_port = htons (port);
146 struct in_addr host_addr;
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);
152 else if (inet_aton (host_name, &host_addr))
153 sa->sin_addr = host_addr;
155 else if (host_name && strlen (host_name) > 0)
157 struct hostent *host = gethostbyname (host_name);
159 error = clib_error_return (0, "unknown host `%s'", config);
161 clib_memcpy (&sa->sin_addr.s_addr, host->h_addr_list[0],
166 sa->sin_addr.s_addr = htonl (ip4_default_address);
168 vec_free (host_name);
178 static clib_error_t *
179 default_socket_write (clib_socket_t * s)
181 clib_error_t *err = 0;
188 /* Map standard input to standard output.
189 Typically, fd is a socket for which read/write both work. */
193 tx_len = vec_len (s->tx_buffer);
194 written = write (fd, s->tx_buffer, tx_len);
196 /* Ignore certain errors. */
197 if (written < 0 && !unix_error_is_fatal (errno))
200 /* A "real" error occurred. */
203 err = clib_error_return_unix (0, "write %wd bytes (fd %d, '%s')",
204 tx_len, s->fd, s->config);
205 vec_free (s->tx_buffer);
209 /* Reclaim the transmitted part of the tx buffer on successful writes. */
210 else if (written > 0)
212 if (written == tx_len)
213 _vec_len (s->tx_buffer) = 0;
215 vec_delete (s->tx_buffer, written, 0);
218 /* If a non-fatal error occurred AND
219 the buffer is full, then we must free it. */
220 else if (written == 0 && tx_len > 64 * 1024)
222 vec_free (s->tx_buffer);
229 static clib_error_t *
230 default_socket_read (clib_socket_t * sock, int n_bytes)
235 /* RX side of socket is down once end of file is reached. */
236 if (sock->flags & SOCKET_RX_END_OF_FILE)
241 n_bytes = clib_max (n_bytes, 4096);
242 vec_add2 (sock->rx_buffer, buf, n_bytes);
244 if ((n_read = read (fd, buf, n_bytes)) < 0)
248 /* Ignore certain errors. */
249 if (!unix_error_is_fatal (errno))
252 return clib_error_return_unix (0, "read %d bytes (fd %d, '%s')",
253 n_bytes, sock->fd, sock->config);
256 /* Other side closed the socket. */
258 sock->flags |= SOCKET_RX_END_OF_FILE;
261 _vec_len (sock->rx_buffer) += n_read - n_bytes;
266 static clib_error_t *
267 default_socket_close (clib_socket_t * s)
269 if (close (s->fd) < 0)
270 return clib_error_return_unix (0, "close (fd %d, %s)", s->fd, s->config);
275 socket_init_funcs (clib_socket_t * s)
278 s->write_func = default_socket_write;
280 s->read_func = default_socket_read;
282 s->close_func = default_socket_close;
286 clib_socket_init (clib_socket_t * s)
291 struct sockaddr_un su;
293 socklen_t addr_len = 0;
294 clib_error_t *error = 0;
297 error = socket_config (s->config, &addr.sa, &addr_len,
298 (s->flags & SOCKET_IS_SERVER
299 ? INADDR_LOOPBACK : INADDR_ANY));
303 socket_init_funcs (s);
305 s->fd = socket (addr.sa.sa_family, SOCK_STREAM, 0);
308 error = clib_error_return_unix (0, "socket (fd %d, '%s')",
314 if (addr.sa.sa_family == PF_INET)
315 port = ((struct sockaddr_in *) &addr)->sin_port;
317 if (s->flags & SOCKET_IS_SERVER)
321 if (addr.sa.sa_family == PF_INET)
325 port = find_free_port (s->fd);
328 error = clib_error_return (0, "no free port (fd %d, '%s')",
335 if (addr.sa.sa_family == PF_LOCAL)
336 unlink (((struct sockaddr_un *) &addr)->sun_path);
338 /* Make address available for multiple users. */
341 if (setsockopt (s->fd, SOL_SOCKET, SO_REUSEADDR, &v, sizeof (v)) < 0)
342 clib_unix_warning ("setsockopt SO_REUSEADDR fails");
345 if (need_bind && bind (s->fd, &addr.sa, addr_len) < 0)
347 error = clib_error_return_unix (0, "bind (fd %d, '%s')",
352 if (listen (s->fd, 5) < 0)
354 error = clib_error_return_unix (0, "listen (fd %d, '%s')",
358 if (addr.sa.sa_family == PF_LOCAL
359 && s->flags & SOCKET_ALLOW_GROUP_WRITE)
361 struct stat st = { 0 };
362 if (stat (((struct sockaddr_un *) &addr)->sun_path, &st) < 0)
364 error = clib_error_return_unix (0, "stat (fd %d, '%s')",
368 st.st_mode |= S_IWGRP;
369 if (chmod (((struct sockaddr_un *) &addr)->sun_path, st.st_mode) <
373 clib_error_return_unix (0, "chmod (fd %d, '%s', mode %o)",
374 s->fd, s->config, st.st_mode);
381 if ((s->flags & SOCKET_NON_BLOCKING_CONNECT)
382 && fcntl (s->fd, F_SETFL, O_NONBLOCK) < 0)
384 error = clib_error_return_unix (0, "fcntl NONBLOCK (fd %d, '%s')",
389 if (connect (s->fd, &addr.sa, addr_len) < 0
390 && !((s->flags & SOCKET_NON_BLOCKING_CONNECT) &&
391 errno == EINPROGRESS))
393 error = clib_error_return_unix (0, "connect (fd %d, '%s')",
408 clib_socket_accept (clib_socket_t * server, clib_socket_t * client)
410 clib_error_t *err = 0;
413 memset (client, 0, sizeof (client[0]));
415 /* Accept the new socket connection. */
416 client->fd = accept (server->fd, 0, 0);
418 return clib_error_return_unix (0, "accept (fd %d, '%s')",
419 server->fd, server->config);
421 /* Set the new socket to be non-blocking. */
422 if (fcntl (client->fd, F_SETFL, O_NONBLOCK) < 0)
424 err = clib_error_return_unix (0, "fcntl O_NONBLOCK (fd %d)",
430 len = sizeof (client->peer);
431 if (getpeername (client->fd, (struct sockaddr *) &client->peer, &len) < 0)
433 err = clib_error_return_unix (0, "getpeername (fd %d)", client->fd);
437 client->flags = SOCKET_IS_CLIENT;
439 socket_init_funcs (client);
448 * fd.io coding-style-patch-verification: ON
451 * eval: (c-set-style "gnu")