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