diff --git a/src/d_clisrv.c b/src/d_clisrv.c index f35428c95..e432580c5 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -531,6 +531,7 @@ typedef enum CL_SEARCHING, CL_CHECKFILES, CL_DOWNLOADFILES, + CL_DOWNLOADFAILED, CL_ASKJOIN, CL_LOADFILES, CL_SETUPFILES, @@ -616,6 +617,7 @@ static inline void CL_DrawConnectionStatus(void) break; case CL_ASKFULLFILELIST: case CL_CONFIRMCONNECT: + case CL_DOWNLOADFAILED: cltext = ""; break; case CL_SETUPFILES: @@ -723,8 +725,10 @@ static inline void CL_DrawConnectionStatus(void) strncpy(tempname, filename, sizeof(tempname)-1); } + V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-58-30, 0, + va(M_GetText("%s downloading"), ((cl_mode == CL_DOWNLOADHTTPFILES) ? "\x82""HTTP" : "\x85""Direct"))); V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-58-22, V_YELLOWMAP, - va(M_GetText("Downloading \"%s\""), tempname)); + va(M_GetText("\"%s\""), tempname)); V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-58, V_20TRANS|V_MONOSPACE, va(" %4uK/%4uK",fileneeded[lastfilenum].currentsize>>10,file->totalsize>>10)); V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-58, V_20TRANS|V_MONOSPACE, @@ -1501,6 +1505,10 @@ static void M_ConfirmConnect(void) { cl_mode = CL_DOWNLOADFILES; } + else + { + cl_mode = CL_DOWNLOADFAILED; + } } #ifdef HAVE_CURL else @@ -1649,6 +1657,10 @@ static boolean CL_FinishedFileList(void) { cl_mode = CL_DOWNLOADFILES; } + else + { + cl_mode = CL_DOWNLOADFAILED; + } } #endif } @@ -1854,6 +1866,21 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic cl_mode = CL_LOADFILES; break; + case CL_DOWNLOADFAILED: + { + CONS_Printf(M_GetText("Legacy downloader request packet failed.\n")); + CONS_Printf(M_GetText("Network game synchronization aborted.\n")); + D_QuitNetGame(); + CL_Reset(); + D_StartTitle(); + M_StartMessage(M_GetText( + "The direct download encountered an error.\n" + "See the logfile for more info.\n" + "\n" + "Press (B)\n" + ), NULL, MM_NOTHING); + return false; + } case CL_LOADFILES: if (CL_LoadServerFiles()) cl_mode = CL_SETUPFILES; diff --git a/src/d_netfil.c b/src/d_netfil.c index f50e37bdb..246567c72 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -354,6 +354,9 @@ void CL_AbortDownloadResume(void) pauseddownload = NULL; } +// The following was written and, against all odds, works. +#define MORELEGACYDOWNLOADER + /** Sends requests for files in the ::fileneeded table with a status of * ::FS_NOTFOUND. * @@ -366,42 +369,135 @@ boolean CL_SendFileRequest(void) char *p; INT32 i; INT64 totalfreespaceneeded = 0, availablefreespace; + INT32 skippedafile = -1; +#ifdef MORELEGACYDOWNLOADER + boolean firstloop = true; +#endif #ifdef PARANOIA if (M_CheckParm("-nodownload")) - I_Error("Attempted to download files in -nodownload mode"); + { + CONS_Printf("Direct download - Attempted to download files in -nodownload mode"); + return false; + } +#endif for (i = 0; i < fileneedednum; i++) + { +#ifdef PARANOIA if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN && (fileneeded[i].willsend == 0 || fileneeded[i].willsend == 2)) { - I_Error("Attempted to download files that were not sendable"); + CONS_Printf("Direct download - attempted to download files that were not sendable\n"); + return false; } #endif + if ((fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD || fileneeded[i].status == FS_FALLBACK)) + { + // Error check for the first time around. + totalfreespaceneeded += fileneeded[i].totalsize; + } + } + + I_GetDiskFreeSpace(&availablefreespace); + if (totalfreespaceneeded > availablefreespace) + { + CONS_Printf("Direct download -\n" + " To play on this server you must download %s KB,\n" + " but you have only %s KB free space on this drive\n", + sizeu1((size_t)(totalfreespaceneeded>>10)), sizeu2((size_t)(availablefreespace>>10))); + return false; + } + +#ifdef MORELEGACYDOWNLOADER +tryagain: + skippedafile = -1; +#endif + +#ifdef VERBOSEREQUESTFILE + CONS_Printf("Preparing packet\n"); +#endif netbuffer->packettype = PT_REQUESTFILE; p = (char *)netbuffer->u.textcmd; + for (i = 0; i < fileneedednum; i++) + { if ((fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD || fileneeded[i].status == FS_FALLBACK)) { - totalfreespaceneeded += fileneeded[i].totalsize; + // Pre-prepare. + size_t checklen; nameonly(fileneeded[i].filename); + + // Figure out if we'd overrun our buffer. + checklen = strlen(fileneeded[i].filename)+2; // plus the fileid (and terminator, in case this is last) + if ((UINT8 *)(p + checklen) >= netbuffer->u.textcmd + MAXTEXTCMD) + { + skippedafile = i; + // we might have a shorter file that can fit in the remaining space, and file ID permits out-of-order data + continue; + } + + // Now write. WRITEUINT8(p, i); // fileid WRITESTRINGN(p, fileneeded[i].filename, MAX_WADPATH); + +#ifdef VERBOSEREQUESTFILE + CONS_Printf(" file \"%s\" (id %d)\n", i, fileneeded[i].filename); +#endif + // put it in download dir strcatbf(fileneeded[i].filename, downloaddir, "/"); fileneeded[i].status = FS_REQUESTED; } - WRITEUINT8(p, 0xFF); - I_GetDiskFreeSpace(&availablefreespace); - if (totalfreespaceneeded > availablefreespace) - I_Error("To play on this server you must download %s KB,\n" - "but you have only %s KB free space on this drive\n", - sizeu1((size_t)(totalfreespaceneeded>>10)), sizeu2((size_t)(availablefreespace>>10))); + } - // prepare to download - I_mkdir(downloaddir, 0755); - return HSendPacket(servernode, true, 0, p - (char *)netbuffer->u.textcmd); +#ifdef MORELEGACYDOWNLOADER + if (firstloop) +#else + // If we're not trying extralong legacy download requests, gotta bail. + if (skippedafile != -1) + { + CONS_Printf("Direct download - missing files are as follows:\n"); + for (i = 0; i < fileneedednum; i++) + { + if ((fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD || fileneeded[i].status == FS_FALLBACK || fileneeded[i].status == FS_REQUESTED)) // FS_REQUESTED added + CONS_Printf(" %s\n", fileneeded[i].filename); + } + return false; + } +#endif + I_mkdir(downloaddir, 0755); + +#ifdef PARANOIA + // Couldn't fit a single one in? + if (p == (char *)netbuffer->u.textcmd) + { + CONS_Printf("Direct download - fileneeded name for %s (fileneeded[%d]) too long??\n", (skippedafile != -1 ? fileneeded[skippedafile].filename : NULL), skippedafile); + return false; + } +#endif + + WRITEUINT8(p, 0xFF); // terminator + if (!HSendPacket(servernode, true, 0, p - (char *)netbuffer->u.textcmd)) + { + CONS_Printf("Direct download - unable to send packet.\n"); + return false; + } + +#ifdef MORELEGACYDOWNLOADER + if (skippedafile != -1) + { + firstloop = false; + goto tryagain; + } +#endif + +#ifdef VERBOSEREQUESTFILE + CONS_Printf("Returning true\n"); +#endif + + return true; } // get request filepak and put it on the send queue @@ -411,16 +507,18 @@ boolean PT_RequestFile(INT32 node) char wad[MAX_WADPATH+1]; UINT8 *p = netbuffer->u.textcmd; UINT8 id; - while (p < netbuffer->u.textcmd + MAXTEXTCMD-1) // Don't allow hacked client to overflow + while (p < netbuffer->u.textcmd + MAXTEXTCMD) // Don't allow hacked client to overflow { id = READUINT8(p); if (id == 0xFF) break; READSTRINGN(p, wad, MAX_WADPATH); - if (!AddFileToSendQueue(node, wad, id)) + if (p >= netbuffer->u.textcmd + MAXTEXTCMD || !AddFileToSendQueue(node, wad, id)) { + if (cv_noticedownload.value) + CONS_Printf("Bad PT_REQUESTFILE from node %d!\n", node); SV_AbortSendFiles(node); - return false; // don't read the rest of the files + return false; // don't read any more } } return true; // no problems with any files @@ -798,7 +896,7 @@ static boolean AddFileToSendQueue(INT32 node, const char *filename, UINT8 fileid char wadfilename[MAX_WADPATH]; if (cv_noticedownload.value) - CONS_Printf("Sending file \"%s\" to node %d (%s)\n", filename, node, I_GetNodeAddress(node)); + CONS_Printf("Sending file \"%s\" (id %d) to node %d (%s)\n", filename, fileid, node, I_GetNodeAddress(node)); // Find the last file in the list and set a pointer to its "next" field q = &transfer[node].txlist; @@ -972,7 +1070,7 @@ static void SV_EndFileSend(INT32 node) { case SF_FILE: // It's a file, close it and free its filename if (cv_noticedownload.value) - CONS_Printf("Ending file transfer for node %d\n", node); + CONS_Printf("Ending file transfer (id %d) for node %d\n", p->fileid, node); if (transfer[node].currentfile) fclose(transfer[node].currentfile); free(p->id.filename);