Line data Source code
1 : /*
2 : This program is free software: you can redistribute it and/or modify
3 : it under the terms of the GNU General Public License as published by
4 : the Free Software Foundation, either version 3 of the License, or
5 : (at your option) any later version.
6 :
7 : This program is distributed in the hope that it will be useful,
8 : but WITHOUT ANY WARRANTY; without even the implied warranty of
9 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 : GNU General Public License for more details.
11 :
12 : You should have received a copy of the GNU General Public License
13 : along with this program. If not, see <http://www.gnu.org/licenses/>.
14 : */
15 : /*
16 : simple socket handling class for systems with BSD socket API
17 : */
18 :
19 : #include <AP_HAL/AP_HAL.h>
20 : #include <AP_Networking/AP_Networking_Config.h>
21 : #if AP_NETWORKING_SOCKETS_ENABLED || defined(AP_SOCKET_NATIVE_ENABLED)
22 :
23 : #ifndef SOCKET_CLASS_NAME
24 : #define SOCKET_CLASS_NAME SocketAPM
25 : #endif
26 :
27 : #ifndef IN_SOCKET_NATIVE_CPP
28 : #include "Socket.hpp"
29 : #endif
30 :
31 : #if AP_NETWORKING_BACKEND_CHIBIOS || AP_NETWORKING_BACKEND_PPP
32 : #include <lwip/sockets.h>
33 : #else
34 : // SITL or Linux
35 : #include <fcntl.h>
36 : #include <unistd.h>
37 : #include <sys/ioctl.h>
38 : #include <sys/socket.h>
39 : #if defined(AP_SOCKET_NATIVE_ENABLED)
40 : #include <sys/stat.h>
41 : #include <sys/un.h>
42 : #endif
43 : #include <netinet/in.h>
44 : #include <netinet/tcp.h>
45 : #include <arpa/inet.h>
46 : #include <sys/select.h>
47 : #include <sys/time.h>
48 : #endif
49 :
50 : #include <errno.h>
51 : #include <stdlib.h>
52 :
53 : #if AP_NETWORKING_BACKEND_CHIBIOS || AP_NETWORKING_BACKEND_PPP
54 : #define CALL_PREFIX(x) ::lwip_##x
55 : #else
56 : #define CALL_PREFIX(x) ::x
57 : #endif
58 :
59 : #ifndef MSG_NOSIGNAL
60 : #define MSG_NOSIGNAL 0
61 : #endif
62 :
63 : #if defined(AP_SOCKET_NATIVE_ENABLED)
64 : struct UnixSocketPath {
65 : int fd;
66 : char *path;
67 : dev_t device;
68 : ino_t inode;
69 : UnixSocketPath *next;
70 : };
71 :
72 : static UnixSocketPath *unix_socket_paths;
73 : static bool unix_socket_cleanup_registered;
74 :
75 0 : static bool unix_path_matches(const char *path, dev_t device, ino_t inode)
76 : {
77 : struct stat path_stat;
78 0 : return lstat(path, &path_stat) == 0 &&
79 0 : S_ISSOCK(path_stat.st_mode) &&
80 0 : path_stat.st_dev == device &&
81 0 : path_stat.st_ino == inode;
82 : }
83 :
84 0 : static void unlink_unix_path(const UnixSocketPath &socket_path)
85 : {
86 0 : if (unix_path_matches(socket_path.path, socket_path.device, socket_path.inode)) {
87 0 : unlink(socket_path.path);
88 : }
89 0 : }
90 :
91 3337 : static void forget_unix_path(int fd)
92 : {
93 3337 : UnixSocketPath **entry = &unix_socket_paths;
94 3337 : while (*entry != nullptr) {
95 0 : if ((*entry)->fd == fd) {
96 0 : UnixSocketPath *removed = *entry;
97 0 : *entry = removed->next;
98 0 : unlink_unix_path(*removed);
99 0 : free(removed->path);
100 0 : free(removed);
101 0 : return;
102 : }
103 0 : entry = &(*entry)->next;
104 : }
105 : }
106 :
107 0 : static void remember_unix_path(int fd, const char *path)
108 : {
109 0 : if (!unix_socket_cleanup_registered) {
110 0 : if (atexit(SOCKET_CLASS_NAME::cleanup_unix_paths) != 0) {
111 0 : return;
112 : }
113 0 : unix_socket_cleanup_registered = true;
114 : }
115 :
116 : struct stat path_stat;
117 0 : if (lstat(path, &path_stat) != 0 || !S_ISSOCK(path_stat.st_mode)) {
118 0 : return;
119 : }
120 :
121 0 : char *path_copy = strdup(path);
122 0 : UnixSocketPath *entry = (UnixSocketPath *)calloc(1, sizeof(*entry));
123 0 : if (path_copy == nullptr || entry == nullptr) {
124 0 : free(path_copy);
125 0 : free(entry);
126 0 : return;
127 : }
128 :
129 0 : entry->fd = fd;
130 0 : entry->path = path_copy;
131 0 : entry->device = path_stat.st_dev;
132 0 : entry->inode = path_stat.st_ino;
133 0 : entry->next = unix_socket_paths;
134 0 : unix_socket_paths = entry;
135 : }
136 : #endif
137 :
138 : /*
139 : constructor
140 : */
141 15221 : SOCKET_CLASS_NAME::SOCKET_CLASS_NAME(bool _datagram) :
142 : SOCKET_CLASS_NAME(_datagram,
143 15221 : CALL_PREFIX(socket)(AF_INET, _datagram?SOCK_DGRAM:SOCK_STREAM, 0))
144 : {
145 : static_assert(sizeof(SOCKET_CLASS_NAME::last_in_addr) >= sizeof(struct sockaddr_in), "last_in_addr must be at least sockaddr_in size");
146 15221 : }
147 :
148 15229 : SOCKET_CLASS_NAME::SOCKET_CLASS_NAME(bool _datagram, int _fd) :
149 15229 : datagram(_datagram),
150 15229 : fd(_fd),
151 15229 : multicast_interface_address(0) // INADDR_ANY; routing table chooses
152 : {
153 : #ifdef FD_CLOEXEC
154 15229 : CALL_PREFIX(fcntl)(fd, F_SETFD, FD_CLOEXEC);
155 : #endif
156 15229 : if (!datagram) {
157 6691 : int one = 1;
158 6691 : CALL_PREFIX(setsockopt)(fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
159 : }
160 15229 : }
161 :
162 3727 : SOCKET_CLASS_NAME::~SOCKET_CLASS_NAME()
163 : {
164 3727 : close();
165 3727 : }
166 :
167 2501 : void SOCKET_CLASS_NAME::make_sockaddr(const char *address, uint16_t port, struct sockaddr_in &sockaddr)
168 : {
169 2501 : memset(&sockaddr, 0, sizeof(sockaddr));
170 :
171 : #ifdef HAVE_SOCK_SIN_LEN
172 : sockaddr.sin_len = sizeof(sockaddr);
173 : #endif
174 2501 : sockaddr.sin_port = htons(port);
175 2501 : sockaddr.sin_family = AF_INET;
176 2501 : sockaddr.sin_addr.s_addr = htonl(inet_str_to_addr(address));
177 2501 : }
178 :
179 : #if !defined(HAL_BOOTLOADER_BUILD) || AP_NETWORKING_CAN_MCAST_ENABLED
180 : /*
181 : connect the socket
182 : */
183 17 : bool SOCKET_CLASS_NAME::connect(const char *address, uint16_t port)
184 : {
185 17 : if (fd == -1) {
186 0 : return false;
187 : }
188 : struct sockaddr_in sockaddr;
189 : int ret;
190 17 : int one = 1;
191 17 : make_sockaddr(address, port, sockaddr);
192 :
193 17 : if (datagram && is_multicast_address(sockaddr)) {
194 : /*
195 : connect fd_in as a multicast UDP socket
196 : */
197 6 : fd_in = CALL_PREFIX(socket)(AF_INET, SOCK_DGRAM, 0);
198 6 : if (fd_in == -1) {
199 0 : return false;
200 : }
201 6 : struct sockaddr_in sockaddr_mc = sockaddr;
202 6 : struct ip_mreq mreq {};
203 : #ifdef FD_CLOEXEC
204 6 : CALL_PREFIX(fcntl)(fd_in, F_SETFD, FD_CLOEXEC);
205 : #endif
206 6 : IGNORE_RETURN(CALL_PREFIX(setsockopt)(fd_in, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)));
207 :
208 : #if defined(__CYGWIN__) || defined(__CYGWIN64__) || defined(CYGWIN_BUILD)
209 : /*
210 : on cygwin you need to bind to INADDR_ANY then use the multicast
211 : IP_ADD_MEMBERSHIP to get on the right address
212 : */
213 : sockaddr_mc.sin_addr.s_addr = htonl(INADDR_ANY);
214 : #endif
215 :
216 6 : ret = CALL_PREFIX(bind)(fd_in, (struct sockaddr *)&sockaddr_mc, sizeof(sockaddr));
217 6 : if (ret == -1) {
218 0 : goto fail_multi;
219 : }
220 :
221 6 : mreq.imr_multiaddr.s_addr = sockaddr.sin_addr.s_addr;
222 6 : mreq.imr_interface.s_addr = multicast_interface_address;
223 :
224 6 : ret = CALL_PREFIX(setsockopt)(fd_in, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
225 6 : if (ret == -1) {
226 0 : goto fail_multi;
227 : }
228 :
229 6 : if (multicast_interface_address != 0) {
230 : /*
231 : also send on that interface; without this the routing
232 : table chooses, which for a multicast address with no
233 : specific route means whichever interface the default
234 : route uses
235 : */
236 5 : struct in_addr ifaddr {};
237 5 : ifaddr.s_addr = multicast_interface_address;
238 5 : ret = CALL_PREFIX(setsockopt)(fd, IPPROTO_IP, IP_MULTICAST_IF, &ifaddr, sizeof(ifaddr));
239 5 : if (ret == -1) {
240 0 : goto fail_multi;
241 : }
242 : }
243 : }
244 :
245 17 : if (datagram && sockaddr.sin_addr.s_addr == INADDR_BROADCAST) {
246 : // setup for bi-directional UDP broadcast
247 1 : set_broadcast();
248 1 : reuseaddress();
249 : }
250 :
251 17 : ret = CALL_PREFIX(connect)(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
252 17 : if (ret != 0) {
253 0 : if (errno == EINPROGRESS) {
254 0 : pending_connect = true;
255 : }
256 0 : return false;
257 : }
258 17 : connected = true;
259 :
260 17 : if (datagram && sockaddr.sin_addr.s_addr == INADDR_BROADCAST) {
261 : // for bi-directional UDP broadcast we need 2 sockets
262 : struct sockaddr_in send_addr;
263 1 : socklen_t send_len = sizeof(send_addr);
264 1 : if (CALL_PREFIX(getsockname)(fd, (struct sockaddr *)&send_addr, &send_len) == -1) {
265 0 : return false;
266 : }
267 1 : fd_in = CALL_PREFIX(socket)(AF_INET, SOCK_DGRAM, 0);
268 1 : if (fd_in == -1) {
269 0 : goto fail_multi;
270 : }
271 1 : CALL_PREFIX(setsockopt)(fd_in, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
272 : // 2nd socket needs to be bound to wildcard
273 1 : send_addr.sin_addr.s_addr = INADDR_ANY;
274 1 : ret = CALL_PREFIX(bind)(fd_in, (struct sockaddr *)&send_addr, sizeof(send_addr));
275 1 : if (ret == -1) {
276 0 : goto fail_multi;
277 : }
278 : }
279 17 : return true;
280 :
281 0 : fail_multi:
282 0 : CALL_PREFIX(close)(fd_in);
283 0 : fd_in = -1;
284 0 : return false;
285 : }
286 : #endif // !defined(HAL_BOOTLOADER_BUILD) || AP_NETWORKING_CAN_MCAST_ENABLED
287 :
288 : /*
289 : connect the socket with a timeout
290 : */
291 386 : bool SOCKET_CLASS_NAME::connect_timeout(const char *address, uint16_t port, uint32_t timeout_ms)
292 : {
293 386 : if (fd == -1) {
294 0 : return false;
295 : }
296 : struct sockaddr_in sockaddr;
297 386 : make_sockaddr(address, port, sockaddr);
298 :
299 386 : set_blocking(false);
300 :
301 386 : int ret = CALL_PREFIX(connect)(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
302 386 : if (ret == 0) {
303 : // instant connect?
304 0 : return true;
305 : }
306 386 : if (errno != EINPROGRESS) {
307 0 : return false;
308 : }
309 386 : bool pollret = pollout(timeout_ms);
310 386 : if (!pollret) {
311 0 : return false;
312 : }
313 386 : int sock_error = 0;
314 386 : socklen_t len = sizeof(sock_error);
315 386 : if (CALL_PREFIX(getsockopt)(fd, SOL_SOCKET, SO_ERROR, (void*)&sock_error, &len) != 0) {
316 0 : return false;
317 : }
318 386 : connected = sock_error == 0;
319 386 : return connected;
320 : }
321 :
322 : /*
323 : bind the socket
324 : */
325 2098 : bool SOCKET_CLASS_NAME::bind(const char *address, uint16_t port)
326 : {
327 2098 : if (fd == -1) {
328 0 : return false;
329 : }
330 : struct sockaddr_in sockaddr;
331 2098 : make_sockaddr(address, port, sockaddr);
332 :
333 2098 : reuseaddress();
334 2098 : if (CALL_PREFIX(bind)(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) != 0) {
335 0 : return false;
336 : }
337 2098 : return true;
338 : }
339 :
340 : #if defined(AP_SOCKET_NATIVE_ENABLED)
341 : /*
342 : connect a native Unix domain socket
343 : */
344 0 : bool SOCKET_CLASS_NAME::connect_unix(const char *path)
345 : {
346 0 : if (path == nullptr || path[0] == '\0') {
347 0 : errno = EINVAL;
348 0 : return false;
349 : }
350 :
351 0 : struct sockaddr_un sockaddr {};
352 0 : if (strlen(path) >= sizeof(sockaddr.sun_path)) {
353 0 : errno = ENAMETOOLONG;
354 0 : return false;
355 : }
356 0 : sockaddr.sun_family = AF_UNIX;
357 0 : strncpy(sockaddr.sun_path, path, sizeof(sockaddr.sun_path) - 1);
358 :
359 0 : const int unix_fd = CALL_PREFIX(socket)(AF_UNIX, datagram ? SOCK_DGRAM : SOCK_STREAM, 0);
360 0 : if (unix_fd == -1) {
361 0 : return false;
362 : }
363 : #ifdef FD_CLOEXEC
364 0 : CALL_PREFIX(fcntl)(unix_fd, F_SETFD, FD_CLOEXEC);
365 : #endif
366 :
367 0 : if (CALL_PREFIX(connect)(unix_fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) == -1) {
368 0 : const int connect_errno = errno;
369 0 : CALL_PREFIX(close)(unix_fd);
370 0 : errno = connect_errno;
371 0 : return false;
372 : }
373 :
374 0 : close();
375 0 : fd = unix_fd;
376 0 : connected = true;
377 0 : pending_connect = false;
378 0 : return true;
379 : }
380 :
381 : /*
382 : bind a native Unix domain datagram socket
383 : */
384 0 : bool SOCKET_CLASS_NAME::bind_unix(const char *path)
385 : {
386 0 : if (!datagram || path == nullptr || path[0] == '\0') {
387 0 : errno = EINVAL;
388 0 : return false;
389 : }
390 :
391 0 : struct sockaddr_un sockaddr {};
392 0 : if (strlen(path) >= sizeof(sockaddr.sun_path)) {
393 0 : errno = ENAMETOOLONG;
394 0 : return false;
395 : }
396 0 : sockaddr.sun_family = AF_UNIX;
397 0 : strncpy(sockaddr.sun_path, path, sizeof(sockaddr.sun_path) - 1);
398 :
399 0 : const int unix_fd = CALL_PREFIX(socket)(AF_UNIX, SOCK_DGRAM, 0);
400 0 : if (unix_fd == -1) {
401 0 : return false;
402 : }
403 : #ifdef FD_CLOEXEC
404 0 : CALL_PREFIX(fcntl)(unix_fd, F_SETFD, FD_CLOEXEC);
405 : #endif
406 :
407 0 : int ret = CALL_PREFIX(bind)(unix_fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
408 0 : if (ret == -1 && errno == EADDRINUSE) {
409 : struct stat path_stat;
410 0 : if (lstat(path, &path_stat) == 0 && S_ISSOCK(path_stat.st_mode)) {
411 0 : const int probe_fd = CALL_PREFIX(socket)(AF_UNIX, SOCK_DGRAM, 0);
412 0 : const int connect_ret = probe_fd == -1 ? -1 : CALL_PREFIX(connect)(
413 : probe_fd,
414 : (struct sockaddr *)&sockaddr,
415 0 : sizeof(sockaddr));
416 0 : const int connect_errno = errno;
417 0 : if (probe_fd != -1) {
418 0 : CALL_PREFIX(close)(probe_fd);
419 : }
420 0 : if (connect_ret == -1 && connect_errno == ECONNREFUSED &&
421 0 : unix_path_matches(path, path_stat.st_dev, path_stat.st_ino) &&
422 0 : unlink(path) == 0) {
423 0 : ret = CALL_PREFIX(bind)(unix_fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
424 : }
425 : }
426 : }
427 0 : if (ret == -1) {
428 0 : const int bind_errno = errno;
429 0 : CALL_PREFIX(close)(unix_fd);
430 0 : errno = bind_errno;
431 0 : return false;
432 : }
433 :
434 0 : if (fd != -1) {
435 : #if defined(AP_SOCKET_NATIVE_ENABLED)
436 0 : forget_unix_path(fd);
437 : #endif
438 0 : CALL_PREFIX(close)(fd);
439 : }
440 0 : fd = unix_fd;
441 0 : remember_unix_path(fd, path);
442 0 : return true;
443 : }
444 :
445 0 : void SOCKET_CLASS_NAME::register_unix_path(int fd, const char *path)
446 : {
447 0 : remember_unix_path(fd, path);
448 0 : }
449 :
450 1640 : void SOCKET_CLASS_NAME::cleanup_unix_paths()
451 : {
452 1640 : for (UnixSocketPath *entry = unix_socket_paths; entry != nullptr; entry = entry->next) {
453 0 : unlink_unix_path(*entry);
454 : }
455 1640 : }
456 : #endif
457 :
458 :
459 : /*
460 : set SO_REUSEADDR
461 : */
462 4208 : bool SOCKET_CLASS_NAME::reuseaddress(void) const
463 : {
464 4208 : if (fd == -1) {
465 0 : return false;
466 : }
467 4208 : int one = 1;
468 4208 : return (CALL_PREFIX(setsockopt)(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) != -1);
469 : }
470 :
471 : /*
472 : set blocking state
473 : */
474 2880 : bool SOCKET_CLASS_NAME::set_blocking(bool blocking) const
475 : {
476 2880 : if (fd == -1) {
477 0 : return false;
478 : }
479 : int fcntl_ret;
480 2880 : if (blocking) {
481 390 : fcntl_ret = CALL_PREFIX(fcntl)(fd, F_SETFL, CALL_PREFIX(fcntl)(fd, F_GETFL, 0) & ~O_NONBLOCK);
482 390 : if (fd_in != -1) {
483 0 : fcntl_ret |= CALL_PREFIX(fcntl)(fd_in, F_SETFL, CALL_PREFIX(fcntl)(fd_in, F_GETFL, 0) & ~O_NONBLOCK);
484 : }
485 : } else {
486 2490 : fcntl_ret = CALL_PREFIX(fcntl)(fd, F_SETFL, CALL_PREFIX(fcntl)(fd, F_GETFL, 0) | O_NONBLOCK);
487 2490 : if (fd_in != -1) {
488 0 : fcntl_ret |= CALL_PREFIX(fcntl)(fd_in, F_SETFL, CALL_PREFIX(fcntl)(fd_in, F_GETFL, 0) | O_NONBLOCK);
489 : }
490 : }
491 2880 : return fcntl_ret != -1;
492 : }
493 :
494 : /*
495 : set cloexec state
496 : */
497 2089 : bool SOCKET_CLASS_NAME::set_cloexec() const
498 : {
499 2089 : if (fd == -1) {
500 0 : return false;
501 : }
502 : #ifdef FD_CLOEXEC
503 2089 : return (CALL_PREFIX(fcntl)(fd, F_SETFD, FD_CLOEXEC) != -1);
504 : #else
505 : return false;
506 : #endif
507 : }
508 :
509 : /*
510 : send some data
511 : */
512 67244 : ssize_t SOCKET_CLASS_NAME::send(const void *buf, size_t size) const
513 : {
514 67244 : if (fd == -1) {
515 0 : return -1;
516 : }
517 67244 : return CALL_PREFIX(send)(fd, buf, size, MSG_NOSIGNAL);
518 : }
519 :
520 : /*
521 : send some data with address as a uint32_t
522 : */
523 4678 : ssize_t SOCKET_CLASS_NAME::sendto(const void *buf, size_t size, uint32_t address, uint16_t port)
524 : {
525 4678 : if (fd == -1) {
526 0 : return -1;
527 : }
528 4678 : struct sockaddr_in sockaddr = {};
529 :
530 : #ifdef HAVE_SOCK_SIN_LEN
531 : sockaddr.sin_len = sizeof(sockaddr);
532 : #endif
533 4678 : sockaddr.sin_port = htons(port);
534 4678 : sockaddr.sin_family = AF_INET;
535 4678 : sockaddr.sin_addr.s_addr = htonl(address);
536 :
537 4678 : return CALL_PREFIX(sendto)(fd, buf, size, 0, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
538 : }
539 :
540 : /*
541 : send some data with address as a string
542 : */
543 0 : ssize_t SOCKET_CLASS_NAME::sendto(const void *buf, size_t size, const char *address, uint16_t port)
544 : {
545 0 : if (fd == -1) {
546 0 : return -1;
547 : }
548 : struct sockaddr_in sockaddr;
549 0 : make_sockaddr(address, port, sockaddr);
550 0 : return CALL_PREFIX(sendto)(fd, buf, size, 0, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
551 : }
552 :
553 : /*
554 : receive some data
555 : */
556 39381408 : ssize_t SOCKET_CLASS_NAME::recv(void *buf, size_t size, uint32_t timeout_ms)
557 : {
558 39381408 : if (!pollin(timeout_ms)) {
559 36583911 : errno = EWOULDBLOCK;
560 36583911 : return -1;
561 : }
562 2797516 : socklen_t len = sizeof(struct sockaddr_in);
563 2797516 : int fin = get_read_fd();
564 : ssize_t ret;
565 2797501 : uint32_t in_addr[4] = {};
566 2797501 : ret = CALL_PREFIX(recvfrom)(fin, buf, size, MSG_DONTWAIT, (sockaddr *)&in_addr[0], &len);
567 2797501 : if (ret > 0) {
568 : // only update last_in_addr if we received data
569 2793560 : memcpy(last_in_addr, in_addr, sizeof(last_in_addr));
570 : } else {
571 3941 : if (!datagram && connected && ret == 0) {
572 : // remote host has closed connection
573 2 : connected = false;
574 : }
575 3941 : return ret;
576 : }
577 2793560 : if (fd_in != -1) {
578 : /*
579 : for multicast check we are not receiving from ourselves
580 : */
581 : struct sockaddr_in send_addr;
582 28132 : socklen_t send_len = sizeof(send_addr);
583 28132 : if (CALL_PREFIX(getsockname)(fd, (struct sockaddr *)&send_addr, &send_len) != 0) {
584 27709 : return -1;
585 : }
586 28132 : const struct sockaddr_in &sin = *(struct sockaddr_in *)&last_in_addr[0];
587 28132 : if (sin.sin_port == send_addr.sin_port &&
588 27709 : sin.sin_family == send_addr.sin_family &&
589 27709 : sin.sin_addr.s_addr == send_addr.sin_addr.s_addr) {
590 : // discard packets from ourselves
591 27709 : return -1;
592 : }
593 : }
594 2765851 : return ret;
595 : }
596 :
597 : /*
598 : return the IP address and port of the last received packet
599 : */
600 0 : void SOCKET_CLASS_NAME::last_recv_address(const char *&ip_addr, uint16_t &port) const
601 : {
602 : static char buf[IP4_STR_LEN];
603 0 : auto *str = last_recv_address(buf, sizeof(buf), port);
604 0 : ip_addr = str;
605 0 : }
606 :
607 : /*
608 : return the IP address and port of the last received packet, using caller supplied buffer
609 : */
610 5 : const char *SOCKET_CLASS_NAME::last_recv_address(char *ip_addr_buf, uint8_t buflen, uint16_t &port) const
611 : {
612 5 : const struct sockaddr_in &sin = *(struct sockaddr_in *)&last_in_addr[0];
613 :
614 5 : const char *ret = inet_addr_to_str(ntohl(sin.sin_addr.s_addr), ip_addr_buf, buflen);
615 5 : if (ret == nullptr) {
616 0 : return nullptr;
617 : }
618 5 : port = ntohs(sin.sin_port);
619 5 : return ret;
620 : }
621 :
622 : /*
623 : return the IP address and port of the last received packet
624 : */
625 11815 : bool SOCKET_CLASS_NAME::last_recv_address(uint32_t &ip_addr, uint16_t &port) const
626 : {
627 11815 : const struct sockaddr_in &sin = *(struct sockaddr_in *)&last_in_addr[0];
628 11815 : if (sin.sin_family != AF_INET) {
629 2 : return false;
630 : }
631 11813 : ip_addr = ntohl(sin.sin_addr.s_addr);
632 11813 : port = ntohs(sin.sin_port);
633 11813 : if (ip_addr == 0 ||
634 11813 : port == 0) {
635 0 : return false;
636 : }
637 11813 : return true;
638 : }
639 :
640 1 : void SOCKET_CLASS_NAME::set_broadcast(void) const
641 : {
642 1 : if (fd == -1) {
643 0 : return;
644 : }
645 1 : int one = 1;
646 1 : CALL_PREFIX(setsockopt)(fd,SOL_SOCKET,SO_BROADCAST,(char *)&one,sizeof(one));
647 : }
648 :
649 : /*
650 : return true if there is pending data for input
651 : */
652 39389406 : bool SOCKET_CLASS_NAME::pollin(uint32_t timeout_ms)
653 : {
654 : fd_set fds;
655 : struct timeval tv;
656 :
657 669619379 : FD_ZERO(&fds);
658 39389406 : int fin = get_read_fd();
659 39389408 : if (fin == -1) {
660 0 : return false;
661 : }
662 39389408 : FD_SET(fin, &fds);
663 :
664 39389408 : tv.tv_sec = timeout_ms / 1000;
665 39389408 : tv.tv_usec = (timeout_ms % 1000) * 1000UL;
666 :
667 39389408 : if (CALL_PREFIX(select)(fin+1, &fds, nullptr, nullptr, &tv) != 1) {
668 36591927 : return false;
669 : }
670 2797507 : return true;
671 : }
672 :
673 :
674 : /*
675 : return true if there is room for output data
676 : */
677 386 : bool SOCKET_CLASS_NAME::pollout(uint32_t timeout_ms)
678 : {
679 386 : if (fd == -1) {
680 0 : return false;
681 : }
682 : fd_set fds;
683 : struct timeval tv;
684 :
685 6562 : FD_ZERO(&fds);
686 386 : FD_SET(fd, &fds);
687 :
688 386 : tv.tv_sec = timeout_ms / 1000;
689 386 : tv.tv_usec = (timeout_ms % 1000) * 1000UL;
690 :
691 386 : if (CALL_PREFIX(select)(fd+1, nullptr, &fds, nullptr, &tv) != 1) {
692 0 : return false;
693 : }
694 :
695 386 : if (pending_connect) {
696 0 : int sock_error = 0;
697 0 : socklen_t len = sizeof(sock_error);
698 0 : if (CALL_PREFIX(getsockopt)(fd, SOL_SOCKET, SO_ERROR, (void*)&sock_error, &len) == 0 &&
699 0 : sock_error == 0) {
700 0 : connected = true;
701 : }
702 0 : pending_connect = false;
703 : }
704 :
705 386 : return true;
706 : }
707 :
708 : /*
709 : start listening for new tcp connections
710 : */
711 8 : bool SOCKET_CLASS_NAME::listen(uint16_t backlog) const
712 : {
713 8 : if (fd == -1) {
714 0 : return false;
715 : }
716 8 : return CALL_PREFIX(listen)(fd, (int)backlog) == 0;
717 : }
718 :
719 : /*
720 : accept a new connection. Only valid for TCP connections after
721 : listen has been used. A new socket is returned
722 : */
723 3244 : SOCKET_CLASS_NAME *SOCKET_CLASS_NAME::accept(uint32_t timeout_ms)
724 : {
725 3244 : if (fd == -1) {
726 0 : return nullptr;
727 : }
728 3244 : if (!pollin(timeout_ms)) {
729 3235 : return nullptr;
730 : }
731 :
732 8 : struct sockaddr_in &sin = *(struct sockaddr_in *)&last_in_addr[0];
733 8 : socklen_t len = sizeof(sin);
734 8 : int newfd = CALL_PREFIX(accept)(fd, (sockaddr *)&sin, &len);
735 8 : if (newfd == -1) {
736 0 : return nullptr;
737 : }
738 8 : auto *ret = NEW_NOTHROW SOCKET_CLASS_NAME(false, newfd);
739 8 : if (ret != nullptr) {
740 8 : ret->connected = true;
741 8 : ret->reuseaddress();
742 : }
743 8 : return ret;
744 : }
745 :
746 : /*
747 : return true if an address is in the multicast range
748 : */
749 8 : bool SOCKET_CLASS_NAME::is_multicast_address(struct sockaddr_in &addr) const
750 : {
751 8 : const uint32_t mc_lower = 0xE0000000; // 224.0.0.0
752 8 : const uint32_t mc_upper = 0xEFFFFFFF; // 239.255.255.255
753 8 : const uint32_t haddr = ntohl(addr.sin_addr.s_addr);
754 8 : return haddr >= mc_lower && haddr <= mc_upper;
755 : }
756 :
757 3729 : void SOCKET_CLASS_NAME::close(void)
758 : {
759 3729 : if (fd != -1) {
760 : #if defined(AP_SOCKET_NATIVE_ENABLED)
761 3337 : forget_unix_path(fd);
762 : #endif
763 3727 : CALL_PREFIX(close)(fd);
764 3727 : fd = -1;
765 : }
766 3729 : if (fd_in != -1) {
767 0 : CALL_PREFIX(close)(fd_in);
768 0 : fd_in = -1;
769 : }
770 3729 : }
771 :
772 : /*
773 : duplicate a socket, giving a new object with the same contents,
774 : the fd in the old object is set to -1
775 : */
776 0 : SOCKET_CLASS_NAME *SOCKET_CLASS_NAME::duplicate(void)
777 : {
778 0 : auto *ret = NEW_NOTHROW SOCKET_CLASS_NAME(datagram, fd);
779 0 : if (ret == nullptr) {
780 0 : return nullptr;
781 : }
782 0 : ret->fd_in = fd_in;
783 0 : ret->connected = connected;
784 0 : fd = -1;
785 0 : fd_in = -1;
786 0 : return ret;
787 : }
788 :
789 : // access to inet_ntop, takes host order ipv4 as uint32_t
790 401 : const char *SOCKET_CLASS_NAME::inet_addr_to_str(uint32_t addr, char *dst, uint16_t len)
791 : {
792 401 : addr = htonl(addr);
793 401 : return CALL_PREFIX(inet_ntop)(AF_INET, (void*)&addr, dst, len);
794 : }
795 :
796 : // access to inet_pton, returns host order ipv4 as uint32_t
797 10893 : uint32_t SOCKET_CLASS_NAME::inet_str_to_addr(const char *ipstr)
798 : {
799 10893 : uint32_t ret = 0;
800 10893 : CALL_PREFIX(inet_pton)(AF_INET, ipstr, &ret);
801 10893 : return ntohl(ret);
802 :
803 : }
804 :
805 : #endif // AP_NETWORKING_SOCKETS_ENABLED || defined(AP_SOCKET_NATIVE_ENABLED)
|