/[LeafOK_CVS]/pvpgn-1.7.4/src/bnproxy/bnproxy.c
ViewVC logotype

Annotation of /pvpgn-1.7.4/src/bnproxy/bnproxy.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1 - (hide annotations)
Tue Jun 6 03:41:37 2006 UTC (19 years, 9 months ago) by sysadm
CVS Tags: pvpgn_1-7-4-0_MIL
Branch point for: GNU, MAIN
Content type: text/x-csrc
Initial revision

1 sysadm 1.1 /*
2     * Copyright (C) 1999,2000 Ross Combs (rocombs@cs.nmsu.edu)
3     *
4     * This program is free software; you can redistribute it and/or
5     * modify it under the terms of the GNU General Public License
6     * as published by the Free Software Foundation; either version 2
7     * of the License, or (at your option) any later version.
8     *
9     * This program is distributed in the hope that it will be useful,
10     * but WITHOUT ANY WARRANTY; without even the implied warranty of
11     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12     * GNU General Public License for more details.
13     *
14     * You should have received a copy of the GNU General Public License
15     * along with this program; if not, write to the Free Software
16     * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17     */
18     #include "common/setup_before.h"
19     #include <stdio.h>
20     #ifdef HAVE_STDDEF_H
21     # include <stddef.h>
22     #else
23     # ifndef NULL
24     # define NULL ((void *)0)
25     # endif
26     #endif
27     #ifdef STDC_HEADERS
28     # include <stdlib.h>
29     #endif
30     #include "compat/exitstatus.h"
31     #ifdef HAVE_UNISTD_H
32     # include <unistd.h>
33     #endif
34     #include "compat/stdfileno.h"
35     #ifdef HAVE_FCNTL_H
36     # include <fcntl.h>
37     #else
38     # ifdef HAVE_SYS_FILE_H
39     # include <sys/file.h>
40     # endif
41     #endif
42     #ifdef HAVE_STRING_H
43     # include <string.h>
44     #else
45     # ifdef HAVE_STRINGS_H
46     # include <strings.h>
47     # endif
48     #endif
49     #ifdef HAVE_MEMORY_H
50     # include <memory.h>
51     #endif
52     #include "compat/memset.h"
53     #include "compat/memcpy.h"
54     #include <ctype.h>
55     #include <errno.h>
56     #include "compat/strerror.h"
57     #ifdef TIME_WITH_SYS_TIME
58     # include <sys/time.h>
59     # include <time.h>
60     #else
61     # ifdef HAVE_SYS_TIME_H
62     # include <sys/time.h>
63     # else
64     # include <time.h>
65     # endif
66     #endif
67     #ifdef HAVE_SYS_TYPES_H
68     # include <sys/types.h>
69     #endif
70     #ifdef HAVE_SYS_SELECT_H
71     # include <sys/select.h>
72     #endif
73     #ifdef HAVE_SYS_SOCKET_H
74     # include <sys/socket.h>
75     #endif
76     #include "compat/socket.h"
77     #include "compat/recv.h"
78     #ifdef HAVE_SYS_PARAM_H
79     # include <sys/param.h>
80     #endif
81     #ifdef HAVE_NETINET_IN_H
82     # include <netinet/in.h>
83     #endif
84     #include "compat/netinet_in.h"
85     #ifdef HAVE_ARPA_INET_H
86     # include <arpa/inet.h>
87     #endif
88     #include "compat/inet_ntoa.h"
89     #ifdef HAVE_NETDB_H
90     # include <netdb.h>
91     #endif
92     #include "compat/psock.h"
93     #include "common/packet.h"
94     #include "common/init_protocol.h"
95     #include "common/hexdump.h"
96     #include "common/eventlog.h"
97     #include "common/bn_type.h"
98     #include "common/queue.h"
99     #include "common/network.h"
100     #include "common/list.h"
101     #include "common/util.h"
102     #include "virtconn.h"
103     #include "common/version.h"
104     #include "common/setup_after.h"
105    
106     FILE * hexstrm=NULL;
107    
108     /* FIXME: This code is horribly unreadable. The UDP stuff is a hack for now. */
109    
110     #define PROXY_FLAG_UDP 1
111    
112    
113     static int init_virtconn(t_virtconn * vc, struct sockaddr_in servaddr);
114     static int proxy_process(unsigned short server_listen_port, struct sockaddr_in servaddr);
115     static void usage(char const * progname);
116    
117    
118     static int init_virtconn(t_virtconn * vc, struct sockaddr_in servaddr)
119     {
120     int addlen;
121     char connect_type;
122    
123     /* determine connection type by first character sent by client */
124     addlen = psock_recv(virtconn_get_client_socket(vc),&connect_type,sizeof(char),0);
125    
126     if (addlen<0 && (psock_errno()==PSOCK_EINTR || psock_errno()==PSOCK_EAGAIN || psock_errno()==PSOCK_EWOULDBLOCK))
127     return 0;
128    
129     /* error occurred or connection lost */
130     if (addlen<1)
131     {
132     eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not get virtconn class (closing connection) (psock_recv: %s)",virtconn_get_client_socket(vc),pstrerror(psock_errno()));
133     return -1;
134     }
135    
136     switch (connect_type)
137     {
138     case CLIENT_INITCONN_CLASS_BNET:
139     eventlog(eventlog_level_info,__FUNCTION__,"[%d] client initiated normal connection",virtconn_get_client_socket(vc));
140     virtconn_set_class(vc,virtconn_class_bnet);
141    
142     break;
143    
144     case CLIENT_INITCONN_CLASS_FILE:
145     eventlog(eventlog_level_info,__FUNCTION__,"[%d] client initiated file download connection",virtconn_get_client_socket(vc));
146     virtconn_set_class(vc,virtconn_class_file);
147    
148     break;
149    
150     case CLIENT_INITCONN_CLASS_BOT:
151     eventlog(eventlog_level_info,__FUNCTION__,"[%d] client initiated chat bot connection",virtconn_get_client_socket(vc));
152     virtconn_set_class(vc,virtconn_class_bot);
153    
154     break;
155    
156     default:
157     eventlog(eventlog_level_error,__FUNCTION__,"[%d] client initiated unknown connection type 0x%02hx (length %d) (closing connection)",virtconn_get_client_socket(vc),(unsigned short)connect_type,addlen);
158     return -1;
159     }
160    
161     /* now connect to the real server */
162     if (psock_connect(virtconn_get_server_socket(vc),(struct sockaddr *)&servaddr,(psock_t_socklen)sizeof(servaddr))<0)
163     {
164     if (psock_errno()!=PSOCK_EINPROGRESS)
165     {
166     eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not connect to server (psock_connect: %s)\n",virtconn_get_client_socket(vc),pstrerror(psock_errno()));
167     return -1;
168     }
169     virtconn_set_state(vc,virtconn_state_connecting);
170     }
171     else
172     virtconn_set_state(vc,virtconn_state_connected);
173    
174     {
175     t_packet * packet;
176    
177     if (!(packet = packet_create(packet_class_raw)))
178     {
179     eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not create packet",virtconn_get_client_socket(vc));
180     return -1;
181     }
182     packet_append_data(packet,&connect_type,1);
183     queue_push_packet(virtconn_get_serverout_queue(vc),packet);
184     packet_del_ref(packet);
185     }
186    
187     return 0;
188     }
189    
190    
191     static int proxy_process(unsigned short server_listen_port, struct sockaddr_in servaddr)
192     {
193     int lsock;
194     struct sockaddr_in laddr;
195     t_psock_fd_set rfds, wfds;
196     int highest_fd;
197     int udpsock;
198     t_virtconn * vc;
199     t_elem const * curr;
200     int csocket;
201     int ssocket;
202    
203     if ((udpsock = psock_socket(PSOCK_PF_INET,PSOCK_SOCK_DGRAM,PSOCK_IPPROTO_UDP))<0)
204     {
205     eventlog(eventlog_level_error,__FUNCTION__,"could not create UDP socket (psock_socket: %s)",pstrerror(psock_errno()));
206     return -1;
207     }
208     if (psock_ctl(udpsock,PSOCK_NONBLOCK)<0)
209     eventlog(eventlog_level_error,__FUNCTION__,"could not set UDP listen socket to non-blocking mode (psock_ctl: %s)",pstrerror(psock_errno()));
210    
211     if ((lsock = psock_socket(PSOCK_PF_INET,PSOCK_SOCK_STREAM,PSOCK_IPPROTO_TCP))<0)
212     {
213     eventlog(eventlog_level_error,__FUNCTION__,"could not create listening socket (psock_socket: %s)",pstrerror(psock_errno()));
214     psock_close(udpsock);
215     return -1;
216     }
217    
218     {
219     int val=1;
220    
221     if (psock_setsockopt(lsock,PSOCK_SOL_SOCKET,PSOCK_SO_REUSEADDR,&val,(psock_t_socklen)sizeof(int))<0)
222     eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not set socket option SO_REUSEADDR (psock_setsockopt: %s)",lsock,pstrerror(psock_errno()));
223     /* not a fatal error... */
224     }
225    
226     memset(&laddr,0,sizeof(laddr));
227     laddr.sin_family = PSOCK_AF_INET;
228     laddr.sin_port = htons(server_listen_port);
229     laddr.sin_addr.s_addr = htonl(INADDR_ANY);
230     if (psock_bind(lsock,(struct sockaddr *)&laddr,(psock_t_socklen)sizeof(laddr))<0)
231     {
232     eventlog(eventlog_level_error,__FUNCTION__,"could not bind socket to address 0.0.0.0:%hu TCP (psock_bind: %s)",server_listen_port,pstrerror(psock_errno()));
233     psock_close(udpsock);
234     psock_close(lsock);
235     return -1;
236     }
237    
238     memset(&laddr,0,sizeof(laddr));
239     laddr.sin_family = PSOCK_AF_INET;
240     laddr.sin_port = htons(server_listen_port);
241     laddr.sin_addr.s_addr = htonl(INADDR_ANY);
242     if (psock_bind(udpsock,(struct sockaddr *)&laddr,(psock_t_socklen)sizeof(laddr))<0)
243     {
244     eventlog(eventlog_level_error,__FUNCTION__,"could not bind socket to address 0.0.0.0:%hu UDP (psock_bind: %s)",server_listen_port,pstrerror(psock_errno()));
245     psock_close(udpsock);
246     psock_close(lsock);
247     return -1;
248     }
249     eventlog(eventlog_level_info,__FUNCTION__,"bound to UDP port %hu",server_listen_port);
250    
251     /* tell socket to listen for connections */
252     if (psock_listen(lsock,LISTEN_QUEUE)<0)
253     {
254     eventlog(eventlog_level_error,__FUNCTION__,"could not listen (psock_listen: %s)",pstrerror(psock_errno()));
255     psock_close(udpsock);
256     psock_close(lsock);
257     return -1;
258     }
259     if (psock_ctl(lsock,PSOCK_NONBLOCK)<0)
260     eventlog(eventlog_level_error,__FUNCTION__,"could not set TCP listen socket to non-blocking mode (psock_ctl: %s)",pstrerror(psock_errno()));
261    
262     eventlog(eventlog_level_info,__FUNCTION__,"listening on TCP port %hu",server_listen_port);
263    
264     for (;;)
265     {
266     /* loop over all connections to create the sets for select() */
267     PSOCK_FD_ZERO(&rfds);
268     PSOCK_FD_ZERO(&wfds);
269     highest_fd = lsock;
270     PSOCK_FD_SET(lsock,&rfds);
271     if (udpsock>highest_fd)
272     highest_fd = udpsock;
273     PSOCK_FD_SET(udpsock,&rfds);
274    
275     LIST_TRAVERSE_CONST(virtconnlist(),curr)
276     {
277     vc = elem_get_data(curr);
278     csocket = virtconn_get_client_socket(vc);
279     if (queue_get_length((t_queue const * const *)virtconn_get_clientout_queue(vc))>0)
280     PSOCK_FD_SET(csocket,&wfds); /* pending output, also check for writeability */
281     PSOCK_FD_SET(csocket,&rfds);
282    
283     if (csocket>highest_fd)
284     highest_fd = csocket;
285    
286     switch (virtconn_get_state(vc))
287     {
288     case virtconn_state_connecting:
289     eventlog(eventlog_level_debug,__FUNCTION__,"waiting for %d to finish connecting",ssocket);
290     ssocket = virtconn_get_server_socket(vc);
291     PSOCK_FD_SET(ssocket,&wfds); /* wait for connect to complete */
292    
293     if (ssocket>highest_fd)
294     highest_fd = ssocket;
295     break;
296     case virtconn_state_connected:
297     eventlog(eventlog_level_debug,__FUNCTION__,"checking for reading on connected socket %d",ssocket);
298     ssocket = virtconn_get_server_socket(vc);
299     if (queue_get_length((t_queue const * const *)virtconn_get_serverout_queue(vc))>0)
300     PSOCK_FD_SET(ssocket,&wfds); /* pending output, also check for writeability */
301     PSOCK_FD_SET(ssocket,&rfds);
302    
303     if (ssocket>highest_fd)
304     highest_fd = ssocket;
305     break;
306     default: /* avoid warning */
307     break;
308     }
309     }
310    
311     /* find which sockets need servicing */
312     if (psock_select(highest_fd+1,&rfds,&wfds,NULL,NULL)<0)
313     {
314     if (errno!=PSOCK_EINTR)
315     eventlog(eventlog_level_error,__FUNCTION__,"select failed (select: %s)",pstrerror(errno));
316     continue;
317     }
318    
319     /* check for incoming connection */
320     if (PSOCK_FD_ISSET(lsock,&rfds))
321     {
322     int asock;
323     struct sockaddr_in caddr;
324     psock_t_socklen caddr_len;
325    
326     /* accept the connection */
327     caddr_len = sizeof(caddr);
328     if ((asock = psock_accept(lsock,(struct sockaddr *)&caddr,&caddr_len))<0)
329     {
330     if (psock_errno()==PSOCK_EWOULDBLOCK || psock_errno()==PSOCK_ECONNABORTED) /* BSD, POSIX error for aborted connections, SYSV often uses EAGAIN */
331     eventlog(eventlog_level_error,__FUNCTION__,"client aborted connection (psock_accept: %s)",pstrerror(psock_errno()));
332     else /* EAGAIN can mean out of resources _or_ connection aborted */
333     if (psock_errno()!=PSOCK_EINTR)
334     eventlog(eventlog_level_error,__FUNCTION__,"could not accept new connection (psock_accept: %s)",pstrerror(psock_errno()));
335     }
336     else
337     {
338     int ssd;
339     int val=1;
340    
341     eventlog(eventlog_level_info,__FUNCTION__,"[%d] accepted connection from %s:%hu",asock,inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port));
342    
343     if (psock_setsockopt(asock,PSOCK_SOL_SOCKET,PSOCK_SO_KEEPALIVE,&val,(psock_t_socklen)sizeof(val))<0)
344     eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not set socket option SO_KEEPALIVE (psock_setsockopt: %s)",asock,pstrerror(psock_errno()));
345     /* not a fatal error */
346    
347     if (psock_ctl(asock,PSOCK_NONBLOCK)<0)
348     {
349     eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not set TCP socket to non-blocking mode (closing connection) (psock_ctl: %s)",asock,pstrerror(psock_errno()));
350     psock_close(asock);
351     }
352     else
353     if ((ssd = psock_socket(PSOCK_PF_INET,PSOCK_SOCK_STREAM,PSOCK_IPPROTO_TCP))<0)
354     {
355     eventlog(eventlog_level_error,__FUNCTION__,"[%d] could create TCP socket (closing connection) (psock_socket: %s)",asock,pstrerror(psock_errno()));
356     psock_close(asock);
357     }
358     else
359     if (psock_ctl(ssd,PSOCK_NONBLOCK)<0)
360     {
361     eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not set TCP socket to non-blocking mode (closing connection) (psock_ctl: %s)",asock,pstrerror(psock_errno()));
362     psock_close(ssd);
363     psock_close(asock);
364     }
365     else
366     if (!(vc = virtconn_create(asock,ssd,ntohl(caddr.sin_addr.s_addr),BNETD_MIN_TEST_PORT)))
367     {
368     eventlog(eventlog_level_error,__FUNCTION__,"[%d] unable to create new connection (closing connection)",asock);
369     psock_close(ssd);
370     psock_close(asock);
371     }
372     else
373     {
374     memset(&caddr,0,sizeof(caddr));
375     caddr.sin_family = PSOCK_AF_INET;
376     caddr.sin_port = htons(virtconn_get_udpport(vc));
377     caddr.sin_addr.s_addr = htonl(virtconn_get_udpaddr(vc));
378     eventlog(eventlog_level_info,__FUNCTION__,"[%d] addr now %s:%hu",asock,inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port));
379     }
380     }
381     }
382    
383     eventlog(eventlog_level_debug,__FUNCTION__,"checking for incoming UDP");
384     if (PSOCK_FD_ISSET(udpsock,&rfds))
385     {
386     t_packet * upacket;
387     struct sockaddr_in toaddr;
388     struct sockaddr_in fromaddr;
389     psock_t_socklen fromlen;
390     int len;
391    
392     if (!(upacket = packet_create(packet_class_raw)))
393     eventlog(eventlog_level_error,__FUNCTION__,"could not allocate raw packet for input");
394     else
395     {
396     /* packet_set_flags(upacket,PROXY_FLAG_UDP);*/
397    
398     fromlen = sizeof(fromaddr);
399     if ((len = psock_recvfrom(udpsock,packet_get_raw_data_build(upacket,0),MAX_PACKET_SIZE,0,(struct sockaddr *)&fromaddr,&fromlen))<0)
400     {
401     if (psock_errno()!=PSOCK_EINTR && psock_errno()!=PSOCK_EAGAIN && psock_errno()!=PSOCK_EWOULDBLOCK)
402     eventlog(eventlog_level_error,__FUNCTION__,"could not recv UDP datagram (psock_recvfrom: %s)",pstrerror(psock_errno()));
403     }
404     else
405     {
406     if (fromaddr.sin_family!=PSOCK_AF_INET)
407     eventlog(eventlog_level_error,__FUNCTION__,"got UDP datagram with bad address family %d",fromaddr.sin_family);
408     else
409     {
410     char tempa[32];
411     char tempb[32];
412    
413     packet_set_size(upacket,len);
414    
415     if (fromaddr.sin_addr.s_addr==servaddr.sin_addr.s_addr) /* from server */
416     {
417     if ((curr = list_get_first_const(virtconnlist()))) /* hack.. find proper client */
418     {
419     vc = elem_get_data(curr);
420     memset(&toaddr,0,sizeof(toaddr));
421     toaddr.sin_family = PSOCK_AF_INET;
422     toaddr.sin_port = htons(virtconn_get_udpport(vc));
423     toaddr.sin_addr.s_addr = htonl(virtconn_get_udpaddr(vc));
424     eventlog(eventlog_level_info,__FUNCTION__,"[%d] addr by UDP send is %s:%hu",virtconn_get_client_socket(vc),inet_ntoa(toaddr.sin_addr),ntohs(toaddr.sin_port));
425    
426     if (hexstrm)
427     {
428     strcpy(tempa,inet_ntoa(fromaddr.sin_addr));
429     strcpy(tempb,inet_ntoa(toaddr.sin_addr));
430     fprintf(hexstrm,"%d: srv prot=UDP from=%s:%hu to=%s:%hu length=%d\n",
431     udpsock,
432     tempa,
433     ntohs(fromaddr.sin_port),
434     tempb,
435     ntohs(toaddr.sin_port),
436     len);
437     hexdump(hexstrm,packet_get_raw_data(upacket,0),len);
438     }
439    
440     /*queue_push_packet(virtconn_get_clientout_queue(__));*/ /* where to queue ... */
441     for (;;) /* hack.. just block for now */
442     {
443     if (psock_sendto(udpsock,packet_get_raw_data_const(upacket,0),len,0,
444     (struct sockaddr *)&toaddr,(psock_t_socklen)sizeof(toaddr))<len)
445     {
446     if (psock_errno()==PSOCK_EINTR || psock_errno()==PSOCK_EAGAIN || psock_errno()==PSOCK_EWOULDBLOCK)
447     continue;
448     eventlog(eventlog_level_error,__FUNCTION__,"could not send UDP datagram to client (psock_sendto: %s)",pstrerror(psock_errno()));
449     }
450     break;
451     }
452     }
453     }
454     else /* from client */
455     {
456     if (hexstrm)
457     {
458     strcpy(tempa,inet_ntoa(fromaddr.sin_addr));
459     strcpy(tempb,inet_ntoa(servaddr.sin_addr));
460    
461     fprintf(hexstrm,"%d: clt prot=UDP from=%s:%hu to=%s:%hu length=%d\n",
462     udpsock,
463     tempa,
464     ntohs(fromaddr.sin_port),
465     tempb,
466     ntohs(servaddr.sin_port),
467     len);
468     hexdump(hexstrm,packet_get_raw_data(upacket,0),len);
469     }
470     /*queue_push_packet(virtconn_get_serverout_queue(vc));*/
471     for (;;) /* hack.. just block for now */
472     {
473     if (psock_sendto(udpsock,packet_get_raw_data_const(upacket,0),len,0,
474     (struct sockaddr *)&servaddr,(psock_t_socklen)sizeof(servaddr))<len)
475     {
476     if (psock_errno()==PSOCK_EINTR || psock_errno()==PSOCK_EAGAIN || psock_errno()==PSOCK_EWOULDBLOCK)
477     continue;
478     eventlog(eventlog_level_error,__FUNCTION__,"could not send UDP datagram to server (psock_sendto: %s)",pstrerror(psock_errno()));
479     }
480     break;
481     }
482     }
483     }
484     }
485     packet_del_ref(upacket);
486     }
487     }
488    
489     /* search connections for sockets that need service */
490     eventlog(eventlog_level_debug,__FUNCTION__,"checking for sockets that need service");
491     LIST_TRAVERSE_CONST(virtconnlist(),curr)
492     {
493     unsigned int currsize;
494     t_packet * packet;
495    
496     vc = elem_get_data(curr);
497    
498     csocket = virtconn_get_client_socket(vc);
499     if (virtconn_get_state(vc)==virtconn_state_connected ||
500     virtconn_get_state(vc)==virtconn_state_connecting)
501     ssocket = virtconn_get_server_socket(vc);
502     else
503     ssocket = -1;
504    
505     eventlog(eventlog_level_debug,__FUNCTION__,"checking %d for client readability",csocket);
506     if (PSOCK_FD_ISSET(csocket,&rfds))
507     {
508     if (virtconn_get_state(vc)==virtconn_state_initial)
509     {
510     if (init_virtconn(vc,servaddr)<0)
511     {
512     virtconn_destroy(vc);
513     continue;
514     }
515     }
516     else
517     {
518     currsize = virtconn_get_clientin_size(vc);
519    
520     if (!queue_get_length(virtconn_get_clientin_queue(vc)))
521     {
522     switch (virtconn_get_class(vc))
523     {
524     case virtconn_class_bnet:
525     if (!(packet = packet_create(packet_class_bnet)))
526     {
527     eventlog(eventlog_level_error,__FUNCTION__,"could not allocate normal packet for input");
528     continue;
529     }
530     break;
531     case virtconn_class_file:
532     if (!(packet = packet_create(packet_class_file)))
533     {
534     eventlog(eventlog_level_error,__FUNCTION__,"could not allocate file packet for input");
535     continue;
536     }
537     break;
538     case virtconn_class_bot:
539     if (!(packet = packet_create(packet_class_raw)))
540     {
541     eventlog(eventlog_level_error,__FUNCTION__,"could not allocate raw packet for input");
542     continue;
543     }
544     packet_set_size(packet,1); /* start by only reading one char */
545     break;
546     default:
547     eventlog(eventlog_level_error,__FUNCTION__,"[%d] connection has bad type (closing connection)",virtconn_get_client_socket(vc));
548     virtconn_destroy(vc);
549     continue;
550     }
551     queue_push_packet(virtconn_get_clientin_queue(vc),packet);
552     packet_del_ref(packet);
553     if (!queue_get_length(virtconn_get_clientin_queue(vc)))
554     continue; /* push failed */
555     currsize = 0;
556     }
557    
558     packet = queue_peek_packet((t_queue const * const *)virtconn_get_clientin_queue(vc)); /* avoid warning */
559     switch (net_recv_packet(csocket,packet,&currsize))
560     {
561     case -1:
562     virtconn_destroy(vc);
563     continue;
564    
565     case 0: /* still working on it */
566     virtconn_set_clientin_size(vc,currsize);
567     break;
568    
569     case 1: /* done reading */
570     if (virtconn_get_class(vc)==virtconn_class_bot &&
571     currsize<MAX_PACKET_SIZE)
572     {
573     char const * const temp=packet_get_raw_data_const(packet,0);
574    
575     if (temp[currsize-1]!='\r' && temp[currsize-1]!='\n')
576     {
577     virtconn_set_clientin_size(vc,currsize);
578     packet_set_size(packet,currsize+1);
579     break; /* no end of line, get another char */
580     }
581     /* got a complete line... fall through */
582     }
583    
584     packet = queue_pull_packet(virtconn_get_clientin_queue(vc));
585    
586     if (hexstrm)
587     {
588     fprintf(hexstrm,"%d: cli class=%s[0x%04hx] type=%s[0x%04hx] length=%hu\n",
589     csocket,
590     packet_get_class_str(packet),packet_get_class(packet),
591     packet_get_type_str(packet,packet_dir_from_client),packet_get_type(packet),
592     packet_get_size(packet));
593     hexdump(hexstrm,packet_get_raw_data_const(packet,0),packet_get_size(packet));
594     }
595    
596     queue_push_packet(virtconn_get_serverout_queue(vc),packet);
597     packet_del_ref(packet);
598     virtconn_set_clientin_size(vc,0);
599     }
600     }
601     }
602    
603     eventlog(eventlog_level_debug,__FUNCTION__,"checking %d for server readability",ssocket);
604     if (ssocket!=-1 && PSOCK_FD_ISSET(ssocket,&rfds))
605     {
606     currsize = virtconn_get_serverin_size(vc);
607    
608     if (!queue_get_length(virtconn_get_serverin_queue(vc)))
609     {
610     switch (virtconn_get_class(vc))
611     {
612     case virtconn_class_bnet:
613     if (!(packet = packet_create(packet_class_bnet)))
614     {
615     eventlog(eventlog_level_error,__FUNCTION__,"could not allocate normal packet for input");
616     continue;
617     }
618     break;
619     case virtconn_class_file:
620     {
621     unsigned int fileleft;
622    
623     if ((fileleft = virtconn_get_fileleft(vc))>0)
624     {
625     if (!(packet = packet_create(packet_class_raw)))
626     {
627     eventlog(eventlog_level_error,__FUNCTION__,"could not allocate raw file packet for input");
628     continue;
629     }
630     if (fileleft>MAX_PACKET_SIZE)
631     packet_set_size(packet,MAX_PACKET_SIZE);
632     else
633     packet_set_size(packet,fileleft);
634     }
635     else
636     {
637     if (!(packet = packet_create(packet_class_file)))
638     {
639     eventlog(eventlog_level_error,__FUNCTION__,"could not allocate file packet for input");
640     continue;
641     }
642     }
643     }
644     break;
645     case virtconn_class_bot:
646     if (!(packet = packet_create(packet_class_raw)))
647     {
648     eventlog(eventlog_level_error,__FUNCTION__,"could not allocate raw packet for input");
649     continue;
650     }
651     packet_set_size(packet,MAX_PACKET_SIZE); /* read as much as possible */
652     break;
653     default:
654     eventlog(eventlog_level_error,__FUNCTION__,"[%d] connection has bad type (closing connection)",virtconn_get_client_socket(vc));
655     virtconn_destroy(vc);
656     continue;
657     }
658     queue_push_packet(virtconn_get_serverin_queue(vc),packet);
659     packet_del_ref(packet);
660     if (!queue_get_length(virtconn_get_serverin_queue(vc)))
661     continue; /* push failed */
662     currsize = 0;
663     }
664    
665     packet = queue_peek_packet((t_queue const * const *)virtconn_get_serverin_queue(vc)); /* avoid warning */
666     switch (net_recv_packet(ssocket,packet,&currsize))
667     {
668     case -1:
669     virtconn_destroy(vc);
670     continue;
671    
672     case 0: /* still working on it */
673     virtconn_set_serverin_size(vc,currsize);
674     if (virtconn_get_class(vc)!=virtconn_class_bot || currsize<1)
675     break;
676     else
677     packet_set_size(packet,currsize);
678     /* fallthough... we take what we can get with the bot data */
679    
680     case 1: /* done reading */
681     packet = queue_pull_packet(virtconn_get_serverin_queue(vc));
682     if (virtconn_get_class(vc)==virtconn_class_file)
683     {
684     unsigned int len=virtconn_get_fileleft(vc);
685    
686     if (len)
687     virtconn_set_fileleft(vc,len-currsize);
688     else if (packet_get_type(packet)==SERVER_FILE_REPLY &&
689     packet_get_size(packet)>=sizeof(t_server_file_reply))
690     virtconn_set_fileleft(vc,bn_int_get(packet->u.server_file_reply.filelen));
691     }
692     queue_push_packet(virtconn_get_clientout_queue(vc),packet);
693     packet_del_ref(packet);
694     virtconn_set_serverin_size(vc,0);
695     }
696     }
697    
698     eventlog(eventlog_level_debug,__FUNCTION__,"checking %d for client writeability",csocket);
699     if (PSOCK_FD_ISSET(csocket,&wfds))
700     {
701     currsize = virtconn_get_clientout_size(vc);
702     switch (net_send_packet(csocket,queue_peek_packet((t_queue const * const *)virtconn_get_clientout_queue(vc)),&currsize)) /* avoid warning */
703     {
704     case -1:
705     virtconn_destroy(vc);
706     continue;
707    
708     case 0: /* still working on it */
709     virtconn_set_clientout_size(vc,currsize);
710     break;
711    
712     case 1: /* done sending */
713     packet = queue_pull_packet(virtconn_get_clientout_queue(vc));
714    
715     if (hexstrm)
716     {
717     fprintf(hexstrm,"%d: srv class=%s[0x%04hx] type=%s[0x%04hx] length=%hu\n",
718     csocket,
719     packet_get_class_str(packet),packet_get_class(packet),
720     packet_get_type_str(packet,packet_dir_from_server),packet_get_type(packet),
721     packet_get_size(packet));
722     hexdump(hexstrm,packet_get_raw_data(packet,0),packet_get_size(packet));
723     }
724    
725     packet_del_ref(packet);
726     virtconn_set_clientout_size(vc,0);
727     }
728     }
729    
730     eventlog(eventlog_level_debug,__FUNCTION__,"checking %d for server writeability",ssocket);
731     if (ssocket!=-1 && PSOCK_FD_ISSET(ssocket,&wfds))
732     {
733     if (virtconn_get_state(vc)==virtconn_state_connecting)
734     {
735     int err;
736     psock_t_socklen errlen;
737    
738     err = 0;
739     errlen = sizeof(err);
740     if (psock_getsockopt(ssocket,PSOCK_SOL_SOCKET,PSOCK_SO_ERROR,&err,&errlen)<0)
741     {
742     eventlog(eventlog_level_error,__FUNCTION__,"[%d] unable to read socket error (psock_getsockopt[psock_connect]: %s)",virtconn_get_client_socket(vc),pstrerror(psock_errno()));
743     virtconn_destroy(vc);
744     continue;
745     }
746     if (errlen==0 || err==0)
747     virtconn_set_state(vc,virtconn_state_connected);
748     else
749     {
750     eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not connect to server (psock_getsockopt[psock_connect]: %s)",virtconn_get_client_socket(vc),pstrerror(err));
751     virtconn_destroy(vc);
752     continue;
753     }
754     }
755     else
756     {
757     currsize = virtconn_get_serverout_size(vc);
758     switch (net_send_packet(ssocket,queue_peek_packet((t_queue const * const *)virtconn_get_serverout_queue(vc)),&currsize)) /* avoid warning */
759     {
760     case -1:
761     virtconn_destroy(vc);
762     continue;
763    
764     case 0: /* still working on it */
765     virtconn_set_serverout_size(vc,currsize);
766     break;
767    
768     case 1: /* done sending */
769     packet = queue_pull_packet(virtconn_get_serverout_queue(vc));
770     packet_del_ref(packet);
771     virtconn_set_serverout_size(vc,0);
772     }
773     }
774     }
775     }
776     eventlog(eventlog_level_debug,__FUNCTION__,"done checking");
777     }
778    
779     return 0;
780     }
781    
782    
783     static void usage(char const * progname)
784     {
785     fprintf(stderr,
786     "usage: %s [<options>] <servername> [<TCP portnumber>]\n"
787     " -d FILE, --hexdump=FILE do hex dump of packets into FILE\n"
788     " -l FILE, --logfile=FILE save eventlog lines into FILE\n"
789     " -p PORT, --port=PORT listen for connections on port PORT\n"
790     #ifdef DO_DAEMONIZE
791     " -f, --foreground don't daemonize\n"
792     #else
793     " -f, --foreground don't daemonize (default)\n"
794     #endif
795     " -h, --help, --usage show this information and exit\n"
796     " -v, --version print version number and exit\n",
797     progname);
798     exit(STATUS_FAILURE);
799     }
800    
801    
802     extern int main(int argc, char * argv[])
803     {
804     int a;
805     char const * logfile=NULL;
806     char const * hexfile=NULL;
807     int foreground=0;
808     unsigned short port=0;
809     char const * servname=NULL;
810     unsigned short servport=0;
811     struct hostent * host;
812     struct sockaddr_in servaddr;
813    
814     if (argc<1 || !argv || !argv[0])
815     {
816     fprintf(stderr,"bad arguments\n");
817     return STATUS_FAILURE;
818     }
819    
820     for (a=1; a<argc; a++)
821     if (servname && isdigit((int)argv[a][0]) && a+1>=argc)
822     {
823     if (str_to_ushort(argv[a],&servport)<0)
824     {
825     fprintf(stderr,"%s: \"%s\" should be a positive integer\n",argv[0],argv[a]);
826     usage(argv[0]);
827     }
828     }
829     else if (!servname && argv[a][0]!='-' && a+2>=argc)
830     servname = argv[a];
831     else if (strncmp(argv[a],"--hexdump=",10)==0)
832     {
833     if (hexfile)
834     {
835     fprintf(stderr,"%s: hexdump file was already specified as \"%s\"\n",argv[0],hexfile);
836     usage(argv[0]);
837     }
838     hexfile = &argv[a][10];
839     }
840     else if (strcmp(argv[a],"-d")==0)
841     {
842     if (a+1>=argc)
843     {
844     fprintf(stderr,"%s: option \"%s\" requires an argument\n",argv[0],argv[a]);
845     usage(argv[0]);
846     }
847     if (hexfile)
848     {
849     fprintf(stderr,"%s: hexdump file was already specified as \"%s\"\n",argv[0],hexfile);
850     usage(argv[0]);
851     }
852     a++;
853     hexfile = argv[a];
854     }
855     else if (strncmp(argv[a],"--logfile=",10)==0)
856     {
857     if (logfile)
858     {
859     fprintf(stderr,"%s: eventlog file was already specified as \"%s\"\n",argv[0],logfile);
860     usage(argv[0]);
861     }
862     logfile = &argv[a][10];
863     }
864     else if (strcmp(argv[a],"-l")==0)
865     {
866     if (a+1>=argc)
867     {
868     fprintf(stderr,"%s: option \"%s\" requires an argument\n",argv[0],argv[a]);
869     usage(argv[0]);
870     }
871     if (logfile)
872     {
873     fprintf(stderr,"%s: eventlog file was already specified as \"%s\"\n",argv[0],logfile);
874     usage(argv[0]);
875     }
876     a++;
877     logfile = argv[a];
878     }
879     else if (strncmp(argv[a],"--port=",7)==0)
880     {
881     if (port>0)
882     {
883     fprintf(stderr,"%s: listen port was already specified as \"%hu\"\n",argv[0],port);
884     usage(argv[0]);
885     }
886     if (str_to_ushort(&argv[a][7],&port)<0)
887     {
888     fprintf(stderr,"%s: \"%s\" should be a positive integer\n",argv[0],argv[a]);
889     usage(argv[0]);
890     }
891     }
892     else if (strcmp(argv[a],"-p")==0)
893     {
894     if (a+1>=argc)
895     {
896     fprintf(stderr,"%s: option \"%s\" requires an argument\n",argv[0],argv[a]);
897     usage(argv[0]);
898     }
899     if (port>0)
900     {
901     fprintf(stderr,"%s: eventlog file was already specified as \"%hu\"\n",argv[0],port);
902     usage(argv[0]);
903     }
904     a++;
905     if (str_to_ushort(argv[a],&port)<0)
906     {
907     fprintf(stderr,"%s: \"%s\" should be a positive integer\n",argv[0],argv[a]);
908     usage(argv[0]);
909     }
910     }
911     else if (strcmp(argv[a],"-f")==0 || strcmp(argv[a],"--foreground")==0)
912     foreground = 1;
913     else if (strcmp(argv[a],"-h")==0 || strcmp(argv[a],"--help")==0 || strcmp(argv[a],"--usage")==0)
914     usage(argv[0]);
915     else if (strcmp(argv[a],"-v")==0 || strcmp(argv[a],"--version")==0)
916     {
917     printf("version "PVPGN_VERSION"\n");
918     return STATUS_SUCCESS;
919     }
920     else if (strcmp(argv[a],"--hexdump")==0 || strcmp(argv[a],"--logfile")==0 || strcmp(argv[a],"--port")==0)
921     {
922     fprintf(stderr,"%s: option \"%s\" requires and argument.\n",argv[0],argv[a]);
923     usage(argv[0]);
924     }
925     else
926     {
927     fprintf(stderr,"%s: bad option \"%s\"\n",argv[0],argv[a]);
928     usage(argv[0]);
929     }
930    
931     if (port==0)
932     port = BNETD_SERV_PORT;
933     if (servport==0)
934     servport = BNETD_SERV_PORT;
935     if (!servname)
936     servname = BNETD_DEFAULT_HOST;
937    
938     if (psock_init()<0)
939     {
940     fprintf(stderr,"%s: could not initialize socket functions\n",argv[0]);
941     return STATUS_FAILURE;
942     }
943    
944     if (!(host = gethostbyname(servname)))
945     {
946     fprintf(stderr,"%s: unknown host \"%s\"\n",argv[0],servname);
947     return STATUS_FAILURE;
948     }
949    
950     memset(&servaddr,0,sizeof(servaddr));
951     servaddr.sin_family = PSOCK_AF_INET;
952     servaddr.sin_port = htons(servport);
953     memcpy(&servaddr.sin_addr.s_addr,host->h_addr_list[0],host->h_length);
954    
955     eventlog_set(stderr);
956     /* errors to eventlog from here on... */
957    
958     if (logfile)
959     {
960     eventlog_clear_level();
961     eventlog_add_level("error");
962     eventlog_add_level("warn");
963     eventlog_add_level("info");
964     eventlog_add_level("debug");
965    
966     if (eventlog_open(logfile)<0)
967     {
968     eventlog(eventlog_level_fatal,__FUNCTION__,"could not use file \"%s\" for the eventlog (exiting)",logfile);
969     return STATUS_FAILURE;
970     }
971     }
972    
973     #ifdef DO_DAEMONIZE
974     if (!foreground)
975     {
976     if (chdir("/")<0)
977     {
978     eventlog(eventlog_level_error,__FUNCTION__,"could not change working directory to / (chdir: %s)",pstrerror(errno));
979     return STATUS_FAILURE;
980     }
981    
982     switch (fork())
983     {
984     case -1:
985     eventlog(eventlog_level_error,__FUNCTION__,"could not fork (fork: %s)",pstrerror(errno));
986     return STATUS_FAILURE;
987     case 0: /* child */
988     break;
989     default: /* parent */
990     return STATUS_SUCCESS;
991     }
992    
993     close(STDINFD);
994     close(STDOUTFD);
995     close(STDERRFD);
996    
997     # ifdef HAVE_SETPGID
998     if (setpgid(0,0)<0)
999     {
1000     eventlog(eventlog_level_error,__FUNCTION__,"could not create new process group (setpgid: %s)",pstrerror(errno));
1001     return STATUS_FAILURE;
1002     }
1003     # else
1004     # ifdef HAVE_SETPGRP
1005     # ifdef SETPGRP_VOID
1006     if (setpgrp()<0)
1007     {
1008     eventlog(eventlog_level_error,__FUNCTION__,"could not create new process group (setpgrp: %s)",pstrerror(errno));
1009     return STATUS_FAILURE;
1010     }
1011     # else
1012     if (setpgrp(0,0)<0)
1013     {
1014     eventlog(eventlog_level_error,__FUNCTION__,"could not create new process group (setpgrp: %s)",pstrerror(errno));
1015     return STATUS_FAILURE;
1016     }
1017     # endif
1018     # else
1019     # ifdef HAVE_SETSID
1020     if (setsid()<0)
1021     {
1022     eventlog(eventlog_level_error,__FUNCTION__,"could not create new process group (setsid: %s)",pstrerror(errno));
1023     return STATUS_FAILURE;
1024     }
1025     # else
1026     # error "One of setpgid(), setpgrp(), or setsid() is required"
1027     # endif
1028     # endif
1029     # endif
1030     }
1031     #endif
1032    
1033     if (hexfile)
1034     if (!(hexstrm = fopen(hexfile,"w")))
1035     eventlog(eventlog_level_error,__FUNCTION__,"could not open file \"%s\" for writing the hexdump (fopen: %s)",hexfile,pstrerror(errno));
1036    
1037     if (proxy_process(port,servaddr)<0)
1038     {
1039     eventlog(eventlog_level_fatal,__FUNCTION__,"failed to initialize network (exiting)");
1040     return STATUS_FAILURE;
1041     }
1042    
1043     if (hexstrm)
1044     if (fclose(hexstrm)<0)
1045     eventlog(eventlog_level_error,__FUNCTION__,"could not close hexdump file \"%s\" after writing (fclose: %s)",hexfile,pstrerror(errno));
1046    
1047     return STATUS_SUCCESS;
1048     }

webmaster@leafok.com
ViewVC Help
Powered by ViewVC 1.3.0-beta1