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", tx_len);
204 vec_free (s->tx_buffer);
208 /* Reclaim the transmitted part of the tx buffer on successful writes. */
209 else if (written > 0)
211 if (written == tx_len)
212 _vec_len (s->tx_buffer) = 0;
214 vec_delete (s->tx_buffer, written, 0);
217 /* If a non-fatal error occurred AND
218 the buffer is full, then we must free it. */
219 else if (written == 0 && tx_len > 64 * 1024)
221 vec_free (s->tx_buffer);
228 static clib_error_t *
229 default_socket_read (clib_socket_t * sock, int n_bytes)
234 /* RX side of socket is down once end of file is reached. */
235 if (sock->flags & SOCKET_RX_END_OF_FILE)
240 n_bytes = clib_max (n_bytes, 4096);
241 vec_add2 (sock->rx_buffer, buf, n_bytes);
243 if ((n_read = read (fd, buf, n_bytes)) < 0)
247 /* Ignore certain errors. */
248 if (!unix_error_is_fatal (errno))
251 return clib_error_return_unix (0, "read %d bytes", n_bytes);
254 /* Other side closed the socket. */
256 sock->flags |= SOCKET_RX_END_OF_FILE;
259 _vec_len (sock->rx_buffer) += n_read - n_bytes;
264 static clib_error_t *
265 default_socket_close (clib_socket_t * s)
267 if (close (s->fd) < 0)
268 return clib_error_return_unix (0, "close");
273 socket_init_funcs (clib_socket_t * s)
276 s->write_func = default_socket_write;
278 s->read_func = default_socket_read;
280 s->close_func = default_socket_close;
284 clib_socket_init (clib_socket_t * s)
289 struct sockaddr_un su;
291 socklen_t addr_len = 0;
292 clib_error_t *error = 0;
295 error = socket_config (s->config, &addr.sa, &addr_len,
296 (s->flags & SOCKET_IS_SERVER
297 ? INADDR_LOOPBACK : INADDR_ANY));
301 socket_init_funcs (s);
303 s->fd = socket (addr.sa.sa_family, SOCK_STREAM, 0);
306 error = clib_error_return_unix (0, "socket");
311 if (addr.sa.sa_family == PF_INET)
312 port = ((struct sockaddr_in *) &addr)->sin_port;
314 if (s->flags & SOCKET_IS_SERVER)
318 if (addr.sa.sa_family == PF_INET)
322 port = find_free_port (s->fd);
325 error = clib_error_return (0, "no free port");
331 if (addr.sa.sa_family == PF_LOCAL)
332 unlink (((struct sockaddr_un *) &addr)->sun_path);
334 /* Make address available for multiple users. */
337 if (setsockopt (s->fd, SOL_SOCKET, SO_REUSEADDR, &v, sizeof (v)) < 0)
338 clib_unix_warning ("setsockopt SO_REUSEADDR fails");
341 if (need_bind && bind (s->fd, &addr.sa, addr_len) < 0)
343 error = clib_error_return_unix (0, "bind");
347 if (listen (s->fd, 5) < 0)
349 error = clib_error_return_unix (0, "listen");
352 if (addr.sa.sa_family == PF_LOCAL
353 && s->flags & SOCKET_ALLOW_GROUP_WRITE)
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);
363 if ((s->flags & SOCKET_NON_BLOCKING_CONNECT)
364 && fcntl (s->fd, F_SETFL, O_NONBLOCK) < 0)
366 error = clib_error_return_unix (0, "fcntl NONBLOCK");
370 if (connect (s->fd, &addr.sa, addr_len) < 0
371 && !((s->flags & SOCKET_NON_BLOCKING_CONNECT) &&
372 errno == EINPROGRESS))
374 error = clib_error_return_unix (0, "connect");
388 clib_socket_accept (clib_socket_t * server, clib_socket_t * client)
390 clib_error_t *err = 0;
393 memset (client, 0, sizeof (client[0]));
395 /* Accept the new socket connection. */
396 client->fd = accept (server->fd, 0, 0);
398 return clib_error_return_unix (0, "accept");
400 /* Set the new socket to be non-blocking. */
401 if (fcntl (client->fd, F_SETFL, O_NONBLOCK) < 0)
403 err = clib_error_return_unix (0, "fcntl O_NONBLOCK");
408 len = sizeof (client->peer);
409 if (getpeername (client->fd, (struct sockaddr *) &client->peer, &len) < 0)
411 err = clib_error_return_unix (0, "getpeername");
415 client->flags = SOCKET_IS_CLIENT;
417 socket_init_funcs (client);
426 * fd.io coding-style-patch-verification: ON
429 * eval: (c-set-style "gnu")