snac2

Fork of https://codeberg.org/grunfink/snac2
git clone https://git.inz.fi/snac2
Log | Files | Refs | README | LICENSE

xs_socket.h (5691B)


      1 /* copyright (c) 2022 - 2025 grunfink et al. / MIT license */
      2 
      3 #ifndef _XS_SOCKET_H
      4 
      5 #define _XS_SOCKET_H
      6 
      7 int xs_socket_timeout(int s, double rto, double sto);
      8 int xs_socket_server(const char *addr, const char *serv);
      9 int xs_socket_accept(int rs);
     10 int _xs_socket_peername(int s, char *buf, int buf_size);
     11 int xs_socket_connect(const char *addr, const char *serv);
     12 
     13 #ifdef _XS_H
     14 xs_str *xs_socket_peername(int s);
     15 #endif
     16 
     17 
     18 #ifdef XS_IMPLEMENTATION
     19 
     20 #include <sys/socket.h>
     21 #include <netdb.h>
     22 #include <netinet/in.h>
     23 #include <arpa/inet.h>
     24 #include <string.h>
     25 #include <stdlib.h>
     26 #include <unistd.h>
     27 
     28 
     29 int xs_socket_timeout(int s, double rto, double sto)
     30 /* sets the socket timeout in seconds */
     31 {
     32     struct timeval tv;
     33     int ret = 0;
     34 
     35     if (rto > 0.0) {
     36         tv.tv_sec  = (int)rto;
     37         tv.tv_usec = (int)((rto - (double)(int)rto) * 1000000.0);
     38 
     39         ret = setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv));
     40     }
     41 
     42     if (sto > 0.0) {
     43         tv.tv_sec  = (int)sto;
     44         tv.tv_usec = (int)((sto - (double)(int)sto) * 1000000.0);
     45 
     46         ret = setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(tv));
     47     }
     48 
     49     return ret;
     50 }
     51 
     52 
     53 int xs_socket_server(const char *addr, const char *serv)
     54 /* opens a server socket by service name (or port as string) */
     55 {
     56     int rs = -1;
     57 #ifndef WITHOUT_GETADDRINFO
     58     struct addrinfo *res;
     59     struct addrinfo hints;
     60     int status;
     61 
     62     memset(&hints, '\0', sizeof(hints));
     63 
     64     hints.ai_family     = AF_UNSPEC;
     65     hints.ai_socktype   = SOCK_STREAM;
     66 
     67     if (getaddrinfo(addr, serv, &hints, &res) != 0) {
     68         goto end;
     69     }
     70 
     71     rs = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
     72 
     73     /* reuse addr */
     74     int i = 1;
     75     setsockopt(rs, SOL_SOCKET, SO_REUSEADDR, (char *)&i, sizeof(i));
     76 
     77     status = bind(rs, res->ai_addr, res->ai_addrlen);
     78     if (status == -1) {
     79         fprintf(stderr, "Error binding with status %d\n", status);
     80         close(rs);
     81         rs = -1;
     82     }
     83     else {
     84 
     85       listen(rs, SOMAXCONN);
     86     }
     87 
     88     freeaddrinfo(res);
     89 
     90 #else /* WITHOUT_GETADDRINFO */
     91    struct sockaddr_in host;
     92 
     93     memset(&host, '\0', sizeof(host));
     94 
     95     if (addr != NULL) {
     96         struct hostent *he;
     97 
     98         if ((he = gethostbyname(addr)) != NULL)
     99             memcpy(&host.sin_addr, he->h_addr_list[0], he->h_length);
    100         else
    101             goto end;
    102     }
    103 
    104     struct servent *se;
    105 
    106     if ((se = getservbyname(serv, "tcp")) != NULL)
    107         host.sin_port = se->s_port;
    108     else
    109         host.sin_port = htons(atoi(serv));
    110 
    111     host.sin_family = AF_INET;
    112 
    113     if ((rs = socket(AF_INET, SOCK_STREAM, 0)) != -1) {
    114         /* reuse addr */
    115         int i = 1;
    116         setsockopt(rs, SOL_SOCKET, SO_REUSEADDR, (char *)&i, sizeof(i));
    117 
    118         if (bind(rs, (struct sockaddr *)&host, sizeof(host)) == -1) {
    119             close(rs);
    120             rs = -1;
    121         }
    122         else
    123             listen(rs, SOMAXCONN);
    124     }
    125 
    126 #endif  /* WITHOUT_GETADDRINFO */
    127 end:
    128     return rs;
    129 }
    130 
    131 
    132 int xs_socket_accept(int rs)
    133 /* accepts an incoming connection */
    134 {
    135     struct sockaddr_storage addr;
    136     socklen_t l = sizeof(addr);
    137 
    138     return accept(rs, (struct sockaddr *)&addr, &l);
    139 }
    140 
    141 
    142 int _xs_socket_peername(int s, char *buf, int buf_size)
    143 /* fill the buffer with the socket peername */
    144 {
    145     struct sockaddr_storage addr;
    146     socklen_t slen = sizeof(addr);
    147     const char *p = NULL;
    148 
    149     if (getpeername(s, (struct sockaddr *)&addr, &slen) != -1) {
    150         if (addr.ss_family == AF_INET) {
    151             struct sockaddr_in *sa = (struct sockaddr_in *)&addr;
    152 
    153             p = inet_ntop(AF_INET, &sa->sin_addr, buf, buf_size);
    154         }
    155         else
    156         if (addr.ss_family == AF_INET6) {
    157             struct sockaddr_in6 *sa = (struct sockaddr_in6 *)&addr;
    158 
    159             p = inet_ntop(AF_INET6, &sa->sin6_addr, buf, buf_size);
    160         }
    161     }
    162 
    163     return p != NULL;
    164 }
    165 
    166 
    167 int xs_socket_connect(const char *addr, const char *serv)
    168 /* creates a client connection socket */
    169 {
    170     int d = -1;
    171 
    172 #ifndef WITHOUT_GETADDRINFO
    173     struct addrinfo *res;
    174     struct addrinfo hints;
    175 
    176     memset(&hints, '\0', sizeof(hints));
    177 
    178     hints.ai_socktype   = SOCK_STREAM;
    179     hints.ai_flags      = AI_ADDRCONFIG;
    180 
    181     if (getaddrinfo(addr, serv, &hints, &res) == 0) {
    182         struct addrinfo *r;
    183 
    184         for (r = res; r != NULL; r = r->ai_next) {
    185             d = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
    186 
    187             if (d != -1) {
    188                 if (connect(d, r->ai_addr, r->ai_addrlen) == 0)
    189                     break;
    190 
    191                 close(d);
    192                 d = -1;
    193             }
    194         }
    195 
    196         freeaddrinfo(res);
    197     }
    198 
    199 #else /* WITHOUT_GETADDRINFO */
    200 
    201     /* traditional socket interface */
    202     struct hostent *he;
    203 
    204     if ((he = gethostbyname(addr)) != NULL) {
    205         struct sockaddr_in host;
    206 
    207         memset(&host, '\0', sizeof(host));
    208 
    209         memcpy(&host.sin_addr, he->h_addr_list[0], he->h_length);
    210         host.sin_family = he->h_addrtype;
    211 
    212         struct servent *se;
    213 
    214         if ((se = getservbyname(serv, "tcp")) != NULL)
    215             host.sin_port = se->s_port;
    216         else
    217             host.sin_port = htons(atoi(serv));
    218 
    219         if ((d = socket(AF_INET, SOCK_STREAM, 0)) != -1) {
    220             if (connect(d, (struct sockaddr *)&host, sizeof(host)) == -1) {
    221                 close(d);
    222                 d = -1;
    223             }
    224         }
    225     }
    226 
    227 #endif  /* WITHOUT_GETADDRINFO */
    228 
    229     return d;
    230 }
    231 
    232 
    233 #ifdef _XS_H
    234 
    235 xs_str *xs_socket_peername(int s)
    236 /* returns the remote address as a string */
    237 {
    238     char buf[2028];
    239     xs_str *p = NULL;
    240 
    241     if (_xs_socket_peername(s, buf, sizeof(buf)))
    242         p = xs_str_new(buf);
    243 
    244     return p;
    245 }
    246 
    247 #endif /* _XS_H */
    248 
    249 #endif /* XS_IMPLEMENTATION */
    250 
    251 #endif /* _XS_SOCKET_H */