extern void bnettime_to_bn_long(t_bnettime in, bn_long * out) { if (!out) { eventlog(eventlog_level_error, __FUNCTION__, "got NULL out"); return; } bn_long_set_a_b(out, in.u, in.l); }
extern int main(int argc, char * argv[]) { bn_long num; t_bnettime bnt; if (argc<1 || !argv || !argv[0]) { fprintf(stderr,"bad arguments\n"); return STATUS_FAILURE; } eventlog_set(stderr); bnt = bnettime(); timeinfo(bnt); bn_long_set_a_b(&num,0x01bedd2d,0xff4e2712); bn_long_to_bnettime(num,&bnt); timeinfo(bnt); bn_long_set_a_b(&num,0x01bf4444,0x09090909); bn_long_to_bnettime(num,&bnt); timeinfo(bnt); bn_long_set_a_b(&num,0x01be370a,0xffffffff); bn_long_to_bnettime(num,&bnt); timeinfo(bnt); bn_long_set_a_b(&num,0x01be8765,0x4321fedc); bn_long_to_bnettime(num,&bnt); timeinfo(bnt); bn_long_set_a_b(&num,0x01bb0000,0x40000000); bn_long_to_bnettime(num,&bnt); timeinfo(bnt); bn_long_set_a_b(&num,0x01bb0000,0x80000000); bn_long_to_bnettime(num,&bnt); timeinfo(bnt); bn_long_set_a_b(&num,0x01bb0000,0xf0000000); bn_long_to_bnettime(num,&bnt); timeinfo(bnt); bn_long_set_a_b(&num,0x004b0000,0xf0000000); bn_long_to_bnettime(num,&bnt); timeinfo(bnt); return STATUS_SUCCESS; }
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; }
/* 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; }