1 /*
2 * Tlf - contest logging program for amateur radio operators
3 * Copyright (C) 2001-2002-2003 Rein Couperus <address@hidden>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20
21 /* Socket server (and client!) utilities, */
22 /* intended to simplify the porting of JNOS servers and clients to Unix */
23 /* Written by N2RJT - Dave Brown */
24
25
26 #include <sys/select.h>
27 #include <sys/socket.h>
28 #include <netinet/in.h>
29 #include <errno.h>
30 #include <netdb.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <unistd.h>
35
36 #include "sockserv.h"
37 #include "tlf_curses.h"
38
39
40 /* This structure holds the buffers for each open socket. It was an */
41 /* afterthought, so it is not used for anything else. The array is only */
42 /* allocated when the socket is opened, and freed when the socket is closed. */
43 struct sockbuffer {
44 char *buf;
45 int buflen;
46 int fragment;
47 int whole_lines;
48 int cr_translation;
49 } sockbuf[FD_SETSIZE];
50
51 /* This array holds the SERVED sockets, that can be connected to. */
52 /* It does not hold CLIENT sockets. */
53 static int lsock[MAX_SERVED_SOCKETS];
54 static int initialized = 0;
55 static int nlsock = 0;
56 static struct timeval *socktimeval = NULL;
57 static struct timeval *selecttimeval = NULL;
58 static struct sockaddr_in udp_peer;
59 static int udpport = 0;
60 static unsigned int peerlen = 0;
61 int udp_socket = -1;
62
63 static fd_set readfds, openfds;
64 static int nfds = 0;
65 static int ifds = -1;
66
67 #define SOBUF 512
68 #define NULLCHAR (char *) NULL
69 #define myperror perror
70
setlinemode(int s,int tf)71 void setlinemode(int s, int tf) {
72 sockbuf[s].whole_lines = tf;
73 }
74
close_s(int s)75 int close_s(int s) {
76 FD_CLR(s, &openfds);
77 if (0 != sockbuf[s].buflen)
78 free(sockbuf[s].buf);
79 sockbuf[s].buflen = 0;
80 sockbuf[s].fragment = 0;
81 shutdown(s, 2);
82 return close(s);
83 }
84
fds_copy(fd_set * tofd,fd_set * fmfd)85 void fds_copy(fd_set *tofd, fd_set *fmfd) {
86 memcpy(tofd, fmfd, sizeof(fd_set));
87 }
88
usputs(int s,char * buf)89 int usputs(int s, char *buf) {
90 int len, i;
91 len = strlen(buf);
92 if (sockbuf[s].cr_translation) {
93 for (i = 0; i < len; i++) {
94 if (buf[i] == '\n')
95 usputb(s, "\r\n", 2);
96 else
97 usputb(s, buf + i, 1);
98 }
99 return len;
100 } else
101 return usputb(s, buf, len);
102 }
103
usputb(int s,char * buf,int buflen)104 int usputb(int s, char *buf, int buflen) {
105
106 extern WINDOW *sclwin;
107
108 strcpy(sockserv_error, "");
109 if (udp_socket == s) {
110 peerlen = sizeof(udp_peer);
111 if (sendto(s, buf, buflen, 0, (struct sockaddr *) &udp_peer,
112 peerlen) < 0) {
113 myperror("usputb:sendto");
114 return -1;
115 } else
116 return buflen;
117 } else {
118 if (write(s, buf, buflen) < 0) {
119 // myperror("usputb:write");
120 wprintw(sclwin, "Not connected !!");
121 wrefresh(sclwin);
122 sleep(2);
123 return -1;
124 } else
125 return buflen;
126 }
127 }
128
usvprintf(int s,char * fmt,va_list args)129 int usvprintf(int s, char *fmt, va_list args) {
130 int len, withargs;
131 char *buf;
132
133 if (strchr(fmt, '%') == NULLCHAR) {
134 /* Common case optimization: no args */
135 withargs = 0;
136 buf = fmt;
137 len = strlen(fmt);
138 } else {
139 /* Use a default value that is huge */
140 withargs = 1;
141 buf = (char *) malloc(SOBUF);
142 if (buf == NULL) {
143 /* no memory available -> just ignore the output to the socket */
144 return 0;
145 }
146 if ((len = vsprintf(buf, fmt, args)) >= SOBUF) {
147 /* It's too late to be sorry. He's dead, Jim */
148 fprintf(stderr, "usprintf() exceeded %d bytes (%d bytes)\n",
149 SOBUF, len);
150 exit(1);
151 }
152 }
153 len = usputs(s, buf);
154 if (withargs)
155 free(buf);
156 return len;
157 }
158
usprintf(int s,char * fmt,...)159 int usprintf(int s, char *fmt, ...) {
160 va_list args;
161 int len;
162
163 va_start(args, fmt);
164 len = usvprintf(s, fmt, args);
165 va_end(args);
166 return len;
167 }
168
tprintf(char * fmt,...)169 int tprintf(char *fmt, ...) {
170 va_list args;
171 int len;
172
173 va_start(args, fmt);
174 len = usvprintf(ifds, fmt, args);
175 va_end(args);
176 return len;
177 }
178
tputstr(char * buf)179 int tputstr(char *buf) {
180 return usputs(ifds, buf);
181 }
182
tputc(char c)183 int tputc(char c) {
184 char ic;
185 ic = c;
186 return usputb(ifds, &ic, 1);
187 }
188
189 static void (*login[MAX_SERVED_SOCKETS])(int i);
190 char sockserv_error[80];
initialize(void)191 static int initialize(void) {
192 int i;
193 strcpy(sockserv_error, "");
194 /* First-time initialization */
195 if (!initialized) {
196 initialized = 1;
197 for (i = 0; i < FD_SETSIZE; i++) {
198 sockbuf[i].buf = NULL;
199 sockbuf[i].buflen = 0;
200 sockbuf[i].fragment = 0;
201 sockbuf[i].whole_lines = 0;
202 sockbuf[i].cr_translation = 0;
203 }
204 FD_ZERO(&openfds);
205 }
206 return 0;
207
208 }
209
startup(int portnum,void (* loginp)(int))210 int startup(int portnum, void (*loginp)(int)) {
211 struct sockaddr_in sin;
212
213 initialize();
214 while ((lsock[nlsock] = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
215 if (errno != EINTR) {
216 myperror("startup: socket");
217 exit(1);
218 }
219 }
220
221 memset(&sin, 0, sizeof(sin));
222 sin.sin_family = AF_INET;
223 sin.sin_addr.s_addr = INADDR_ANY;
224 sin.sin_port = htons(portnum);
225 setsockopt(lsock[nlsock], SOL_SOCKET, SO_REUSEADDR, (char *) 0, 0);
226 while (bind(lsock[nlsock], (struct sockaddr *) &sin, sizeof(sin)) == -1) {
227 if (errno != EINTR) {
228 myperror("startup: bind");
229 exit(1);
230 }
231 }
232 while (listen(lsock[nlsock], 5) == -1) {
233 if (errno != EINTR) {
234 myperror("startup: listen");
235 exit(1);
236 }
237 }
238
239 login[nlsock] = loginp;
240 FD_SET(lsock[nlsock], &openfds);
241 sockbuf[lsock[nlsock]].buf = (char *) malloc(sizeof(char) * SOBUF);
242 sockbuf[lsock[nlsock]].buflen = 0;
243 sockbuf[lsock[nlsock]].fragment = 0;
244 sockbuf[lsock[nlsock]].whole_lines = 0;
245 sockbuf[lsock[nlsock]].cr_translation = 0;
246 if (nfds <= lsock[nlsock])
247 nfds = lsock[nlsock] + 1;
248 if (ifds == -1)
249 ifds = nfds - 1;
250 nlsock++;
251 return lsock[nlsock - 1];
252 }
253
startup_udp(int portnum)254 int startup_udp(int portnum) {
255 struct sockaddr_in sin;
256
257 initialize();
258 if (udp_socket == -1) {
259 while ((udp_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
260 if (errno != EINTR) {
261 myperror("startup_udp: socket");
262 exit(1);
263 }
264 }
265 }
266 if (portnum && !udpport) {
267 memset(&sin, 0, sizeof(sin));
268 sin.sin_family = AF_INET;
269 sin.sin_addr.s_addr = INADDR_ANY;
270 sin.sin_port = htons(portnum);
271 while (bind(udp_socket, (struct sockaddr *) &sin, sizeof(sin)) == -1) {
272 if (errno != EINTR) {
273 myperror("startup_udp: bind");
274 exit(1);
275 }
276 }
277 }
278 udpport = portnum;
279
280 FD_SET(udp_socket, &openfds);
281 sockbuf[udp_socket].buf = (char *) malloc(sizeof(char) * SOBUF);
282 sockbuf[udp_socket].buflen = 0;
283 sockbuf[udp_socket].fragment = 0;
284 sockbuf[udp_socket].whole_lines = 0;
285 sockbuf[udp_socket].cr_translation = 0;
286 if (nfds <= udp_socket)
287 nfds = udp_socket + 1;
288 if (ifds == -1)
289 ifds = nfds - 1;
290 return udp_socket;
291 }
292
recvline(int * fd,char * buf,int buflen)293 int recvline(int *fd, char *buf, int buflen) {
294 unsigned int len;
295 int ns, i;
296 struct sockaddr_in client;
297 char *nl;
298
299 strcpy(sockserv_error, "");
300
301 if (selecttimeval != NULL && socktimeval != NULL) {
302 selecttimeval->tv_sec = socktimeval->tv_sec;
303 selecttimeval->tv_usec = socktimeval->tv_usec;
304 }
305 if (ifds == -1)
306 ifds = nfds - 1;
307 while (1) {
308 if (++ifds == nfds) {
309 fds_copy(&readfds, &openfds);
310 while ((ifds = select(nfds, &readfds, (fd_set *) NULL, (fd_set *) NULL,
311 selecttimeval)) < 0) {
312 if (errno != EINTR) {
313 myperror("recvline: select");
314 exit(1);
315 }
316 fds_copy(&readfds, &openfds);
317 }
318 if (!ifds)
319 return -2;
320 ifds = 0;
321 } else if (FD_ISSET(ifds, &readfds)) {
322 for (i = 0; i < nlsock; i++)
323 if (lsock[i] == ifds)
324 break;
325 if (i < nlsock) {
326 if (FD_ISSET(lsock[i], &readfds)) {
327 len = sizeof(client);
328 while ((ns = accept(lsock[i], (struct sockaddr *) &client,
329 &len)) == -1) {
330 if (errno != EINTR) {
331 myperror("recvline: accept");
332 exit(1);
333 }
334 }
335 if (nfds <= ns)
336 nfds = ns + 1;
337 FD_SET(ns, &openfds);
338 sockbuf[ns].buf = (char *) malloc(sizeof(char) * SOBUF);
339 sockbuf[ns].buflen = 0;
340 sockbuf[ns].fragment = 0;
341 sockbuf[ns].whole_lines = sockbuf[lsock[i]].whole_lines;
342 sockbuf[ns].cr_translation = 0;
343 (*login[i])(ns);
344 }
345 FD_CLR(lsock[i], &readfds);
346 } else {
347 if (!sockbuf[ifds].buflen) {
348 if (ifds == udp_socket) {
349 peerlen = sizeof(udp_peer);
350 while ((sockbuf[ifds].buflen =
351 recvfrom(ifds, sockbuf[ifds].buf + sockbuf[ifds].fragment,
352 SOBUF - 1, 0, (struct sockaddr *) &udp_peer, &peerlen)) == -1) {
353 if (errno != EINTR) {
354 break;
355 }
356 peerlen = sizeof(udp_peer);
357 }
358 } else {
359 while ((sockbuf[ifds].buflen =
360 read(ifds, sockbuf[ifds].buf + sockbuf[ifds].fragment,
361 SOBUF - 1)) == -1) {
362 if (errno != EINTR) {
363 break;
364 }
365 }
366 }
367 if (sockbuf[ifds].buflen <= 0) {
368 if (ifds != udp_socket) {
369 FD_CLR(ifds, &openfds);
370 free(sockbuf[ifds].buf);
371 }
372 sockbuf[ifds].buflen = 0;
373 *fd = ifds;
374 buf[0] = '\0';
375 return -1;
376 } else {
377 sockbuf[ifds].buflen += sockbuf[ifds].fragment;
378 sockbuf[ifds].fragment = 0;
379 sockbuf[ifds].buf[sockbuf[ifds].buflen] = '\0';
380 }
381 }
382 nl = strchr(sockbuf[ifds].buf, '\n');
383 if (nl == NULL && sockbuf[ifds].whole_lines) {
384 nl = strchr(sockbuf[ifds].buf, '\r');
385 if (nl) {
386 sockbuf[ifds].cr_translation = 1;
387 printf("Enabling CR translation for socket %d\n", ifds);
388 }
389 }
390 if (nl == NULL && sockbuf[ifds].whole_lines) {
391 sockbuf[ifds].fragment = sockbuf[ifds].buflen;
392 sockbuf[ifds].buflen = 0;
393 continue;
394 } else {
395 /* nl != NULL || whole_lines == 0 */
396 if (sockbuf[ifds].whole_lines) {
397 if (nl != NULL)
398 *nl = '\0';
399 len = strlen(sockbuf[ifds].buf) + 1;
400 } else if (sockbuf[ifds].buflen > buflen)
401 len = buflen;
402 else
403 len = sockbuf[ifds].buflen;
404 memcpy(buf, sockbuf[ifds].buf, len);
405 if (sockbuf[ifds].buflen > len)
406 memmove(sockbuf[ifds].buf, sockbuf[ifds].buf + len,
407 sockbuf[ifds].buflen - len);
408 sockbuf[ifds].buflen -= len;
409 *fd = ifds;
410 if (sockbuf[ifds].buflen)
411 ifds--;
412 }
413 return len;
414 }
415 }
416 }
417 }
418
resolve(char * hostname)419 long resolve(char *hostname) {
420 unsigned long int haddr;
421 unsigned char a[4];
422 int i;
423 char *s, *d, *c;
424 int valid = 1;
425
426 if (initialize())
427 return -1L;
428
429 s = hostname;
430 for (i = 0; i < 4; i++) {
431 if (s) {
432 d = strchr(s, '.');
433 if (!d)
434 d = s + strlen(s);
435 for (c = s; c < d; c++)
436 if (*c < '0' || *c > '9')
437 valid = 0;
438 if (!valid)
439 break;
440 a[i] = atoi(s);
441 s = strchr(s, '.');
442 if (s)
443 s++;
444 } else {
445 valid = 0;
446 break;
447 }
448 }
449 if (valid) {
450 haddr = a[3] + 256u * (a[2] + 256u * (a[1] + 256u * a[0]));
451 haddr = htonl(haddr);
452 } else {
453 struct hostent *hp;
454
455 if ((hp = gethostbyname(hostname)) == NULL) {
456 herror("resolve: gethostbyname");
457 return -1L;
458 }
459 memcpy(&haddr, hp->h_addr, hp->h_length);
460
461 }
462
463 strcpy(sockserv_error, "");
464 return (haddr);
465 }
466
startcliaddr(int family,unsigned long int addr,unsigned short int portnum)467 int startcliaddr(int family, unsigned long int addr,
468 unsigned short int portnum) {
469 extern WINDOW *sclwin;
470
471 int s;
472 struct sockaddr_in sin;
473
474 initialize();
475 memset(&sin, 0, sizeof(sin));
476 sin.sin_addr.s_addr = addr;
477 sin.sin_family = family;
478 sin.sin_port = htons(portnum);
479
480 while ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
481 if (errno != EINTR) {
482 wprintw(sclwin, "socket failure");
483 wrefresh(sclwin);
484 sleep(1);
485 return -1;
486 }
487 }
488
489 while (connect(s, (struct sockaddr *) &sin, sizeof(sin)) == -1) {
490 if (errno != EINTR) {
491
492 return (-1);
493 }
494 }
495
496 if (nfds <= s)
497 nfds = s + 1;
498 if (ifds == -1)
499 ifds = nfds - 1;
500 FD_SET(s, &openfds);
501
502 wprintw(sclwin, "still here...");
503 wrefresh(sclwin);
504 sleep(2);
505
506 sockbuf[s].buf = (char *) malloc(sizeof(char) * SOBUF);
507
508 // sockbuf[s].buf = (char *)socketbuffer; // debug
509 sockbuf[s].buflen = 0;
510 sockbuf[s].fragment = 0;
511 sockbuf[s].whole_lines = 0;
512
513 wprintw(sclwin, "not dead...");
514 wrefresh(sclwin);
515 sleep(1);
516
517 return s;
518 }
519
startcli(void)520 int startcli(void) {
521 extern char pr_hostaddress[];
522 extern int portnum;
523
524 unsigned long int haddr;
525 int addrtype;
526 haddr = resolve(pr_hostaddress);
527 addrtype = AF_INET;
528
529 return (startcliaddr(addrtype, haddr, (short) portnum));
530 }
531
socktimeout(int msec)532 void socktimeout(int msec) {
533 if (!socktimeval)
534 socktimeval = (struct timeval *) malloc(sizeof(struct timeval));
535 if (!selecttimeval)
536 selecttimeval = (struct timeval *) malloc(sizeof(struct timeval));
537 socktimeval->tv_sec = msec / 1000L;
538 socktimeval->tv_usec = (msec % 1000L) * 1000L;
539 }
540
nosocktimeout(void)541 void nosocktimeout(void) {
542 free(socktimeval);
543 socktimeval = NULL;
544 free(selecttimeval);
545 selecttimeval = NULL;
546 }
547
set_udp_peer(long address,int portnum)548 void set_udp_peer(long address, int portnum) {
549 memset(&udp_peer, 0, sizeof(udp_peer));
550 udp_peer.sin_addr.s_addr = address;
551 udp_peer.sin_family = AF_INET;
552 udp_peer.sin_port = htons(portnum);
553 peerlen = sizeof(udp_peer);
554 }
555
get_udp_peer(long * address,int * portnum)556 void get_udp_peer(long *address, int *portnum) {
557 *address = udp_peer.sin_addr.s_addr;
558 *portnum = 0;
559 *portnum = ntohs(udp_peer.sin_port);
560 }
561