blob: d84278524008395c006235ef5d40ca32c71dc645 [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
Nathan Moos323418d2021-01-15 16:45:14 -080041#define _GNU_SOURCE
Ed Warnickecb9cada2015-12-08 15:45:58 -070042#include <sys/types.h>
43#include <sys/socket.h>
Damjan Marionf49921f2017-09-11 16:52:11 +020044#include <sys/un.h>
Damjan Marionf6616382017-06-21 12:01:37 +020045#include <sys/stat.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070046#include <netinet/in.h>
47#include <arpa/inet.h>
48#include <netdb.h>
49#include <unistd.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070050#include <fcntl.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070051
52#include <vppinfra/mem.h>
53#include <vppinfra/vec.h>
54#include <vppinfra/socket.h>
55#include <vppinfra/format.h>
56#include <vppinfra/error.h>
57
Nathan Moos323418d2021-01-15 16:45:14 -080058#ifndef __GLIBC__
59/* IPPORT_USERRESERVED is not part of musl libc. */
60#define IPPORT_USERRESERVED 5000
61#endif
62
Damjan Mariondae1c7e2020-10-17 13:32:25 +020063__clib_export void
Dave Barachc3799992016-08-15 11:12:27 -040064clib_socket_tx_add_formatted (clib_socket_t * s, char *fmt, ...)
Ed Warnickecb9cada2015-12-08 15:45:58 -070065{
66 va_list va;
67 va_start (va, fmt);
68 clib_socket_tx_add_va_formatted (s, fmt, &va);
69 va_end (va);
70}
71
72/* Return and bind to an unused port. */
Dave Barachc3799992016-08-15 11:12:27 -040073static word
74find_free_port (word sock)
Ed Warnickecb9cada2015-12-08 15:45:58 -070075{
76 word port;
77
78 for (port = IPPORT_USERRESERVED; port < 1 << 16; port++)
79 {
80 struct sockaddr_in a;
81
Dave Barachb7b92992018-10-17 10:38:51 -040082 clib_memset (&a, 0, sizeof (a)); /* Warnings be gone */
Ed Warnickecb9cada2015-12-08 15:45:58 -070083
84 a.sin_family = PF_INET;
85 a.sin_addr.s_addr = INADDR_ANY;
86 a.sin_port = htons (port);
87
88 if (bind (sock, (struct sockaddr *) &a, sizeof (a)) >= 0)
89 break;
90 }
Dave Barachc3799992016-08-15 11:12:27 -040091
Ed Warnickecb9cada2015-12-08 15:45:58 -070092 return port < 1 << 16 ? port : -1;
93}
94
95/* Convert a config string to a struct sockaddr and length for use
96 with bind or connect. */
97static clib_error_t *
Dave Barachc3799992016-08-15 11:12:27 -040098socket_config (char *config,
99 void *addr, socklen_t * addr_len, u32 ip4_default_address)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700100{
Dave Barachc3799992016-08-15 11:12:27 -0400101 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700102
Dave Barachc3799992016-08-15 11:12:27 -0400103 if (!config)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700104 config = "";
105
106 /* Anything that begins with a / is a local PF_LOCAL socket. */
107 if (config[0] == '/')
108 {
Dave Barachc3799992016-08-15 11:12:27 -0400109 struct sockaddr_un *su = addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700110 su->sun_family = PF_LOCAL;
Damjan Marionf1213b82016-03-13 02:22:06 +0100111 clib_memcpy (&su->sun_path, config,
Dave Barachc3799992016-08-15 11:12:27 -0400112 clib_min (sizeof (su->sun_path), 1 + strlen (config)));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700113 *addr_len = sizeof (su[0]);
114 }
115
116 /* Hostname or hostname:port or port. */
117 else
118 {
Dave Barachc3799992016-08-15 11:12:27 -0400119 char *host_name;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700120 int port = -1;
Dave Barachc3799992016-08-15 11:12:27 -0400121 struct sockaddr_in *sa = addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700122
123 host_name = 0;
124 port = -1;
125 if (config[0] != 0)
126 {
127 unformat_input_t i;
128
129 unformat_init_string (&i, config, strlen (config));
130 if (unformat (&i, "%s:%d", &host_name, &port)
131 || unformat (&i, "%s:0x%x", &host_name, &port))
132 ;
133 else if (unformat (&i, "%s", &host_name))
134 ;
135 else
136 error = clib_error_return (0, "unknown input `%U'",
137 format_unformat_error, &i);
138 unformat_free (&i);
139
140 if (error)
141 goto done;
142 }
143
144 sa->sin_family = PF_INET;
145 *addr_len = sizeof (sa[0]);
146 if (port != -1)
147 sa->sin_port = htons (port);
148 else
149 sa->sin_port = 0;
150
151 if (host_name)
152 {
153 struct in_addr host_addr;
154
155 /* Recognize localhost to avoid host lookup in most common cast. */
Dave Barachc3799992016-08-15 11:12:27 -0400156 if (!strcmp (host_name, "localhost"))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700157 sa->sin_addr.s_addr = htonl (INADDR_LOOPBACK);
158
159 else if (inet_aton (host_name, &host_addr))
160 sa->sin_addr = host_addr;
161
162 else if (host_name && strlen (host_name) > 0)
163 {
Dave Barachc3799992016-08-15 11:12:27 -0400164 struct hostent *host = gethostbyname (host_name);
165 if (!host)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700166 error = clib_error_return (0, "unknown host `%s'", config);
167 else
Dave Barachc3799992016-08-15 11:12:27 -0400168 clib_memcpy (&sa->sin_addr.s_addr, host->h_addr_list[0],
169 host->h_length);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700170 }
171
172 else
173 sa->sin_addr.s_addr = htonl (ip4_default_address);
174
175 vec_free (host_name);
176 if (error)
177 goto done;
178 }
179 }
180
Dave Barachc3799992016-08-15 11:12:27 -0400181done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700182 return error;
183}
184
185static clib_error_t *
186default_socket_write (clib_socket_t * s)
187{
Dave Barachc3799992016-08-15 11:12:27 -0400188 clib_error_t *err = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700189 word written = 0;
190 word fd = 0;
191 word tx_len;
192
193 fd = s->fd;
194
195 /* Map standard input to standard output.
196 Typically, fd is a socket for which read/write both work. */
197 if (fd == 0)
198 fd = 1;
199
200 tx_len = vec_len (s->tx_buffer);
201 written = write (fd, s->tx_buffer, tx_len);
202
203 /* Ignore certain errors. */
Dave Barachc3799992016-08-15 11:12:27 -0400204 if (written < 0 && !unix_error_is_fatal (errno))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700205 written = 0;
206
207 /* A "real" error occurred. */
208 if (written < 0)
209 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400210 err = clib_error_return_unix (0, "write %wd bytes (fd %d, '%s')",
211 tx_len, s->fd, s->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700212 vec_free (s->tx_buffer);
213 goto done;
214 }
215
216 /* Reclaim the transmitted part of the tx buffer on successful writes. */
217 else if (written > 0)
218 {
219 if (written == tx_len)
220 _vec_len (s->tx_buffer) = 0;
221 else
222 vec_delete (s->tx_buffer, written, 0);
223 }
224
225 /* If a non-fatal error occurred AND
226 the buffer is full, then we must free it. */
Dave Barachc3799992016-08-15 11:12:27 -0400227 else if (written == 0 && tx_len > 64 * 1024)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700228 {
229 vec_free (s->tx_buffer);
230 }
231
Dave Barachc3799992016-08-15 11:12:27 -0400232done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700233 return err;
234}
235
236static clib_error_t *
237default_socket_read (clib_socket_t * sock, int n_bytes)
238{
239 word fd, n_read;
Dave Barachc3799992016-08-15 11:12:27 -0400240 u8 *buf;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700241
242 /* RX side of socket is down once end of file is reached. */
Damjan Marionf49921f2017-09-11 16:52:11 +0200243 if (sock->flags & CLIB_SOCKET_F_RX_END_OF_FILE)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700244 return 0;
245
246 fd = sock->fd;
247
248 n_bytes = clib_max (n_bytes, 4096);
249 vec_add2 (sock->rx_buffer, buf, n_bytes);
250
251 if ((n_read = read (fd, buf, n_bytes)) < 0)
252 {
253 n_read = 0;
254
255 /* Ignore certain errors. */
Dave Barachc3799992016-08-15 11:12:27 -0400256 if (!unix_error_is_fatal (errno))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700257 goto non_fatal;
Dave Barachc3799992016-08-15 11:12:27 -0400258
Dave Wallace70ec09d2017-09-06 16:45:04 -0400259 return clib_error_return_unix (0, "read %d bytes (fd %d, '%s')",
260 n_bytes, sock->fd, sock->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700261 }
Dave Barachc3799992016-08-15 11:12:27 -0400262
Ed Warnickecb9cada2015-12-08 15:45:58 -0700263 /* Other side closed the socket. */
264 if (n_read == 0)
Damjan Marionf49921f2017-09-11 16:52:11 +0200265 sock->flags |= CLIB_SOCKET_F_RX_END_OF_FILE;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700266
Dave Barachc3799992016-08-15 11:12:27 -0400267non_fatal:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700268 _vec_len (sock->rx_buffer) += n_read - n_bytes;
269
270 return 0;
271}
272
Dave Barachc3799992016-08-15 11:12:27 -0400273static clib_error_t *
274default_socket_close (clib_socket_t * s)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700275{
276 if (close (s->fd) < 0)
Dave Wallace70ec09d2017-09-06 16:45:04 -0400277 return clib_error_return_unix (0, "close (fd %d, %s)", s->fd, s->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700278 return 0;
279}
280
Damjan Marionf49921f2017-09-11 16:52:11 +0200281static clib_error_t *
282default_socket_sendmsg (clib_socket_t * s, void *msg, int msglen,
283 int fds[], int num_fds)
284{
285 struct msghdr mh = { 0 };
286 struct iovec iov[1];
Damjan Marion0215fb42018-10-30 13:04:19 +0100287 char ctl[CMSG_SPACE (sizeof (int) * num_fds)];
Damjan Marionf49921f2017-09-11 16:52:11 +0200288 int rv;
289
290 iov[0].iov_base = msg;
291 iov[0].iov_len = msglen;
292 mh.msg_iov = iov;
293 mh.msg_iovlen = 1;
294
295 if (num_fds > 0)
296 {
297 struct cmsghdr *cmsg;
Dave Barachb7b92992018-10-17 10:38:51 -0400298 clib_memset (&ctl, 0, sizeof (ctl));
Damjan Marionf49921f2017-09-11 16:52:11 +0200299 mh.msg_control = ctl;
300 mh.msg_controllen = sizeof (ctl);
301 cmsg = CMSG_FIRSTHDR (&mh);
302 cmsg->cmsg_len = CMSG_LEN (sizeof (int) * num_fds);
303 cmsg->cmsg_level = SOL_SOCKET;
304 cmsg->cmsg_type = SCM_RIGHTS;
305 memcpy (CMSG_DATA (cmsg), fds, sizeof (int) * num_fds);
306 }
307 rv = sendmsg (s->fd, &mh, 0);
308 if (rv < 0)
309 return clib_error_return_unix (0, "sendmsg");
310 return 0;
311}
312
313
314static clib_error_t *
315default_socket_recvmsg (clib_socket_t * s, void *msg, int msglen,
316 int fds[], int num_fds)
317{
Damjan Marion4dffd1c2018-09-03 12:30:36 +0200318#ifdef __linux__
Damjan Marionf49921f2017-09-11 16:52:11 +0200319 char ctl[CMSG_SPACE (sizeof (int) * num_fds) +
320 CMSG_SPACE (sizeof (struct ucred))];
Damjan Marion4dffd1c2018-09-03 12:30:36 +0200321 struct ucred *cr = 0;
322#else
323 char ctl[CMSG_SPACE (sizeof (int) * num_fds)];
324#endif
Damjan Marionf49921f2017-09-11 16:52:11 +0200325 struct msghdr mh = { 0 };
326 struct iovec iov[1];
327 ssize_t size;
Damjan Marionf49921f2017-09-11 16:52:11 +0200328 struct cmsghdr *cmsg;
329
330 iov[0].iov_base = msg;
331 iov[0].iov_len = msglen;
332 mh.msg_iov = iov;
333 mh.msg_iovlen = 1;
334 mh.msg_control = ctl;
335 mh.msg_controllen = sizeof (ctl);
336
Dave Barachb7b92992018-10-17 10:38:51 -0400337 clib_memset (ctl, 0, sizeof (ctl));
Damjan Marionf49921f2017-09-11 16:52:11 +0200338
339 /* receive the incoming message */
340 size = recvmsg (s->fd, &mh, 0);
341 if (size != msglen)
342 {
343 return (size == 0) ? clib_error_return (0, "disconnected") :
344 clib_error_return_unix (0, "recvmsg: malformed message (fd %d, '%s')",
345 s->fd, s->config);
346 }
347
348 cmsg = CMSG_FIRSTHDR (&mh);
349 while (cmsg)
350 {
351 if (cmsg->cmsg_level == SOL_SOCKET)
352 {
Damjan Marion4dffd1c2018-09-03 12:30:36 +0200353#ifdef __linux__
Damjan Marionf49921f2017-09-11 16:52:11 +0200354 if (cmsg->cmsg_type == SCM_CREDENTIALS)
355 {
356 cr = (struct ucred *) CMSG_DATA (cmsg);
357 s->uid = cr->uid;
358 s->gid = cr->gid;
359 s->pid = cr->pid;
360 }
Damjan Marion4dffd1c2018-09-03 12:30:36 +0200361 else
362#endif
363 if (cmsg->cmsg_type == SCM_RIGHTS)
Damjan Marionf49921f2017-09-11 16:52:11 +0200364 {
Dave Barach178cf492018-11-13 16:34:13 -0500365 clib_memcpy_fast (fds, CMSG_DATA (cmsg),
366 num_fds * sizeof (int));
Damjan Marionf49921f2017-09-11 16:52:11 +0200367 }
368 }
369 cmsg = CMSG_NXTHDR (&mh, cmsg);
370 }
371 return 0;
372}
373
Dave Barachc3799992016-08-15 11:12:27 -0400374static void
375socket_init_funcs (clib_socket_t * s)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700376{
Dave Barachc3799992016-08-15 11:12:27 -0400377 if (!s->write_func)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700378 s->write_func = default_socket_write;
Dave Barachc3799992016-08-15 11:12:27 -0400379 if (!s->read_func)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700380 s->read_func = default_socket_read;
Dave Barachc3799992016-08-15 11:12:27 -0400381 if (!s->close_func)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700382 s->close_func = default_socket_close;
Damjan Marionf49921f2017-09-11 16:52:11 +0200383 if (!s->sendmsg_func)
384 s->sendmsg_func = default_socket_sendmsg;
385 if (!s->recvmsg_func)
386 s->recvmsg_func = default_socket_recvmsg;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700387}
388
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200389__clib_export clib_error_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -0700390clib_socket_init (clib_socket_t * s)
391{
Dave Barachc3799992016-08-15 11:12:27 -0400392 union
393 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700394 struct sockaddr sa;
395 struct sockaddr_un su;
396 } addr;
397 socklen_t addr_len = 0;
Florin Coras42ddf692020-01-06 20:23:07 +0000398 int socket_type, rv;
Dave Barachc3799992016-08-15 11:12:27 -0400399 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700400 word port;
401
402 error = socket_config (s->config, &addr.sa, &addr_len,
Damjan Marionf49921f2017-09-11 16:52:11 +0200403 (s->flags & CLIB_SOCKET_F_IS_SERVER
Dave Barachc3799992016-08-15 11:12:27 -0400404 ? INADDR_LOOPBACK : INADDR_ANY));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700405 if (error)
406 goto done;
407
408 socket_init_funcs (s);
409
Damjan Marionf49921f2017-09-11 16:52:11 +0200410 socket_type = s->flags & CLIB_SOCKET_F_SEQPACKET ?
411 SOCK_SEQPACKET : SOCK_STREAM;
412
413 s->fd = socket (addr.sa.sa_family, socket_type, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700414 if (s->fd < 0)
415 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400416 error = clib_error_return_unix (0, "socket (fd %d, '%s')",
417 s->fd, s->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700418 goto done;
419 }
420
421 port = 0;
422 if (addr.sa.sa_family == PF_INET)
423 port = ((struct sockaddr_in *) &addr)->sin_port;
424
Damjan Marionf49921f2017-09-11 16:52:11 +0200425 if (s->flags & CLIB_SOCKET_F_IS_SERVER)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700426 {
427 uword need_bind = 1;
428
429 if (addr.sa.sa_family == PF_INET)
430 {
431 if (port == 0)
432 {
433 port = find_free_port (s->fd);
434 if (port < 0)
435 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400436 error = clib_error_return (0, "no free port (fd %d, '%s')",
437 s->fd, s->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700438 goto done;
439 }
440 need_bind = 0;
441 }
442 }
443 if (addr.sa.sa_family == PF_LOCAL)
444 unlink (((struct sockaddr_un *) &addr)->sun_path);
445
446 /* Make address available for multiple users. */
447 {
448 int v = 1;
449 if (setsockopt (s->fd, SOL_SOCKET, SO_REUSEADDR, &v, sizeof (v)) < 0)
450 clib_unix_warning ("setsockopt SO_REUSEADDR fails");
451 }
452
Damjan Marion4dffd1c2018-09-03 12:30:36 +0200453#if __linux__
Damjan Marionf49921f2017-09-11 16:52:11 +0200454 if (addr.sa.sa_family == PF_LOCAL && s->flags & CLIB_SOCKET_F_PASSCRED)
455 {
456 int x = 1;
457 if (setsockopt (s->fd, SOL_SOCKET, SO_PASSCRED, &x, sizeof (x)) < 0)
458 {
459 error = clib_error_return_unix (0, "setsockopt (SO_PASSCRED, "
460 "fd %d, '%s')", s->fd,
461 s->config);
462 goto done;
463 }
464 }
Damjan Marion4dffd1c2018-09-03 12:30:36 +0200465#endif
Damjan Marionf49921f2017-09-11 16:52:11 +0200466
Dave Barachc3799992016-08-15 11:12:27 -0400467 if (need_bind && bind (s->fd, &addr.sa, addr_len) < 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700468 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400469 error = clib_error_return_unix (0, "bind (fd %d, '%s')",
470 s->fd, s->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700471 goto done;
472 }
473
474 if (listen (s->fd, 5) < 0)
475 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400476 error = clib_error_return_unix (0, "listen (fd %d, '%s')",
477 s->fd, s->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700478 goto done;
479 }
Damjan Marionf6616382017-06-21 12:01:37 +0200480 if (addr.sa.sa_family == PF_LOCAL
Damjan Marionf49921f2017-09-11 16:52:11 +0200481 && s->flags & CLIB_SOCKET_F_ALLOW_GROUP_WRITE)
Damjan Marionf6616382017-06-21 12:01:37 +0200482 {
483 struct stat st = { 0 };
Chris Lukeab7b8d92017-09-07 07:40:13 -0400484 if (stat (((struct sockaddr_un *) &addr)->sun_path, &st) < 0)
485 {
486 error = clib_error_return_unix (0, "stat (fd %d, '%s')",
487 s->fd, s->config);
488 goto done;
489 }
Damjan Marionf6616382017-06-21 12:01:37 +0200490 st.st_mode |= S_IWGRP;
Chris Lukeab7b8d92017-09-07 07:40:13 -0400491 if (chmod (((struct sockaddr_un *) &addr)->sun_path, st.st_mode) <
492 0)
493 {
494 error =
495 clib_error_return_unix (0, "chmod (fd %d, '%s', mode %o)",
496 s->fd, s->config, st.st_mode);
497 goto done;
498 }
Damjan Marionf6616382017-06-21 12:01:37 +0200499 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700500 }
501 else
502 {
Damjan Marionf49921f2017-09-11 16:52:11 +0200503 if ((s->flags & CLIB_SOCKET_F_NON_BLOCKING_CONNECT)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700504 && fcntl (s->fd, F_SETFL, O_NONBLOCK) < 0)
505 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400506 error = clib_error_return_unix (0, "fcntl NONBLOCK (fd %d, '%s')",
507 s->fd, s->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700508 goto done;
509 }
510
Florin Coras42ddf692020-01-06 20:23:07 +0000511 while ((rv = connect (s->fd, &addr.sa, addr_len)) < 0
512 && errno == EAGAIN)
513 ;
514 if (rv < 0 && !((s->flags & CLIB_SOCKET_F_NON_BLOCKING_CONNECT) &&
515 errno == EINPROGRESS))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700516 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400517 error = clib_error_return_unix (0, "connect (fd %d, '%s')",
518 s->fd, s->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700519 goto done;
520 }
Florin Coras57e0af92021-05-26 10:21:10 -0700521 /* Connect was blocking so set fd to non-blocking now unless
522 * blocking mode explicitly requested. */
Florin Coras5fe94572021-05-24 08:58:15 -0700523 if (!(s->flags & CLIB_SOCKET_F_NON_BLOCKING_CONNECT) &&
Florin Coras57e0af92021-05-26 10:21:10 -0700524 !(s->flags & CLIB_SOCKET_F_BLOCKING) &&
Florin Coras5fe94572021-05-24 08:58:15 -0700525 fcntl (s->fd, F_SETFL, O_NONBLOCK) < 0)
526 {
527 error = clib_error_return_unix (0, "fcntl NONBLOCK2 (fd %d, '%s')",
528 s->fd, s->config);
529 goto done;
530 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700531 }
532
533 return error;
534
Dave Barachc3799992016-08-15 11:12:27 -0400535done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700536 if (s->fd > 0)
537 close (s->fd);
538 return error;
539}
540
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200541__clib_export clib_error_t *
Dave Barachc3799992016-08-15 11:12:27 -0400542clib_socket_accept (clib_socket_t * server, clib_socket_t * client)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700543{
Dave Barachc3799992016-08-15 11:12:27 -0400544 clib_error_t *err = 0;
545 socklen_t len = 0;
546
Dave Barachb7b92992018-10-17 10:38:51 -0400547 clib_memset (client, 0, sizeof (client[0]));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700548
549 /* Accept the new socket connection. */
550 client->fd = accept (server->fd, 0, 0);
Dave Barachc3799992016-08-15 11:12:27 -0400551 if (client->fd < 0)
Dave Wallace70ec09d2017-09-06 16:45:04 -0400552 return clib_error_return_unix (0, "accept (fd %d, '%s')",
553 server->fd, server->config);
Dave Barachc3799992016-08-15 11:12:27 -0400554
Ed Warnickecb9cada2015-12-08 15:45:58 -0700555 /* Set the new socket to be non-blocking. */
556 if (fcntl (client->fd, F_SETFL, O_NONBLOCK) < 0)
557 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400558 err = clib_error_return_unix (0, "fcntl O_NONBLOCK (fd %d)",
559 client->fd);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700560 goto close_client;
561 }
Dave Barachc3799992016-08-15 11:12:27 -0400562
Ed Warnickecb9cada2015-12-08 15:45:58 -0700563 /* Get peer info. */
564 len = sizeof (client->peer);
565 if (getpeername (client->fd, (struct sockaddr *) &client->peer, &len) < 0)
566 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400567 err = clib_error_return_unix (0, "getpeername (fd %d)", client->fd);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700568 goto close_client;
569 }
570
Damjan Marionf49921f2017-09-11 16:52:11 +0200571 client->flags = CLIB_SOCKET_F_IS_CLIENT;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700572
573 socket_init_funcs (client);
574 return 0;
575
Dave Barachc3799992016-08-15 11:12:27 -0400576close_client:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700577 close (client->fd);
578 return err;
579}
Dave Barachc3799992016-08-15 11:12:27 -0400580
581/*
582 * fd.io coding-style-patch-verification: ON
583 *
584 * Local Variables:
585 * eval: (c-set-style "gnu")
586 * End:
587 */