blob: 87a9333f904baef6974da03b1b215fe7a42248fc [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
Damjan Marionf49921f2017-09-11 16:52:11 +020038#include <stdio.h>
39#include <string.h> /* strchr */
40#define __USE_GNU
Ed Warnickecb9cada2015-12-08 15:45:58 -070041#include <sys/types.h>
42#include <sys/socket.h>
Damjan Marionf49921f2017-09-11 16:52:11 +020043#include <sys/un.h>
Damjan Marionf6616382017-06-21 12:01:37 +020044#include <sys/stat.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070045#include <netinet/in.h>
46#include <arpa/inet.h>
47#include <netdb.h>
48#include <unistd.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070049#include <fcntl.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070050
51#include <vppinfra/mem.h>
52#include <vppinfra/vec.h>
53#include <vppinfra/socket.h>
54#include <vppinfra/format.h>
55#include <vppinfra/error.h>
56
Dave Barachc3799992016-08-15 11:12:27 -040057void
58clib_socket_tx_add_formatted (clib_socket_t * s, char *fmt, ...)
Ed Warnickecb9cada2015-12-08 15:45:58 -070059{
60 va_list va;
61 va_start (va, fmt);
62 clib_socket_tx_add_va_formatted (s, fmt, &va);
63 va_end (va);
64}
65
66/* Return and bind to an unused port. */
Dave Barachc3799992016-08-15 11:12:27 -040067static word
68find_free_port (word sock)
Ed Warnickecb9cada2015-12-08 15:45:58 -070069{
70 word port;
71
72 for (port = IPPORT_USERRESERVED; port < 1 << 16; port++)
73 {
74 struct sockaddr_in a;
75
Dave Barachc3799992016-08-15 11:12:27 -040076 memset (&a, 0, sizeof (a)); /* Warnings be gone */
Ed Warnickecb9cada2015-12-08 15:45:58 -070077
78 a.sin_family = PF_INET;
79 a.sin_addr.s_addr = INADDR_ANY;
80 a.sin_port = htons (port);
81
82 if (bind (sock, (struct sockaddr *) &a, sizeof (a)) >= 0)
83 break;
84 }
Dave Barachc3799992016-08-15 11:12:27 -040085
Ed Warnickecb9cada2015-12-08 15:45:58 -070086 return port < 1 << 16 ? port : -1;
87}
88
89/* Convert a config string to a struct sockaddr and length for use
90 with bind or connect. */
91static clib_error_t *
Dave Barachc3799992016-08-15 11:12:27 -040092socket_config (char *config,
93 void *addr, socklen_t * addr_len, u32 ip4_default_address)
Ed Warnickecb9cada2015-12-08 15:45:58 -070094{
Dave Barachc3799992016-08-15 11:12:27 -040095 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -070096
Dave Barachc3799992016-08-15 11:12:27 -040097 if (!config)
Ed Warnickecb9cada2015-12-08 15:45:58 -070098 config = "";
99
100 /* Anything that begins with a / is a local PF_LOCAL socket. */
101 if (config[0] == '/')
102 {
Dave Barachc3799992016-08-15 11:12:27 -0400103 struct sockaddr_un *su = addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700104 su->sun_family = PF_LOCAL;
Damjan Marionf1213b82016-03-13 02:22:06 +0100105 clib_memcpy (&su->sun_path, config,
Dave Barachc3799992016-08-15 11:12:27 -0400106 clib_min (sizeof (su->sun_path), 1 + strlen (config)));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700107 *addr_len = sizeof (su[0]);
108 }
109
110 /* Hostname or hostname:port or port. */
111 else
112 {
Dave Barachc3799992016-08-15 11:12:27 -0400113 char *host_name;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700114 int port = -1;
Dave Barachc3799992016-08-15 11:12:27 -0400115 struct sockaddr_in *sa = addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700116
117 host_name = 0;
118 port = -1;
119 if (config[0] != 0)
120 {
121 unformat_input_t i;
122
123 unformat_init_string (&i, config, strlen (config));
124 if (unformat (&i, "%s:%d", &host_name, &port)
125 || unformat (&i, "%s:0x%x", &host_name, &port))
126 ;
127 else if (unformat (&i, "%s", &host_name))
128 ;
129 else
130 error = clib_error_return (0, "unknown input `%U'",
131 format_unformat_error, &i);
132 unformat_free (&i);
133
134 if (error)
135 goto done;
136 }
137
138 sa->sin_family = PF_INET;
139 *addr_len = sizeof (sa[0]);
140 if (port != -1)
141 sa->sin_port = htons (port);
142 else
143 sa->sin_port = 0;
144
145 if (host_name)
146 {
147 struct in_addr host_addr;
148
149 /* Recognize localhost to avoid host lookup in most common cast. */
Dave Barachc3799992016-08-15 11:12:27 -0400150 if (!strcmp (host_name, "localhost"))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700151 sa->sin_addr.s_addr = htonl (INADDR_LOOPBACK);
152
153 else if (inet_aton (host_name, &host_addr))
154 sa->sin_addr = host_addr;
155
156 else if (host_name && strlen (host_name) > 0)
157 {
Dave Barachc3799992016-08-15 11:12:27 -0400158 struct hostent *host = gethostbyname (host_name);
159 if (!host)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700160 error = clib_error_return (0, "unknown host `%s'", config);
161 else
Dave Barachc3799992016-08-15 11:12:27 -0400162 clib_memcpy (&sa->sin_addr.s_addr, host->h_addr_list[0],
163 host->h_length);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700164 }
165
166 else
167 sa->sin_addr.s_addr = htonl (ip4_default_address);
168
169 vec_free (host_name);
170 if (error)
171 goto done;
172 }
173 }
174
Dave Barachc3799992016-08-15 11:12:27 -0400175done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700176 return error;
177}
178
179static clib_error_t *
180default_socket_write (clib_socket_t * s)
181{
Dave Barachc3799992016-08-15 11:12:27 -0400182 clib_error_t *err = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700183 word written = 0;
184 word fd = 0;
185 word tx_len;
186
187 fd = s->fd;
188
189 /* Map standard input to standard output.
190 Typically, fd is a socket for which read/write both work. */
191 if (fd == 0)
192 fd = 1;
193
194 tx_len = vec_len (s->tx_buffer);
195 written = write (fd, s->tx_buffer, tx_len);
196
197 /* Ignore certain errors. */
Dave Barachc3799992016-08-15 11:12:27 -0400198 if (written < 0 && !unix_error_is_fatal (errno))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700199 written = 0;
200
201 /* A "real" error occurred. */
202 if (written < 0)
203 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400204 err = clib_error_return_unix (0, "write %wd bytes (fd %d, '%s')",
205 tx_len, s->fd, s->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700206 vec_free (s->tx_buffer);
207 goto done;
208 }
209
210 /* Reclaim the transmitted part of the tx buffer on successful writes. */
211 else if (written > 0)
212 {
213 if (written == tx_len)
214 _vec_len (s->tx_buffer) = 0;
215 else
216 vec_delete (s->tx_buffer, written, 0);
217 }
218
219 /* If a non-fatal error occurred AND
220 the buffer is full, then we must free it. */
Dave Barachc3799992016-08-15 11:12:27 -0400221 else if (written == 0 && tx_len > 64 * 1024)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700222 {
223 vec_free (s->tx_buffer);
224 }
225
Dave Barachc3799992016-08-15 11:12:27 -0400226done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700227 return err;
228}
229
230static clib_error_t *
231default_socket_read (clib_socket_t * sock, int n_bytes)
232{
233 word fd, n_read;
Dave Barachc3799992016-08-15 11:12:27 -0400234 u8 *buf;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700235
236 /* RX side of socket is down once end of file is reached. */
Damjan Marionf49921f2017-09-11 16:52:11 +0200237 if (sock->flags & CLIB_SOCKET_F_RX_END_OF_FILE)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700238 return 0;
239
240 fd = sock->fd;
241
242 n_bytes = clib_max (n_bytes, 4096);
243 vec_add2 (sock->rx_buffer, buf, n_bytes);
244
245 if ((n_read = read (fd, buf, n_bytes)) < 0)
246 {
247 n_read = 0;
248
249 /* Ignore certain errors. */
Dave Barachc3799992016-08-15 11:12:27 -0400250 if (!unix_error_is_fatal (errno))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700251 goto non_fatal;
Dave Barachc3799992016-08-15 11:12:27 -0400252
Dave Wallace70ec09d2017-09-06 16:45:04 -0400253 return clib_error_return_unix (0, "read %d bytes (fd %d, '%s')",
254 n_bytes, sock->fd, sock->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700255 }
Dave Barachc3799992016-08-15 11:12:27 -0400256
Ed Warnickecb9cada2015-12-08 15:45:58 -0700257 /* Other side closed the socket. */
258 if (n_read == 0)
Damjan Marionf49921f2017-09-11 16:52:11 +0200259 sock->flags |= CLIB_SOCKET_F_RX_END_OF_FILE;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700260
Dave Barachc3799992016-08-15 11:12:27 -0400261non_fatal:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700262 _vec_len (sock->rx_buffer) += n_read - n_bytes;
263
264 return 0;
265}
266
Dave Barachc3799992016-08-15 11:12:27 -0400267static clib_error_t *
268default_socket_close (clib_socket_t * s)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700269{
270 if (close (s->fd) < 0)
Dave Wallace70ec09d2017-09-06 16:45:04 -0400271 return clib_error_return_unix (0, "close (fd %d, %s)", s->fd, s->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700272 return 0;
273}
274
Damjan Marionf49921f2017-09-11 16:52:11 +0200275static clib_error_t *
276default_socket_sendmsg (clib_socket_t * s, void *msg, int msglen,
277 int fds[], int num_fds)
278{
279 struct msghdr mh = { 0 };
280 struct iovec iov[1];
281 char ctl[CMSG_SPACE (sizeof (int)) * num_fds];
282 int rv;
283
284 iov[0].iov_base = msg;
285 iov[0].iov_len = msglen;
286 mh.msg_iov = iov;
287 mh.msg_iovlen = 1;
288
289 if (num_fds > 0)
290 {
291 struct cmsghdr *cmsg;
292 memset (&ctl, 0, sizeof (ctl));
293 mh.msg_control = ctl;
294 mh.msg_controllen = sizeof (ctl);
295 cmsg = CMSG_FIRSTHDR (&mh);
296 cmsg->cmsg_len = CMSG_LEN (sizeof (int) * num_fds);
297 cmsg->cmsg_level = SOL_SOCKET;
298 cmsg->cmsg_type = SCM_RIGHTS;
299 memcpy (CMSG_DATA (cmsg), fds, sizeof (int) * num_fds);
300 }
301 rv = sendmsg (s->fd, &mh, 0);
302 if (rv < 0)
303 return clib_error_return_unix (0, "sendmsg");
304 return 0;
305}
306
307
308static clib_error_t *
309default_socket_recvmsg (clib_socket_t * s, void *msg, int msglen,
310 int fds[], int num_fds)
311{
312 char ctl[CMSG_SPACE (sizeof (int) * num_fds) +
313 CMSG_SPACE (sizeof (struct ucred))];
314 struct msghdr mh = { 0 };
315 struct iovec iov[1];
316 ssize_t size;
317 struct ucred *cr = 0;
318 struct cmsghdr *cmsg;
319
320 iov[0].iov_base = msg;
321 iov[0].iov_len = msglen;
322 mh.msg_iov = iov;
323 mh.msg_iovlen = 1;
324 mh.msg_control = ctl;
325 mh.msg_controllen = sizeof (ctl);
326
327 memset (ctl, 0, sizeof (ctl));
328
329 /* receive the incoming message */
330 size = recvmsg (s->fd, &mh, 0);
331 if (size != msglen)
332 {
333 return (size == 0) ? clib_error_return (0, "disconnected") :
334 clib_error_return_unix (0, "recvmsg: malformed message (fd %d, '%s')",
335 s->fd, s->config);
336 }
337
338 cmsg = CMSG_FIRSTHDR (&mh);
339 while (cmsg)
340 {
341 if (cmsg->cmsg_level == SOL_SOCKET)
342 {
343 if (cmsg->cmsg_type == SCM_CREDENTIALS)
344 {
345 cr = (struct ucred *) CMSG_DATA (cmsg);
346 s->uid = cr->uid;
347 s->gid = cr->gid;
348 s->pid = cr->pid;
349 }
350 else if (cmsg->cmsg_type == SCM_RIGHTS)
351 {
352 clib_memcpy (fds, CMSG_DATA (cmsg), num_fds * sizeof (int));
353 }
354 }
355 cmsg = CMSG_NXTHDR (&mh, cmsg);
356 }
357 return 0;
358}
359
Dave Barachc3799992016-08-15 11:12:27 -0400360static void
361socket_init_funcs (clib_socket_t * s)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700362{
Dave Barachc3799992016-08-15 11:12:27 -0400363 if (!s->write_func)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700364 s->write_func = default_socket_write;
Dave Barachc3799992016-08-15 11:12:27 -0400365 if (!s->read_func)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700366 s->read_func = default_socket_read;
Dave Barachc3799992016-08-15 11:12:27 -0400367 if (!s->close_func)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700368 s->close_func = default_socket_close;
Damjan Marionf49921f2017-09-11 16:52:11 +0200369 if (!s->sendmsg_func)
370 s->sendmsg_func = default_socket_sendmsg;
371 if (!s->recvmsg_func)
372 s->recvmsg_func = default_socket_recvmsg;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700373}
374
375clib_error_t *
376clib_socket_init (clib_socket_t * s)
377{
Dave Barachc3799992016-08-15 11:12:27 -0400378 union
379 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700380 struct sockaddr sa;
381 struct sockaddr_un su;
382 } addr;
383 socklen_t addr_len = 0;
Damjan Marionf49921f2017-09-11 16:52:11 +0200384 int socket_type;
Dave Barachc3799992016-08-15 11:12:27 -0400385 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700386 word port;
387
388 error = socket_config (s->config, &addr.sa, &addr_len,
Damjan Marionf49921f2017-09-11 16:52:11 +0200389 (s->flags & CLIB_SOCKET_F_IS_SERVER
Dave Barachc3799992016-08-15 11:12:27 -0400390 ? INADDR_LOOPBACK : INADDR_ANY));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700391 if (error)
392 goto done;
393
394 socket_init_funcs (s);
395
Damjan Marionf49921f2017-09-11 16:52:11 +0200396 socket_type = s->flags & CLIB_SOCKET_F_SEQPACKET ?
397 SOCK_SEQPACKET : SOCK_STREAM;
398
399 s->fd = socket (addr.sa.sa_family, socket_type, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700400 if (s->fd < 0)
401 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400402 error = clib_error_return_unix (0, "socket (fd %d, '%s')",
403 s->fd, s->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700404 goto done;
405 }
406
407 port = 0;
408 if (addr.sa.sa_family == PF_INET)
409 port = ((struct sockaddr_in *) &addr)->sin_port;
410
Damjan Marionf49921f2017-09-11 16:52:11 +0200411 if (s->flags & CLIB_SOCKET_F_IS_SERVER)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700412 {
413 uword need_bind = 1;
414
415 if (addr.sa.sa_family == PF_INET)
416 {
417 if (port == 0)
418 {
419 port = find_free_port (s->fd);
420 if (port < 0)
421 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400422 error = clib_error_return (0, "no free port (fd %d, '%s')",
423 s->fd, s->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700424 goto done;
425 }
426 need_bind = 0;
427 }
428 }
429 if (addr.sa.sa_family == PF_LOCAL)
430 unlink (((struct sockaddr_un *) &addr)->sun_path);
431
432 /* Make address available for multiple users. */
433 {
434 int v = 1;
435 if (setsockopt (s->fd, SOL_SOCKET, SO_REUSEADDR, &v, sizeof (v)) < 0)
436 clib_unix_warning ("setsockopt SO_REUSEADDR fails");
437 }
438
Damjan Marionf49921f2017-09-11 16:52:11 +0200439 if (addr.sa.sa_family == PF_LOCAL && s->flags & CLIB_SOCKET_F_PASSCRED)
440 {
441 int x = 1;
442 if (setsockopt (s->fd, SOL_SOCKET, SO_PASSCRED, &x, sizeof (x)) < 0)
443 {
444 error = clib_error_return_unix (0, "setsockopt (SO_PASSCRED, "
445 "fd %d, '%s')", s->fd,
446 s->config);
447 goto done;
448 }
449 }
450
Dave Barachc3799992016-08-15 11:12:27 -0400451 if (need_bind && bind (s->fd, &addr.sa, addr_len) < 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700452 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400453 error = clib_error_return_unix (0, "bind (fd %d, '%s')",
454 s->fd, s->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700455 goto done;
456 }
457
458 if (listen (s->fd, 5) < 0)
459 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400460 error = clib_error_return_unix (0, "listen (fd %d, '%s')",
461 s->fd, s->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700462 goto done;
463 }
Damjan Marionf6616382017-06-21 12:01:37 +0200464 if (addr.sa.sa_family == PF_LOCAL
Damjan Marionf49921f2017-09-11 16:52:11 +0200465 && s->flags & CLIB_SOCKET_F_ALLOW_GROUP_WRITE)
Damjan Marionf6616382017-06-21 12:01:37 +0200466 {
467 struct stat st = { 0 };
Chris Lukeab7b8d92017-09-07 07:40:13 -0400468 if (stat (((struct sockaddr_un *) &addr)->sun_path, &st) < 0)
469 {
470 error = clib_error_return_unix (0, "stat (fd %d, '%s')",
471 s->fd, s->config);
472 goto done;
473 }
Damjan Marionf6616382017-06-21 12:01:37 +0200474 st.st_mode |= S_IWGRP;
Chris Lukeab7b8d92017-09-07 07:40:13 -0400475 if (chmod (((struct sockaddr_un *) &addr)->sun_path, st.st_mode) <
476 0)
477 {
478 error =
479 clib_error_return_unix (0, "chmod (fd %d, '%s', mode %o)",
480 s->fd, s->config, st.st_mode);
481 goto done;
482 }
Damjan Marionf6616382017-06-21 12:01:37 +0200483 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700484 }
485 else
486 {
Damjan Marionf49921f2017-09-11 16:52:11 +0200487 if ((s->flags & CLIB_SOCKET_F_NON_BLOCKING_CONNECT)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700488 && fcntl (s->fd, F_SETFL, O_NONBLOCK) < 0)
489 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400490 error = clib_error_return_unix (0, "fcntl NONBLOCK (fd %d, '%s')",
491 s->fd, s->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700492 goto done;
493 }
494
495 if (connect (s->fd, &addr.sa, addr_len) < 0
Damjan Marionf49921f2017-09-11 16:52:11 +0200496 && !((s->flags & CLIB_SOCKET_F_NON_BLOCKING_CONNECT) &&
Dave Barachc3799992016-08-15 11:12:27 -0400497 errno == EINPROGRESS))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700498 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400499 error = clib_error_return_unix (0, "connect (fd %d, '%s')",
500 s->fd, s->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700501 goto done;
502 }
503 }
504
505 return error;
506
Dave Barachc3799992016-08-15 11:12:27 -0400507done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700508 if (s->fd > 0)
509 close (s->fd);
510 return error;
511}
512
Dave Barachc3799992016-08-15 11:12:27 -0400513clib_error_t *
514clib_socket_accept (clib_socket_t * server, clib_socket_t * client)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700515{
Dave Barachc3799992016-08-15 11:12:27 -0400516 clib_error_t *err = 0;
517 socklen_t len = 0;
518
Ed Warnickecb9cada2015-12-08 15:45:58 -0700519 memset (client, 0, sizeof (client[0]));
520
521 /* Accept the new socket connection. */
522 client->fd = accept (server->fd, 0, 0);
Dave Barachc3799992016-08-15 11:12:27 -0400523 if (client->fd < 0)
Dave Wallace70ec09d2017-09-06 16:45:04 -0400524 return clib_error_return_unix (0, "accept (fd %d, '%s')",
525 server->fd, server->config);
Dave Barachc3799992016-08-15 11:12:27 -0400526
Ed Warnickecb9cada2015-12-08 15:45:58 -0700527 /* Set the new socket to be non-blocking. */
528 if (fcntl (client->fd, F_SETFL, O_NONBLOCK) < 0)
529 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400530 err = clib_error_return_unix (0, "fcntl O_NONBLOCK (fd %d)",
531 client->fd);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700532 goto close_client;
533 }
Dave Barachc3799992016-08-15 11:12:27 -0400534
Ed Warnickecb9cada2015-12-08 15:45:58 -0700535 /* Get peer info. */
536 len = sizeof (client->peer);
537 if (getpeername (client->fd, (struct sockaddr *) &client->peer, &len) < 0)
538 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400539 err = clib_error_return_unix (0, "getpeername (fd %d)", client->fd);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700540 goto close_client;
541 }
542
Damjan Marionf49921f2017-09-11 16:52:11 +0200543 client->flags = CLIB_SOCKET_F_IS_CLIENT;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700544
545 socket_init_funcs (client);
546 return 0;
547
Dave Barachc3799992016-08-15 11:12:27 -0400548close_client:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700549 close (client->fd);
550 return err;
551}
Dave Barachc3799992016-08-15 11:12:27 -0400552
553/*
554 * fd.io coding-style-patch-verification: ON
555 *
556 * Local Variables:
557 * eval: (c-set-style "gnu")
558 * End:
559 */