blob: 4522514bba93eba9fb4f079a2395bfcd912528c9 [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 Barachb7b92992018-10-17 10:38:51 -040076 clib_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];
Damjan Marion0215fb42018-10-30 13:04:19 +0100281 char ctl[CMSG_SPACE (sizeof (int) * num_fds)];
Damjan Marionf49921f2017-09-11 16:52:11 +0200282 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;
Dave Barachb7b92992018-10-17 10:38:51 -0400292 clib_memset (&ctl, 0, sizeof (ctl));
Damjan Marionf49921f2017-09-11 16:52:11 +0200293 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{
Damjan Marion4dffd1c2018-09-03 12:30:36 +0200312#ifdef __linux__
Damjan Marionf49921f2017-09-11 16:52:11 +0200313 char ctl[CMSG_SPACE (sizeof (int) * num_fds) +
314 CMSG_SPACE (sizeof (struct ucred))];
Damjan Marion4dffd1c2018-09-03 12:30:36 +0200315 struct ucred *cr = 0;
316#else
317 char ctl[CMSG_SPACE (sizeof (int) * num_fds)];
318#endif
Damjan Marionf49921f2017-09-11 16:52:11 +0200319 struct msghdr mh = { 0 };
320 struct iovec iov[1];
321 ssize_t size;
Damjan Marionf49921f2017-09-11 16:52:11 +0200322 struct cmsghdr *cmsg;
323
324 iov[0].iov_base = msg;
325 iov[0].iov_len = msglen;
326 mh.msg_iov = iov;
327 mh.msg_iovlen = 1;
328 mh.msg_control = ctl;
329 mh.msg_controllen = sizeof (ctl);
330
Dave Barachb7b92992018-10-17 10:38:51 -0400331 clib_memset (ctl, 0, sizeof (ctl));
Damjan Marionf49921f2017-09-11 16:52:11 +0200332
333 /* receive the incoming message */
334 size = recvmsg (s->fd, &mh, 0);
335 if (size != msglen)
336 {
337 return (size == 0) ? clib_error_return (0, "disconnected") :
338 clib_error_return_unix (0, "recvmsg: malformed message (fd %d, '%s')",
339 s->fd, s->config);
340 }
341
342 cmsg = CMSG_FIRSTHDR (&mh);
343 while (cmsg)
344 {
345 if (cmsg->cmsg_level == SOL_SOCKET)
346 {
Damjan Marion4dffd1c2018-09-03 12:30:36 +0200347#ifdef __linux__
Damjan Marionf49921f2017-09-11 16:52:11 +0200348 if (cmsg->cmsg_type == SCM_CREDENTIALS)
349 {
350 cr = (struct ucred *) CMSG_DATA (cmsg);
351 s->uid = cr->uid;
352 s->gid = cr->gid;
353 s->pid = cr->pid;
354 }
Damjan Marion4dffd1c2018-09-03 12:30:36 +0200355 else
356#endif
357 if (cmsg->cmsg_type == SCM_RIGHTS)
Damjan Marionf49921f2017-09-11 16:52:11 +0200358 {
Dave Barach178cf492018-11-13 16:34:13 -0500359 clib_memcpy_fast (fds, CMSG_DATA (cmsg),
360 num_fds * sizeof (int));
Damjan Marionf49921f2017-09-11 16:52:11 +0200361 }
362 }
363 cmsg = CMSG_NXTHDR (&mh, cmsg);
364 }
365 return 0;
366}
367
Dave Barachc3799992016-08-15 11:12:27 -0400368static void
369socket_init_funcs (clib_socket_t * s)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700370{
Dave Barachc3799992016-08-15 11:12:27 -0400371 if (!s->write_func)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700372 s->write_func = default_socket_write;
Dave Barachc3799992016-08-15 11:12:27 -0400373 if (!s->read_func)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700374 s->read_func = default_socket_read;
Dave Barachc3799992016-08-15 11:12:27 -0400375 if (!s->close_func)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700376 s->close_func = default_socket_close;
Damjan Marionf49921f2017-09-11 16:52:11 +0200377 if (!s->sendmsg_func)
378 s->sendmsg_func = default_socket_sendmsg;
379 if (!s->recvmsg_func)
380 s->recvmsg_func = default_socket_recvmsg;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700381}
382
383clib_error_t *
384clib_socket_init (clib_socket_t * s)
385{
Dave Barachc3799992016-08-15 11:12:27 -0400386 union
387 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700388 struct sockaddr sa;
389 struct sockaddr_un su;
390 } addr;
391 socklen_t addr_len = 0;
Florin Coras42ddf692020-01-06 20:23:07 +0000392 int socket_type, rv;
Dave Barachc3799992016-08-15 11:12:27 -0400393 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700394 word port;
395
396 error = socket_config (s->config, &addr.sa, &addr_len,
Damjan Marionf49921f2017-09-11 16:52:11 +0200397 (s->flags & CLIB_SOCKET_F_IS_SERVER
Dave Barachc3799992016-08-15 11:12:27 -0400398 ? INADDR_LOOPBACK : INADDR_ANY));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700399 if (error)
400 goto done;
401
402 socket_init_funcs (s);
403
Damjan Marionf49921f2017-09-11 16:52:11 +0200404 socket_type = s->flags & CLIB_SOCKET_F_SEQPACKET ?
405 SOCK_SEQPACKET : SOCK_STREAM;
406
407 s->fd = socket (addr.sa.sa_family, socket_type, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700408 if (s->fd < 0)
409 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400410 error = clib_error_return_unix (0, "socket (fd %d, '%s')",
411 s->fd, s->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700412 goto done;
413 }
414
415 port = 0;
416 if (addr.sa.sa_family == PF_INET)
417 port = ((struct sockaddr_in *) &addr)->sin_port;
418
Damjan Marionf49921f2017-09-11 16:52:11 +0200419 if (s->flags & CLIB_SOCKET_F_IS_SERVER)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700420 {
421 uword need_bind = 1;
422
423 if (addr.sa.sa_family == PF_INET)
424 {
425 if (port == 0)
426 {
427 port = find_free_port (s->fd);
428 if (port < 0)
429 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400430 error = clib_error_return (0, "no free port (fd %d, '%s')",
431 s->fd, s->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700432 goto done;
433 }
434 need_bind = 0;
435 }
436 }
437 if (addr.sa.sa_family == PF_LOCAL)
438 unlink (((struct sockaddr_un *) &addr)->sun_path);
439
440 /* Make address available for multiple users. */
441 {
442 int v = 1;
443 if (setsockopt (s->fd, SOL_SOCKET, SO_REUSEADDR, &v, sizeof (v)) < 0)
444 clib_unix_warning ("setsockopt SO_REUSEADDR fails");
445 }
446
Damjan Marion4dffd1c2018-09-03 12:30:36 +0200447#if __linux__
Damjan Marionf49921f2017-09-11 16:52:11 +0200448 if (addr.sa.sa_family == PF_LOCAL && s->flags & CLIB_SOCKET_F_PASSCRED)
449 {
450 int x = 1;
451 if (setsockopt (s->fd, SOL_SOCKET, SO_PASSCRED, &x, sizeof (x)) < 0)
452 {
453 error = clib_error_return_unix (0, "setsockopt (SO_PASSCRED, "
454 "fd %d, '%s')", s->fd,
455 s->config);
456 goto done;
457 }
458 }
Damjan Marion4dffd1c2018-09-03 12:30:36 +0200459#endif
Damjan Marionf49921f2017-09-11 16:52:11 +0200460
Dave Barachc3799992016-08-15 11:12:27 -0400461 if (need_bind && bind (s->fd, &addr.sa, addr_len) < 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700462 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400463 error = clib_error_return_unix (0, "bind (fd %d, '%s')",
464 s->fd, s->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700465 goto done;
466 }
467
468 if (listen (s->fd, 5) < 0)
469 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400470 error = clib_error_return_unix (0, "listen (fd %d, '%s')",
471 s->fd, s->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700472 goto done;
473 }
Damjan Marionf6616382017-06-21 12:01:37 +0200474 if (addr.sa.sa_family == PF_LOCAL
Damjan Marionf49921f2017-09-11 16:52:11 +0200475 && s->flags & CLIB_SOCKET_F_ALLOW_GROUP_WRITE)
Damjan Marionf6616382017-06-21 12:01:37 +0200476 {
477 struct stat st = { 0 };
Chris Lukeab7b8d92017-09-07 07:40:13 -0400478 if (stat (((struct sockaddr_un *) &addr)->sun_path, &st) < 0)
479 {
480 error = clib_error_return_unix (0, "stat (fd %d, '%s')",
481 s->fd, s->config);
482 goto done;
483 }
Damjan Marionf6616382017-06-21 12:01:37 +0200484 st.st_mode |= S_IWGRP;
Chris Lukeab7b8d92017-09-07 07:40:13 -0400485 if (chmod (((struct sockaddr_un *) &addr)->sun_path, st.st_mode) <
486 0)
487 {
488 error =
489 clib_error_return_unix (0, "chmod (fd %d, '%s', mode %o)",
490 s->fd, s->config, st.st_mode);
491 goto done;
492 }
Damjan Marionf6616382017-06-21 12:01:37 +0200493 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700494 }
495 else
496 {
Damjan Marionf49921f2017-09-11 16:52:11 +0200497 if ((s->flags & CLIB_SOCKET_F_NON_BLOCKING_CONNECT)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700498 && fcntl (s->fd, F_SETFL, O_NONBLOCK) < 0)
499 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400500 error = clib_error_return_unix (0, "fcntl NONBLOCK (fd %d, '%s')",
501 s->fd, s->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700502 goto done;
503 }
504
Florin Coras42ddf692020-01-06 20:23:07 +0000505 while ((rv = connect (s->fd, &addr.sa, addr_len)) < 0
506 && errno == EAGAIN)
507 ;
508 if (rv < 0 && !((s->flags & CLIB_SOCKET_F_NON_BLOCKING_CONNECT) &&
509 errno == EINPROGRESS))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700510 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400511 error = clib_error_return_unix (0, "connect (fd %d, '%s')",
512 s->fd, s->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700513 goto done;
514 }
515 }
516
517 return error;
518
Dave Barachc3799992016-08-15 11:12:27 -0400519done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700520 if (s->fd > 0)
521 close (s->fd);
522 return error;
523}
524
Dave Barachc3799992016-08-15 11:12:27 -0400525clib_error_t *
526clib_socket_accept (clib_socket_t * server, clib_socket_t * client)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700527{
Dave Barachc3799992016-08-15 11:12:27 -0400528 clib_error_t *err = 0;
529 socklen_t len = 0;
530
Dave Barachb7b92992018-10-17 10:38:51 -0400531 clib_memset (client, 0, sizeof (client[0]));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700532
533 /* Accept the new socket connection. */
534 client->fd = accept (server->fd, 0, 0);
Dave Barachc3799992016-08-15 11:12:27 -0400535 if (client->fd < 0)
Dave Wallace70ec09d2017-09-06 16:45:04 -0400536 return clib_error_return_unix (0, "accept (fd %d, '%s')",
537 server->fd, server->config);
Dave Barachc3799992016-08-15 11:12:27 -0400538
Ed Warnickecb9cada2015-12-08 15:45:58 -0700539 /* Set the new socket to be non-blocking. */
540 if (fcntl (client->fd, F_SETFL, O_NONBLOCK) < 0)
541 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400542 err = clib_error_return_unix (0, "fcntl O_NONBLOCK (fd %d)",
543 client->fd);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700544 goto close_client;
545 }
Dave Barachc3799992016-08-15 11:12:27 -0400546
Ed Warnickecb9cada2015-12-08 15:45:58 -0700547 /* Get peer info. */
548 len = sizeof (client->peer);
549 if (getpeername (client->fd, (struct sockaddr *) &client->peer, &len) < 0)
550 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400551 err = clib_error_return_unix (0, "getpeername (fd %d)", client->fd);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700552 goto close_client;
553 }
554
Damjan Marionf49921f2017-09-11 16:52:11 +0200555 client->flags = CLIB_SOCKET_F_IS_CLIENT;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700556
557 socket_init_funcs (client);
558 return 0;
559
Dave Barachc3799992016-08-15 11:12:27 -0400560close_client:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700561 close (client->fd);
562 return err;
563}
Dave Barachc3799992016-08-15 11:12:27 -0400564
565/*
566 * fd.io coding-style-patch-verification: ON
567 *
568 * Local Variables:
569 * eval: (c-set-style "gnu")
570 * End:
571 */