void Netchan_ClearFragments(netchan_t *chan) { fragbufwaiting_t *wait, *next; for (int i = 0; i < MAX_STREAMS; i++) { wait = chan->waitlist[i]; while (wait) { next = wait->next; Netchan_ClearFragbufs(&wait->fragbufs); Mem_Free(wait); wait = next; } chan->waitlist[i] = nullptr; Netchan_ClearFragbufs(&chan->fragbufs[i]); Netchan_FlushIncoming(chan, i); } }
/* ============================== Netchan_ClearFragments ============================== */ void Netchan_ClearFragments( netchan_t *chan ) { fragbufwaiting_t *wait; int i; for( i = 0; i < MAX_STREAMS; i++ ) { wait = chan->waitlist[i]; while( wait ) { Netchan_ClearFragbufs( &wait->fragbufs ); wait = wait->next; } chan->waitlist[i] = NULL; Netchan_ClearFragbufs( &chan->fragbufs[i] ); Netchan_FlushIncoming( chan, i ); } }
qboolean Netchan_CopyFileFragments(netchan_t *chan) { fragbuf_t *p; int nsize; unsigned char *buffer; int pos; signed int cursize; char filename[MAX_PATH]; char compressor[32]; fragbuf_s *n; qboolean bCompressed; unsigned int uncompressedSize; if (!chan->incomingready[FRAG_FILE_STREAM]) return FALSE; p = chan->incomingbufs[FRAG_FILE_STREAM]; if (!p) { Con_Printf("%s: Called with no fragments readied\n", __func__); chan->incomingready[FRAG_FILE_STREAM] = FALSE; return FALSE; } bCompressed = FALSE; SZ_Clear(&net_message); MSG_BeginReading(); SZ_Write(&net_message, p->frag_message.data, p->frag_message.cursize); Q_strncpy(filename, MSG_ReadString(), sizeof(filename) - 1); filename[sizeof(filename) - 1] = 0; Q_strncpy(compressor, MSG_ReadString(), sizeof(compressor) - 1); compressor[sizeof(compressor) - 1] = 0; if (!Q_stricmp(compressor, "bz2")) bCompressed = TRUE; uncompressedSize = (unsigned int)MSG_ReadLong(); #ifdef REHLDS_FIXES // TODO: this condition is invalid for server->client // TODO: add console message for client // TODO: add client name to message if (uncompressedSize > 1024 * 64) { Con_Printf("Received too large file (size=%u)\nFlushing input queue\n", uncompressedSize); Netchan_FlushIncoming(chan, 1); return FALSE; } #endif if (Q_strlen(filename) <= 0) { Con_Printf("File fragment received with no filename\nFlushing input queue\n"); Netchan_FlushIncoming(chan, 1); return FALSE; } if (Q_strstr(filename, "..")) { Con_Printf("File fragment received with relative path, ignoring\n"); Netchan_FlushIncoming(chan, 1); return FALSE; } if (filename[0] != '!' && !IsSafeFileToDownload(filename)) { Con_Printf("File fragment received with bad path, ignoring\n"); Netchan_FlushIncoming(chan, 1); return FALSE; } // This prohibits to write files to FS on server if (g_pcls.state == ca_dedicated && filename[0] != '!') { Con_Printf("File fragment received with bad path, ignoring (2)\n"); Netchan_FlushIncoming(chan, 1); return FALSE; } Q_strncpy(chan->incomingfilename, filename, MAX_PATH - 1); chan->incomingfilename[MAX_PATH - 1] = 0; if (filename[0] != '!' && FS_FileExists(filename)) { Con_Printf("Can't download %s, already exists\n", filename); Netchan_FlushIncoming(chan, 1); return TRUE; } nsize = 0; while (p) { nsize += p->frag_message.cursize; if (p == chan->incomingbufs[FRAG_FILE_STREAM]) nsize -= msg_readcount; p = p->next; } buffer = (unsigned char*)Mem_ZeroMalloc(nsize + 1); if (!buffer) { Con_Printf("Buffer allocation failed on %i bytes\n", nsize + 1); Netchan_FlushIncoming(chan, 1); return FALSE; } p = chan->incomingbufs[FRAG_FILE_STREAM]; pos = 0; while (p) { n = p->next; cursize = p->frag_message.cursize; // First message has the file name, don't write that into the data stream, just write the rest of the actual data if (p == chan->incomingbufs[FRAG_FILE_STREAM]) { // Copy it in cursize -= msg_readcount; Q_memcpy(&buffer[pos], &p->frag_message.data[msg_readcount], cursize); p->frag_message.cursize = cursize; } else { Q_memcpy(&buffer[pos], p->frag_message.data, cursize); } pos += p->frag_message.cursize; Mem_Free(p); p = n; } if (bCompressed) { unsigned char* uncompressedBuffer = (unsigned char*)Mem_Malloc(uncompressedSize); Con_DPrintf("Decompressing file %s (%d -> %d)\n", filename, nsize, uncompressedSize); BZ2_bzBuffToBuffDecompress((char*)uncompressedBuffer, &uncompressedSize, (char*)buffer, nsize, 1, 0); Mem_Free(buffer); pos = uncompressedSize; buffer = uncompressedBuffer; } if (filename[0] == '!') { if (chan->tempbuffer) { Con_DPrintf("Netchan_CopyFragments: Freeing holdover tempbuffer\n"); Mem_Free(chan->tempbuffer); } chan->tempbuffer = buffer; chan->tempbuffersize = pos; } else { char filedir[MAX_PATH]; char *pszFileName; FileHandle_t handle; #ifdef REHLDS_CHECKS Q_strncpy(filedir, filename, sizeof(filedir) - 1); filedir[sizeof(filedir) - 1] = 0; #else Q_strncpy(filedir, filename, sizeof(filedir)); #endif // REHLDS_CHECKS COM_FixSlashes(filedir); pszFileName = Q_strrchr(filedir, '\\'); if (pszFileName) { *pszFileName = 0; #ifdef REHLDS_FIXES FS_CreateDirHierarchy(filedir, "GAMEDOWNLOAD"); #endif } #ifndef REHLDS_FIXES FS_CreateDirHierarchy(filedir, "GAMEDOWNLOAD"); #endif handle = FS_OpenPathID(filename, "wb", "GAMEDOWNLOAD"); if (!handle) { Con_Printf("File open failed %s\n", filename); Netchan_FlushIncoming(chan, 1); #ifdef REHLDS_FIXES Mem_Free(buffer); #endif return FALSE; } Sys_Printf("COM_WriteFile: %s\n", filename); FS_Write(buffer, pos, 1, handle); FS_Close(handle); Mem_Free(buffer); } SZ_Clear(&net_message); chan->incomingbufs[FRAG_FILE_STREAM] = nullptr; chan->incomingready[FRAG_FILE_STREAM] = FALSE; msg_readcount = 0; return TRUE; }
/* ============================== Netchan_CopyFileFragments ============================== */ qboolean Netchan_CopyFileFragments( netchan_t *chan, sizebuf_t *msg ) { fragbuf_t *p, *n; char filename[CS_SIZE]; int nsize; byte *buffer; int pos; if( !chan->incomingready[FRAG_FILE_STREAM] ) return false; if( !chan->incomingbufs[FRAG_FILE_STREAM] ) { MsgDev( D_WARN, "Netchan_CopyFileFragments: Called with no fragments readied\n" ); chan->incomingready[FRAG_FILE_STREAM] = false; return false; } p = chan->incomingbufs[FRAG_FILE_STREAM]; BF_Init( msg, "NetMessage", net_message_buffer, sizeof( net_message_buffer )); // copy in first chunk so we can get filename out BF_WriteBits( msg, BF_GetData( &p->frag_message ), BF_GetNumBitsWritten( &p->frag_message )); BF_SeekToBit( msg, 0 ); // rewind buffer //Q_strncpy( filename, BF_ReadString( msg ), sizeof( filename )); Q_snprintf( filename, sizeof( filename ), "downloaded/%s", BF_ReadString( msg ) ); if( Q_strlen( filename ) <= 0 ) { MsgDev( D_ERROR, "File fragment received with no filename\nFlushing input queue\n" ); // clear out bufs Netchan_FlushIncoming( chan, FRAG_FILE_STREAM ); return false; } else if( Q_strstr( filename, ".." )) { MsgDev( D_ERROR, "File fragment received with relative path, ignoring\n" ); // clear out bufs Netchan_FlushIncoming( chan, FRAG_FILE_STREAM ); return false; } Q_strncpy( chan->incomingfilename, filename, sizeof( chan->incomingfilename )); if( FS_FileExists( filename, false )) { MsgDev( D_ERROR, "Can't download %s, already exists\n", filename ); // clear out bufs Netchan_FlushIncoming( chan, FRAG_FILE_STREAM ); return true; } // create file from buffers nsize = 0; while ( p ) { nsize += BF_GetNumBytesWritten( &p->frag_message ); // Size will include a bit of slop, oh well if( p == chan->incomingbufs[FRAG_FILE_STREAM] ) { nsize -= BF_GetNumBytesRead( msg ); } p = p->next; } buffer = Mem_Alloc( net_mempool, nsize + 1 ); p = chan->incomingbufs[ FRAG_FILE_STREAM ]; pos = 0; while( p ) { int cursize; n = p->next; cursize = BF_GetNumBytesWritten( &p->frag_message ); // first message has the file name, don't write that into the data stream, // just write the rest of the actual data if( p == chan->incomingbufs[FRAG_FILE_STREAM] ) { // copy it in cursize -= BF_GetNumBytesRead( msg ); Q_memcpy( &buffer[pos], &p->frag_message.pData[BF_GetNumBytesRead( msg )], cursize ); } else { Q_memcpy( &buffer[pos], p->frag_message.pData, cursize ); } pos += cursize; Mem_Free( p ); p = n; } FS_WriteFile( filename, buffer, pos ); Mem_Free( buffer ); // clear remnants BF_Clear( msg ); chan->incomingbufs[FRAG_FILE_STREAM] = NULL; // reset flag chan->incomingready[FRAG_FILE_STREAM] = false; return true; }