2.67 xs_socket.h
  1/* copyright (c) 2022 - 2024 grunfink et al. / MIT license */
  2
  3#ifndef _XS_SOCKET_H
  4
  5#define _XS_SOCKET_H
  6
  7int xs_socket_timeout(int s, double rto, double sto);
  8int xs_socket_server(const char *addr, const char *serv);
  9int xs_socket_accept(int rs);
 10int _xs_socket_peername(int s, char *buf, int buf_size);
 11int xs_socket_connect(const char *addr, const char *serv);
 12
 13#ifdef _XS_H
 14xs_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
 29int 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
 53int 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    struct sockaddr_in host;
 58
 59    memset(&host, '\0', sizeof(host));
 60
 61    if (addr != NULL) {
 62        struct hostent *he;
 63
 64        if ((he = gethostbyname(addr)) != NULL)
 65            memcpy(&host.sin_addr, he->h_addr_list[0], he->h_length);
 66        else
 67            goto end;
 68    }
 69
 70    struct servent *se;
 71
 72    if ((se = getservbyname(serv, "tcp")) != NULL)
 73        host.sin_port = se->s_port;
 74    else
 75        host.sin_port = htons(atoi(serv));
 76
 77    host.sin_family = AF_INET;
 78
 79    if ((rs = socket(AF_INET, SOCK_STREAM, 0)) != -1) {
 80        /* reuse addr */
 81        int i = 1;
 82        setsockopt(rs, SOL_SOCKET, SO_REUSEADDR, (char *)&i, sizeof(i));
 83
 84        if (bind(rs, (struct sockaddr *)&host, sizeof(host)) == -1) {
 85            close(rs);
 86            rs = -1;
 87        }
 88        else
 89            listen(rs, SOMAXCONN);
 90    }
 91
 92end:
 93    return rs;
 94}
 95
 96
 97int xs_socket_accept(int rs)
 98/* accepts an incoming connection */
 99{
100    struct sockaddr_storage addr;
101    socklen_t l = sizeof(addr);
102
103    return accept(rs, (struct sockaddr *)&addr, &l);
104}
105
106
107int _xs_socket_peername(int s, char *buf, int buf_size)
108/* fill the buffer with the socket peername */
109{
110    struct sockaddr_storage addr;
111    socklen_t slen = sizeof(addr);
112    const char *p = NULL;
113
114    if (getpeername(s, (struct sockaddr *)&addr, &slen) != -1) {
115        if (addr.ss_family == AF_INET) {
116            struct sockaddr_in *sa = (struct sockaddr_in *)&addr;
117
118            p = inet_ntop(AF_INET, &sa->sin_addr, buf, buf_size);
119        }
120        else
121        if (addr.ss_family == AF_INET6) {
122            struct sockaddr_in6 *sa = (struct sockaddr_in6 *)&addr;
123
124            p = inet_ntop(AF_INET6, &sa->sin6_addr, buf, buf_size);
125        }
126    }
127
128    return p != NULL;
129}
130
131
132int xs_socket_connect(const char *addr, const char *serv)
133/* creates a client connection socket */
134{
135    int d = -1;
136
137#ifndef WITHOUT_GETADDRINFO
138    struct addrinfo *res;
139    struct addrinfo hints;
140
141    memset(&hints, '\0', sizeof(hints));
142
143    hints.ai_socktype   = SOCK_STREAM;
144    hints.ai_flags      = AI_ADDRCONFIG;
145
146    if (getaddrinfo(addr, serv, &hints, &res) == 0) {
147        struct addrinfo *r;
148
149        for (r = res; r != NULL; r = r->ai_next) {
150            d = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
151
152            if (d != -1) {
153                if (connect(d, r->ai_addr, r->ai_addrlen) == 0)
154                    break;
155
156                close(d);
157                d = -1;
158            }
159        }
160
161        freeaddrinfo(res);
162    }
163
164#else /* WITHOUT_GETADDRINFO */
165
166    /* traditional socket interface */
167    struct hostent *he;
168
169    if ((he = gethostbyname(addr)) != NULL) {
170        struct sockaddr_in host;
171
172        memset(&host, '\0', sizeof(host));
173
174        memcpy(&host.sin_addr, he->h_addr_list[0], he->h_length);
175        host.sin_family = he->h_addrtype;
176
177        struct servent *se;
178
179        if ((se = getservbyname(serv, "tcp")) != NULL)
180            host.sin_port = se->s_port;
181        else
182            host.sin_port = htons(atoi(serv));
183
184        if ((d = socket(AF_INET, SOCK_STREAM, 0)) != -1) {
185            if (connect(d, (struct sockaddr *)&host, sizeof(host)) == -1) {
186                close(d);
187                d = -1;
188            }
189        }
190    }
191
192#endif  /* WITHOUT_GETADDRINFO */
193
194    return d;
195}
196
197
198#ifdef _XS_H
199
200xs_str *xs_socket_peername(int s)
201/* returns the remote address as a string */
202{
203    char buf[2028];
204    xs_str *p = NULL;
205
206    if (_xs_socket_peername(s, buf, sizeof(buf)))
207        p = xs_str_new(buf);
208
209    return p;
210}
211
212#endif /* _XS_H */
213
214#endif /* XS_IMPLEMENTATION */
215
216#endif /* _XS_SOCKET_H */