2 # Parent e319e618448fe7163635b08206f48d214e59d738
4 diff -r e319e618448f tools/sbounce/Makefile
5 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
6 +++ b/tools/sbounce/Makefile Sun Jul 14 18:14:29 2013 +0100
9 +# Makefile for sbounce
13 +CFLAGS=-O3 -Wall -pedantic
17 +DEFINES=-DSETTINGSFILE=\"${PREFIX}/lib/bounce.conf\"\
18 + -DLOGFILE=\"${PREFIX}/lib/${PROG}.log\"\
19 + -DPIDFILE=\"${PREFIX}/lib/${PROG}.pid\"
21 +all: ${PROG} logrotate.conf
24 + gcc -O3 -lz -o ${PROG} ${PROG}.o
27 + gcc ${DEFINES} -c ${PROG}.c
29 +logrotate.conf: logrotate.conf.in
30 + @sed -e 's,LOGFILE,${PREFIX}/lib/${PROG}.log,g'\
31 + -e 's,PIDFILE,${PREFIX}/lib/${PROG}.pid,g' <logrotate.conf.in >logrotate.conf
34 + @if [ ! -d ${PREFIX} -a ! -f ${PREFIX} ]; then \
35 + echo "Creating directory ${PREFIX}"; \
37 + chmod 555 ${PREFIX}; \
40 + @if [ ! -d ${PREFIX}/bin -a ! -f ${PREFIX}/bin ]; then \
41 + echo "Creating directory ${PREFIX}/bin"; \
42 + mkdir ${PREFIX}/bin; \
43 + chmod 555 ${PREFIX}/bin; \
46 + @if [ -f ${PREFIX}/bin/${PROG} ]; then \
47 + echo "Saving existing ${PREFIX}/bin/${PROG} as .old"; \
48 + mv ${PREFIX}/bin/${PROG} ${PREFIX}/bin/${PROG}.old; \
51 + cp ${PROG} ${PREFIX}/bin
52 + chmod 555 ${PREFIX}/bin/${PROG}
54 + @if [ -d /etc/logrotate.d ]; then \
55 + echo "Installing /etc/logrotate.d/sbounce"; \
56 + cp logrotate.conf /etc/logrotate.d/sbounce; \
57 + chmod 444 /etc/logrotate.d/sbounce; \
61 + rm -f ${PROG}.o ${PROG} logrotate.conf
62 diff -r e319e618448f tools/sbounce/logrotate.conf.in
63 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
64 +++ b/tools/sbounce/logrotate.conf.in Sun Jul 14 18:14:29 2013 +0100
72 + [ -f PIDFILE ] && kill -HUP `cat PIDFILE`
78 diff -r e319e618448f tools/sbounce/sbounce.c
79 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
80 +++ b/tools/sbounce/sbounce.c Sun Jul 14 18:14:29 2013 +0100
82 +/* sbounce: splidge's zBounce alike.
86 + * Copyright (C) 2003 David Mansell.
88 + * Redistribution and use in source and binary forms, with or without
89 + * modification, are permitted provided that redistributions of source code
90 + * retain the above copyright notice, this condition and the following
93 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
94 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
95 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
96 + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
97 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
98 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
99 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
100 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
101 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
102 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
117 +#include <sys/types.h>
118 +#include <sys/socket.h>
119 +#include <sys/poll.h>
120 +#include <sys/ioctl.h>
121 +#include <sys/types.h>
122 +#include <sys/stat.h>
123 +#include <sys/time.h>
124 +#include <netinet/in.h>
127 + * Various settings and constants that CAN be tweaked if you so desire..
130 +/* Buffer / network settings */
131 +#define BUFSIZE 65536
133 +#define LISTEN_RECVBUF 61440
134 +#define RECVBUF 61440
135 +#define SENDBUF 61440
138 +#ifndef SETTINGSFILE
139 +#define SETTINGSFILE "/opt/ircd/lib/bounce.conf"
142 +#define LOGFILE "/opt/ircd/lib/sbounce.log"
145 +#define PIDFILE "/opt/ircd/lib/sbounce.pid"
148 +#define STATSINTERVAL 300 /* How frequently to write compression stats to a file */
150 +/* These two directly affect the lag induced by the bouncer.. */
151 +#define POLLTIMEOUT 100 /* The main poll timeout */
152 +#define FLUSHTIMEOUT 80000 /* How long (in uSec) between last output and forcing a flush */
154 +#undef DONTDETACH /* Define this to make it not detach */
156 +/* Magic constants and macros etc. - these should NOT be tweaked :) */
157 +#define SST_IDLE 0x00000
158 +#define SST_LISTEN_COMP 0x10001
159 +#define SST_LISTEN_DECOMP 0x10002
160 +#define SST_COMP 0x20001
161 +#define SST_DECOMP 0x20002
163 +#define IsListenSocket(x) (ssa[(x)].type & 0x10000)
164 +#define IsActiveSocket(x) (ssa[(x)].type & 0x20000)
166 +#define IsCompressSocket(x) (ssa[(x)].type & 0x1)
167 +#define IsDecompressSocket(x) (ssa[(x)].type & 0x2)
169 +/* Function prototypes */
170 +void handlefd(int fd, short events);
171 +void handlelistenfd(int fd, short events);
175 +typedef struct ssock {
178 + /* poll() stuff - valid for all types */
182 + /* Address stuff - valid for listen types only */
183 + unsigned int listenaddr;
184 + unsigned short listenport;
185 + unsigned int remoteaddr;
186 + unsigned short remoteport;
189 + /* Things valid for connected sockets only */
192 + unsigned char *inbuf;
193 + unsigned char *outbuf;
194 + unsigned char *overflow;
196 + struct timeval lastoutput;
201 +typedef struct validip {
202 + unsigned int IPaddress;
203 + struct validip *next;
207 +struct pollfd pfd[MAXFDS];
211 +char configfile[512];
217 + memset(ssa, 0, MAXFDS * sizeof(ssock));
218 + memset(pfd, 0, MAXFDS * sizeof(struct pollfd));
220 + /* Non-zero init here */
221 + for(i=0;i<MAXFDS;i++) {
222 + ssa[i].pollfdpos = -1;
223 + ssa[i].companion = -1;
231 + if ((logfd=open(LOGFILE, O_CREAT | O_WRONLY | O_APPEND,00660)) < 0) {
232 + printf("ERROR: can't open logfile.\n");
243 + f = fopen(PIDFILE, "w");
245 + fprintf(stderr, "Couldn't create pid file \"%s\": %s",
246 + PIDFILE, strerror(errno));
248 + fprintf(f, "%ld\n", (long) getpid());
253 +long usecdiff(struct timeval *tv1, struct timeval *tv2) {
254 + long secdiff = tv2->tv_sec - tv1->tv_sec;
255 + long usecdiff = tv2->tv_usec - tv1->tv_usec;
257 + return (secdiff * 1000000) + usecdiff;
260 +void logwrite(char *message, ...) {
270 + va_start(va,message);
271 + vsnprintf(buf,512,message,va);
275 + tmp=localtime(&now);
276 + strftime(buf2, 512, "%Y-%m-%d %H:%M",tmp);
278 + printf("[%s] %s",buf2,buf);
280 + len=snprintf(buf3,512,"[%s] %s",buf2,buf);
282 + write(logfd, buf3, len);
286 +char *IPtostr(unsigned int ip) {
287 + static char buf1[15];
288 + static char buf2[15];
290 + static int count=0;
297 + sprintf(buf,"%d.%d.%d.%d",ip&255,(ip>>8)&255,(ip>>16)&255,(ip>>24)&255);
302 +/* setpoll(): Set the specified fd to be checked for the specified events.
303 + * If events==0, remove the fd from the array.
306 +void setpoll(int fd, short events) {
308 + if (ssa[fd].pollfdpos > -1) {
309 + /* Already in the array.. */
310 + assert(pfd[ssa[fd].pollfdpos].fd == fd);
311 + pfd[ssa[fd].pollfdpos].events=events;
312 + ssa[fd].events=events;
315 + /* Not in the array, add to the end */
316 + ssa[fd].pollfdpos=cur_pfds;
317 + pfd[cur_pfds].fd=fd;
318 + pfd[cur_pfds].events=events;
319 + pfd[cur_pfds].revents=0;
320 + ssa[fd].events=events;
326 + if (ssa[fd].pollfdpos==-1) {
327 + /* This FD wasn't in the array */
331 + if (ssa[fd].pollfdpos!=cur_pfds) {
332 + /* We need to swap the entry from the end in here */
333 + pfd[ssa[fd].pollfdpos].fd = pfd[cur_pfds].fd;
334 + pfd[ssa[fd].pollfdpos].events = pfd[cur_pfds].events;
335 + pfd[ssa[fd].pollfdpos].revents = pfd[cur_pfds].revents;
337 + ssa[pfd[cur_pfds].fd].pollfdpos = ssa[fd].pollfdpos;
340 + ssa[fd].pollfdpos=-1;
348 + * dopoll(): Calls poll(), and then calls handlefd() for each fd that had
352 +int dopoll(int timeout) {
355 + if ((ret=poll(pfd, cur_pfds, timeout))) {
356 + if (ret<0 && errno!=EINTR) {
357 + logwrite("poll() error: %d\n",errno);
360 + for(i=0;i<cur_pfds;i++) {
361 + if (pfd[i].revents) {
362 + handlefd(pfd[i].fd, pfd[i].revents);
372 + * initconnection(): Set up to compressor/decompressor for the specified socket.
373 + * Allocate buffers and set socket options.
376 +void initconnection(int fd) {
377 + unsigned int rbuf=RECVBUF, sbuf=SENDBUF, opt=1;
379 + ssa[fd].inbuf =(unsigned char *)malloc(BUFSIZE);
380 + ssa[fd].outbuf=(unsigned char *)malloc(BUFSIZE);
381 + memset(&(ssa[fd].zs), 0, sizeof(z_stream));
383 + if (IsCompressSocket(fd)) {
384 + if (deflateInit(&(ssa[fd].zs), 6) != Z_OK) {
385 + logwrite("Error initialising deflate!\n");
388 + if (inflateInit(&(ssa[fd].zs)) != Z_OK) {
389 + logwrite("Error initialising inflate!\n");
393 + ssa[fd].zs.next_in=ssa[fd].inbuf;
394 + ssa[fd].zs.avail_in=0;
395 + ssa[fd].zs.next_out=ssa[fd].outbuf;
396 + ssa[fd].zs.avail_out=0;
399 + ssa[fd].lastdump=time(NULL);
401 + if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char*) &rbuf, sizeof(rbuf)) ||
402 + setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const char*) &sbuf, sizeof(sbuf))) {
403 + logwrite("Error setting socket buffers on fd %d\n",fd);
406 + if (ioctl(fd, FIONBIO, &opt) == -1) {
407 + logwrite("Error setting socket non-blocking on fd %d\n",fd);
410 + ssa[fd].overflowsize=0;
414 + * killconnection(): Kills off the compressor/decompressor and frees all buffers
417 +void killconnection(int fd) {
420 + free(ssa[fd].inbuf);
421 + free(ssa[fd].outbuf);
422 + if (IsCompressSocket(fd)) {
423 + deflateEnd(&(ssa[fd].zs));
425 + inflateEnd(&(ssa[fd].zs));
427 + ssa[fd].type=SST_IDLE;
431 + * flushdata(): Flushes all data from the specified fd.
432 + * Returns 0 if all data was written.
433 + * Returns 1 if there is some data left.
434 + * Returns -1 if there was a socket error.
437 +int flushdata(int fd) {
438 + int genbytes,bytesout;
439 + int companionfd=ssa[fd].companion;
441 + if ((genbytes=ssa[fd].overflowsize)==0)
442 + return 0; /* nothing there */
444 + bytesout=write(companionfd, ssa[fd].overflow, genbytes);
446 + if (bytesout!=genbytes) {
447 + /* It didn't all get written */
448 + if (bytesout==-1) {
449 + if (errno==EAGAIN) {
452 + logwrite("Error writing to fd %d: %d\n",companionfd,errno);
457 + /* Short write - I'm ASSUMING this is cos the socket buffer filled up */
458 + ssa[fd].overflowsize-=bytesout;
459 + ssa[fd].overflow+=bytesout;
463 + /* Clear the overflow and return */
464 + ssa[fd].overflowsize=0;
470 + * handledata(): Handles data outstanding on the specified fd.
471 + * Returns 0 if everything went OK
472 + * Returns 1 if there was an error
474 + * This function will manipulate the poll() array as necessary if sockets become blocked.
477 +int handledata(int fd, int forceflush) {
479 + int companionfd = ssa[fd].companion;
480 + struct timezone tz;
482 + /* Check we don't have outstanding data to write.. */
483 + if ((ret=flushdata(fd))) {
491 + if (ssa[fd].dirty == 0) {
492 + gettimeofday(&(ssa[fd].lastoutput), &tz);
495 + if (ssa[fd].zs.avail_in || forceflush) {
497 + ssa[fd].zs.next_out=ssa[fd].outbuf;
498 + ssa[fd].zs.avail_out=BUFSIZE;
500 + if (IsCompressSocket(fd)) {
501 + ret=deflate(&(ssa[fd].zs), forceflush ? Z_SYNC_FLUSH : 0);
503 + ret=inflate(&(ssa[fd].zs), Z_SYNC_FLUSH);
506 + if (ret != Z_OK && ret != Z_BUF_ERROR) {
507 + logwrite("Compression error %d on fd %d.\n",ret,fd);
511 + /* Mark all generated data as overflow */
512 + ssa[fd].overflowsize = (BUFSIZE - ssa[fd].zs.avail_out);
513 + ssa[fd].overflow = ssa[fd].outbuf;
515 + /* If it actually produced anything, make a note.. */
516 + if (ssa[fd].overflowsize) {
517 + gettimeofday(&(ssa[fd].lastoutput), &tz);
520 + if ((ret=flushdata(fd))) {
522 + /* It's full - swap the poll() stuff around */
523 + setpoll(fd, ssa[fd].events & ~POLLIN);
524 + setpoll(companionfd, ssa[companionfd].events | POLLOUT);
528 + /* It broke, return error */
534 + if (ssa[fd].zs.avail_in == 0)
539 + /* OK, we dealt with everything */
540 + if (!(ssa[fd].events & POLLIN)) {
541 + /* We need to swap poll() things back */
542 + setpoll(fd, ssa[fd].events | POLLIN);
543 + setpoll(companionfd, ssa[companionfd].events & ~POLLOUT);
551 + * handlefd(): Deals with events occuring on the specified fd.
554 +void handlefd(int fd, short events) {
555 + /* Palm off listen sockets elsewhere */
559 + companionfd=ssa[fd].companion;
561 + if (IsListenSocket(fd)) {
562 + handlelistenfd(fd, events);
566 + if (events & POLLIN) {
567 + /* Input data to be handled by the [de]compressor - read all data, compress
568 + and send to companion socket. If the companion blocks, we make the companion
569 + poll for POLLOUT and stop this socket polling for POLLIN. */
571 + /* It's an INVARIANT that if we were polling for POLLIN there is nothing in the input OR output buffers
572 + * from this socket. */
574 + if (ssa[fd].overflowsize || ssa[fd].zs.avail_in || !(ssa[fd].events & POLLIN)) {
575 + logwrite("Unexpected input data on fd %d. - overflowsize=%d avail_in=%d ev=%d pfdev=%d rev=%d\n",fd,ssa[fd].overflowsize,
576 + ssa[fd].zs.avail_in, pfd[ssa[fd].pollfdpos].events, ssa[fd].events, events);
578 + if ((bytes=read(fd, ssa[fd].inbuf, BUFSIZE))<=0) {
581 + logwrite("Connection closed (EOF) - closing fds %d and %d.\n",fd,companionfd);
582 + killconnection(companionfd);
583 + killconnection(fd);
585 + } else if (errno==EAGAIN) {
586 + /* Just EAGAIN.. return and come back later */
589 + logwrite("Connection close (Read error - %s) - closing fds %d and %d.\n",strerror(errno),fd,companionfd);
590 + killconnection(companionfd);
591 + killconnection(fd);
596 + ssa[fd].zs.next_in=ssa[fd].inbuf;
597 + ssa[fd].zs.avail_in=bytes;
599 + if (handledata(fd, 0)) {
600 + /* Error return - close connection */
601 + logwrite("Connection closed (ERROR) - closing fds %d and %d.\n",fd,companionfd);
602 + killconnection(companionfd);
603 + killconnection(fd);
607 + if (time(NULL) - ssa[fd].lastdump > STATSINTERVAL) {
608 + ssa[fd].lastdump=time(NULL);
609 + logwrite("fd %d Stats: %d bytes in, %d bytes out.\n",fd,ssa[fd].zs.total_in,ssa[fd].zs.total_out);
614 + if (events & POLLOUT) {
615 + /* We can write - need to grab output data from companion socket and write it out.
616 + If we manage to empty the buffer, we should set the companion socket to wait
617 + for POLLIN again -- handledata() does ALL this for us */
619 + if (handledata(companionfd, 0)) {
620 + /* Error return - close connection */
621 + logwrite("Connection closed (ERROR) - closing fds %d and %d.\n",fd,companionfd);
622 + killconnection(companionfd);
623 + killconnection(fd);
628 + if (events & (POLLERR|POLLHUP|POLLNVAL)) {
629 + /* Something has broken - close this socket and companion and clean everything up */
630 + logwrite("Connection error - closing fds %d and %d.\n",fd,ssa[fd].companion);
631 + killconnection(ssa[fd].companion);
632 + killconnection(fd);
637 + * handlelistenfd(): Deals with activity on a listening FD (i.e. incoming connection)
640 +void handlelistenfd(int fd, short events) {
641 + int newfd, companionfd;
642 + struct sockaddr_in sin;
643 + unsigned int len=sizeof(struct sockaddr_in);
647 + if (events & POLLIN) {
648 + /* We have a connection - need to accept(), initialise the [de]compressor and set up
649 + * a companion socket, initiating a non-blocking connect() to the remote address. */
651 + newfd=accept(fd, (struct sockaddr *) &sin, &len);
653 + if (newfd >= MAXFDS) {
654 + logwrite("FD %d out of range - closing connection. Recompile with larger MAXFDS\n",newfd);
659 + /* Check that this host is authorised to connect */
660 + for (vip=okhosts;vip;vip=vip->next) {
661 + if (vip->IPaddress == sin.sin_addr.s_addr)
666 + logwrite("Rejecting unauthorised connection from %d.%d.%d.%d\n",sin.sin_addr.s_addr & 255,
667 + (sin.sin_addr.s_addr >> 8) & 255, (sin.sin_addr.s_addr >> 16) & 255,
668 + (sin.sin_addr.s_addr >> 24) & 255);
674 + ssa[newfd].type = ssa[fd].type+0x10000;
675 + initconnection(newfd);
677 + /* By default we listen on the NEW socket we open only.. */
680 + /* Now set up the companion socket */
681 + if ((companionfd=socket(AF_INET,SOCK_STREAM,0))==-1) {
682 + logwrite("Error creating companion socket!\n");
683 + killconnection(newfd);
687 + if (companionfd >= MAXFDS) {
688 + logwrite("FD %d out of range - closing connection. Recompile with larger MAXFDS.\n",companionfd);
689 + close(companionfd);
690 + killconnection(newfd);
694 + logwrite("Accepted connection from %d.%d.%d.%d. fd=%d, companion=%d\n",sin.sin_addr.s_addr & 255,
695 + (sin.sin_addr.s_addr >> 8) & 255, (sin.sin_addr.s_addr >> 16) & 255,
696 + (sin.sin_addr.s_addr >> 24) & 255, newfd, companionfd);
698 + if (ssa[newfd].type == SST_COMP)
699 + ssa[companionfd].type = SST_DECOMP;
701 + ssa[companionfd].type = SST_COMP;
703 + initconnection(companionfd);
705 + sin.sin_addr.s_addr=ssa[fd].remoteaddr;
706 + sin.sin_port = htons(ssa[fd].remoteport);
707 + if ((res=connect(companionfd, (struct sockaddr *) &sin, sizeof(struct sockaddr)))) {
708 + if (errno != EINPROGRESS) {
709 + logwrite("Error connecting companion socket: %d\n",errno);
710 + killconnection(newfd);
711 + killconnection(companionfd);
716 + setpoll(companionfd, POLLIN|POLLOUT);
718 + /* Set the companion fields up */
719 + ssa[companionfd].companion = newfd;
720 + ssa[newfd].companion = companionfd;
723 + if (events & (POLLERR|POLLHUP|POLLNVAL)) {
724 + /* Something has broken - this shouldn't happen (famous last words)
725 + * but clean up the listen socket */
726 + ssa[fd].type = SST_IDLE;
733 + * openlistenfd(): Creates a listening socket
736 +int openlistenfd(int type, unsigned int listenip, unsigned short listenport,
737 + unsigned int remoteip, unsigned short remoteport) {
738 + struct sockaddr_in sin;
740 + unsigned int opt=1;
742 + if ((fd=socket(AF_INET,SOCK_STREAM,0))==-1) {
743 + logwrite("openlistenfd(): Error creating socket\n");
747 + logwrite("Creating %s listener on %s:%d forwarding to %s:%d\n",
748 + type==SST_LISTEN_COMP ? "compressing" : "decompressing", IPtostr(listenip),listenport,IPtostr(remoteip),remoteport);
751 + logwrite("openlistenfd(): fd out of range - recompile with larger MAXFDS\n");
756 + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *) &opt, sizeof(opt))!=0) {
757 + logwrite("openlistenfd(): Error setting SO_REUSEADDR\n");
762 + /* Initialiase the addresses */
763 + memset(&sin,0,sizeof(sin));
764 + sin.sin_family=AF_INET;
765 + sin.sin_port=htons(listenport);
766 + sin.sin_addr.s_addr=listenip;
768 + if (bind(fd, (struct sockaddr *) &sin, sizeof(sin))) {
769 + logwrite("openlistenfd(): Unable to bind socket.\n");
774 + opt = LISTEN_RECVBUF;
775 + if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char*) &opt, sizeof(opt))) {
776 + logwrite("openlistenfd(): Error setting socket buffer size.\n");
779 + if (listen(fd,5)) {
780 + logwrite("openlistenfd(): Unable to listen.\n");
785 + /* Now do the specific setup - only the following fields are relevant for listeners */
786 + ssa[fd].type = type;
787 + ssa[fd].listenaddr = listenip;
788 + ssa[fd].listenport = listenport;
789 + ssa[fd].remoteaddr = remoteip;
790 + ssa[fd].remoteport = remoteport;
791 + ssa[fd].marker = 1;
793 + setpoll(fd, POLLIN);
799 + * parseconfig(): Reads the config file, setting up and destroying listeners as necessary
802 +int parseconfig(const char *filename) {
803 + validip *vip, *nvip;
807 + unsigned int ip1,ip2;
808 + unsigned short port1, port2;
810 + struct hostent *hep;
814 + /* Check that we can open the file before we blow away the old state.. */
815 + if (!(fp=fopen(filename,"r"))) {
816 + logwrite("parseconfig(): Can't open config file!\n");
820 + /* Clear out the list of trusted IPs */
821 + for (vip=okhosts;vip;vip=nvip) {
827 + /* Clear all markers */
828 + for (i=0;i<MAXFDS;i++) {
833 + fgets(buf, 512, fp);
838 + /* Check for valid config types.. */
841 + logwrite("parseconfig(): malformed config line %s\n",buf);
845 + for (cp=buf+2;*cp;cp++) {
852 + hep=gethostbyname(buf+2);
853 + if (hep && hep->h_addr) {
854 + vip=malloc(sizeof(struct validip));
855 + vip->IPaddress=*(unsigned int *)hep->h_addr;
859 + logwrite("parseconfig(): unable to parse: %s\n",buf+2);
863 + if (*buf=='p' || *buf=='P') {
864 + type=(*buf=='p'?SST_LISTEN_DECOMP:SST_LISTEN_COMP);
867 + logwrite("parseconfig(): malformed config line %s\n",buf);
871 + /* P:212.115.48.227:4480:212.115.48.164:4410 */
873 + for (cp=buf+2;*cp && *cp!=':';cp++);
875 + logwrite("parseconfig(): malformed config line %s\n",buf);
880 + hep=gethostbyname(cp2);
881 + if (!hep || !(ip1=*(unsigned int *)hep->h_addr)) {
882 + logwrite("parseconfig(): Invalid host %s\n",cp2);
886 + if (!(port1=strtol(cp, &cp, 10))) {
887 + logwrite("parseconfig(): Invalid config line\n");
892 + logwrite("parseconfig(): Malformed config line\n");
897 + for (;*cp && *cp!=':';cp++);
899 + logwrite("parseconfig(): malformed config line.\n");
904 + hep=gethostbyname(cp2);
905 + if (!hep || !(ip2=*((unsigned int *)hep->h_addr))) {
906 + logwrite("parseconfig(): Invalid host %s\n",cp2);
910 + if (!(port2=strtol(cp, &cp, 10))) {
911 + logwrite("parseconfig(): Invalid config line\n");
915 + /* Check for matching listeners.. */
917 + for (i=0;i<MAXFDS;i++) {
918 + if (IsListenSocket(i) && ssa[i].listenaddr==ip1 && ssa[i].listenport==port1 &&
919 + ssa[i].remoteaddr==ip2 && ssa[i].remoteport==port2) {
920 + /* Found one, just set the type (allows p: <-> P: rehashes) */
928 + openlistenfd(type, ip1, port1, ip2, port2);
934 + /* Kill off dead listeners */
935 + for (i=0;i<MAXFDS;i++) {
936 + if (IsListenSocket(i) && ssa[i].marker==0) {
937 + logwrite("Closing extinct listen socket %d\n",i);
939 + ssa[i].type=SST_IDLE;
947 +void handlehup(int x) {
953 + if ((logfd=open(LOGFILE, O_CREAT | O_WRONLY | O_APPEND,00660)) < 0) {
954 + printf("ERROR: can't reopen logfile.\n");
957 + logwrite("Received SIGHUP - reloading config file.\n");
958 + parseconfig(configfile);
962 +int main(int argc, char **argv) {
963 + struct sigaction sa;
965 + struct timezone tz;
968 + sa.sa_handler=handlehup;
969 + sigemptyset(&(sa.sa_mask));
972 + strncpy(configfile, (argc > 1 ? argv[1] : SETTINGSFILE), 511);
975 + sigaction(SIGHUP, &sa, NULL);
976 + sa.sa_handler=SIG_IGN;
977 + sigaction(SIGPIPE, &sa, NULL);
979 + if (parseconfig(configfile)) {
984 + if (!dopoll(POLLTIMEOUT)) {
985 + for (i=0;i<MAXFDS;i++) {
986 + if (ssa[i].dirty==1 && IsActiveSocket(i)) {
987 + /* Flush everything */
992 + while (!dopoll(1000)) {
997 + /* something happened - do a more detailed dirty check */
998 + gettimeofday(&tv, &tz);
999 + for (i=0;i<MAXFDS;i++) {
1000 + if (ssa[i].dirty==1 && IsActiveSocket(i)) {
1001 + if (usecdiff(&(ssa[i].lastoutput), &tv) > FLUSHTIMEOUT) {