2.52
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);
9FILE *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
97FILE *xs_socket_accept(int rs)
98/* accepts an incoming connection */
99{
100 int cs = -1;
101 struct sockaddr_storage addr;
102 socklen_t l = sizeof(addr);
103
104 cs = accept(rs, (struct sockaddr *)&addr, &l);
105
106 return cs == -1 ? NULL : fdopen(cs, "r+");
107}
108
109
110int _xs_socket_peername(int s, char *buf, int buf_size)
111/* fill the buffer with the socket peername */
112{
113 struct sockaddr_storage addr;
114 socklen_t slen = sizeof(addr);
115 const char *p = NULL;
116
117 if (getpeername(s, (struct sockaddr *)&addr, &slen) != -1) {
118 if (addr.ss_family == AF_INET) {
119 struct sockaddr_in *sa = (struct sockaddr_in *)&addr;
120
121 p = inet_ntop(AF_INET, &sa->sin_addr, buf, buf_size);
122 }
123 else
124 if (addr.ss_family == AF_INET6) {
125 struct sockaddr_in6 *sa = (struct sockaddr_in6 *)&addr;
126
127 p = inet_ntop(AF_INET6, &sa->sin6_addr, buf, buf_size);
128 }
129 }
130
131 return p != NULL;
132}
133
134
135int xs_socket_connect(const char *addr, const char *serv)
136/* creates a client connection socket */
137{
138 int d = -1;
139
140#ifndef WITHOUT_GETADDRINFO
141 struct addrinfo *res;
142 struct addrinfo hints;
143
144 memset(&hints, '\0', sizeof(hints));
145
146 hints.ai_socktype = SOCK_STREAM;
147 hints.ai_flags = AI_ADDRCONFIG;
148
149 if (getaddrinfo(addr, serv, &hints, &res) == 0) {
150 struct addrinfo *r;
151
152 for (r = res; r != NULL; r = r->ai_next) {
153 d = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
154
155 if (d != -1) {
156 if (connect(d, r->ai_addr, r->ai_addrlen) == 0)
157 break;
158
159 close(d);
160 d = -1;
161 }
162 }
163
164 freeaddrinfo(res);
165 }
166
167#else /* WITHOUT_GETADDRINFO */
168
169 /* traditional socket interface */
170 struct hostent *he;
171
172 if ((he = gethostbyname(addr)) != NULL) {
173 struct sockaddr_in host;
174
175 memset(&host, '\0', sizeof(host));
176
177 memcpy(&host.sin_addr, he->h_addr_list[0], he->h_length);
178 host.sin_family = he->h_addrtype;
179
180 struct servent *se;
181
182 if ((se = getservbyname(serv, "tcp")) != NULL)
183 host.sin_port = se->s_port;
184 else
185 host.sin_port = htons(atoi(serv));
186
187 if ((d = socket(AF_INET, SOCK_STREAM, 0)) != -1) {
188 if (connect(d, (struct sockaddr *)&host, sizeof(host)) == -1)
189 d = -1;
190 }
191 }
192
193#endif /* WITHOUT_GETADDRINFO */
194
195 return d;
196}
197
198
199#ifdef _XS_H
200
201xs_str *xs_socket_peername(int s)
202/* returns the remote address as a string */
203{
204 char buf[2028];
205 xs_str *p = NULL;
206
207 if (_xs_socket_peername(s, buf, sizeof(buf)))
208 p = xs_str_new(buf);
209
210 return p;
211}
212
213#endif /* _XS_H */
214
215#endif /* XS_IMPLEMENTATION */
216
217#endif /* _XS_SOCKET_H */