/* Send a file. If the file doesn't exist we still need to respond * to the file request. This will set filelen to 0 and send the server * reply message and the client will be happy and not hang. */ extern int file_send(t_connection * c, char const * rawname, unsigned int adid, unsigned int etag, unsigned int startoffset, int need_header) { char const * filename; t_packet * rpacket; std::FILE * fp; unsigned int filelen; int nbytes; if (!c) { eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection"); return -1; } if (!rawname) { eventlog(eventlog_level_error,__FUNCTION__,"got NULL rawname"); return -1; } if (!(rpacket = packet_create(packet_class_file))) { eventlog(eventlog_level_error,__FUNCTION__,"could not create file packet"); return -1; } packet_set_size(rpacket,sizeof(t_server_file_reply)); packet_set_type(rpacket,SERVER_FILE_REPLY); if ((filename = file_get_info(rawname,&filelen,&rpacket->u.server_file_reply.timestamp))) { if (!(fp = std::fopen(filename,"rb"))) { /* FIXME: check for lower-case version of filename */ eventlog(eventlog_level_error,__FUNCTION__, "stat() succeeded yet could not open file \"%s\" for reading (std::fopen: %s)", filename, std::strerror(errno)); filelen = 0; } xfree((void *)filename); /* avoid warning */ } else { fp = NULL; filelen = 0; bn_long_set_a_b(&rpacket->u.server_file_reply.timestamp,0,0); } if (fp) { if (startoffset<filelen) { std::fseek(fp,startoffset,SEEK_SET); } else { eventlog(eventlog_level_warn,__FUNCTION__,"[%d] startoffset is beyond end of file (%u>%u)",conn_get_socket(c),startoffset,filelen); /* Keep the real filesize. Battle.net does it the same way ... */ std::fclose(fp); fp = NULL; } } if (need_header) { /* send the header from the server with the rawname and length. */ bn_int_set(&rpacket->u.server_file_reply.filelen,filelen); bn_int_set(&rpacket->u.server_file_reply.adid,adid); bn_int_set(&rpacket->u.server_file_reply.extensiontag,etag); /* rpacket->u.server_file_reply.timestamp is set above */ packet_append_string(rpacket,rawname); conn_push_outqueue(c,rpacket); } packet_del_ref(rpacket); /* Now send the data. Since it may be longer than a packet; we use * the raw packet class. */ if (!fp) { eventlog(eventlog_level_warn,__FUNCTION__,"[%d] sending no data for file \"%s\"",conn_get_socket(c),rawname); return -1; } eventlog(eventlog_level_info,__FUNCTION__,"[%d] sending file \"%s\" of length %d",conn_get_socket(c),rawname,filelen); for (;;) { if (!(rpacket = packet_create(packet_class_raw))) { eventlog(eventlog_level_error,__FUNCTION__,"could not create raw packet"); if (std::fclose(fp)<0) eventlog(eventlog_level_error,__FUNCTION__,"could not close file \"%s\" after reading (std::fclose: %s)",rawname,std::strerror(errno)); return -1; } if ((nbytes = std::fread(packet_get_raw_data_build(rpacket,0),1,MAX_PACKET_SIZE,fp))<(int)MAX_PACKET_SIZE) { if (nbytes>0) /* send out last portion */ { packet_set_size(rpacket,nbytes); conn_push_outqueue(c,rpacket); } packet_del_ref(rpacket); if (std::ferror(fp)) eventlog(eventlog_level_error,__FUNCTION__,"read failed before EOF on file \"%s\" (std::fread: %s)",rawname,std::strerror(errno)); break; } packet_set_size(rpacket,nbytes); conn_push_outqueue(c,rpacket); packet_del_ref(rpacket); } if (std::fclose(fp)<0) eventlog(eventlog_level_error,__FUNCTION__,"could not close file \"%s\" after reading (std::fclose: %s)",rawname,std::strerror(errno)); return 0; }
extern int main(int argc, char * argv[]) { int a; int sd; struct sockaddr_in saddr; t_packet * packet; t_packet * rpacket; t_packet * fpacket; char const * clienttag=NULL; char const * archtag=NULL; char const * servname=NULL; unsigned short servport=0; char const * hexfile=NULL; char text[MAX_MESSAGE_LEN]; char const * reqfile=NULL; struct hostent * host; unsigned int commpos; struct termios in_attr_old; struct termios in_attr_new; int changed_in; unsigned int currsize; unsigned int filelen; unsigned int startoffset; int startoffsetoverride=0; #define EXIST_ACTION_UNSPEC -1 #define EXIST_ACTION_ASK 0 #define EXIST_ACTION_OVERWRITE 1 #define EXIST_ACTION_BACKUP 2 #define EXIST_ACTION_RESUME 3 int exist_action=EXIST_ACTION_UNSPEC; struct stat exist_buf; char const * filename; FILE * fp; FILE * hexstrm=NULL; int fd_stdin; t_bnettime bntime; time_t tm; char timestr[FILE_TIME_MAXLEN]; unsigned int screen_width,screen_height; int munged; if (argc<1 || !argv || !argv[0]) { fprintf(stderr,"bad arguments\n"); return STATUS_FAILURE; } for (a=1; a<argc; a++) if (servname && isdigit((int)argv[a][0]) && a+1>=argc) { if (str_to_ushort(argv[a],&servport)<0) { fprintf(stderr,"%s: \"%s\" should be a positive integer\n",argv[0],argv[a]); usage(argv[0]); } } else if (!servname && argv[a][0]!='-' && a+2>=argc) servname = argv[a]; else if (strcmp(argv[a],"-b")==0 || strcmp(argv[a],"--client=SEXP")==0) { if (clienttag) { fprintf(stderr,"%s: client type was already specified as \"%s\"\n",argv[0],clienttag); usage(argv[0]); } clienttag = CLIENTTAG_BROODWARS; } else if (strcmp(argv[a],"-d")==0 || strcmp(argv[a],"--client=DRTL")==0) { if (clienttag) { fprintf(stderr,"%s: client type was already specified as \"%s\"\n",argv[0],clienttag); usage(argv[0]); } clienttag = CLIENTTAG_DIABLORTL; } else if (strcmp(argv[a],"--client=DSHR")==0) { if (clienttag) { fprintf(stderr,"%s: client type was already specified as \"%s\"\n",argv[0],clienttag); usage(argv[0]); } clienttag = CLIENTTAG_DIABLOSHR; } else if (strcmp(argv[a],"-s")==0 || strcmp(argv[a],"--client=STAR")==0) { if (clienttag) { fprintf(stderr,"%s: client type was already specified as \"%s\"\n",argv[0],clienttag); usage(argv[0]); } clienttag = CLIENTTAG_STARCRAFT; } else if (strcmp(argv[a],"--client=SSHR")==0) { if (clienttag) { fprintf(stderr,"%s: client type was already specified as \"%s\"\n",argv[0],clienttag); usage(argv[0]); } clienttag = CLIENTTAG_SHAREWARE; } else if (strcmp(argv[a],"-w")==0 || strcmp(argv[a],"--client=W2BN")==0) { if (clienttag) { fprintf(stderr,"%s: client type was already specified as \"%s\"\n",argv[0],clienttag); usage(argv[0]); } clienttag = CLIENTTAG_WARCIIBNE; } else if (strcmp(argv[a],"--client=D2DV")==0) { if (clienttag) { fprintf(stderr,"%s: client type was already specified as \"%s\"\n",argv[0],clienttag); usage(argv[0]); } clienttag = CLIENTTAG_DIABLO2DV; } else if (strcmp(argv[a],"--client=D2XP")==0) { if (clienttag) { fprintf(stderr,"%s: client type was already specified as \"%s\"\n",argv[0],clienttag); usage(argv[0]); } clienttag = CLIENTTAG_DIABLO2XP; } else if (strcmp(argv[a],"--client=WAR3")==0) { if (clienttag) { fprintf(stderr,"%s: client type was already specified as \"%s\"\n",argv[0],clienttag); usage(argv[0]); } clienttag = CLIENTTAG_WARCRAFT3; } else if (strncmp(argv[a],"--client=",9)==0) { fprintf(stderr,"%s: unknown client tag \"%s\"\n",argv[0],&argv[a][9]); usage(argv[0]); } else if (strncmp(argv[a],"--hexdump=",10)==0) { if (hexfile) { fprintf(stderr,"%s: hexdump file was already specified as \"%s\"\n",argv[0],hexfile); usage(argv[0]); } hexfile = &argv[a][10]; } else if (strcmp(argv[a],"--arch=IX86")==0) { if (archtag) { fprintf(stderr,"%s: client arch was already specified as \"%s\"\n",argv[0],archtag); usage(argv[0]); } archtag = ARCHTAG_WINX86; } else if (strcmp(argv[a],"--arch=PMAC")==0) { if (archtag) { fprintf(stderr,"%s: client arch was already specified as \"%s\"\n",argv[0],archtag); usage(argv[0]); } archtag = ARCHTAG_MACPPC; } else if (strcmp(argv[a],"--arch=XMAC")==0) { if (archtag) { fprintf(stderr,"%s: client arch was already specified as \"%s\"\n",argv[0],archtag); usage(argv[0]); } archtag = ARCHTAG_OSXPPC; } else if (strncmp(argv[a],"--arch=",7)==0) { fprintf(stderr,"%s: unknown arch tag \"%s\"\n",argv[0],&argv[a][9]); usage(argv[0]); } else if (strncmp(argv[a],"--startoffset=",14)==0) { if (startoffsetoverride) { fprintf(stderr,"%s: startoffset was already specified as %u\n",argv[0],startoffset); usage(argv[0]); } if (str_to_uint(&argv[a][14],&startoffset)<0) { fprintf(stderr,"%s: startoffset \"%s\" should be a positive integer\n",argv[0],&argv[a][14]); usage(argv[0]); } startoffsetoverride = 1; } else if (strncmp(argv[a],"--exists=",9)==0) { if (exist_action!=EXIST_ACTION_UNSPEC) { fprintf(stderr,"%s: exists was already specified\n",argv[0]); usage(argv[0]); } if (argv[a][9]=='o' || argv[a][9]=='O') exist_action = EXIST_ACTION_OVERWRITE; else if (argv[a][9]=='a' || argv[a][9]=='A') exist_action = EXIST_ACTION_ASK; else if (argv[a][9]=='b' || argv[a][9]=='B') exist_action = EXIST_ACTION_BACKUP; else if (argv[a][9]=='r' || argv[a][9]=='R') exist_action = EXIST_ACTION_RESUME; else { fprintf(stderr,"%s: exists must begin with a,A,o,O,b,B,r or R",argv[0]); usage(argv[0]); } } else if (strncmp(argv[a],"--file=",7)==0) { if (reqfile) { fprintf(stderr,"%s: file was already specified as \"%s\"\n",argv[0],reqfile); usage(argv[0]); } reqfile = &argv[a][7]; } else if (strcmp(argv[a],"-v")==0 || strcmp(argv[a],"--version")==0) { printf("version "BNETD_VERSION"\n"); return 0; } else if (strcmp(argv[a],"-h")==0 || strcmp(argv[a],"--help")==0 || strcmp(argv[a],"--usage")==0) usage(argv[0]); else if (strcmp(argv[a],"--client")==0 || strcmp(argv[a],"--hexdump")==0) { fprintf(stderr,"%s: option \"%s\" requires an argument\n",argv[0],argv[a]); usage(argv[0]); } else { fprintf(stderr,"%s: unknown option \"%s\"\n",argv[0],argv[a]); usage(argv[0]); } if (servport==0) servport = BNETD_SERV_PORT; if (!clienttag) clienttag = CLIENTTAG_STARCRAFT; if (!archtag) archtag = ARCHTAG_WINX86; if (!servname) servname = BNETD_DEFAULT_HOST; if (exist_action==EXIST_ACTION_UNSPEC) exist_action = EXIST_ACTION_ASK; if (hexfile) if (!(hexstrm = fopen(hexfile,"w"))) fprintf(stderr,"%s: could not open file \"%s\" for writing the hexdump (fopen: %s)",argv[0],hexfile,strerror(errno)); else fprintf(hexstrm,"# dump generated by bnftp version "BNETD_VERSION"\n"); if (psock_init()<0) { fprintf(stderr,"%s: could not inialialize socket functions\n",argv[0]); return STATUS_FAILURE; } if (!(host = gethostbyname(servname))) { fprintf(stderr,"%s: unknown host \"%s\"\n",argv[0],servname); return STATUS_FAILURE; } fd_stdin = fileno(stdin); if (tcgetattr(fd_stdin,&in_attr_old)>=0) { in_attr_new = in_attr_old; in_attr_new.c_lflag &= ~(ECHO | ICANON); /* turn off ECHO and ICANON */ in_attr_new.c_cc[VMIN] = 1; /* require reads to return at least one byte */ in_attr_new.c_cc[VTIME] = 0; /* no timeout */ tcsetattr(fd_stdin,TCSANOW,&in_attr_new); changed_in = 1; } else { fprintf(stderr,"%s: could not get terminal attributes for stdin\n",argv[0]); changed_in = 0; } if (client_get_termsize(fd_stdin,&screen_width,&screen_height)<0) { fprintf(stderr,"%s: could not determine screen size\n",argv[0]); if (changed_in) tcsetattr(fd_stdin,TCSAFLUSH,&in_attr_old); return STATUS_FAILURE; } if ((sd = psock_socket(PSOCK_PF_INET,PSOCK_SOCK_STREAM,PSOCK_IPPROTO_TCP))<0) { fprintf(stderr,"%s: could not create socket (psock_socket: %s)\n",argv[0],strerror(psock_errno())); if (changed_in) tcsetattr(fd_stdin,TCSAFLUSH,&in_attr_old); return STATUS_FAILURE; } memset(&saddr,0,sizeof(saddr)); saddr.sin_family = PSOCK_AF_INET; saddr.sin_port = htons(servport); memcpy(&saddr.sin_addr.s_addr,host->h_addr_list[0],host->h_length); if (psock_connect(sd,(struct sockaddr *)&saddr,sizeof(saddr))<0) { fprintf(stderr,"%s: could not connect to server \"%s\" port %hu (psock_connect: %s)\n",argv[0],servname,servport,strerror(psock_errno())); if (changed_in) tcsetattr(fd_stdin,TCSAFLUSH,&in_attr_old); return STATUS_FAILURE; } printf("Connected to %s:%hu.\n",inet_ntoa(saddr.sin_addr),servport); #ifdef CLIENTDEBUG eventlog_set(stderr); #endif if (!(packet = packet_create(packet_class_init))) { fprintf(stderr,"%s: could not create packet\n",argv[0]); if (changed_in) tcsetattr(fd_stdin,TCSAFLUSH,&in_attr_old); return STATUS_FAILURE; } bn_byte_set(&packet->u.client_initconn.class,CLIENT_INITCONN_CLASS_FILE); if (hexstrm) { fprintf(hexstrm,"%d: send class=%s[0x%02hx] type=%s[0x%04hx] length=%u\n", sd, packet_get_class_str(packet),(unsigned int)packet_get_class(packet), packet_get_type_str(packet,packet_dir_from_client),packet_get_type(packet), packet_get_size(packet)); hexdump(hexstrm,packet_get_raw_data(packet,0),packet_get_size(packet)); } client_blocksend_packet(sd,packet); packet_del_ref(packet); if (!(rpacket = packet_create(packet_class_file))) { fprintf(stderr,"%s: could not create packet\n",argv[0]); if (changed_in) tcsetattr(fd_stdin,TCSAFLUSH,&in_attr_old); return STATUS_FAILURE; } if (!(fpacket = packet_create(packet_class_raw))) { fprintf(stderr,"%s: could not create packet\n",argv[0]); if (changed_in) tcsetattr(fd_stdin,TCSAFLUSH,&in_attr_old); packet_del_ref(rpacket); return STATUS_FAILURE; } if (!reqfile) /* if not specified on the command line then prompt for it */ { munged = 1; commpos = 0; text[0] = '\0'; for (;;) { switch (client_get_comm("filename: ",text,sizeof(text),&commpos,1,munged,screen_width)) { case -1: /* cancel or error */ printf("\n"); if (changed_in) tcsetattr(fd_stdin,TCSAFLUSH,&in_attr_old); packet_del_ref(fpacket); packet_del_ref(rpacket); return STATUS_FAILURE; case 0: /* timeout */ munged = 0; continue; case 1: munged = 0; if (text[0]=='\0') continue; printf("\n"); } break; } reqfile = text; } if (stat(reqfile,&exist_buf)==0) /* check if the file exists */ { char text2[MAX_MESSAGE_LEN]; munged = 1; commpos = 0; text2[0] = '\0'; while (exist_action==EXIST_ACTION_ASK) { switch (client_get_comm("File exists [O]verwrite, [B]ackup or [R]esume?: ",text2,sizeof(text2),&commpos,1,munged,screen_width)) { case -1: /* cancel or error */ printf("\n"); if (changed_in) tcsetattr(fd_stdin,TCSAFLUSH,&in_attr_old); packet_del_ref(fpacket); packet_del_ref(rpacket); return STATUS_FAILURE; case 0: /* timeout */ munged = 0; continue; case 1: munged = 0; if (text2[0]=='\0') continue; printf("\n"); break; } switch (text2[0]) { case 'o': case 'O': exist_action = EXIST_ACTION_OVERWRITE; break; case 'b': case 'B': exist_action = EXIST_ACTION_BACKUP; break; case 'r': case 'R': exist_action = EXIST_ACTION_RESUME; break; default: printf("Please answer with o,O,b,B,r or R.\n"); munged = 1; continue; } break; } switch (exist_action) { case EXIST_ACTION_OVERWRITE: if (!startoffsetoverride) startoffset = 0; break; case EXIST_ACTION_BACKUP: { char * bakfile; unsigned int bnr; int renamed=0; if (!(bakfile = malloc(strlen(reqfile)+1+2+1))) /* assuming we go up to bnr 99 we need reqfile+'.'+'99'+'\0' */ { fprintf(stderr,"%s: unable to allocate memory for backup filename.\n",argv[0]); if (changed_in) tcsetattr(fd_stdin,TCSAFLUSH,&in_attr_old); packet_del_ref(fpacket); packet_del_ref(rpacket); return STATUS_FAILURE; } for (bnr=0; bnr<100; bnr++) { sprintf(bakfile,"%s.%d",reqfile,bnr); if (stat(bakfile,&exist_buf)==0) continue; /* backup exists */ /* backup does not exist */ if (rename(reqfile,bakfile)<0) /* just rename the existing file to the backup */ fprintf(stderr,"%s: could not create backup file \"%s\" (rename: %s)\n",argv[0],bakfile,strerror(errno)); else { renamed = 1; printf("Renaming \"%s\" to \"%s\".\n",reqfile,bakfile); } break; } free(bakfile); if (!renamed) { fprintf(stderr,"%s: could not create backup for \"%s\".\n",argv[0],reqfile); if (changed_in) tcsetattr(fd_stdin,TCSAFLUSH,&in_attr_old); packet_del_ref(fpacket); packet_del_ref(rpacket); return STATUS_FAILURE; } if (!startoffsetoverride) startoffset = 0; } break; case EXIST_ACTION_RESUME: if (!startoffsetoverride) startoffset = exist_buf.st_size; break; } } else if (!startoffsetoverride) startoffset = 0; if (changed_in) tcsetattr(fd_stdin,TCSAFLUSH,&in_attr_old); if (!(packet = packet_create(packet_class_file))) { fprintf(stderr,"%s: could not create packet\n",argv[0]); packet_del_ref(fpacket); packet_del_ref(rpacket); return STATUS_FAILURE; } packet_set_size(packet,sizeof(t_client_file_req)); packet_set_type(packet,CLIENT_FILE_REQ); bn_int_tag_set(&packet->u.client_file_req.archtag,archtag); bn_int_tag_set(&packet->u.client_file_req.clienttag,clienttag); bn_int_set(&packet->u.client_file_req.adid,0); bn_int_set(&packet->u.client_file_req.extensiontag,0); bn_int_set(&packet->u.client_file_req.startoffset,startoffset); bn_long_set_a_b(&packet->u.client_file_req.timestamp,0x00000000,0x00000000); packet_append_string(packet,reqfile); if (hexstrm) { fprintf(hexstrm,"%d: send class=%s[0x%02hx] type=%s[0x%04hx] length=%u\n", sd, packet_get_class_str(packet),(unsigned int)packet_get_class(packet), packet_get_type_str(packet,packet_dir_from_client),packet_get_type(packet), packet_get_size(packet)); hexdump(hexstrm,packet_get_raw_data(packet,0),packet_get_size(packet)); } printf("\nRequesting info..."); fflush(stdout); client_blocksend_packet(sd,packet); packet_del_ref(packet); do { if (client_blockrecv_packet(sd,rpacket)<0) { fprintf(stderr,"%s: server closed connection\n",argv[0]); packet_del_ref(fpacket); packet_del_ref(rpacket); return STATUS_FAILURE; } if (hexstrm) { fprintf(hexstrm,"%d: recv class=%s[0x%02hx] type=%s[0x%04hx] length=%u\n", sd, packet_get_class_str(rpacket),(unsigned int)packet_get_class(rpacket), packet_get_type_str(rpacket,packet_dir_from_server),packet_get_type(rpacket), packet_get_size(rpacket)); hexdump(hexstrm,packet_get_raw_data(rpacket,0),packet_get_size(rpacket)); } } while (packet_get_type(rpacket)!=SERVER_FILE_REPLY); filelen = bn_int_get(rpacket->u.server_file_reply.filelen); bn_long_to_bnettime(rpacket->u.server_file_reply.timestamp,&bntime); tm = bnettime_to_time(bntime); strftime(timestr,FILE_TIME_MAXLEN,FILE_TIME_FORMAT,localtime(&tm)); filename = packet_get_str_const(rpacket,sizeof(t_server_file_reply),MAX_FILENAME_STR); if (exist_action==EXIST_ACTION_RESUME) { if (!(fp = fopen(reqfile,"ab"))) { fprintf(stderr,"%s: could not open file \"%s\" for appending (fopen: %s)\n",argv[0],reqfile,strerror(errno)); packet_del_ref(fpacket); packet_del_ref(rpacket); return STATUS_FAILURE; } } else { if (!(fp = fopen(reqfile,"wb"))) { fprintf(stderr,"%s: could not open file \"%s\" for writing (fopen: %s)\n",argv[0],reqfile,strerror(errno)); packet_del_ref(fpacket); packet_del_ref(rpacket); return STATUS_FAILURE; } } printf("\n name: \""); str_print_term(stdout,filename,0,0); printf("\"\n changed: %s\n length: %u bytes\n",timestr,filelen); fflush(stdout); if (startoffset>0) { filelen -= startoffset; /* for resuming files */ printf("Resuming at position %u (%u bytes remaining).\n",startoffset,filelen); } printf("\nSaving to \"%s\"...",reqfile); for (currsize=0; currsize+MAX_PACKET_SIZE<=filelen; currsize+=MAX_PACKET_SIZE) { printf("."); fflush(stdout); if (client_blockrecv_raw_packet(sd,fpacket,MAX_PACKET_SIZE)<0) { printf("error\n"); fprintf(stderr,"%s: server closed connection\n",argv[0]); if (fclose(fp)<0) fprintf(stderr,"%s: could not close file \"%s\" after writing (fclose: %s)\n",argv[0],reqfile,strerror(errno)); packet_del_ref(fpacket); packet_del_ref(rpacket); return STATUS_FAILURE; } if (hexstrm) { fprintf(hexstrm,"%d: recv class=%s[0x%02hx] type=%s[0x%04hx] length=%u\n", sd, packet_get_class_str(fpacket),(unsigned int)packet_get_class(fpacket), packet_get_type_str(fpacket,packet_dir_from_server),packet_get_type(fpacket), packet_get_size(fpacket)); hexdump(hexstrm,packet_get_raw_data(fpacket,0),packet_get_size(fpacket)); } if (fwrite(packet_get_raw_data_const(fpacket,0),1,MAX_PACKET_SIZE,fp)<MAX_PACKET_SIZE) { printf("error\n"); fprintf(stderr,"%s: could not write to file \"%s\" (fwrite: %s)\n",argv[0],reqfile,strerror(errno)); if (fclose(fp)<0) fprintf(stderr,"%s: could not close file \"%s\" after writing (fclose: %s)\n",argv[0],reqfile,strerror(errno)); packet_del_ref(fpacket); packet_del_ref(rpacket); return STATUS_FAILURE; } } filelen -= currsize; if (filelen) { printf("."); fflush(stdout); if (client_blockrecv_raw_packet(sd,fpacket,filelen)<0) { printf("error\n"); fprintf(stderr,"%s: server closed connection\n",argv[0]); if (fclose(fp)<0) fprintf(stderr,"%s: could not close file \"%s\" after writing (fclose: %s)\n",argv[0],reqfile,strerror(errno)); packet_del_ref(fpacket); packet_del_ref(rpacket); return STATUS_FAILURE; } if (hexstrm) { fprintf(hexstrm,"%d: recv class=%s[0x%02hx] type=%s[0x%04hx] length=%u\n", sd, packet_get_class_str(fpacket),(unsigned int)packet_get_class(fpacket), packet_get_type_str(fpacket,packet_dir_from_server),packet_get_type(fpacket), packet_get_size(fpacket)); hexdump(hexstrm,packet_get_raw_data(fpacket,0),packet_get_size(fpacket)); } if (fwrite(packet_get_raw_data_const(fpacket,0),1,filelen,fp)<filelen) { printf("error\n"); fprintf(stderr,"%s: could not write to file \"%s\"\n",argv[0],reqfile); if (fclose(fp)<0) fprintf(stderr,"%s: could not close file \"%s\" after writing (fclose: %s)\n",argv[0],reqfile,strerror(errno)); packet_del_ref(fpacket); packet_del_ref(rpacket); return STATUS_FAILURE; } } packet_del_ref(fpacket); packet_del_ref(rpacket); if (hexstrm) { fprintf(hexstrm,"# end of dump\n"); if (fclose(hexstrm)<0) fprintf(stderr,"%s: could not close hexdump file \"%s\" after writing (fclose: %s)",argv[0],hexfile,strerror(errno)); } if (fclose(fp)<0) { fprintf(stderr,"%s: could not close file \"%s\" after writing (fclose: %s)\n",argv[0],reqfile,strerror(errno)); return STATUS_FAILURE; } printf("done\n"); return STATUS_FAILURE; }
static int _client_anongame_infos(t_connection * c, t_packet const * const packet) { t_packet * rpacket; if (bn_int_get(packet->u.client_findanongame_inforeq.count) > 1) { /* reply with 0 entries found */ int temp = 0; if ((rpacket = packet_create(packet_class_bnet)) == NULL) { eventlog(eventlog_level_error, __FUNCTION__, "could not create new packet"); return -1; } packet_set_size(rpacket, sizeof(t_server_findanongame_inforeply)); packet_set_type(rpacket, SERVER_FINDANONGAME_INFOREPLY); bn_byte_set(&rpacket->u.server_findanongame_inforeply.option, CLIENT_FINDANONGAME_INFOS); bn_int_set(&rpacket->u.server_findanongame_inforeply.count, bn_int_get(packet->u.client_findanongame_inforeq.count)); bn_byte_set(&rpacket->u.server_findanongame_inforeply.noitems, 0); packet_append_data(rpacket, &temp, 1); conn_push_outqueue(c,rpacket); packet_del_ref(rpacket); } else { int i; int client_tag; int server_tag_count = 0; int client_tag_unk; int server_tag_unk; bn_int temp; char noitems; char * tmpdata; int tmplen; t_clienttag clienttag = conn_get_clienttag(c); char last_packet = 0x00; char other_packet = 0x01; char langstr[5]; t_gamelang gamelang = conn_get_gamelang(c); bn_int_tag_get((bn_int const *)&gamelang, langstr, 5); /* Send seperate packet for each item requested * sending all at once overloaded w3xp * [Omega] */ for (i=0;i<bn_byte_get(packet->u.client_findanongame_inforeq.noitems);i++){ noitems = 0; if ((rpacket = packet_create(packet_class_bnet)) == NULL) { eventlog(eventlog_level_error, __FUNCTION__, "could not create new packet"); return -1; } /* Starting the packet stuff */ packet_set_size(rpacket, sizeof(t_server_findanongame_inforeply)); packet_set_type(rpacket, SERVER_FINDANONGAME_INFOREPLY); bn_byte_set(&rpacket->u.server_findanongame_inforeply.option, CLIENT_FINDANONGAME_INFOS); bn_int_set(&rpacket->u.server_findanongame_inforeply.count, 1); std::memcpy(&temp,(packet_get_data_const(packet,10+(i*8),4)),sizeof(int)); client_tag=bn_int_get(temp); std::memcpy(&temp,packet_get_data_const(packet,14+(i*8),4),sizeof(int)); client_tag_unk=bn_int_get(temp); switch (client_tag){ case CLIENT_FINDANONGAME_INFOTAG_URL: bn_int_set((bn_int*)&server_tag_unk,0xBF1F1047); packet_append_data(rpacket, "LRU\0" , 4); packet_append_data(rpacket, &server_tag_unk , 4); // FIXME: Maybe need do do some checks to avoid prefs empty strings. tmpdata = anongame_infos_data_get_url(clienttag, conn_get_versionid(c), &tmplen); packet_append_data(rpacket, tmpdata, tmplen); noitems++; server_tag_count++; eventlog(eventlog_level_debug,__FUNCTION__,"client_tag request tagid=(0x%01x) tag=(%s) tag_unk=(0x%04x)",i,"CLIENT_FINDANONGAME_INFOTAG_URL",client_tag_unk); break; case CLIENT_FINDANONGAME_INFOTAG_MAP: bn_int_set((bn_int*)&server_tag_unk,0x70E2E0D5); packet_append_data(rpacket, "PAM\0" , 4); packet_append_data(rpacket, &server_tag_unk , 4); tmpdata = anongame_infos_data_get_map(clienttag, conn_get_versionid(c), &tmplen); packet_append_data(rpacket, tmpdata, tmplen); noitems++; server_tag_count++; eventlog(eventlog_level_debug,__FUNCTION__,"client_tag request tagid=(0x%01x) tag=(%s) tag_unk=(0x%04x)",i,"CLIENT_FINDANONGAME_INFOTAG_MAP",client_tag_unk); break; case CLIENT_FINDANONGAME_INFOTAG_TYPE: bn_int_set((bn_int*)&server_tag_unk,0x7C87DEEE); packet_append_data(rpacket, "EPYT" , 4); packet_append_data(rpacket, &server_tag_unk , 4); tmpdata = anongame_infos_data_get_type(clienttag, conn_get_versionid(c), &tmplen); packet_append_data(rpacket, tmpdata, tmplen); noitems++; server_tag_count++; eventlog(eventlog_level_debug,__FUNCTION__,"client_tag request tagid=(0x%01x) tag=(%s) tag_unk=(0x%04x)",i,"CLIENT_FINDANONGAME_INFOTAG_TYPE",client_tag_unk); break; case CLIENT_FINDANONGAME_INFOTAG_DESC: bn_int_set((bn_int*)&server_tag_unk,0xA4F0A22F); packet_append_data(rpacket, "CSED" , 4); packet_append_data(rpacket,&server_tag_unk,4); tmpdata = anongame_infos_data_get_desc(langstr, clienttag, conn_get_versionid(c), &tmplen); packet_append_data(rpacket, tmpdata, tmplen); eventlog(eventlog_level_debug,__FUNCTION__,"client_tag request tagid=(0x%01x) tag=(%s) tag_unk=(0x%04x)",i,"CLIENT_FINDANONGAME_INFOTAG_DESC",client_tag_unk); noitems++; server_tag_count++; break; case CLIENT_FINDANONGAME_INFOTAG_LADR: bn_int_set((bn_int*)&server_tag_unk,0x3BADE25A); packet_append_data(rpacket, "RDAL" , 4); packet_append_data(rpacket, &server_tag_unk , 4); tmpdata = anongame_infos_data_get_ladr(langstr, clienttag, conn_get_versionid(c), &tmplen); packet_append_data(rpacket, tmpdata, tmplen); noitems++; server_tag_count++; eventlog(eventlog_level_debug,__FUNCTION__,"client_tag request tagid=(0x%01x) tag=(%s) tag_unk=(0x%04x)",i,"CLIENT_FINDANONGAME_INFOTAG_LADR",client_tag_unk); break; default: eventlog(eventlog_level_debug,__FUNCTION__,"unrec client_tag request tagid=(0x%01x) tag=(0x%04x)",i,client_tag); } //Adding a last padding null-byte if (server_tag_count == bn_byte_get(packet->u.client_findanongame_inforeq.noitems)) packet_append_data(rpacket, &last_packet, 1); /* only last packet in group gets 0x00 */ else packet_append_data(rpacket, &other_packet, 1); /* the rest get 0x01 */ //Go,go,go bn_byte_set(&rpacket->u.server_findanongame_inforeply.noitems, noitems); conn_push_outqueue(c,rpacket); packet_del_ref(rpacket); } } return 0; }
/* tournament notice disabled at this time, but responce is sent to cleint */ static int _client_anongame_tournament(t_connection * c, t_packet const * const packet) { t_packet * rpacket; t_account * account = conn_get_account(c); t_clienttag clienttag = conn_get_clienttag(c); unsigned int start_prelim = tournament_get_start_preliminary(); unsigned int end_signup = tournament_get_end_signup(); unsigned int end_prelim = tournament_get_end_preliminary(); unsigned int start_r1 = tournament_get_start_round_1(); if ((rpacket = packet_create(packet_class_bnet)) == NULL) { eventlog(eventlog_level_error, __FUNCTION__, "could not create new packet"); return -1; } packet_set_size(rpacket, sizeof(t_server_anongame_tournament_reply)); packet_set_type(rpacket, SERVER_FINDANONGAME_TOURNAMENT_REPLY); bn_byte_set(&rpacket->u.server_anongame_tournament_reply.option, 7); bn_int_set(&rpacket->u.server_anongame_tournament_reply.count, bn_int_get(packet->u.client_anongame_tournament_request.count)); if ( !start_prelim || (end_signup <= now && tournament_user_signed_up(account) < 0) || tournament_check_client(clienttag) < 0) { /* No Tournament Notice */ bn_byte_set( &rpacket->u.server_anongame_tournament_reply.type, 0); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.unknown, 0); bn_short_set( &rpacket->u.server_anongame_tournament_reply.unknown4, 0); bn_int_set( &rpacket->u.server_anongame_tournament_reply.timestamp, 0); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.unknown5, 0); bn_short_set( &rpacket->u.server_anongame_tournament_reply.countdown, 0); bn_short_set( &rpacket->u.server_anongame_tournament_reply.unknown2, 0); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.wins, 0); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.losses, 0); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.ties, 0); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.unknown3, 0); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.selection, 0); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.descnum, 0); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.nulltag, 0); } else if (start_prelim>=now) { /* Tournament Notice */ bn_byte_set( &rpacket->u.server_anongame_tournament_reply.type, 1); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.unknown, 0); bn_short_set( &rpacket->u.server_anongame_tournament_reply.unknown4, 0x0000); /* random */ bn_int_set( &rpacket->u.server_anongame_tournament_reply.timestamp, _tournament_time_convert(start_prelim)); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.unknown5, 0x01); bn_short_set( &rpacket->u.server_anongame_tournament_reply.countdown, start_prelim-now); bn_short_set( &rpacket->u.server_anongame_tournament_reply.unknown2, 0); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.wins, 0); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.losses, 0); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.ties, 0); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.unknown3, 0x00); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.selection, 2); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.descnum, 0); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.nulltag, 0); } else if (end_signup>=now) { /* Tournament Signup Notice - Play Game Active */ bn_byte_set( &rpacket->u.server_anongame_tournament_reply.type, 2); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.unknown, 0); bn_short_set( &rpacket->u.server_anongame_tournament_reply.unknown4, 0x0828); /* random */ bn_int_set( &rpacket->u.server_anongame_tournament_reply.timestamp, _tournament_time_convert(end_signup)); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.unknown5, 0x01); bn_short_set( &rpacket->u.server_anongame_tournament_reply.countdown, end_signup-now); bn_short_set( &rpacket->u.server_anongame_tournament_reply.unknown2, 0); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.wins, tournament_get_stat(account, 1)); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.losses, tournament_get_stat(account, 2)); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.ties, tournament_get_stat(account, 3)); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.unknown3, 0x08); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.selection, 2); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.descnum, 0); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.nulltag, 0); } else if (end_prelim>=now) { /* Tournament Prelim Period - Play Game Active */ bn_byte_set( &rpacket->u.server_anongame_tournament_reply.type, 3); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.unknown, 0); bn_short_set( &rpacket->u.server_anongame_tournament_reply.unknown4, 0x0828); /* random */ bn_int_set( &rpacket->u.server_anongame_tournament_reply.timestamp, _tournament_time_convert(end_prelim)); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.unknown5, 0x01); bn_short_set( &rpacket->u.server_anongame_tournament_reply.countdown, end_prelim-now); bn_short_set( &rpacket->u.server_anongame_tournament_reply.unknown2, 0); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.wins, tournament_get_stat(account, 1)); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.losses, tournament_get_stat(account, 2)); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.ties, tournament_get_stat(account, 3)); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.unknown3, 0x08); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.selection, 2); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.descnum, 0); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.nulltag, 0); } else if (start_r1>=now && (tournament_get_game_in_progress()) ) { /* Prelim Period Over - Shows user stats (not all prelim games finished) */ bn_byte_set( &rpacket->u.server_anongame_tournament_reply.type, 4); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.unknown, 0); bn_short_set( &rpacket->u.server_anongame_tournament_reply.unknown4, 0x0000); /* random */ bn_int_set( &rpacket->u.server_anongame_tournament_reply.timestamp, _tournament_time_convert(start_r1)); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.unknown5, 0x01); bn_short_set( &rpacket->u.server_anongame_tournament_reply.countdown, start_r1-now); bn_short_set( &rpacket->u.server_anongame_tournament_reply.unknown2, 0); /* 00 00 */ bn_byte_set( &rpacket->u.server_anongame_tournament_reply.wins, tournament_get_stat(account, 1)); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.losses, tournament_get_stat(account, 2)); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.ties, tournament_get_stat(account, 3)); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.unknown3, 0x08); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.selection, 2); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.descnum, 0); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.nulltag, 0); } else if (!(tournament_get_in_finals_status(account))) { /* Prelim Period Over - user did not make finals - Shows user stats */ bn_byte_set( &rpacket->u.server_anongame_tournament_reply.type, 5); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.unknown, 0); bn_short_set( &rpacket->u.server_anongame_tournament_reply.unknown4, 0); bn_int_set( &rpacket->u.server_anongame_tournament_reply.timestamp, 0); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.unknown5, 0); bn_short_set( &rpacket->u.server_anongame_tournament_reply.countdown, 0); bn_short_set( &rpacket->u.server_anongame_tournament_reply.unknown2, 0); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.wins, tournament_get_stat(account, 1)); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.losses, tournament_get_stat(account, 2)); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.ties, tournament_get_stat(account, 3)); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.unknown3, 0x04); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.selection, 2); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.descnum, 0); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.nulltag, 0); } /* cycle through [type-6] & [type-7] packets * * use [type-6] to show client "eliminated" or "continue" * timestamp , countdown & round number (of next round) must be set if clinet continues * * use [type-7] to make cleint wait for 44FF packet option 1 to start game (A guess, not tested) * * not sure if there is overall winner packet sent at end of last final round */ else if ( (0) ) { /* User in finals - Shows user stats and start of next round*/ bn_byte_set( &rpacket->u.server_anongame_tournament_reply.type, 6); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.unknown, 0); bn_short_set( &rpacket->u.server_anongame_tournament_reply.unknown4, 0x0000); bn_int_set( &rpacket->u.server_anongame_tournament_reply.timestamp, _tournament_time_convert(start_r1)); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.unknown5, 0x01); bn_short_set( &rpacket->u.server_anongame_tournament_reply.countdown, start_r1-now); bn_short_set( &rpacket->u.server_anongame_tournament_reply.unknown2, 0x0000); /* 00 00 */ bn_byte_set( &rpacket->u.server_anongame_tournament_reply.wins, 4); /* round number */ bn_byte_set( &rpacket->u.server_anongame_tournament_reply.losses, 0); /* 0 = continue , 1= eliminated */ bn_byte_set( &rpacket->u.server_anongame_tournament_reply.ties, 0); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.unknown3, 0x04); /* number of rounds in finals */ bn_byte_set( &rpacket->u.server_anongame_tournament_reply.selection, 2); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.descnum, 0); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.nulltag, 0); } else if ( (0) ) { /* user waiting for match to be made */ bn_byte_set( &rpacket->u.server_anongame_tournament_reply.type, 7); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.unknown, 0); bn_short_set( &rpacket->u.server_anongame_tournament_reply.unknown4, 0); bn_int_set( &rpacket->u.server_anongame_tournament_reply.timestamp, 0); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.unknown5, 0); bn_short_set( &rpacket->u.server_anongame_tournament_reply.countdown, 0); bn_short_set( &rpacket->u.server_anongame_tournament_reply.unknown2, 0); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.wins, 1); /* round number */ bn_byte_set( &rpacket->u.server_anongame_tournament_reply.losses, 0); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.ties, 0); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.unknown3, 0x04); /* number of finals */ bn_byte_set( &rpacket->u.server_anongame_tournament_reply.selection, 2); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.descnum, 0); bn_byte_set( &rpacket->u.server_anongame_tournament_reply.nulltag, 0); } conn_push_outqueue(c,rpacket); packet_del_ref(rpacket); return 0; }
int capture_ws_check_packet(packet_t *packet) { int ws_off = 0; u_char ws_fin; u_char ws_opcode; u_char ws_mask; uint8_t ws_len; u_char ws_mask_key[4]; u_char *payload, *newpayload; uint32_t size_payload; int i; /** * WSocket header definition according to RFC 6455 * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-------+-+-------------+-------------------------------+ * |F|R|R|R| opcode|M| Payload len | Extended payload length | * |I|S|S|S| (4) |A| (7) | (16/64) | * |N|V|V|V| |S| | (if payload len==126/127) | * | |1|2|3| |K| | | * +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + * | Extended payload length continued, if payload len == 127 | * + - - - - - - - - - - - - - - - +-------------------------------+ * | |Masking-key, if MASK set to 1 | * +-------------------------------+-------------------------------+ * | Masking-key (continued) | Payload Data | * +-------------------------------- - - - - - - - - - - - - - - - + * : Payload Data continued ... : * + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * | Payload Data continued ... | * +---------------------------------------------------------------+ */ // Get payload from packet(s) size_payload = packet_payloadlen(packet); payload = packet_payload(packet); // Check we have payload if (size_payload == 0) return 0; // Flags && Opcode ws_fin = (*payload & WH_FIN) >> 4; ws_opcode = *payload & WH_OPCODE; ws_off++; // Only interested in Ws text packets if (ws_opcode != WS_OPCODE_TEXT) return 0; // Masked flag && Payload len ws_mask = (*(payload + ws_off) & WH_MASK) >> 4; ws_len = (*(payload + ws_off) & WH_LEN); ws_off++; // Skip Payload len switch (ws_len) { // Extended case 126: ws_off += 2; break; case 127: ws_off += 8; break; default: return 0; } // Get Masking key if mask is enabled if (ws_mask) { memcpy(ws_mask_key, (payload + ws_off), 4); ws_off += 4; } // Skip Websocket headers size_payload -= ws_off; if ((int32_t) size_payload <= 0) return 0; newpayload = sng_malloc(size_payload); memcpy(newpayload, payload + ws_off, size_payload); // If mask is enabled, unmask the payload if (ws_mask) { for (i = 0; i < size_payload; i++) newpayload[i] = newpayload[i] ^ ws_mask_key[i % 4]; } // Set new packet payload into the packet packet_set_payload(packet, newpayload, size_payload); // Free the new payload sng_free(newpayload); if (packet->type == PACKET_SIP_TLS) { packet_set_type(packet, PACKET_SIP_WSS); } else { packet_set_type(packet, PACKET_SIP_WS); } return 1; }
static int _client_anongame_get_icon(t_connection * c, t_packet const * const packet) { t_packet * rpacket; //BlacKDicK 04/20/2003 Need some huge re-work on this. { struct { char icon_code[4]; unsigned int portrait_code; char race; bn_short required_wins; char client_enabled; } tempicon; //FIXME: Add those to the prefs and also merge them on accoun_wrap; // FIXED BY DJP 07/16/2003 FOR 110 CHANGE ( TOURNEY & RACE WINS ) + Table_witdh short icon_req_race_wins; short icon_req_tourney_wins; int race[]={W3_RACE_RANDOM,W3_RACE_HUMANS,W3_RACE_ORCS,W3_RACE_UNDEAD,W3_RACE_NIGHTELVES,W3_RACE_DEMONS}; char race_char[6] ={'R','H','O','U','N','D'}; char icon_pos[5] ={'2','3','4','5','6',}; char table_width = 6; char table_height= 5; int i,j; char rico; unsigned int rlvl,rwins; t_clienttag clienttag; t_account * acc; char user_icon[5]; char const * uicon; clienttag = conn_get_clienttag(c); acc = conn_get_account(c); /* WAR3 uses a different table size, might change if blizzard add tournament support to RoC */ if (clienttag==CLIENTTAG_WARCRAFT3_UINT) { table_width = 5; table_height= 4; } eventlog(eventlog_level_info,__FUNCTION__,"[%d] got FINDANONGAME Get Icons packet",conn_get_socket(c)); if ((rpacket = packet_create(packet_class_bnet)) == NULL) { eventlog(eventlog_level_error, __FUNCTION__, "could not create new packet"); return -1; } packet_set_size(rpacket, sizeof(t_server_findanongame_iconreply)); packet_set_type(rpacket, SERVER_FINDANONGAME_ICONREPLY); bn_int_set(&rpacket->u.server_findanongame_iconreply.count, bn_int_get(packet->u.client_findanongame_inforeq.count)); bn_byte_set(&rpacket->u.server_findanongame_iconreply.option, CLIENT_FINDANONGAME_GET_ICON); if ((uicon = account_get_user_icon(acc,clienttag))) { std::memcpy(&rpacket->u.server_findanongame_iconreply.curricon, uicon,4); } else { account_get_raceicon(acc,&rico,&rlvl,&rwins,clienttag); std::sprintf(user_icon,"%1d%c3W",rlvl,rico); std::memcpy(&rpacket->u.server_findanongame_iconreply.curricon,user_icon,4); } bn_byte_set(&rpacket->u.server_findanongame_iconreply.table_width, table_width); bn_byte_set(&rpacket->u.server_findanongame_iconreply.table_size, table_width*table_height); for (j=0;j<table_height;j++){ icon_req_race_wins = anongame_infos_get_ICON_REQ(j+1,clienttag); for (i=0;i<table_width;i++){ tempicon.race=i; tempicon.icon_code[0] = icon_pos[j]; tempicon.icon_code[1] = race_char[i]; tempicon.icon_code[2] = '3'; tempicon.icon_code[3] = 'W'; tempicon.portrait_code = (account_icon_to_profile_icon(tempicon.icon_code,acc,clienttag)); if (i<=4){ //Building the icon for the races bn_short_set(&tempicon.required_wins,icon_req_race_wins); if (account_get_racewins(acc,race[i],clienttag)>=icon_req_race_wins) { tempicon.client_enabled=1; }else{ tempicon.client_enabled=0; } }else{ //Building the icon for the tourney icon_req_tourney_wins = anongame_infos_get_ICON_REQ_TOURNEY(j+1); bn_short_set(&tempicon.required_wins,icon_req_tourney_wins); if (account_get_racewins(acc,race[i],clienttag)>=icon_req_tourney_wins) { tempicon.client_enabled=1; }else{ tempicon.client_enabled=0;} } packet_append_data(rpacket, &tempicon, sizeof(tempicon)); } } //Go,go,go conn_push_outqueue(c,rpacket); packet_del_ref(rpacket); } return 0; }
static int on_d2cs_charloginreq(t_connection * c, t_packet const * packet) { t_connection * client; char const * charname; char const * portrait; char const * clienttag; char * temp; unsigned int sessionnum; t_realm * realm; char const * realmname; unsigned int pos, reply; t_packet * rpacket; if (packet_get_size(packet)<sizeof(t_d2cs_bnetd_charloginreq)) { eventlog(eventlog_level_error,__FUNCTION__,"got bad packet size"); return -1; } sessionnum=bn_int_get(packet->u.d2cs_bnetd_charloginreq.sessionnum); pos=sizeof(t_d2cs_bnetd_charloginreq); if (!(charname=packet_get_str_const(packet,pos,CHAR_NAME_LEN))) { eventlog(eventlog_level_error,__FUNCTION__,"got bad character name"); return -1; } pos+=strlen(charname)+1; if (!(portrait=packet_get_str_const(packet,pos,CHAR_PORTRAIT_LEN))) { eventlog(eventlog_level_error,__FUNCTION__,"got bad character portrait"); return -1; } if (!(client=connlist_find_connection_by_sessionnum(sessionnum))) { eventlog(eventlog_level_error,__FUNCTION__,"user %d not found",sessionnum); reply = BNETD_D2CS_CHARLOGINREPLY_FAILED; } else if (!(clienttag=clienttag_uint_to_str(conn_get_clienttag(client)))) { eventlog(eventlog_level_error,__FUNCTION__,"got NULL clienttag"); reply = BNETD_D2CS_CHARLOGINREPLY_FAILED; } else if (!(realm=conn_get_realm(client))) { eventlog(eventlog_level_error,__FUNCTION__,"got NULL realm"); reply = BNETD_D2CS_CHARLOGINREPLY_FAILED; } else { char revtag[8]; realmname = realm_get_name(realm); temp=xmalloc(strlen(clienttag)+strlen(realmname)+1+strlen(charname)+1+ strlen(portrait)+1); reply = BNETD_D2CS_CHARLOGINREPLY_SUCCEED; strcpy(revtag,clienttag); strreverse(revtag); sprintf(temp,"%4s%s,%s,%s",revtag,realmname,charname,portrait); conn_set_charname(client,charname); conn_set_realminfo(client,temp); xfree(temp); eventlog(eventlog_level_debug,__FUNCTION__, "loaded portrait for character %s",charname); } if ((rpacket=packet_create(packet_class_d2cs_bnetd))) { packet_set_size(rpacket,sizeof(t_bnetd_d2cs_charloginreply)); packet_set_type(rpacket,BNETD_D2CS_CHARLOGINREPLY); bn_int_set(&rpacket->u.bnetd_d2cs_charloginreply.h.seqno, bn_int_get(packet->u.d2cs_bnetd_charloginreq.h.seqno)); bn_int_set(&rpacket->u.bnetd_d2cs_charloginreply.reply,reply); conn_push_outqueue(c,rpacket); packet_del_ref(rpacket); } return 0; }
void parse_packet(u_char *info, const struct pcap_pkthdr *header, const u_char *packet) { // Capture info capture_info_t *capinfo = (capture_info_t *) info; // UDP header data struct udphdr *udp; // UDP header size uint16_t udp_off; // TCP header data struct tcphdr *tcp; // TCP header size uint16_t tcp_off; // Packet data u_char data[MAX_CAPTURE_LEN]; // Packet payload data u_char *payload = NULL; // Whole packet size uint32_t size_capture = header->caplen; // Packet payload size uint32_t size_payload = size_capture - capinfo->link_hl; // Captured packet info packet_t *pkt; // Ignore packets while capture is paused if (capture_paused()) return; // Check if we have reached capture limit if (capture_cfg.limit && sip_calls_count() >= capture_cfg.limit) { // If capture rotation is disabled, just skip this packet if (!capture_cfg.rotate) { return; } } // Check maximum capture length if (header->caplen > MAX_CAPTURE_LEN) return; // Copy packet payload memcpy(data, packet, header->caplen); // Check if we have a complete IP packet if (!(pkt = capture_packet_reasm_ip(capinfo, header, data, &size_payload, &size_capture))) return; // Only interested in UDP packets if (pkt->proto == IPPROTO_UDP) { // Get UDP header udp = (struct udphdr *)((u_char *)(data) + (size_capture - size_payload)); udp_off = sizeof(struct udphdr); // Set packet ports pkt->src.port = htons(udp->uh_sport); pkt->dst.port = htons(udp->uh_dport); // Remove UDP Header from payload size_payload -= udp_off; if ((int32_t)size_payload < 0) size_payload = 0; // Remove TCP Header from payload payload = (u_char *) (udp) + udp_off; // Complete packet with Transport information packet_set_type(pkt, PACKET_SIP_UDP); packet_set_payload(pkt, payload, size_payload); } else if (pkt->proto == IPPROTO_TCP) { // Get TCP header tcp = (struct tcphdr *)((u_char *)(data) + (size_capture - size_payload)); tcp_off = (tcp->th_off * 4); // Set packet ports pkt->src.port = htons(tcp->th_sport); pkt->dst.port = htons(tcp->th_dport); // Get actual payload size size_payload -= tcp_off; if ((int32_t)size_payload < 0) size_payload = 0; // Get payload start payload = (u_char *)(tcp) + tcp_off; // Complete packet with Transport information packet_set_type(pkt, PACKET_SIP_TCP); packet_set_payload(pkt, payload, size_payload); // Create a structure for this captured packet if (!(pkt = capture_packet_reasm_tcp(pkt, tcp, payload, size_payload))) return; #if defined(WITH_GNUTLS) || defined(WITH_OPENSSL) // Check if packet is TLS if (capture_cfg.keyfile) { tls_process_segment(pkt, tcp); } #endif // Check if packet is WS or WSS capture_ws_check_packet(pkt); } else { // Not handled protocol packet_destroy(pkt); return; } // Avoid parsing from multiples sources. // Avoid parsing while screen in being redrawn capture_lock(); // Check if we can handle this packet if (capture_packet_parse(pkt) == 0) { #ifdef USE_EEP // Send this packet through eep capture_eep_send(pkt); #endif // Store this packets in output file dump_packet(capture_cfg.pd, pkt); // If storage is disabled, delete frames payload if (capture_cfg.storage == 0) { packet_free_frames(pkt); } // Allow Interface refresh and user input actions capture_unlock(); return; } // Not an interesting packet ... packet_destroy(pkt); // Allow Interface refresh and user input actions capture_unlock(); }
static int on_d2cs_accountloginreq(t_connection * c, t_packet const * packet) { unsigned int sessionkey; unsigned int sessionnum; unsigned int salt; char const * account; char const * tname; t_connection * client; int reply; t_packet * rpacket; struct { bn_int salt; bn_int sessionkey; bn_int sessionnum; bn_int secret; bn_int passhash[5]; } temp; t_hash secret_hash; char const * pass_str; t_hash passhash; t_hash try_hash; if (packet_get_size(packet)<sizeof(t_d2cs_bnetd_accountloginreq)) { eventlog(eventlog_level_error,__FUNCTION__,"got bad packet size"); return -1; } if (!(account=packet_get_str_const(packet,sizeof(t_d2cs_bnetd_accountloginreq),USER_NAME_MAX))) { eventlog(eventlog_level_error,__FUNCTION__,"missing or too long account name"); return -1; } sessionkey=bn_int_get(packet->u.d2cs_bnetd_accountloginreq.sessionkey); sessionnum=bn_int_get(packet->u.d2cs_bnetd_accountloginreq.sessionnum); salt=bn_int_get(packet->u.d2cs_bnetd_accountloginreq.seqno); if (!(client=connlist_find_connection_by_sessionnum(sessionnum))) { eventlog(eventlog_level_error,__FUNCTION__,"sessionnum %d not found",sessionnum); reply=BNETD_D2CS_ACCOUNTLOGINREPLY_FAILED; } else if (sessionkey!=conn_get_sessionkey(client)) { eventlog(eventlog_level_error,__FUNCTION__,"sessionkey %d not match",sessionkey); reply=BNETD_D2CS_ACCOUNTLOGINREPLY_FAILED; } else if (!(tname=conn_get_username(client))) { eventlog(eventlog_level_error,__FUNCTION__,"got NULL username"); reply=BNETD_D2CS_ACCOUNTLOGINREPLY_FAILED; } else if (strcasecmp(account,tname)) { eventlog(eventlog_level_error,__FUNCTION__,"username %s not match",account); reply=BNETD_D2CS_ACCOUNTLOGINREPLY_FAILED; } else { bn_int_set(&temp.salt,salt); bn_int_set(&temp.sessionkey,sessionkey); bn_int_set(&temp.sessionnum,sessionnum); bn_int_set(&temp.secret,conn_get_secret(client)); pass_str=account_get_pass(conn_get_account(client)); if (hash_set_str(&passhash,pass_str)<0) { reply=BNETD_D2CS_ACCOUNTLOGINREPLY_FAILED; } else { hash_to_bnhash((t_hash const *)&passhash,temp.passhash); bnet_hash(&secret_hash,sizeof(temp),&temp); bnhash_to_hash(packet->u.d2cs_bnetd_accountloginreq.secret_hash,&try_hash); if (hash_eq(try_hash,secret_hash)==1) { eventlog(eventlog_level_debug,__FUNCTION__,"user %s loggedin on d2cs", account); reply=BNETD_D2CS_ACCOUNTLOGINREPLY_SUCCEED; } else { eventlog(eventlog_level_error,__FUNCTION__,"user %s hash not match", account); reply=BNETD_D2CS_ACCOUNTLOGINREPLY_FAILED; } } } if ((rpacket=packet_create(packet_class_d2cs_bnetd))) { packet_set_size(rpacket,sizeof(t_bnetd_d2cs_accountloginreply)); packet_set_type(rpacket,BNETD_D2CS_ACCOUNTLOGINREPLY); bn_int_set(&rpacket->u.bnetd_d2cs_accountloginreply.h.seqno, bn_int_get(packet->u.d2cs_bnetd_accountloginreq.h.seqno)); bn_int_set(&rpacket->u.bnetd_d2cs_accountloginreply.reply,reply); conn_push_outqueue(c,rpacket); packet_del_ref(rpacket); } return 0; }
packet_t * capture_eep_receive_v3() { struct hep_generic hg; hep_chunk_ip4_t src_ip4, dst_ip4; #ifdef USE_IPV6 hep_chunk_ip6_t src_ip6, dst_ip6; #endif hep_chunk_t payload_chunk; hep_chunk_t authkey_chunk; uint8_t family, proto; char password[100]; int password_len; unsigned char *payload = 0; uint32_t len, pos; char buffer[MAX_CAPTURE_LEN] ; //! Source and Destination Address address_t src, dst; //! EEP client data struct sockaddr eep_client; socklen_t eep_client_len; //! Packet header struct pcap_pkthdr header; //! New created packet pointer packet_t *pkt; /* Receive EEP generic header */ if (recvfrom(eep_cfg.server_sock, buffer, MAX_CAPTURE_LEN, 0, &eep_client, &eep_client_len) == -1) return NULL; /* Copy initial bytes to EEP Generic header */ memcpy(&hg, buffer, sizeof(struct hep_generic)); /* header check */ if (memcmp(hg.header.id, "\x48\x45\x50\x33", 4) != 0) return NULL; /* IP proto */ family = hg.ip_family.data; /* Proto ID */ proto = hg.ip_proto.data; len = ntohs(hg.header.length) - sizeof(struct hep_generic); pos = sizeof(struct hep_generic); /* IPv4 */ if (family == AF_INET) { /* SRC IP */ memcpy(&src_ip4, (void*) buffer + pos, sizeof(struct hep_chunk_ip4)); inet_ntop(AF_INET, &src_ip4.data, src.ip, sizeof(src.ip)); pos += sizeof(struct hep_chunk_ip4); /* DST IP */ memcpy(&dst_ip4, (void*) buffer + pos, sizeof(struct hep_chunk_ip4)); inet_ntop(AF_INET, &dst_ip4.data, dst.ip, sizeof(src.ip)); pos += sizeof(struct hep_chunk_ip4); } #ifdef USE_IPV6 /* IPv6 */ else if(family == AF_INET6) { /* SRC IPv6 */ memcpy(&src_ip6, (void*) buffer + pos, sizeof(struct hep_chunk_ip6)); inet_ntop(AF_INET6, &src_ip6.data, src.ip, sizeof(src.ip)); pos += sizeof(struct hep_chunk_ip6); /* DST IP */ memcpy(&src_ip6, (void*) buffer + pos, sizeof(struct hep_chunk_ip6)); inet_ntop(AF_INET6, &dst_ip6.data, dst.ip, sizeof(dst.ip)); pos += sizeof(struct hep_chunk_ip6); } #endif /* SRC PORT */ src.port = ntohs(hg.src_port.data); /* DST PORT */ dst.port = ntohs(hg.dst_port.data); /* TIMESTAMP*/ header.ts.tv_sec = ntohl(hg.time_sec.data); header.ts.tv_usec = ntohl(hg.time_usec.data); /* Protocol TYPE */ /* Capture ID */ /* auth key */ if (eep_cfg.capt_srv_password != NULL) { memcpy(&authkey_chunk, (void*) buffer + pos, sizeof(authkey_chunk)); pos += sizeof(authkey_chunk); password_len = ntohs(authkey_chunk.length) - sizeof(authkey_chunk); memcpy(password, (void*) buffer + pos, password_len); pos += password_len; // Validate the password if (strncmp(password, eep_cfg.capt_srv_password, password_len) != 0) return NULL; } /* Payload */ memcpy(&payload_chunk, (void*) buffer + pos, sizeof(payload_chunk)); pos += sizeof(payload_chunk); // Calculate payload size header.caplen = header.len = ntohs(payload_chunk.length) - sizeof(payload_chunk); // Receive packet payload payload = sng_malloc(header.caplen); memcpy(payload, (void*) buffer + pos, header.caplen); // Create a new packet pkt = packet_create((family == AF_INET)?4:6, proto, src, dst, 0); packet_add_frame(pkt, &header, payload); packet_set_type(pkt, PACKET_SIP_UDP); packet_set_payload(pkt, payload, header.caplen); /* FREE */ sng_free(payload); return pkt; }
packet_t * capture_eep_receive_v2() { uint8_t family, proto; unsigned char *payload = 0; uint32_t pos; char buffer[MAX_CAPTURE_LEN] ; //! Source Address address_t src; //! Destination address address_t dst; //! Packet header struct pcap_pkthdr header; //! New created packet pointer packet_t *pkt; //! EEP client data struct sockaddr eep_client; socklen_t eep_client_len; struct hep_hdr hdr; struct hep_timehdr hep_time; struct hep_iphdr hep_ipheader; #ifdef USE_IPV6 struct hep_ip6hdr hep_ip6header; #endif // Initialize buffer memset(buffer, 0, MAX_CAPTURE_LEN); /* Receive EEP generic header */ if (recvfrom(eep_cfg.server_sock, buffer, MAX_CAPTURE_LEN, 0, &eep_client, &eep_client_len) == -1) return NULL; /* Copy initial bytes to HEPv2 header */ memcpy(&hdr, buffer, sizeof(struct hep_hdr)); // Check HEP version if (hdr.hp_v != 2) return NULL; /* IP proto */ family = hdr.hp_f; /* Proto ID */ proto = hdr.hp_p; pos = sizeof(struct hep_hdr); /* IPv4 */ if (family == AF_INET) { memcpy(&hep_ipheader, (void*) buffer + pos, sizeof(struct hep_iphdr)); inet_ntop(AF_INET, &hep_ipheader.hp_src, src.ip, sizeof(src.ip)); inet_ntop(AF_INET, &hep_ipheader.hp_dst, dst.ip, sizeof(dst.ip)); pos += sizeof(struct hep_iphdr); } #ifdef USE_IPV6 /* IPv6 */ else if(family == AF_INET6) { memcpy(&hep_ip6header, (void*) buffer + pos, sizeof(struct hep_ip6hdr)); inet_ntop(AF_INET6, &hep_ip6header.hp6_src, src.ip, sizeof(src.ip)); inet_ntop(AF_INET6, &hep_ip6header.hp6_dst, dst.ip, sizeof(dst.ip)); pos += sizeof(struct hep_ip6hdr); } #endif /* PORTS */ src.port = ntohs(hdr.hp_sport); dst.port = ntohs(hdr.hp_dport); /* TIMESTAMP*/ memcpy(&hep_time, (void*) buffer + pos, sizeof(struct hep_timehdr)); pos += sizeof(struct hep_timehdr); header.ts.tv_sec = hep_time.tv_sec; header.ts.tv_usec = hep_time.tv_usec; /* Protocol TYPE */ /* Capture ID */ // Calculate payload size (Total size - headers size) header.caplen = header.len = ntohs(hdr.hp_l) - pos; // Copy packet payload payload = sng_malloc(header.caplen + 1); memcpy(payload, (void*) buffer + pos, header.caplen); // Create a new packet pkt = packet_create((family == AF_INET) ? 4 : 6, proto, src, dst, 0); packet_add_frame(pkt, &header, payload); packet_set_transport_data(pkt, src.port, dst.port); packet_set_type(pkt, PACKET_SIP_UDP); packet_set_payload(pkt, payload, header.caplen); /* FREE */ sng_free(payload); return pkt; }
int tls_process_segment(packet_t *packet, struct tcphdr *tcp) { struct SSLConnection *conn; const u_char *payload = packet_payload(packet); uint32_t size_payload = packet_payloadlen(packet); uint8_t *out; uint32_t outl = packet->payload_len; out = sng_malloc(outl); struct in_addr ip_src, ip_dst; uint16_t sport = packet->src.port; uint16_t dport = packet->dst.port; // Convert addresses inet_pton(AF_INET, packet->src.ip, &ip_src); inet_pton(AF_INET, packet->dst.ip, &ip_dst); // Try to find a session for this ip if ((conn = tls_connection_find(ip_src, sport))) { // Update last connection direction conn->direction = tls_connection_dir(conn, ip_src, sport); // Check current connection state switch (conn->state) { case TCP_STATE_SYN: // First SYN received, this package must be SYN/ACK if (tcp->th_flags & TH_SYN & ~TH_ACK) conn->state = TCP_STATE_SYN_ACK; break; case TCP_STATE_SYN_ACK: // We expect an ACK packet here if (tcp->th_flags & ~TH_SYN & TH_ACK) conn->state = TCP_STATE_ESTABLISHED; break; case TCP_STATE_ACK: case TCP_STATE_ESTABLISHED: // Process data segment! if (tls_process_record(conn, payload, size_payload, &out, &outl) == 0) { if ((int32_t) outl > 0) { packet_set_payload(packet, out, outl); packet_set_type(packet, PACKET_SIP_TLS); return 0; } } break; case TCP_STATE_FIN: case TCP_STATE_CLOSED: // We can delete this connection tls_connection_destroy(conn); break; } } else { if (tcp->th_flags & TH_SYN & ~TH_ACK) { // New connection, store it status and leave tls_connection_create(ip_src, sport, ip_dst, dport); } } sng_free(out); return 0; }
static int message_bnet_format(t_packet * packet, t_message_type type, t_connection * me, t_connection * dst, char const * text, unsigned int dstflags) { if (!packet) { eventlog(eventlog_level_error,"message_bnet_format","got NULL packet"); return -1; } if (text && text[0]=='\0') text = " "; /* empty messages crash some clients, just send whitespace */ packet_set_size(packet,sizeof(t_server_message)); packet_set_type(packet,SERVER_MESSAGE); bn_int_set(&packet->u.server_message.unknown1,SERVER_MESSAGE_UNKNOWN1); bn_int_nset(&packet->u.server_message.player_ip,SERVER_MESSAGE_PLAYER_IP_DUMMY); bn_int_set(&packet->u.server_message.unknown3,SERVER_MESSAGE_UNKNOWN3); switch (type) { case message_type_adduser: if (!me) { eventlog(eventlog_level_error,"message_bnet_format","got NULL connection for %s",message_type_get_str(type)); return -1; } bn_int_set(&packet->u.server_message.type,SERVER_MESSAGE_TYPE_ADDUSER); bn_int_set(&packet->u.server_message.flags,conn_get_flags(me)|dstflags); bn_int_set(&packet->u.server_message.latency,conn_get_latency(me)); { char const * playerinfo; char const * tname; if(!(tname = conn_get_chatcharname(me, dst))) return -1; packet_append_string(packet,tname); conn_unget_chatcharname(me,tname); if (!(playerinfo = conn_get_playerinfo(me))) playerinfo = ""; packet_append_string(packet,playerinfo); } break; case message_type_join: if (!me) { eventlog(eventlog_level_error,"message_bnet_format","got NULL connection for %s",message_type_get_str(type)); return -1; } bn_int_set(&packet->u.server_message.type,SERVER_MESSAGE_TYPE_JOIN); bn_int_set(&packet->u.server_message.flags,conn_get_flags(me)|dstflags); bn_int_set(&packet->u.server_message.latency,conn_get_latency(me)); { char const * playerinfo; char const * tname; if(!(tname = conn_get_chatcharname(me, dst))) return -1; packet_append_string(packet,tname); conn_unget_chatcharname(me,tname); if (!(playerinfo = conn_get_playerinfo(me))) playerinfo = ""; packet_append_string(packet,playerinfo); /* FIXME: should we just send "" here instead of playerinfo? */ } break; case message_type_part: if (!me) { eventlog(eventlog_level_error,"message_bnet_format","got NULL connection for %s",message_type_get_str(type)); return -1; } bn_int_set(&packet->u.server_message.type,SERVER_MESSAGE_TYPE_PART); bn_int_set(&packet->u.server_message.flags,conn_get_flags(me)|dstflags); bn_int_set(&packet->u.server_message.latency,conn_get_latency(me)); { char const * tname; if(!(tname = conn_get_chatcharname(me, dst))) return -1; packet_append_string(packet,tname); conn_unget_chatcharname(me,tname); packet_append_string(packet,""); } break; case message_type_whisper: if (!me) { eventlog(eventlog_level_error,"message_bnet_format","got NULL connection for %s",message_type_get_str(type)); return -1; } if (!text) { eventlog(eventlog_level_error,"message_bnet_format","got NULL text for %s",message_type_get_str(type)); return -1; } if (dstflags&MF_X) return -1; /* player is ignored */ bn_int_set(&packet->u.server_message.type,SERVER_MESSAGE_TYPE_WHISPER); bn_int_set(&packet->u.server_message.flags,conn_get_flags(me)|dstflags); bn_int_set(&packet->u.server_message.latency,conn_get_latency(me)); { char const * tname; if(!(tname = conn_get_chatcharname(me, dst))) return -1; packet_append_string(packet,tname); conn_unget_chatcharname(me,tname); packet_append_string(packet,text); } break; case message_type_talk: if (!me) { eventlog(eventlog_level_error,"message_bnet_format","got NULL connection for %s",message_type_get_str(type)); return -1; } if (!text) { eventlog(eventlog_level_error,"message_bnet_format","got NULL text for %s",message_type_get_str(type)); return -1; } if (dstflags&MF_X) return -1; /* player is ignored */ bn_int_set(&packet->u.server_message.type,SERVER_MESSAGE_TYPE_TALK); bn_int_set(&packet->u.server_message.flags,conn_get_flags(me)|dstflags); bn_int_set(&packet->u.server_message.latency,conn_get_latency(me)); { char const * tname; if(!(tname = conn_get_chatcharname(me, me))) /* FIXME: second should be dst but cache gets in the way */ return -1; packet_append_string(packet,tname); conn_unget_chatcharname(me,tname); packet_append_string(packet,text); } break; case message_type_broadcast: if (!text) { eventlog(eventlog_level_error,"message_bnet_format","got NULL text for %s",message_type_get_str(type)); return -1; } if (dstflags&MF_X) return -1; /* player is ignored */ bn_int_set(&packet->u.server_message.type,SERVER_MESSAGE_TYPE_BROADCAST); bn_int_set(&packet->u.server_message.flags,conn_get_flags(me)|dstflags); bn_int_set(&packet->u.server_message.latency,conn_get_latency(me)); { char const * tname; if(!(tname = conn_get_chatcharname(me, dst))) return -1; packet_append_string(packet,tname); conn_unget_chatcharname(me,tname); packet_append_string(packet,text); } break; case message_type_channel: if (!me) { eventlog(eventlog_level_error,"message_bnet_format","got NULL connection for %s",message_type_get_str(type)); return -1; } if (!text) { eventlog(eventlog_level_error,"message_bnet_format","got NULL text for %s",message_type_get_str(type)); return -1; } bn_int_set(&packet->u.server_message.type,SERVER_MESSAGE_TYPE_CHANNEL); { t_channel const * channel; if (!(channel = conn_get_channel(me))) bn_int_set(&packet->u.server_message.flags,0); else bn_int_set(&packet->u.server_message.flags,cflags_to_bncflags(channel_get_flags(channel))); } bn_int_set(&packet->u.server_message.latency,conn_get_latency(me)); { char const * tname; if(!(tname = conn_get_chatname(me))) return -1; packet_append_string(packet,tname); conn_unget_chatname(me,tname); packet_append_string(packet,text); } break; case message_type_userflags: if (!me) { eventlog(eventlog_level_error,"message_bnet_format","got NULL connection for %s",message_type_get_str(type)); return -1; } bn_int_set(&packet->u.server_message.type,SERVER_MESSAGE_TYPE_USERFLAGS); bn_int_set(&packet->u.server_message.flags,conn_get_flags(me)|dstflags); bn_int_set(&packet->u.server_message.latency,conn_get_latency(me)); { char const * playerinfo; char const * tname; if(!(tname = conn_get_chatcharname(me, dst))) return -1; packet_append_string(packet,tname); conn_unget_chatcharname(me,tname); if (!(playerinfo = conn_get_playerinfo(me))) playerinfo = ""; #if 0 /* FIXME: which is correct? does it depend on the client type? */ packet_append_string(packet,""); #else packet_append_string(packet,playerinfo); #endif } break; case message_type_whisperack: if (!me) { eventlog(eventlog_level_error,"message_bnet_format","got NULL connection for %s",message_type_get_str(type)); return -1; } if (!text) { eventlog(eventlog_level_error,"message_bnet_format","got NULL text for %s",message_type_get_str(type)); return -1; } bn_int_set(&packet->u.server_message.type,SERVER_MESSAGE_TYPE_WHISPERACK); bn_int_set(&packet->u.server_message.flags,conn_get_flags(me)|dstflags); bn_int_set(&packet->u.server_message.latency,conn_get_latency(me)); { char const * tname; if(!(tname = conn_get_chatcharname(me, dst))) return -1; packet_append_string(packet,tname); conn_unget_chatcharname(me,tname); packet_append_string(packet,text); } break; case message_type_channelfull: /* FIXME */ bn_int_set(&packet->u.server_message.type,SERVER_MESSAGE_TYPE_CHANNELFULL); bn_int_set(&packet->u.server_message.flags,0); bn_int_set(&packet->u.server_message.latency,0); packet_append_string(packet,""); packet_append_string(packet,""); break; case message_type_channeldoesnotexist: if (!me) { eventlog(eventlog_level_error,"message_bnet_format","got NULL connection for %s",message_type_get_str(type)); return -1; } if (!text) { eventlog(eventlog_level_error,"message_bnet_format","got NULL text for %s",message_type_get_str(type)); return -1; } bn_int_set(&packet->u.server_message.type,SERVER_MESSAGE_TYPE_CHANNELDOESNOTEXIST); bn_int_set(&packet->u.server_message.flags,conn_get_flags(me)|dstflags); bn_int_set(&packet->u.server_message.latency,conn_get_latency(me)); { char const * tname; tname = conn_get_chatname(me); packet_append_string(packet,tname); conn_unget_chatname(me,tname); packet_append_string(packet,text); } break; case message_type_channelrestricted: /* FIXME */ bn_int_set(&packet->u.server_message.type,SERVER_MESSAGE_TYPE_CHANNELRESTRICTED); bn_int_set(&packet->u.server_message.flags,0); bn_int_set(&packet->u.server_message.latency,0); packet_append_string(packet,""); packet_append_string(packet,""); break; case message_type_info: if (!text) { eventlog(eventlog_level_error,"message_bnet_format","got NULL text for %s",message_type_get_str(type)); return -1; } bn_int_set(&packet->u.server_message.type,SERVER_MESSAGE_TYPE_INFO); bn_int_set(&packet->u.server_message.flags,0); bn_int_set(&packet->u.server_message.latency,0); packet_append_string(packet,""); packet_append_string(packet,text); break; case message_type_error: if (!text) { eventlog(eventlog_level_error,"message_bnet_format","got NULL text for %s",message_type_get_str(type)); return -1; } bn_int_set(&packet->u.server_message.type,SERVER_MESSAGE_TYPE_ERROR); bn_int_set(&packet->u.server_message.flags,0); bn_int_set(&packet->u.server_message.latency,0); packet_append_string(packet,""); packet_append_string(packet,text); break; case message_type_emote: if (!me) { eventlog(eventlog_level_error,"message_bnet_format","got NULL connection for %s",message_type_get_str(type)); return -1; } if (!text) { eventlog(eventlog_level_error,"message_bnet_format","got NULL text for %s",message_type_get_str(type)); return -1; } if (dstflags&MF_X) return -1; /* player is ignored */ bn_int_set(&packet->u.server_message.type,SERVER_MESSAGE_TYPE_EMOTE); bn_int_set(&packet->u.server_message.flags,conn_get_flags(me)|dstflags); bn_int_set(&packet->u.server_message.latency,conn_get_latency(me)); { char const * tname; if(!(tname = conn_get_chatcharname(me, me))) /* FIXME: second should be dst but cache gets in the way */ return -1; packet_append_string(packet,tname); conn_unget_chatcharname(me,tname); packet_append_string(packet,text); } break; default: eventlog(eventlog_level_error,"message_bnet_format","got bad message type %d",(int)type); return -1; } return 0; }