#include #include #include /*#include /*sometimes needed*/ #include #include #include #include #include #include #define KSIZE 10000 #define DSIZE 1032 #define CMDSIZE 32 #define P(msg) printf("DEBUG: %s\n",msg); fflush(stdin); /* QUAKE messages */ unsigned char ctrl_accept[]= {0x80,0x00,0x00,0x09,0x81}; unsigned char msg_part[]= {0x00,0x01}; unsigned char msg_end[]= {0x00,0x09}; unsigned char msg_ack[]= {0x00,0x02,0x00,0x08,0x00,0x00,0x00,0x00}; /* BOT commands */ int no_of_macros=0; struct macro_s { char name[CMDSIZE]; char *expansion; } *macro; /* connection data */ int sock; /* the socket descriptor */ struct sockaddr_in remoteaddr; /* holds remode address/port */ int remoteaddrsize; char *sv_name; int sv_port=26000, sv_world; /* prototypes */ void UDPconnect(char *sv_name, int sv_port); void senddata(unsigned char *data, size_t size); void recvdata(unsigned char *data, size_t *size); void console(char *kbuf, unsigned char *data, size_t *size); void macro_load(char *filename); void macro_unload(); void macro_expand(char *kbuf); void mountdata(char *kbuf, unsigned char *data, size_t *size); void printsockaddr(struct sockaddr_in *addr); void printdata(unsigned char *data, size_t size); void shut() { macro_unload(); shutdown(sock,2); close(sock); } /*************************************************************
*************************************************************/ int main(int argc, char *argv[]) { int sel; /* select result */ fd_set readmask; /* select mask */ char kbuf[KSIZE]; unsigned char data[DSIZE]; size_t size; switch(argc) { case 3: sv_port=atoi(argv[2]); case 2: sv_name=argv[1];break; default: perror("usage: s "); exit(1); } macro_load("macros.txt"); UDPconnect(sv_name,sv_port); for(;;) { /* read pending messages */ FD_ZERO(&readmask); FD_SET(0,&readmask); FD_SET(sock,&readmask); sel=select(sock+1,&readmask,NULL,NULL,NULL); if(sel<0) { perror("ERR_SELECT"); exit(1); } else if( sel>0 ) { if( FD_ISSET(0,&readmask) ) { console(kbuf, data, &size); } else if( FD_ISSET(sock,&readmask) ) { recvdata(data,&size); } } } } /************************************************************* PROCESSING CONSOLE *************************************************************/ void console(char *kbuf, unsigned char *data, size_t *size) { bzero(kbuf,KSIZE); if( read( 0, kbuf, KSIZE) <= 0 ) { perror("ERR_READ"); exit(1); } cleanstr(kbuf); if( kbuf[0]==';' ) return;/* comment character */ macro_expand(kbuf);/* pre built messages */ printf("cmd %s\n",kbuf); mountdata(kbuf,data,size); senddata(data,*size); } /* MACRO PRE-PROCESSING */ void macro_expand(char *kbuf) { int i; for(i=0;ih_addr, (char *)&remoteaddr.sin_addr, hp->h_length); remoteaddr.sin_family = AF_INET; remoteaddr.sin_port = htons(sv_port); remoteaddrsize=sizeof(struct sockaddr_in); printf("local");printsockaddr(&localaddr); printf("remote");printsockaddr(&remoteaddr); } /************************************************************* SEND *************************************************************/ void senddata(unsigned char *data, size_t size) { static long rel_ord=0,unrel_ord=0; long ord; if( !size ) return; printf("send");printdata(data,size); /* auto-fill packet size */ data[2]=size>>8; data[3]=size&0xff; /* auto-fill packet order */ if( data[0]==0x00 ) { switch(data[1]) { case 0x01: case 0x09: ord= rel_ord++; break; case 0x10: ord= unrel_ord++; } data[4] = ord >>24; data[5] = (ord >>16) & 0xff; data[6] = (ord >>8) & 0xff; data[7] = ord & 0xff; } /* send the message */ if( sendto( sock, data, size, 0, (struct sockaddr *)&remoteaddr, remoteaddrsize) != size ) { perror("ERR_SEND"); exit(1); } } /************************************************************* RECEIVE *************************************************************/ void recvdata(unsigned char *data, size_t *size) { if( (*size=recvfrom( sock, data, DSIZE, 0, (struct sockaddr *)&remoteaddr, &remoteaddrsize)) < 0 ) { perror("ERR_RECV"); exit(1); } printf("recv");printdata(data,*size); /* answer acks 2 reliable packets */ if( data[0]==0x00 && (data[1]==0x01||data[1]==0x09) ) { bcopy((char *)data+4,(char *)msg_ack+4, sizeof(long)); bcopy((char *)msg_ack,(char *)data, *size=sizeof(msg_ack)); if( sendto( sock, data, *size, 0, (struct sockaddr *)&remoteaddr, remoteaddrsize) != *size ) { perror("ERR_SEND_ACK"); exit(1); } } /* check 4 accept and swap 2 world port */ else if( bcmp(data,ctrl_accept,sizeof(ctrl_accept))==0 ) { sv_world=data[5]|data[6]<<8; remoteaddr.sin_port = htons(sv_world); printf("redirect to worldport %d",sv_world); printf("remote");printsockaddr(&remoteaddr); } } /************************************************************* DEBUG *************************************************************/ void printsockaddr(struct sockaddr_in *addr) { int t; printf("IP ",addr->sin_family); for(t=0;t<4;t++) printf("%u.",(unsigned)*(((unsigned char *)&addr->sin_addr.s_addr) +t ) ); printf("\b:%lu\n",ntohs(addr->sin_port)); } void printdata(unsigned char *data, size_t size) { int i; for(i=0;i