5748237 [rkeene@sledge /home/rkeene/devel/old/rutil_tcpcgi-0.1.17]$ cat -n tcpcgi.c
  1 /*
  2     tcpcgi.c -- Client portion of rutil_tcpcgi.
  3     Copyright (C) 2003  Roy Keene
  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     email: tcpcgi@rkeene.org
 20 
 21 */
 22 
 23 /*
 24  * tcpcgi.c -- Local listener part of reverse-utils::TCP-over-HTTP/CGI:
 25  *    This needs to do quite a bit of work in the background.
 26  *
 27  *    It will create a listening socket, upon connection to that socket
 28  *    it will send the proper HTTP request to create the socket on the
 29  *    other end, and wait for an ackowledgement.
 30  *
 31  *    Every second it will query the remote machine for all the sessions
 32  *    that exist and pass the data to the client socket.
 33  *
 34  *    When data arrives, it needs to hex-encode it and put it on the socket.
 35  *               -- Roy Keene [300820031505] <tcpcgi@rkeene.org>    
 36  */
 37 
 38 #include <string.h>
 39 #define _XOPEN_SOURCE_EXTENDED
 40 #include <netinet/in.h>
 41 #include <sys/socket.h>
 42 #include <sys/types.h>
 43 #include <arpa/inet.h>
 44 #include <sys/time.h>
 45 #include <sys/poll.h>
 46 #include <sys/wait.h>
 47 #include <unistd.h>
 48 #include <signal.h>
 49 #include <stdlib.h>
 50 #include <stdio.h>
 51 #include <ctype.h>
 52 #include <fcntl.h>
 53 #include <netdb.h>
 54 #include <errno.h>
 55 #include <time.h>
 56 
 57 #include "tcpcgi.h"
 58 #include "tcpnet.h"
 59 
 60 extern char *optarg;
 61 extern int optind, opterr, optopt;
 62 
 63 
 64 struct sockinfo {
 65     char *session;
 66     char *http_host;
 67     char *http_path;
 68     int http_port;
 69     signed int fd;
 70 };
 71 
 72 int use_post=1;
 73 int local_only=0;
 74 int poll_time_min=TCPCGI_CLIENT_POLLTIME_MIN;
 75 int poll_time_max=TCPCGI_CLIENT_POLLTIME_MAX;
 76 char *userpass=NULL;
 77 char *proxyhost=NULL;
 78 struct sockinfo socks_info[128]; /* Needs to be num of elements as socks_poll in main() */
 79 
 80 
 81 char *mimecode(void *databuf, int datalen) {
 82     unsigned char buffer[3];
 83     unsigned char *data=databuf;
 84     char mimeabet[64]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 85     char *ret;
 86     int outlen, retlen;
 87     int i,x=0;
 88 
 89     outlen=(int) ((((double) datalen)*1.3333333)+0.9);
 90     retlen=((int) ((((double) datalen)/3.00)+0.9))*4;
 91     ret=malloc(retlen+1);
 92 
 93     for (i=0; i<datalen; i+=3) {
 94         buffer[0]=data[i];
 95         buffer[1]=data[i+1];
 96         buffer[2]=data[i+2];
 97         ret[x++]=mimeabet[((buffer[0]&0xfc)>>2)%sizeof(mimeabet)];
 98         if (x>=outlen) break;
 99         ret[x++]=mimeabet[(((buffer[0]&0x3)<<4)|((buffer[1]&0xf0)>>4))%sizeof(mimeabet)];
100         if (x>=outlen) break;
101         ret[x++]=mimeabet[(((buffer[1]&0xf)<<2)|((buffer[2]&0xc0)>>6))%sizeof(mimeabet)];
102         if (x>=outlen) break;
103         ret[x++]=mimeabet[(buffer[2]&0x3f)%sizeof(mimeabet)];
104         if (x>=outlen) break;
105     }
106     while (x!=retlen) ret[x++]='=';
107     ret[x]='\0';
108     return(ret);
109 }
110 
111 char *hexcode(void *data, int datalen) {
112     char hexabet[]="0123456789abcdef";
113     unsigned char *data_num=data;
114     char *ret;
115     int i, destpos=0;
116 
117     if (data==NULL || datalen==0) return(strdup(""));
118 
119     ret=malloc(datalen*3+1);
120 
121     for (i=0; i<datalen; i++) {
122         if (data_num[i]==' ') {
123             ret[destpos++]='+';
124             continue;
125         }
126 #if 1
127         /* if it's a nonprintable charectar, or [%?@&=+: ], convert it */
128         if (!isgraph(data_num[i]) || data_num[i]==' ' || \
129         data_num[i]=='&' || data_num[i]=='=' || \
130         data_num[i]==':' || data_num[i]=='@' || \
131         data_num[i]=='?' || data_num[i]=='%' || \
132         data_num[i]=='+' || data_num[i]=='#') {
133 #else
134         /* If the charectar is not alphanumeric or and not [+./-], convert it to hex. */
135         if (!isalnum(data_num[i]) && data_num[i]!='/' && data_num[i]!='.' && data_num[i]!='~' && data_num[i]!='+') {
136 #endif
137             ret[destpos++]='#';
138             ret[destpos++]=hexabet[(data_num[i]>>4)&0xf];
139             ret[destpos++]=hexabet[data_num[i]&0xf];
140             continue;
141         }
142         /* Otherwise, we just copy it over. */
143         ret[destpos++]=data_num[i];
144     }
145     ret[destpos]='\0';
146 
147 #ifdef PARANOID
148     ret=realloc(ret, strlen(ret)+1);
149 #endif
150     return(ret);
151 }
152 
153 void *tcpcgi_getdata(char *http_host, int http_port, char *http_path, char *http_userpass, char *cmd, char *session,
	char *dest, void *data, int *datalen, signed int *status, int proto_type) {
154     FILE *fp;
155     char *hex_cmd=NULL, *hex_session=NULL, *hex_data=NULL, *hex_path=NULL, *hex_host=NULL;
156     char *host=NULL, *port_str=NULL, *hostport;
157     char *http_auth=NULL;
158     char http_realhost[1024], *http_realport_tmp;
159     char buf[8192], *retbuf=NULL;
160     int fd;
161     int sink=0;
162     int datalen_val;
163     int http_authlen=0;
164     int http_realport=http_port;
165     unsigned int datalen_loc;
166 
167     PRINTERR("Entering tcpcgi_getdata()");
168     if (http_host==NULL || http_path==NULL || cmd==NULL || session==NULL) {
169         PRINTERR("Invalid parameters passed.");
170         if (status) *status=-1;
171         return(NULL);
172     }
173 
174     datalen_val=(datalen)?(*datalen):(0);
175     /* Need to free the hex_* variables past this point. */
176     hex_cmd=hexcode(cmd, strlen(cmd)); /* Guarenteed not NULL */
177     hex_session=hexcode(session, strlen(session)); /* Guarenteed not NULL */
178     hex_path=hexcode(http_path, strlen(http_path)); /* Guarenteed not NULL */
179     hex_data=hexcode(data, datalen_val);
180     if (dest) {
181         hostport=strdup(dest);
182         /* Parse the host:port value into two seperate variables */
183         port_str=strchr(hostport, ':');
184         if (!port_str) {
185             PRINTERR("Unable to parse destination.");
186             if (status) *status=-1;
187             if (hex_cmd) free(hex_cmd);
188             if (hex_session) free(hex_session);
189             if (hex_data) free(hex_data);
190             if (hex_path) free(hex_path);
191             return(NULL);
192         }
193         *port_str=0;
194         port_str++;
195         host=hostport;
196         hex_host=hexcode(host, strlen(host));
197     }
198 
199     if (proxyhost) {
200         /* This will cause a slow, steady memory leak ... */
201         strcpy(http_realhost, proxyhost);
202         http_realport_tmp=strchr(http_realhost, ':');
203         if (http_realport_tmp) {
204             *http_realport_tmp='\0';
205             http_realport=atoi(http_realport_tmp+1);
206         } else {
207             http_realport=http_port;
208         }
209     } else {
210         strcpy(http_realhost, http_host);
211         http_realport=http_port;
212     }
213     PRINTERR("Creating connection to \"%s\" on port %i", http_realhost, http_realport);
214 
215     fd=createconnection_tcp(http_realhost, http_realport);
216 
217     if (fd<0) {
218         PERROR("connect");
219         PRINTERR("Couldn't connect!");
220         if (status) *status=-1;
221         if (hex_cmd) free(hex_cmd);
222         if (hex_session) free(hex_session);
223         if (hex_data) free(hex_data);
224         if (hex_host) free(hex_host);
225         if (hex_path) free(hex_path);
226         return(NULL);
227     }
228     fp=fdopen(fd, "r+");
229     if (!fp) {
230         PERROR("fdopen");
231         if (status) *status=-1;
232         if (http_auth[0]!='\0') free(http_auth);
233         if (hex_cmd) free(hex_cmd);
234         if (hex_session) free(hex_session);
235         if (hex_data) free(hex_data);
236         if (hex_host) free(hex_host);
237         if (hex_path) free(hex_path);
238         return(NULL);
239     }
240 
241     if (http_userpass) {
242         http_authlen=128+strlen(http_userpass);
243         http_auth=malloc(http_authlen);
244         snprintf(http_auth, http_authlen, "Authorization: Basic %s\r\n", http_userpass);
245     } else {
246         http_auth="";
247     }
248 
249     snprintf(buf, sizeof(buf), "action=%s&id=%s&host=%s&port=%s&data=%s&datalen=%i&ts=%i&proto=%s", hex_cmd,
	hex_session, hex_host, port_str, hex_data, datalen_val, (unsigned int) time(NULL),
	(proto_type==SOCK_DGRAM)?"udp":"tcp");
250 
251 
252     buf[sizeof(buf)-1]='\0';
253     if (use_post) {
254         fprintf(fp, "POST %s HTTP/1.0\r\nHost: %s:%i\r\n%sContent-length: %i\r\n\r\n%s\r\n", hex_path, http_host,
	http_port, http_auth, (int) strlen(buf), buf);
255         PRINTERR("POST http://%s:%i%s?[%i]%s HTTP/1.0\n", http_host, http_port, hex_path, (int) strlen(buf), buf);
256     } else {
257         fprintf(fp, "GET %s:%i?%s HTTP/1.0\r\nHost: %s:%i\r\n%s\r\n", hex_path, http_port, buf, http_host, http_port,
	http_auth);
258         PRINTERR("GET http://%s:%i%s?[%i]%s HTTP/1.0\n", http_host, http_port, hex_path, (int) strlen(buf), buf);
259     }
260     fflush(fp);
261 
262     if (status) *status=0;
263     if (datalen) *datalen=0;
264     PRINTERR("Scheduling panic alarm.");
265     alarm(120); /* In case of emergency, please panic. */
266     if (fgets(buf, sizeof(buf), fp)==NULL) {
267         if (http_auth[0]!='\0') free(http_auth);
268         if (hex_cmd) free(hex_cmd);
269         if (hex_session) free(hex_session);
270         if (hex_data) free(hex_data);
271         if (hex_host) free(hex_host);
272         if (hex_path) free(hex_path);
273         fclose(fp);
274         return(NULL);
275     }
276     PRINTERR("Unscheduling panic alarm.");
277     alarm(0); /* Panic no more. */
278     if (strstr(buf," 40")) {
279         PRINTERR("File not available error, %s", buf);
280         if (http_auth[0]!='\0') free(http_auth);
281         if (hex_cmd) free(hex_cmd);
282         if (hex_session) free(hex_session);
283         if (hex_data) free(hex_data);
284         if (hex_host) free(hex_host);
285         if (hex_path) free(hex_path);
286         fclose(fp);
287         return(NULL);
288     }
289     if (!strstr(buf, " 200 ")) {
290         PRINTERR("Invalid response, %s", buf);
291         if (http_auth[0]!='\0') free(http_auth);
292         if (hex_cmd) free(hex_cmd);
293         if (hex_session) free(hex_session);
294         if (hex_data) free(hex_data);
295         if (hex_host) free(hex_host);
296         if (hex_path) free(hex_path);
297         sleep(1); /* Primitive backoff */
298         fclose(fp);
299         return(tcpcgi_getdata(http_host, http_port, http_path, http_userpass, cmd, session, dest, data, datalen, status,
	SOCK_STREAM));
300     }
301     PRINTERR("Scheduling panic alarm.");
302     alarm(240); /* In case of emergency, please panic. */
303     while (1) {
304         if (fgets(buf, sizeof(buf), fp)==NULL) break;
305         while (buf[strlen(buf)-1]<' ' && buf[0]!='\0') buf[strlen(buf)-1]='\0';
306         /* On the first blank line, assume the HTTP headers have ended. */
307         if (buf[0]=='\0' && !sink) {
308             sink=1; /* Only come here once. */
309             if (fgets(buf, sizeof(buf), fp)==NULL) break;
310             PRINTERR("statusmsg=%s", buf);
311             if (strstr(buf, "stat: FAIL -")!=NULL) {
312                 PRINTERR("Setting status to -ERR");
313                 if (status) *status=-1;
314             }
315             datalen_loc=(fgetc(fp))<<8;
316             datalen_loc|=fgetc(fp);
317             if (datalen_loc>16384) continue;
318             if (datalen_loc) {
319                 PRINTERR("Now expecting %i bytes of data.", datalen_loc);
320                 retbuf=malloc(datalen_loc);
321                 datalen_loc=fread(retbuf, 1, datalen_loc, fp);
322                 PRINTERR("[%i](omitted)", datalen_loc);
323             }
324             if (datalen) *datalen=datalen_loc;
325             PRINTERR("We got all that we want, let's get outta here.");
326             break;
327         }
328         PRINTERR("buf=%s", buf);
329     }
330     PRINTERR("Unscheduling panic alarm.");
331     alarm(0);
332 
333     fclose(fp);
334     if (http_auth[0]!='\0') free(http_auth);
335     if (hex_cmd) free(hex_cmd);
336     if (hex_session) free(hex_session);
337     if (hex_data) free(hex_data);
338     if (hex_host) free(hex_host);
339     if (hex_path) free(hex_path);
340     return(retbuf);
341 }
342 
343 char *tcpcgi_gensess(void) {
344     static char ret[12]={0,0,0,0,0,0,0,0,0,0,0,0};
345     signed int i=0;
346     char alphabet[]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
347     int j;
348 
349     srand(time(NULL)+ret[0]+ret[1]);
350     for (i=0; i<sizeof(ret); i++) {
351         j=rand()%(sizeof(alphabet)-1);
352         if (alphabet[j]=='\0' && i==0) { i--; continue; } /* Don't generate an empty session. */
353         ret[i]=alphabet[j];
354     }
355     ret[sizeof(ret)-1]='\0';
356     return(ret);
357 }
358 
359 void tcpcgi_closesession(int fd, char *http_host, int http_port, char *http_path, char *session) {
360     if (!session || fd<0) return;
361     PRINTERR("Terminating session \"%s\".", session);
362 
363     tcpcgi_getdata(http_host, http_port, http_path, userpass, "close", session, NULL, NULL, NULL, NULL, 0);
364     return;
365 }
366 
367 /*
368  * Return values here:
369  *    -1  (error)
370  *    0   (no error, but no data was recvd)
371  *    1   (no error, data recv)
372  */
373 int tcpcgi_handledata(char *http_host, int http_port, char *http_path, char *session, int proto_type, char *dest, int
	fd, void *buf, int datalen) {
374     unsigned char *ret;
375     unsigned char *lbuf=buf;
376     char *cmd;
377     int status=0;
378     int dataretlen;
379     int rv;
380 
381     while (datalen>1024) {
382         if ((rv=tcpcgi_handledata(http_host, http_port, http_path, session, proto_type, dest, fd, lbuf, 1024))<0) {
383             return(rv);
384         }
385         datalen-=1024;
386         lbuf+=1024;
387     }
388 
389     if (lbuf && datalen!=0) {
390         cmd="write";
391         dataretlen=datalen;
392     } else {
393         cmd="read";
394         dataretlen=0;
395     }
396 
397     ret=tcpcgi_getdata(http_host, http_port, http_path, userpass, cmd, session, dest, lbuf, &dataretlen, &status,
	proto_type);
398     PRINTERR("[%i](omitted, again)", dataretlen);
399     if (dataretlen>0 && ret && status>=0) {
400         write(fd, ret, dataretlen);
401         free(ret);
402         status=1;
403     }
404 
405     PRINTERR("Returning %i", status);
406     return(status);
407 }
408 
409 
410 
411 int handle_background(void) {
412     int i;
413     char *http_host, *http_path, *session;
414     int fd, http_port;
415     int ret=0;
416     int rv;
417 
418     for (i=0; i<(sizeof(socks_info)/sizeof(struct sockinfo)); i++) {
419         if (socks_info[i].fd<0) continue;
420         http_host=socks_info[i].http_host;
421         http_port=socks_info[i].http_port;
422         http_path=socks_info[i].http_path;
423         session=socks_info[i].session;
424         fd=socks_info[i].fd;
425         if ((rv=tcpcgi_handledata(http_host, http_port, http_path, session, SOCK_STREAM, NULL, fd, NULL, 0))<0) {
426             PRINTERR("[fd=%i] We got an error in the background and we don't know how to handle it!", fd);
427             close(fd);
428             continue;
429         }
430         if (rv>0) ret++;
431     }
432     return(ret);
433 }
434 
435 void sighandler(int sig) {
436     if (sig==SIGALRM) {
437         PRINTERR("Recieved SIGALRM!");
438         return;
439     }
440     PRINTERR("Recieved weird signal %i", sig);
441 }
442 
443 int print_help(char *msg) {
444     fprintf(stderr, "Usage: tcpcgi -H host -f file -d dest [-P port] [-p port] [-m time]\n");
445     fprintf(stderr, "              [-x time] [-t time] [-b amt] [-V proxy] [-U user] [-rigluvh]\n");
446     fprintf(stderr, "    Options:\n");
447     fprintf(stderr, "         -H host      HTTP Server which has tcpcgi.cgi.\n");
448     fprintf(stderr, "         -f file      Full URL-relative on HTTP server to tcpcgi.cgi,\n");
449     fprintf(stderr, "                      including tcpcgi.cgi.\n");
450     fprintf(stderr, "         -d dest      Destination to for HTTP server to connect to and\n");
451     fprintf(stderr, "                      proxy to (must be in the form of host:port).\n");
452     fprintf(stderr, "         -P port      Port to connect to HTTP server on.\n");
453     fprintf(stderr, "         -p port      Port to listen for connections on locally (%i is\n", TCPCGI_CLIENT_PORT);
454     fprintf(stderr, "                      the default).\n");
455     fprintf(stderr, "         -m time      Lowest amount of time (in milliseconds) to check for\n");
456     fprintf(stderr, "                      data from HTTP server (%i is the default).\n", TCPCGI_CLIENT_POLLTIME_MIN);
457     fprintf(stderr, "         -x time      Greatest amount of time (in milliseconds) to check\n");
458     fprintf(stderr, "                      for data from HTTP server (%i is the default).\n",
	TCPCGI_CLIENT_POLLTIME_MAX);
459     fprintf(stderr, "         -t time      Specify that the amount of time for polling be fixed\n");
460     fprintf(stderr, "                      at this value (in ms).\n");
461     fprintf(stderr, "         -b amt       Backoff amount, if less than 5, specifies backoff\n");
462     fprintf(stderr, "                      should multiply the backoff time by this number,\n");
463     fprintf(stderr, "                      otherwise it's incremented by this amount (2 is the\n"); 
464     fprintf(stderr, "                      default).\n");
465     fprintf(stderr, "         -V proxy     Specify a host to send all HTTP traffic through.\n");
466     fprintf(stderr, "         -U user      Username and password to use for http authentication\n");
467     fprintf(stderr, "                      (must be in the form of user:pass).\n");
468     fprintf(stderr, "         -r           Specify that the backoff algorithm reset when remote\n");
469     fprintf(stderr, "                      activity occurs, instead of decrementing.\n");
470     fprintf(stderr, "         -i           Specify that the backoff algorithm should respond to\n");
471     fprintf(stderr, "                      local traffic as well as remote.\n");
472     fprintf(stderr, "         -g           Toggle between HTTP get and HTTP post (%s is\n", use_post?"POST":"GET");
473     fprintf(stderr, "                      the default).\n");
474     fprintf(stderr, "         -l           Bind to %s only for listening (%s is the\n", local_only?"ALL":"LOCALHOST",
	local_only?"LOCAL":"ALL");
475     fprintf(stderr, "                      default).\n");
476     fprintf(stderr, "         -u           Use UDP instead of TCP.\n");
477     fprintf(stderr, "         -v           Print version (%s) and exit.\n", TCPCGI_VERSION);
478     fprintf(stderr, "         -h           This help information.\n");
479     if (msg) {
480         fprintf(stderr, "\ntcpcgi: %s\n", msg);
481     }
482     return(1);
483 }
484 
485 #ifdef CLOSE_POLL
486 #undef CLOSE_POLL
487 #endif
488 #define CLOSE_POLL(idx) { \
489     if (idx!=0) { \
490         tcpcgi_closesession(socks_poll[idx].fd, http_host, http_port, http_path, socks_info[idx].session); \
491         close(socks_poll[idx].fd); \
492         socks_poll[idx].fd=-1; \
493         socks_info[idx].fd=-1; \
494         pollcnt--; \
495         pollpos=idx; \
496     } \
497 }
498 int main(int argc, char **argv) {
499     struct pollfd socks_poll[sizeof(socks_info)/sizeof(struct sockinfo)];
500     struct sockaddr_in *addr;
501     struct sigaction sac;
502     signed int pollpos=0;
503     signed int status=0;
504     signed int ch;
505     char buf[8192];
506     char *http_host=NULL, *http_path=NULL;
507     char *hostport=NULL;
508     char udp_sess_wrk[128], *udp_sess, *socks_sess;
509     socklen_t addrlen;
510     sigset_t s;
511     int masterfd, fd, clientfd;
512     int pollcnt=0, pollmax;
513     int num_events;
514     int errcnt=0;
515     int i,x, rv;
516     int listen_port=TCPCGI_CLIENT_PORT;
517     int poll_time=200; /* Start out with a reasonably fast poll_time. */
518     int poll_backoff=2;
519     int poll_backoff_reset=0, poll_backoff_ireset=0;
520     int http_port=80;
521     int proto_type=SOCK_STREAM;
522 #ifndef DEBUG
523     pid_t chpid;
524 #endif
525 
526     while ((ch=getopt(argc, argv, "H:f:P:p:d:m:x:t:b:V:U:vgriulh"))!=-1) {
527         switch (ch) {
528             case 'H':
529                 http_host=strdup(optarg);
530                 break;
531             case 'f':
532                 if (optarg[0]!='/') return(print_help("File should begin with a `/\'"));
533                 http_path=strdup(optarg);
534                 break;
535             case 'P':
536                 http_port=atoi(optarg);
537                 if (http_port<=0) return(print_help("Port cannot be <= 0."));
538                 break;
539             case 'p':
540                 listen_port=atoi(optarg);
541                 if (listen_port<=0) return(print_help("Port cannot be <= 0."));
542                 break;
543             case 'd':
544                 hostport=strdup(optarg);
545                 if (strchr(hostport,':')==NULL) return(print_help("Destination must be in the form of host:port"));
546                 break;
547             case 'm':
548                 poll_time_min=atoi(optarg);
549                 if (poll_time_min<=0) return(print_help("Polltime min cannot be <= 0."));
550                 if (poll_time<poll_time_min) poll_time=poll_time_min;
551                 break;
552             case 'x':
553                 poll_time_max=atoi(optarg);
554                 if (poll_time_max<=0) return(print_help("Polltime max cannot be <= 0."));
555                 if (poll_time>poll_time_max) poll_time=poll_time_max;
556                 break;
557             case 't':
558                 poll_time=poll_time_max=poll_time_min=atoi(optarg);
559                 if (poll_time_max<=0) return(print_help("Polltime cannot be <= 0."));
560                 break;
561             case 'b':
562                 poll_backoff=atoi(optarg);
563                 if (poll_backoff<=0) return(print_help("Poll backoff cannot be <= 0."));
564                 break;
565             case 'r':
566                 poll_backoff_reset=!poll_backoff_reset;
567                 break;
568             case 'i':
569                 poll_backoff_ireset=!poll_backoff_ireset;
570                 break;
571             case 'g':
572                 use_post=!use_post;
573                 break;
574             case 'v':
575                 printf("Reverse utilities::TCP-over-HTTP/CGI v%s\n", TCPCGI_VERSION);
576                 return(0);
577                 break;
578             case 'l':
579                 local_only=!local_only;
580                 break;
581             case 'u':
582                 proto_type=(proto_type==SOCK_STREAM)?SOCK_DGRAM:SOCK_STREAM;
583                 break;
584             case 'U':
585                 userpass=mimecode(optarg, strlen(optarg));
586                 break;
587             case 'V':
588                 proxyhost=strdup(optarg);
589                 break;
590             case ':':
591             case '?':
592             case 'h':
593                 return(print_help(NULL));
594                 break;
595         }
596     }
597 
598     /* Basic sanity checks for supplied args */
599     if (http_host==NULL || http_path==NULL) {
600         return(print_help("You must specify the HOST (-H) and FILE (-f) options."));
601     }
602     if (http_path[0]!='/') {
603         return(print_help("File should begin with a `/\'"));
604     }
605     if (hostport==NULL) {
606         return(print_help("You must specify the DEST (-d) option."));
607     }
608     if (poll_time_max<poll_time_min) {
609         return(print_help("Polltime max cannot be less than polltime min."));
610     }
611 
612     sigemptyset(&s);
613     sigaddset(&s, SIGALRM);
614     sac.sa_handler=sighandler;
615     sac.sa_mask=s;
616     sac.sa_flags=0;
617     sigaction(SIGALRM, &sac, NULL);
618 
619     signal(SIGPIPE, SIG_IGN);
620     masterfd=createlisten(listen_port, local_only, proto_type);
621     if (masterfd<0) {
622         PERROR("createlisten()");
623         return(1);
624     }
625 
626 #ifndef DEBUG
627     /* We're all out of complaints at this point, and should be ready to go in the background. */
628     if ((chpid=fork())<0) { PERROR("fork"); return(1); }
629     if (chpid!=0) {
630         /* Parent */
631         wait(NULL);
632         return(0);
633     }
634     /* Child */
635     if ((chpid=fork())<0) { return(1); }
636     if (chpid!=0) return(0);
637     /* Grand-child */
638     setsid();
639 #endif
640 
641     for (i=0; i<(sizeof(socks_poll)/sizeof(struct pollfd)); i++) socks_poll[i].fd=-1;
642     for (i=0; i<(sizeof(socks_info)/sizeof(struct sockinfo)); i++) {
643         socks_info[i].session=NULL;
644         socks_info[i].fd=-1;
645     }
646     socks_poll[pollpos].fd=masterfd;
647     socks_poll[pollpos].events=POLLIN;
648     socks_poll[pollpos].revents=0;
649     pollpos++;
650     pollcnt++;
651 
652     addrlen=sizeof(struct sockaddr_in);
653     addr=malloc(addrlen);
654 
655     while (1) {
656         for (i=0; i<(sizeof(socks_poll)/sizeof(struct pollfd)); i++) {
657             if (socks_poll[i].fd!=-1) pollmax=(i+1);
658         }
659 
660         num_events=poll(socks_poll, pollmax, (pollcnt>1)?(poll_time):(-1));
661         if (num_events<0) {
662             if (errcnt==TCPCGI_DAEMON_MAXERR) {
663                 fprintf(stderr, "Maximum error count (%i) reached, aborting...\n", TCPCGI_DAEMON_MAXERR);
664                 break;
665             }
666             errcnt++;
667             PERROR("poll()");
668             continue;
669         }
670         errcnt=0;
671         if (num_events==0) {
672             /* If we just have the listening socket in our poll group, don't adjust polltime */
673             if (pollcnt==1) continue;
674 
675             /* Check background activity, and adjust polltime if needed. */
676             if (handle_background()==0) {
677                 /* If nothing is happening in the background, slow down. */
678                 if (poll_backoff<5) { poll_time*=poll_backoff; } else { poll_time+=poll_backoff; }
679                 PRINTERR("Lengthening polltime [poll_time=%i], nothing is happening.", poll_time);
680             } else {
681                 /* If we're active in the background, speed up! */
682                 if (poll_backoff<5) { poll_time/=poll_backoff; } else { poll_time-=poll_backoff; }
683                 if (poll_backoff_reset) poll_time=poll_time_min;
684                 PRINTERR("Shortening polltime [poll_time=%i], stuff is happening.", poll_time);
685             }
686             if (poll_time>poll_time_max) poll_time=poll_time_max;
687             if (poll_time<poll_time_min) poll_time=poll_time_min;
688             continue;
689         }
690         for (i=0; i<pollmax; i++) {
691             if (socks_poll[i].revents&(POLLERR|POLLHUP|POLLNVAL)) {
692                 /* Socket is broke, close it. */
693                 CLOSE_POLL(i);
694                 PRINTERR("Closing socket [idx=%i, fd=%i], due to errors.", i, fd);
695                 num_events--;
696                 if (num_events==0) break;
697                 continue;
698             }
699             if ((socks_poll[i].revents&POLLIN)!=POLLIN) continue; 
700             num_events--;
701             fd=socks_poll[i].fd;
702             socks_poll[i].events=POLLIN;
703             socks_poll[i].revents=0;
704             /*
705                This is special for UDP, since 
706                it will never have a connection
707                we have just guess at this by
708                the existance (or lack of...)
709                a session with a generated name
710             */
711             if (proto_type==SOCK_DGRAM) {
712                 PRINTERR("Incoming UDP ...");
713                 if (fd!=masterfd) {
714                     PRINTERR("... not from master?! IGNORING!");
715                     continue;
716                 }
717                 addrlen=sizeof(struct sockaddr_in);
718                 recvfrom(fd, buf, 5, MSG_PEEK, (struct sockaddr *)addr, &addrlen);
719                 memcpy(udp_sess_wrk, &addr->sin_port, 2);
720                 memcpy(udp_sess_wrk+2, &addr->sin_addr.s_addr, sizeof(addr->sin_addr.s_addr));
721                 udp_sess=hexcode(udp_sess_wrk, 2+sizeof(addr->sin_addr.s_addr));
722                 PRINTERR("Session name is .. %s", udp_sess);
723             }
724             if (fd==masterfd && proto_type!=SOCK_DGRAM) {
725                 /* Handle incoming connection. */
726                 PRINTERR("New connection...");
727                 addrlen=sizeof(struct sockaddr_in);
728                 clientfd=accept(fd, (struct sockaddr *)addr, &addrlen);
729                 if (clientfd<0) {
730                     PERROR("accept");
731                     continue;
732                 }
733                 if (pollpos==-1) {
734                     for (x=0; x<pollmax; x++) {
735                         if (socks_poll[x].fd==-1) {
736                             pollpos=x;
737                             break;
738                         }
739                     }
740                 }
741                 if (pollpos==-1) pollpos=pollmax;
742                 if (pollpos>=(sizeof(socks_poll)/sizeof(struct pollfd))) {
743                     PRINTERR("Ran out of available socks_poll[] entries.");
744                     close(fd);
745                     continue;
746                 }
747                 socks_poll[pollpos].fd=clientfd;
748                 socks_poll[pollpos].events=POLLIN|POLLERR|POLLHUP|POLLNVAL;
749                 socks_poll[pollpos].revents=0;
750                 pollcnt++;
751 
752                 /* Create session */
753                 socks_info[pollpos].session=strdup(tcpcgi_gensess());
754                 socks_info[pollpos].http_port=http_port;
755                 socks_info[pollpos].http_host=http_host;
756                 socks_info[pollpos].http_path=http_path;
757                 tcpcgi_getdata(http_host, http_port, http_path, userpass, "open", socks_info[pollpos].session, hostport,
	NULL, NULL, &status, proto_type);
758                 if (status<0) {
759                     PRINTERR("Error creating session on remote end.");
760                     CLOSE_POLL(pollpos);
761                     continue;
762                 }
763 
764                 /* This needs to be the last step, it actually registers the session for updates. */
765                 socks_info[pollpos].fd=clientfd;
766 
767 
768                 PRINTERR("... from [idx=%i, fd=%i], pollcnt=%i, pollmax=%i: session=%s", pollpos, clientfd, pollcnt,
	pollmax, socks_info[pollpos].session);
769                 pollpos=-1;
770                 if (num_events==0) break;
771                 continue;
772             }
773             /* Handle data from an existing connection. */
774             PRINTERR("Data waiting on [idx=%i, fd=%i]...", i, fd);
775             x=read(fd, buf, sizeof(buf));
776             PRINTERR(".. not anymore, we read %i bytes.", x);
777             if (x<0) PERROR("read");
778             if (x==0) {
779                 PRINTERR("EOF from [idx=%i, fd=%i].", i, fd);
780                 CLOSE_POLL(i);
781                 continue;
782             }
783             if (proto_type==SOCK_DGRAM) {
784                 socks_sess=udp_sess;
785             } else {
786                 socks_sess=socks_info[i].session;
787             }
788 
789             /* Do the actual transmission */
790             if ((rv=tcpcgi_handledata(http_host, http_port, http_path, socks_sess, proto_type, hostport, fd, buf, x))<0)
	{
791                 PRINTERR("Unable to put data.");
792                 CLOSE_POLL(i);
793                 continue;
794             }
795             if (poll_backoff_ireset) {
796                 /* Check background activity, and adjust polltime if needed. */
797                 if (handle_background()==0) {
798                     /* If nothing is happening in the background, slow down. */
799                     if (poll_backoff<5) { poll_time*=poll_backoff; } else { poll_time+=poll_backoff; }
800                     PRINTERR("Lengthening polltime [poll_time=%i], nothing is happening.", poll_time);
801                 } else {
802                     /* If we're active in the background, speed up! */
803                     if (poll_backoff<5) { poll_time/=poll_backoff; } else { poll_time-=poll_backoff; }
804                     if (poll_backoff_reset) poll_time=poll_time_min;
805                     PRINTERR("Shortening polltime [poll_time=%i], stuff is happening.", poll_time);
806                 }
807                 if (poll_time>poll_time_max) poll_time=poll_time_max;
808                 if (poll_time<poll_time_min) poll_time=poll_time_min;
809             }
810             if (num_events==0) break;
811         }
812     }
813     return(errcnt);
814 }
5748238 [rkeene@sledge /home/rkeene/devel/old/rutil_tcpcgi-0.1.17]$

Click here to go back to the directory listing.
Click here to download this file.
last modified: 2004-01-01 16:22:42