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}