2.62
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 */