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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1.1.1 - (show annotations) (vendor branch)
Tue Jun 6 03:41:37 2006 UTC (19 years, 9 months ago) by sysadm
Branch: GNU, MAIN
CVS Tags: arelease, HEAD
Changes since 1.1: +0 -0 lines
Content type: text/x-csrc
Error occurred while calculating annotation data.
no message

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