bnproxy.c
上传用户:tany51
上传日期:2013-06-12
资源大小:1397k
文件大小:34k
源码类别:

MySQL数据库

开发平台:

Visual C++

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