1#include <errno.h>
2#include <fcntl.h>
3#include <netdb.h>
4#include <sys/un.h>
5#include <unistd.h>
6
7#include "include/pw_args.h"
8#include "include/pwlib/netutils.h"
9#include "include/pwlib/socket.h"
10#include "include/pw_utf.h"
11#include "src/pw_interfaces_internal.h"
12#include "src/types/struct_internal.h"
13
14// status codes
15uint16_t PW_ERROR_BAD_ADDRESS_FAMILY = 0;
16uint16_t PW_ERROR_BAD_IP_ADDRESS = 0;
17uint16_t PW_ERROR_BAD_PORT = 0;
18uint16_t PW_ERROR_HOST_ADDRESS_EXPECTED = 0;
19uint16_t PW_ERROR_ADDRESS_FAMILY_MISMATCH = 0;
20uint16_t PW_ERROR_SOCKET_NAME_TOO_LONG = 0;
21uint16_t PW_ERROR_MISSING_NETMASK = 0;
22uint16_t PW_ERROR_BAD_NETMASK = 0;
23uint16_t PW_ERROR_PORT_UNSPECIFIED = 0;
24
25// socket data
26
27typedef struct {
28 int sock;
29 int listen_backlog; // 0: not listening
30 uint16_t new_sock_type; // for accept, to create socket of desired type
31 bool own_fd;
32
33 // args the socket() was called with
34 int domain;
35 int type;
36 int proto;
37
38 _PwValue local_addr; // set when bind returns success
39 _PwValue remote_addr; // set when connect returns success or "in progress"
40
41} _PwSocket;
42
43#define get_this_socket(value) _pw_get_this_struct_ptr(_PwSocket*, mthis, (value))
44
45static void close_socket(_PwSocket* s)
46{
47 if (s->sock != -1 && s->own_fd) {
48 close(s->sock);
49 s->sock = -1;
50 }
51 pw_destroy(&s->local_addr);
52 pw_destroy(&s->remote_addr);
53}
54
55/****************************************************************
56 * SockAddr basic interface
57 */
58
59uint16_t PwTypeId_SockAddr = 0;
60
61#define get_this_sockaddr(value) _pw_get_this_struct_ptr(_PwSockAddrData*, mthis, (value))
62
63static bool sockaddr_hash(PwMethod_Basic_hash* mthis, PwValuePtr self, PwHashContext* ctx, _PwCompoundChain* tail)
64{
65 _PwSockAddrData* sa = get_this_sockaddr(self);
66
67 _pw_hash_uint64(ctx, self->type_id);
68 _pw_hash_uint64(ctx, sa->addr.ss_family);
69 switch (sa->addr.ss_family) {
70 case AF_LOCAL: {
71 char* path = ((struct sockaddr_un*) &sa->addr)->sun_path;
72 for (;;) {
73 unsigned char chr = *path++;
74 if (chr == 0) {
75 break;
76 }
77 _pw_hash_uint64(ctx, chr);
78 }
79 break;
80 }
81 case AF_INET:
82 _pw_hash_uint64(ctx, ((struct sockaddr_in*) &sa->addr)->sin_addr.s_addr);
83 _pw_hash_uint64(ctx, ((struct sockaddr_in*) &sa->addr)->sin_port);
84 break;
85 case AF_INET6: {
86 uint64_t* addr = (uint64_t*) &((struct sockaddr_in6*) &sa->addr)->sin6_addr;
87 _pw_hash_uint64(ctx, *addr++);
88 _pw_hash_uint64(ctx, *addr);
89 _pw_hash_uint64(ctx, ((struct sockaddr_in6*) &sa->addr)->sin6_port);
90 break;
91 }
92 default:
93 break;
94 }
95 _pw_hash_uint64(ctx, sa->netmask);
96 return true;
97}
98
99static bool dump_sockaddr(FILE* fp, PwValuePtr sockaddr)
100{
101 _PwSockAddrData* sa = _pw_get_struct_ptr(sockaddr, PwTypeId_SockAddr);
102
103 const char* addr;
104 char addr_buf[1024];
105 in_port_t port = 0;
106 switch (sa->addr.ss_family) {
107 case AF_UNSPEC:
108 addr = "[unspecified]";
109 break;
110 case AF_LOCAL:
111 addr = ((struct sockaddr_un*) &sa->addr)->sun_path;
112 break;
113 case AF_INET:
114 port = ntohs(((struct sockaddr_in*) &sa->addr)->sin_port);
115 addr = inet_ntop(AF_INET, &((struct sockaddr_in*) &sa->addr)->sin_addr, addr_buf, sizeof(addr_buf));
116 break;
117 case AF_INET6:
118 port = ntohs(((struct sockaddr_in6*) &sa->addr)->sin6_port);
119 addr = inet_ntop(AF_INET6, &((struct sockaddr_in6*) &sa->addr)->sin6_addr, addr_buf, sizeof(addr_buf));
120 break;
121 default:
122 addr = "<not supported>";
123 break;
124 }
125 if (!addr) {
126 addr = "<error>";
127 }
128 if (port) {
129 if (sa->addr.ss_family == AF_INET6) {
130 fprintf(fp, " [%s]:%u", addr, port);
131 } else {
132 fprintf(fp, " %s:%u", addr, port);
133 }
134 } else {
135 fputc(' ', fp);
136 fputs(addr, fp);
137 }
138 if (sa->netmask) {
139 fprintf(fp, "/%u\n", sa->netmask);
140 } else {
141 fputc('\n', fp);
142 }
143 return true;
144}
145
146static bool sockaddr_dump(PwMethod_Basic_dump* mthis, PwValuePtr self, FILE* fp, int indent, _PwCompoundChain* tail)
147{
148 if (!pw_super(mthis, self, fp, indent, tail)) {
149 return false;
150 }
151 _pw_print_indent(fp, indent);
152 dump_sockaddr(fp, self);
153 return true;
154}
155
156static PwInterface_Basic sockaddr_basic_interface = {
157 .hash = { .func = sockaddr_hash },
158 .dump = { .func = sockaddr_dump }
159};
160
161/****************************************************************
162 * Socket type and basic intrerface
163 */
164
165uint16_t PwTypeId_Socket = 0;
166
167static bool socket_create(PwMethod_Basic_create* mthis, PwValuePtr result, PwCtorArgs* ctor_args)
168{
169 if (!pw_super(mthis, result, ctor_args)) {
170 return false;
171 }
172
173 _PwSocket* s = get_this_socket(result);
174
175 PwSocketCtorArgs* args = pw_get_ctor_args(PwTypeId_Socket, ctor_args);
176
177 if (!args) {
178 // special case for internal use in accept method
179 s->sock = -1;
180 return true;
181 }
182
183 s->sock = socket(args->domain, args->type, args->protocol);
184 if (s->sock != -1) {
185
186 s->own_fd = true;
187 s->domain = args->domain;
188 s->type = args->type;
189 s->proto = args->protocol;
190
191 return true;
192 }
193 int _errno = errno;
194 if (!pw_super_call(destroy, mthis, result, nullptr)) { /* no op */ }
195 pw_set_status(PwErrno(_errno));
196 return false;
197}
198
199static bool socket_destroy(PwMethod_Basic_destroy* mthis, PwValuePtr self, _PwCompoundChain* tail)
200{
201 PwValuePtr value_seen = _pw_on_chain(self, tail);
202 if (value_seen) {
203 return true;
204 }
205 close_socket(get_this_socket(self));
206 return pw_super(mthis, self, nullptr);
207}
208
209static bool socket_dump(PwMethod_Basic_dump* mthis, PwValuePtr self, FILE* fp, int indent, _PwCompoundChain* tail)
210{
211 if (!pw_super(mthis, self, fp, indent, tail)) {
212 return false;
213 }
214
215 _PwSocket* s = get_this_socket(self);
216
217 // domain to string
218
219 char* domain;
220 char domain_other[32];
221 switch (s->domain) {
222 case AF_UNSPEC: domain = "AF_UNSPEC"; break;
223 case AF_LOCAL: domain = "AF_LOCAL"; break;
224 case AF_INET: domain = "AF_INET"; break;
225 case AF_INET6: domain = "AF_INET6"; break;
226 case AF_NETLINK: domain = "AF_NETLINK"; break;
227 case AF_PACKET: domain = "AF_PACKET"; break;
228 default:
229 snprintf(domain_other, sizeof(domain_other), "AF_(%d)", s->domain);
230 domain = domain_other;
231 break;
232 }
233
234 // socket type to string
235
236 char* type;
237 char type_other[32];
238 char type_buf[80];
239 int t = s->type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK);
240 switch (t) {
241 case SOCK_STREAM: type = "SOCK_STREAM"; break;
242 case SOCK_DGRAM: type = "SOCK_DGRAM"; break;
243 case SOCK_RAW: type = "SOCK_RAW"; break;
244 default:
245 snprintf(type_other, sizeof(type_other), "SOCK_(%d)", t);
246 type = type_other;
247 break;
248 }
249 if (s->type & (SOCK_CLOEXEC | SOCK_NONBLOCK)) {
250 strcpy(type_buf, type);
251 strcat(type_buf, "{");
252 if (s->type & SOCK_CLOEXEC) {
253 strcat(type_buf, "SOCK_CLOEXEC");
254 }
255 if (s->type & SOCK_NONBLOCK) {
256 if (s->type & SOCK_CLOEXEC) {
257 strcat(type_buf, ",");
258 }
259 strcat(type_buf, "SOCK_NONBLOCK");
260 }
261 strcat(type_buf, "}");
262 type = type_buf;
263 }
264
265 // proto to string
266
267 char* protocol;
268 struct protoent proto;
269 struct protoent *proto_result;
270 char proto_buf[1024];
271 if (getprotobynumber_r(s->proto, &proto, proto_buf, sizeof(proto_buf), &proto_result) == 0) {
272 protocol = proto_result->p_name;
273 } else {
274 snprintf(proto_buf, sizeof(proto_buf), "%d", s->proto);
275 protocol = proto_buf;
276 }
277
278 // listen backlog to string
279
280 char* listening = "";
281 char listening_buf[128];
282 if (s->listen_backlog) {
283 snprintf(listening_buf, sizeof(listening_buf), ", listening (backlog=%d, new_type=%u)", s->listen_backlog, s->new_sock_type);
284 listening = listening_buf;
285 }
286
287 // dump
288
289 _pw_print_indent(fp, indent);
290 fprintf(fp, "socket(%s, %s, %s) fd=%d%s\n", domain, type, protocol, s->sock, listening);
291
292 if (pw_is_sockaddr(&s->local_addr)) {
293 _pw_print_indent(fp, indent);
294 fputs("Local address: ", fp);
295 dump_sockaddr(fp, &s->local_addr);
296 }
297 if (pw_is_sockaddr(&s->remote_addr)) {
298 _pw_print_indent(fp, indent);
299 fputs("Remote address: ", fp);
300 dump_sockaddr(fp, &s->remote_addr);
301 }
302 return true;
303}
304
305static PwInterface_Basic socket_basic_interface = {
306 .create = { .func = socket_create },
307 .destroy = { .func = socket_destroy },
308 .dump = { .func = socket_dump }
309};
310
311/****************************************************************
312 * Socket interface
313 */
314
315uint16_t PwInterfaceId_Socket = 0;
316
317[[nodiscard]] static bool make_address(int domain, PwValuePtr addr, socklen_t* ss_addr_size, PwValuePtr result)
318/*
319 * Helper function for bind and connect.
320 *
321 * If `addr` is SockAddr, clone it if address family matches domain.
322 * If `addr` is String, try to convert it to SockAddr.
323 *
324 * Write size of sockaddr atructure to `ss_addr_size`.
325 */
326{
327 *ss_addr_size = sizeof(struct sockaddr_storage);
328
329 if (pw_is_sockaddr(addr)) {
330 _PwSockAddrData* sa = _pw_get_struct_ptr(addr, PwTypeId_SockAddr);
331 if (sa->netmask != 0) {
332 pw_set_status(PwStatus(PW_ERROR_HOST_ADDRESS_EXPECTED));
333 return false;
334 }
335 if (sa->addr.ss_family != domain) {
336 pw_set_status(PwStatus(PW_ERROR_ADDRESS_FAMILY_MISMATCH));
337 return false;
338 }
339 pw_clone2(addr, result);
340 return true;
341 }
342
343 if (!pw_validate(addr, PwTypeId_String)) {
344 return false;
345 }
346
347 switch (domain) {
348 case AF_LOCAL: {
349 if (!pw_create(PwTypeId_SockAddr, result)) {
350 return false;
351 }
352
353 _PwSockAddrData* sa = _pw_get_struct_ptr(result, PwTypeId_SockAddr);
354 sa->addr.ss_family = AF_LOCAL;
355
356 unsigned len = pw_strlen_in_utf8(addr);
357 if (len >= sizeof(((struct sockaddr_un*)0)->sun_path)) {
358 pw_set_status(PwStatus(PW_ERROR_SOCKET_NAME_TOO_LONG));
359 return false;
360 }
361 pw_string_to_utf8(addr, ((struct sockaddr_un*) &sa->addr)->sun_path);
362 *ss_addr_size = offsetof(struct sockaddr_un, sun_path) + len + 1;
363 return true;
364 }
365 case AF_INET:
366 case AF_INET6:
367 return pw_parse_inet_address(addr, result);
368
369 default:
370 pw_panic("Address family %d is not supported yet\n", domain);
371 }
372}
373
374static bool socket_bind(PwMethod_Socket_bind* mthis, PwValuePtr self, PwValuePtr local_addr)
375{
376 _PwSocket* s = get_this_socket(self);
377
378 pw_destroy(&s->local_addr);
379
380 socklen_t addr_size;
381 PwValue addr = PW_NULL;
382 if (!make_address(s->domain, local_addr, &addr_size, &addr)) {
383 return false;
384 }
385
386 pw_move(&addr, &s->local_addr);
387 _PwSockAddrData* sa = _pw_get_struct_ptr(&s->local_addr, PwTypeId_SockAddr);
388
389 if (bind(s->sock, (struct sockaddr*) &sa->addr, addr_size) == 0) {
390 return true;
391 } else {
392 pw_set_status(PwErrno(errno));
393 return false;
394 }
395}
396
397static bool socket_reuse_addr(PwMethod_Socket_reuse_addr* mthis, PwValuePtr self, bool reuse)
398{
399 _PwSocket* s = get_this_socket(self);
400
401 int i = reuse;
402 if (setsockopt(s->sock, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) < 0) {
403 pw_set_status(PwErrno(errno));
404 return false;
405 } else {
406 return true;
407 }
408}
409
410static bool socket_listen(PwMethod_Socket_listen* mthis, PwValuePtr self, int backlog, uint16_t new_sock_type)
411{
412 _PwSocket* s = get_this_socket(self);
413
414 if (backlog == 0) {
415 backlog = 5;
416 }
417 if (new_sock_type == PwTypeId_Null) {
418 new_sock_type = self->type_id;
419 }
420 if (listen(s->sock, backlog) == -1) {
421 pw_set_status(PwErrno(errno));
422 return false;
423 }
424 s->listen_backlog = backlog;
425 s->new_sock_type = new_sock_type;
426 return true;
427}
428
429static bool socket_is_listening(PwMethod_Socket_is_listening* mthis, PwValuePtr self, bool* result)
430{
431 _PwSocket* s = get_this_socket(self);
432 *result = s->listen_backlog != 0;
433 return true;
434}
435
436static bool socket_accept(PwMethod_Socket_accept* mthis, PwValuePtr self, PwValuePtr result)
437{
438 _PwSocket* s_lsnr = get_this_socket(self);
439
440 // create uninitialized socket
441 if (!pw_create(s_lsnr->new_sock_type, result)) {
442 return false;
443 }
444
445 _PwSocket* s_new = get_this_socket(result);
446
447 // initialize addresses for new socket
448 pw_clone2(&s_lsnr->local_addr, &s_new->local_addr);
449 if (!pw_create(PwTypeId_SockAddr, &s_new->remote_addr)) {
450 return false;
451 }
452
453 // get pointer to remote address structure
454 _PwSockAddrData* sa_remote = _pw_get_struct_ptr(&s_new->remote_addr, PwTypeId_SockAddr);
455
456 // call accept and initialize new socket and remote address
457 socklen_t addrlen = sizeof(sa_remote->addr);
458 s_new->sock = accept(s_lsnr->sock, (struct sockaddr*) &sa_remote->addr, &addrlen);
459 if (s_new->sock < 0) {
460 pw_set_status(PwErrno(errno));
461 return false;
462 }
463 // initialize other fields (they are mainly for informational purposes)
464 s_new->domain = s_lsnr->domain;
465 s_new->type = s_lsnr->type;
466 s_new->proto = s_lsnr->proto;
467
468 return true;
469}
470
471static bool socket_connect(PwMethod_Socket_connect* mthis, PwValuePtr self, PwValuePtr remote_addr)
472{
473 _PwSocket* s = get_this_socket(self);
474
475 pw_destroy(&s->local_addr);
476
477 socklen_t addr_size;
478 PwValue addr = PW_NULL;
479 if (!make_address(s->domain, remote_addr, &addr_size, &addr)) {
480 return false;
481 }
482
483 pw_move(&addr, &s->remote_addr);
484 _PwSockAddrData* sa = _pw_get_struct_ptr(&s->remote_addr, PwTypeId_SockAddr);
485
486 int rc;
487 do {
488 rc = connect(s->sock, (struct sockaddr*) &sa->addr, sizeof(sa->addr));
489 } while (rc != 0 && errno == EINTR);
490
491 if (rc == 0) {
492 return true;
493 }
494 if (errno == EAGAIN && sa->addr.ss_family == AF_LOCAL) {
495 // make it consistent
496 errno = EINPROGRESS;
497 }
498 pw_set_status(PwErrno(errno));
499 return false;
500}
501
502static bool socket_shutdown(PwMethod_Socket_shutdown* mthis, PwValuePtr self, int how)
503{
504 _PwSocket* s = get_this_socket(self);
505
506 if (shutdown(s->sock, how) == 0) {
507 return true;
508 } else {
509 pw_set_status(PwErrno(errno));
510 return false;
511 }
512}
513
514static bool socket_get_socket_error(PwMethod_Socket_get_socket_error* mthis, PwValuePtr self, PwValuePtr result)
515{
516 _PwSocket* s = get_this_socket(self);
517 int err;
518 socklen_t len = sizeof(int);
519 if (getsockopt(s->sock, SOL_SOCKET, SO_ERROR, (void*) &err, &len) == -1) {
520 fprintf(stderr, "%s:%d getsockopt: %s\n", __FILE__, __LINE__, strerror(errno));
521 return false;
522 }
523 pw_destroy(result);
524 if (err) {
525 *result = PwErrno(err);
526 } else {
527 *result = PwStatus(PW_SUCCESS);
528 }
529 return true;
530}
531
532static PwInterface_Socket socket_interface = {
533#define X(name, ...) .name = { .func = socket_##name } __VA_OPT__(,)
534 PW_SOCKET_INTERFACE_METHODS
535#undef X
536};
537
538/****************************************************************
539 * Fd interface
540 */
541
542static bool socket_get_fd(PwMethod_Fd_get_fd* mthis, PwValuePtr self, int* result)
543{
544 *result = get_this_socket(self)->sock;
545 return true;
546}
547
548static bool socket_set_fd(PwMethod_Fd_set_fd* mthis, PwValuePtr self, int fd, bool move)
549{
550 _PwSocket* s = get_this_socket(self);
551
552 if (s->sock != -1) {
553 // fd already set
554 pw_set_status(PwStatus(PW_ERROR_FD_ALREADY_SET));
555 return false;
556 }
557 s->sock = fd;
558 s->own_fd = move;
559 return true;
560}
561
562static bool socket_close(PwMethod_Fd_close* mthis, PwValuePtr self)
563{
564 close_socket(get_this_socket(self));
565 return true;
566}
567
568static bool socket_set_nonblocking(PwMethod_Fd_set_nonblocking* mthis, PwValuePtr self, bool mode)
569{
570 _PwSocket* s = get_this_socket(self);
571
572 int flags = fcntl(s->sock, F_GETFL, 0);
573 if (mode) {
574 flags |= O_NONBLOCK;
575 } else {
576 flags &= ~O_NONBLOCK;
577 }
578 if (fcntl(s->sock, F_SETFL, flags) == -1) {
579 pw_set_status(PwErrno(errno));
580 return false;
581 } else {
582 return true;
583 }
584}
585
586static PwInterface_Fd socket_fd_interface = {
587#define X(name, ...) .name = { .func = socket_##name } __VA_OPT__(,)
588 PW_FD_INTERFACE_METHODS
589#undef X
590};
591
592/****************************************************************
593 * Reader and writer interfaces
594 */
595
596static bool socket_read(PwMethod_Reader_read* mthis, PwValuePtr self, void* buffer, unsigned buffer_size, unsigned* bytes_read)
597{
598 _PwSocket* s = get_this_socket(self);
599
600 ssize_t result;
601 do {
602 result = read(s->sock, buffer, buffer_size);
603 } while (result < 0 && errno == EINTR);
604
605 if (result < 0) {
606 pw_set_status(PwErrno(errno));
607 return false;
608 } else {
609 *bytes_read = (unsigned) result;
610 return true;
611 }
612}
613
614static bool socket_write(PwMethod_Writer_write* mthis, PwValuePtr self, void* data, unsigned size, unsigned* bytes_written)
615{
616 _PwSocket* s = get_this_socket(self);
617
618 ssize_t result;
619 do {
620 result = write(s->sock, data, size);
621 } while (result < 0 && errno == EINTR);
622
623 if (result < 0) {
624 pw_set_status(PwErrno(errno));
625 return false;
626 } else {
627 *bytes_written = (unsigned) result;
628 return true;
629 }
630}
631
632static PwInterface_Reader socket_reader_interface = {
633#define X(name, ...) .name = { .func = socket_##name } __VA_OPT__(,)
634 PW_READER_INTERFACE_METHODS
635#undef X
636};
637
638static PwInterface_Writer socket_writer_interface = {
639#define X(name, ...) .name = { .func = socket_##name } __VA_OPT__(,)
640 PW_WRITER_INTERFACE_METHODS
641#undef X
642};
643
644/****************************************************************
645 * Initialization
646 */
647
648[[ gnu::constructor ]]
649void _pw_init_socket()
650{
651 // interface can be already registered
652 // basically. interfaces can be registered by any type in any order
653 if (PwInterfaceId_Socket == 0) {
654 _pw_init_interfaces();
655# define X(name, ...) #name __VA_OPT__(,)
656 PwInterfaceId_Socket = pw_register_interface("Socket", PW_SOCKET_INTERFACE_METHODS, nullptr);
657# undef X
658 }
659
660 if (PwTypeId_Socket != 0) {
661 return;
662 }
663
664 _pw_init_types();
665
666 // init statuses
667 PW_ERROR_BAD_ADDRESS_FAMILY = pw_define_status("BAD_ADDRESS_FAMILY");
668 PW_ERROR_BAD_IP_ADDRESS = pw_define_status("BAD_IP_ADDRESS");
669 PW_ERROR_BAD_PORT = pw_define_status("BAD_PORT");
670 PW_ERROR_HOST_ADDRESS_EXPECTED = pw_define_status("HOST_ADDRESS_EXPECTED");
671 PW_ERROR_ADDRESS_FAMILY_MISMATCH = pw_define_status("ADDRESS_FAMILY_MISMATCH");
672 PW_ERROR_SOCKET_NAME_TOO_LONG = pw_define_status("SOCKET_NAME_TOO_LONG");
673 PW_ERROR_MISSING_NETMASK = pw_define_status("MISSING_NETMASK");
674 PW_ERROR_BAD_NETMASK = pw_define_status("BAD_NETMASK");
675 PW_ERROR_PORT_UNSPECIFIED = pw_define_status("PORT_UNSPECIFIED");
676
677 // init types
678
679 PwTypeId_SockAddr = pw_add_type2(
680 "SockAddr", _PwSockAddrData,
681 PW_PARENTS,
682 PwTypeId_Struct,
683 PW_INTERFACES,
684 PwInterfaceId_Basic, &sockaddr_basic_interface
685 );
686
687 PwTypeId_Socket = pw_add_type2(
688 "Socket", _PwSocket,
689 PW_PARENTS,
690 PwTypeId_Struct,
691 PW_INTERFACES,
692 PwInterfaceId_Basic, &socket_basic_interface,
693 PwInterfaceId_Fd, &socket_fd_interface,
694 PwInterfaceId_Socket, &socket_interface,
695 PwInterfaceId_Reader, &socket_reader_interface,
696 PwInterfaceId_Writer, &socket_writer_interface
697 );
698}