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