summaryrefslogtreecommitdiff
path: root/other/reverb/network.c
diff options
context:
space:
mode:
Diffstat (limited to 'other/reverb/network.c')
-rw-r--r--other/reverb/network.c458
1 files changed, 458 insertions, 0 deletions
diff --git a/other/reverb/network.c b/other/reverb/network.c
new file mode 100644
index 0000000..3335b1a
--- /dev/null
+++ b/other/reverb/network.c
@@ -0,0 +1,458 @@
1
2/* scut's leet network library ;)
3 * 1999 (c) scut
4 *
5 * networking routines
6 * based on my hbot networking sources,
7 * revised, extended and adapted 990405
8 * extended, improved and fixed 990430
9 * ripped down to minimal functionality for reverb 990803
10 *
11 * for the full version of this library just contact me, i'd be glad to send
12 * them to you :)
13 *
14 * nearly all of this code wouldn't have been possible without w. richard stevens
15 * excellent network coding book. if you are interested in network coding,
16 * there is no way around it.
17 */
18
19#include <sys/types.h>
20#include <sys/ioctl.h>
21#include <sys/socket.h>
22#include <sys/time.h>
23#include <arpa/inet.h>
24#include <netdb.h>
25#include <net/if.h>
26#include <netinet/in.h>
27#include <errno.h>
28#include <fcntl.h>
29#include <stdarg.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33#include <unistd.h>
34#include "network.h"
35
36int net_readtimeout = NET_READTIMEOUT;
37int net_conntimeout = NET_CONNTIMEOUT;
38
39
40int
41net_parseip (char *inp, char **ip, unsigned short int *port)
42{
43 int n;
44
45 if (inp == NULL)
46 return (0);
47 if (strchr (inp, ':') == NULL)
48 return (0);
49
50 *ip = calloc (1, 256);
51 if (*ip == NULL)
52 return (0);
53
54 n = sscanf (inp, "%[^:]:%hu", *ip, port);
55 if (n != 2)
56 return (0);
57
58 *ip = realloc (*ip, strlen (*ip) + 1);
59 if (*ip == NULL || (*port < 1 || *port > 65535))
60 return (0);
61
62 return (1);
63}
64
65
66int
67net_accept (int s, struct sockaddr_in *cs, int maxsec)
68{
69 int flags, n;
70 fd_set ac_s;
71 int len;
72 struct timeval tval;
73
74 flags = fcntl(s, F_GETFL, 0);
75 if (flags == -1)
76 return (-1);
77 n = fcntl(s, F_SETFL, flags | O_NONBLOCK);
78 if (flags == -1)
79 return (-1);
80
81 FD_ZERO(&ac_s);
82 FD_SET(s, &ac_s);
83 tval.tv_sec = maxsec;
84 tval.tv_usec = 0;
85
86 n = select(s + 1, &ac_s, NULL, NULL, maxsec ? &tval : NULL);
87 if (n == 0)
88 return (0);
89
90 if (FD_ISSET(s, &ac_s)) {
91 len = sizeof(struct sockaddr_in);
92 n = accept(s, (struct sockaddr *) cs, &len);
93 if (n == -1) {
94 switch (errno) {
95 case EWOULDBLOCK:
96 case ECONNABORTED:
97 case EPROTO:
98 case EINTR: if (fcntl(s, F_SETFL, flags) == -1)
99 return (-1);
100 return (0);
101 default: return (-1);
102 }
103 }
104 if (fcntl(s, F_SETFL, flags) == -1)
105 return (-1);
106 return (n);
107 }
108 if (fcntl(s, F_SETFL, flags) == -1)
109 return (-1);
110 return (0);
111}
112
113
114void
115net_boundfree (bound *bf)
116{
117 close (bf->bs);
118 free(bf);
119 return;
120}
121
122
123bound *
124net_bind (char *ip, unsigned short int port)
125{
126 bound *b;
127 int br, gsnr, lr;
128 int len, reusetmp;
129 struct sockaddr_in *sap;
130
131 if (port >= 65536)
132 return (NULL);
133
134 b = calloc(1, sizeof (bound));
135 if (b == NULL)
136 return (NULL);
137 b->bs = socket (AF_INET, SOCK_STREAM, 0);
138 if (b->bs == -1)
139 goto berror;
140
141 reusetmp = 1;
142#ifdef SO_REUSEPORT
143 if (setsockopt (b->bs, SOL_SOCKET, SO_REUSEPORT, &reusetmp, sizeof (reusetmp)) == -1)
144 goto berror;
145#else
146 if (setsockopt (b->bs, SOL_SOCKET, SO_REUSEADDR, &reusetmp, sizeof (reusetmp)) == -1)
147 goto berror;
148#endif
149
150 sap = (struct sockaddr_in *) &b->bsa;
151 sap->sin_family = AF_INET;
152 sap->sin_port = htons (port); /* 0 = ephemeral */
153
154 if (ip != NULL) {
155 if (strcmp (ip, "*") == 0) {
156 sap->sin_addr.s_addr = htonl (INADDR_ANY);
157 } else {
158 if (!(sap->sin_addr.s_addr = net_resolve (ip))) {
159 goto berror;
160 }
161 }
162 } else {
163 sap->sin_addr.s_addr = htonl (INADDR_ANY);
164 }
165
166 br = bind (b->bs, (struct sockaddr *) &b->bsa, sizeof (struct sockaddr));
167 if (br == -1)
168 goto berror;
169
170 len = sizeof (struct sockaddr);
171 gsnr = getsockname (b->bs, (struct sockaddr *) &b->bsa, &len);
172 b->port = ntohs (sap->sin_port);
173 if (gsnr == -1)
174 goto berror;
175
176 lr = listen (b->bs, 16);
177 if (lr == -1) {
178 goto berror;
179 }
180 return (b);
181
182berror:
183 free(b);
184
185 return(NULL);
186}
187
188
189unsigned long int
190net_resolve (char *host)
191{
192 long i;
193 struct hostent *he;
194
195 i = inet_addr(host);
196 if (i == -1) {
197 he = gethostbyname(host);
198 if (he == NULL) {
199 return (0);
200 } else {
201 return (*(unsigned long *) he->h_addr);
202 }
203 }
204 return (i);
205}
206
207
208int
209net_connect (struct sockaddr_in *cs, char *server, unsigned short int port, int sec)
210{
211 int n, len, error, flags;
212 int fd;
213 struct timeval tv;
214 fd_set rset, wset;
215
216 /* first allocate a socket */
217 cs->sin_family = AF_INET;
218 cs->sin_port = htons (port);
219 fd = socket (cs->sin_family, SOCK_STREAM, 0);
220 if (fd == -1)
221 return (-1);
222
223 if (!(cs->sin_addr.s_addr = net_resolve (server))) {
224 close (fd);
225 return (-1);
226 }
227
228 flags = fcntl (fd, F_GETFL, 0);
229 if (flags == -1) {
230 close (fd);
231 return (-1);
232 }
233 n = fcntl (fd, F_SETFL, flags | O_NONBLOCK);
234 if (n == -1) {
235 close (fd);
236 return (-1);
237 }
238
239 error = 0;
240
241 n = connect (fd, (struct sockaddr *) cs, sizeof (struct sockaddr_in));
242 if (n < 0) {
243 if (errno != EINPROGRESS) {
244 close (fd);
245 return (-1);
246 }
247 }
248 if (n == 0)
249 goto done;
250
251 FD_ZERO(&rset);
252 FD_ZERO(&wset);
253 FD_SET(fd, &rset);
254 FD_SET(fd, &wset);
255 tv.tv_sec = sec;
256 tv.tv_usec = 0;
257
258 n = select(fd + 1, &rset, &wset, NULL, &tv);
259 if (n == 0) {
260 close(fd);
261 errno = ETIMEDOUT;
262 return (-1);
263 }
264 if (n == -1)
265 return (-1);
266
267 if (FD_ISSET(fd, &rset) || FD_ISSET(fd, &wset)) {
268 if (FD_ISSET(fd, &rset) && FD_ISSET(fd, &wset)) {
269 len = sizeof(error);
270 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
271 errno = ETIMEDOUT;
272 return (-1);
273 }
274 if (error == 0) {
275 goto done;
276 } else {
277 errno = error;
278 return (-1);
279 }
280 }
281 } else
282 return (-1);
283
284done:
285 n = fcntl(fd, F_SETFL, flags);
286 if (n == -1)
287 return (-1);
288 return (fd);
289}
290
291
292int
293net_tline (char *buf, int bufsize)
294{
295 int p;
296
297 for (p = 0; p < bufsize; p++) {
298 if (buf[p] == '\n')
299 return (p + 1);
300 }
301 return (-1);
302}
303
304
305int
306net_rlinet (int fd, char *buf, int bufsize, int sec)
307{
308 int n;
309 unsigned long int rb = 0;
310 struct timeval tv_start, tv_cur;
311
312 memset(buf, '\0', bufsize);
313 (void) gettimeofday(&tv_start, NULL);
314
315 do {
316 (void) gettimeofday(&tv_cur, NULL);
317 if (sec > 0) {
318 if ((((tv_cur.tv_sec * 1000000) + (tv_cur.tv_usec)) -
319 ((tv_start.tv_sec * 1000000) + (tv_start.tv_usec))) > (sec * 1000000)) {
320 return (-1);
321 }
322 }
323 n = net_rtimeout(fd, net_readtimeout);
324 if (n <= 0) {
325 return (-1);
326 }
327 n = read(fd, buf, 1);
328 if (n <= 0) {
329 return (n);
330 }
331 rb++;
332 if (*buf == '\n')
333 return (rb);
334 buf++;
335 if (rb >= bufsize)
336 return (-1);
337 } while (1);
338}
339
340
341long int
342net_rbuf (int fd, char **dst)
343{
344 long int ml = 0;
345 long int read_bytes;
346 int p;
347
348 while ((p = net_rtimeout(fd, net_readtimeout)) == 1) {
349 *dst = (char *) realloc(*dst, ml + NET_BSIZE);
350 if (*dst == NULL)
351 return (-1);
352 ml += read_bytes = read(fd, *dst + ml, NET_BSIZE);
353 if (read_bytes == 0) {
354 *dst = (char *) realloc(*dst, ml);
355 if ((*dst == NULL) && (ml == 0)) {
356 return (1);
357 } else if (*dst == NULL) {
358 return (-1);
359 } else {
360 return (ml);
361 }
362 }
363 }
364 return (-1);
365}
366
367
368int
369net_rbuft (int fd, char *dst, unsigned long int dsize)
370{
371 unsigned long int bl = 0, m;
372 int p;
373
374 while (bl < dsize) {
375 p = net_rtimeout(fd, net_readtimeout);
376 if ((p == 0) || (p == -1)) {
377 return (-1);
378 }
379
380 m = read(fd, dst + bl, (dsize - bl));
381 if ((m == 0) || (m == -1)) {
382 return (-1);
383 }
384 bl += m;
385 }
386 return (1);
387}
388
389
390int
391net_rtimeout (int fd, int sec)
392{
393 fd_set rset;
394 struct timeval tv;
395 int n, error, flags;
396
397 error = 0;
398 flags = fcntl(fd, F_GETFL, 0);
399 n = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
400 if (n == -1)
401 return (-1);
402
403 FD_ZERO(&rset);
404 FD_SET(fd, &rset);
405 tv.tv_sec = sec;
406 tv.tv_usec = 0;
407
408 /* now we wait until more data is received then the tcp low level watermark,
409 * which should be setted to 1 in this case (1 is default)
410 */
411
412 n = select(fd + 1, &rset, NULL, NULL, &tv);
413 if (n == 0) {
414 n = fcntl(fd, F_SETFL, flags);
415 if (n == -1)
416 return (-1);
417 errno = ETIMEDOUT;
418 return (-1);
419 }
420 if (n == -1) {
421 return (-1);
422 }
423 /* socket readable ? */
424 if (FD_ISSET(fd, &rset)) {
425 n = fcntl(fd, F_SETFL, flags);
426 if (n == -1)
427 return (-1);
428 return (1);
429 } else {
430 n = fcntl(fd, F_SETFL, flags);
431 if (n == -1)
432 return (-1);
433 errno = ETIMEDOUT;
434 return (-1);
435 }
436}
437
438
439void
440net_write (int fd, const char *str, ...)
441{
442 char tmp[1025];
443 va_list vl;
444 int i;
445
446 va_start(vl, str);
447 memset(tmp, 0, sizeof(tmp));
448 i = vsnprintf(tmp, sizeof(tmp), str, vl);
449 va_end(vl);
450
451#ifdef DEBUG
452 printf("[snd] %s\n", tmp);
453#endif
454
455 send(fd, tmp, i, 0);
456 return;
457}
458