Ejemplo n.º 1
0
/**
 * @brief Called from the precache check to queue a download.
 * @sa CL_CheckOrDownloadFile
 */
bool CL_QueueHTTPDownload (const char *ufoPath)
{
	/* no http server (or we got booted) */
	if (!cls.downloadServer[0] || abortDownloads || !cl_http_downloads->integer)
		return false;

	dlqueue_t** anchor = &cls.downloadQueue;
	for (; *anchor; anchor = &(*anchor)->next) {
		/* avoid sending duplicate requests */
		if (Q_streq(ufoPath, (*anchor)->ufoPath))
			return true;
	}

	dlqueue_t* const q = Mem_AllocType(dlqueue_t);
	q->next = NULL;
	q->state = DLQ_STATE_NOT_STARTED;
	Q_strncpyz(q->ufoPath, ufoPath, sizeof(q->ufoPath));
	*anchor = q;

	/* special case for map file lists */
	if (cl_http_filelists->integer) {
		const char *extension = Com_GetExtension(ufoPath);
		if (extension != NULL && !Q_strcasecmp(extension, "bsp")) {
			char listPath[MAX_OSPATH];
			const size_t len = strlen(ufoPath);
			Com_sprintf(listPath, sizeof(listPath), BASEDIRNAME"/%.*s.filelist", (int)(len - 4), ufoPath);
			CL_QueueHTTPDownload(listPath);
		}
	}

	/* if a download entry has made it this far, CL_FinishHTTPDownload is guaranteed to be called. */
	pendingCount++;

	return true;
}
Ejemplo n.º 2
0
/**
 * @return true if the file exists, otherwise it attempts to start a download via curl
 * @sa CL_CheckAndQueueDownload
 * @sa CL_RequestNextDownload
 */
bool CL_CheckOrDownloadFile (const char *filename)
{
	static char lastfilename[MAX_OSPATH] = "";

	if (Q_strnull(filename))
		return true;

	/* r1: don't attempt same file many times */
	if (Q_streq(filename, lastfilename))
		return true;

	Q_strncpyz(lastfilename, filename, sizeof(lastfilename));

	if (strstr(filename, "..")) {
		Com_Printf("Refusing to check a path with .. (%s)\n", filename);
		return true;
	}

	if (strchr(filename, ' ')) {
		Com_Printf("Refusing to check a path containing spaces (%s)\n", filename);
		return true;
	}

	if (strchr(filename, ':')) {
		Com_Printf("Refusing to check a path containing a colon (%s)\n", filename);
		return true;
	}

	if (filename[0] == '/') {
		Com_Printf("Refusing to check a path starting with / (%s)\n", filename);
		return true;
	}

	if (FS_LoadFile(filename, NULL) != -1) {
		/* it exists, no need to download */
		return true;
	}

	if (CL_QueueHTTPDownload(filename))
		return false;

	return true;
}
Ejemplo n.º 3
0
/*
===============
CL_CheckOrDownloadFile

Returns true if the file exists, otherwise it attempts
to start a download from the server.
===============
*/
qboolean	CL_CheckOrDownloadFile (const char *filename)
{
	FILE	*fp;
	int		length;
	char	*p;
	char	name[MAX_OSPATH];
	static char lastfilename[MAX_OSPATH] = {0};

	//r1: don't attempt same file many times
	if (!strcmp (filename, lastfilename))
		return true;

	strcpy (lastfilename, filename);

	if (strstr (filename, ".."))
	{
		Com_Printf ("Refusing to check a path with .. (%s)\n", LOG_CLIENT, filename);
		return true;
	}

	if (strchr (filename, ' '))
	{
		Com_Printf ("Refusing to check a path containing spaces (%s)\n", LOG_CLIENT, filename);
		return true;
	}

	if (strchr (filename, ':'))
	{
		Com_Printf ("Refusing to check a path containing a colon (%s)\n", LOG_CLIENT, filename);
		return true;
	}

	if (filename[0] == '/')
	{
		Com_Printf ("Refusing to check a path starting with / (%s)\n", LOG_CLIENT, filename);
		return true;
	}

	if (FS_LoadFile (filename, NULL) != -1)
	{	
		// it exists, no need to download
		return true;
	}

#ifdef USE_CURL
	if (CL_QueueHTTPDownload (filename))
	{
		//we return true so that the precache check keeps feeding us more files.
		//since we have multiple HTTP connections we want to minimize latency
		//and be constantly sending requests, not one at a time.
		return true;
	}
	else
#endif
	{
		strcpy (cls.downloadname, filename);

		//r1: fix \ to /
		p = cls.downloadname;
		while ((p = strchr(p, '\\')) != NULL)
			p[0] = '/';

		length = (int)strlen(cls.downloadname);

		//normalize path
		p = cls.downloadname;
		while ((p = strstr (p, "./")) != NULL)
		{
			memmove (p, p+2, length - (p - cls.downloadname) - 1);
			length -= 2;
		}

		//r1: verify we are giving the server a legal path
		if (cls.downloadname[length-1] == '/')
		{
			Com_Printf ("Refusing to download bad path (%s)\n", LOG_CLIENT, filename);
			return true;
		}

		// download to a temp name, and only rename
		// to the real name when done, so if interrupted
		// a runt file wont be left
		COM_StripExtension (cls.downloadname, cls.downloadtempname);
		strcat (cls.downloadtempname, ".tmp");

	//ZOID
		// check to see if we already have a tmp for this file, if so, try to resume
		// open the file if not opened yet
		CL_DownloadFileName(name, sizeof(name), cls.downloadtempname);

	//	FS_CreatePath (name);

		fp = fopen (name, "r+b");
		if (fp)
		{
			// it exists
			int len;
			
			fseek(fp, 0, SEEK_END);
			len = ftell(fp);

			cls.download = fp;

			// give the server an offset to start the download
			Com_Printf ("Resuming %s\n", LOG_CLIENT, cls.downloadname);

			MSG_WriteByte (clc_stringcmd);
			if (cls.serverProtocol == PROTOCOL_R1Q2)
				MSG_WriteString (va("download \"%s\" %i udp-zlib", cls.downloadname, len));
			else
				MSG_WriteString (va("download \"%s\" %i", cls.downloadname, len));
		}
		else
		{
			Com_Printf ("Downloading %s\n", LOG_CLIENT, cls.downloadname);

			MSG_WriteByte (clc_stringcmd);
			if (cls.serverProtocol == PROTOCOL_R1Q2)
				MSG_WriteString (va("download \"%s\" 0 udp-zlib", cls.downloadname));
			else
				MSG_WriteString (va("download \"%s\"", cls.downloadname));
		}

		MSG_EndWriting (&cls.netchan.message);

		send_packet_now = true;
		cls.downloadpending = true;

		return false;
	}
}
Ejemplo n.º 4
0
/*
===============
CL_ParseFileList

Validate a path supplied by a filelist.
===============
*/
static void CL_CheckAndQueueDownload (char *path)
{
	size_t		length;
	char		*ext;
	qboolean	pak;
	qboolean	gameLocal;

	StripHighBits (path, 1);

	length = strlen(path);

	if (length >= MAX_QPATH)
		return;

	ext = strrchr (path, '.');

	if (!ext)
		return;

	ext++;

	if (!ext[0])
		return;

	Q_strlwr (ext);

	if ( !strcmp (ext, "pak") || !strcmp (ext, "pk3") )
	{
		Com_Printf ("NOTICE: Filelist is requesting a .pak file (%s)\n", path);
		pak = true;
	}
	else
		pak = false;

	if (!pak && strcmp (ext, "pcx") && strcmp (ext, "wal") && strcmp (ext, "wav") && strcmp (ext, "md2") &&
		strcmp (ext, "sp2") && strcmp (ext, "tga") && strcmp (ext, "png") && strcmp (ext, "jpg") &&
		strcmp (ext, "bsp") && strcmp (ext, "ent") && strcmp (ext, "txt") && strcmp (ext, "dm2") &&
		strcmp (ext, "loc"))
	{
		Com_Printf ("WARNING: Illegal file type '%s' in filelist.\n", MakePrintable(path, length));
		return;
	}

	if (path[0] == '@')
	{
		if (pak)
		{
			Com_Printf ("WARNING: @ prefix used on a pak file (%s) in filelist.\n", MakePrintable(path, length));
			return;
		}
		gameLocal = true;
		path++;
		length--;
	}
	else
		gameLocal = false;

	if (strstr (path, "..") || !IsValidChar (path[0]) || !IsValidChar (path[length-1]) || strstr(path, "//") ||
		strchr (path, '\\') || (!pak && !strchr (path, '/')) || (pak && strchr(path, '/')))
	{
		Com_Printf ("WARNING: Illegal path '%s' in filelist.\n", MakePrintable(path, length));
		return;
	}

	// by definition paks are game-local
	if (gameLocal || pak)
	{
		qboolean	exists;
		FILE		*f;
		char		gamePath[MAX_OSPATH];

		if (pak)
		{
			Com_sprintf (gamePath, sizeof(gamePath),"%s/%s",FS_Gamedir(), path);
			f = fopen (gamePath, "rb");
			if (!f)
			{
				exists = false;;
			}
			else
			{
				exists = true;
				fclose (f);
			}
		}
		else
		{
		//	exists = FS_ExistsInGameDir (path);
			exists = FS_LocalFileExists (path);
		}

		if (!exists)
		{
			if (CL_QueueHTTPDownload (path))
			{
				//paks get bumped to the top and HTTP switches to single downloading.
				//this prevents someone on 28k dialup trying to do both the main .pak
				//and referenced configstrings data at once.
				if (pak)
				{
					dlqueue_t	*q, *last;

					last = q = &cls.downloadQueue;

					while (q->next)
					{
						last = q;
						q = q->next;
					}

					last->next = NULL;
					q->next = cls.downloadQueue.next;
					cls.downloadQueue.next = q;
				}
			}
		}
	}
	else
	{
		CL_CheckOrDownloadFile (path);
	}
}
Ejemplo n.º 5
0
/*
===============
CL_QueueHTTPDownload

Called from the precache check to queue a download. Return value of
false will cause standard UDP downloading to be used instead.
===============
*/
qboolean CL_QueueHTTPDownload (const char *quakePath)
{
	size_t		len;
	dlqueue_t	*q;
	qboolean	needList;

	// no http server (or we got booted)
	if (!cls.downloadServer[0] || abortDownloads || thisMapAbort || !cl_http_downloads->value)
		return false;

	needList = false;

	// first download queued, so we want the mod filelist
	if (!cls.downloadQueue.next && cl_http_filelists->value)
		needList = true;

	q = &cls.downloadQueue;

	while (q->next)
	{
		q = q->next;

		//avoid sending duplicate requests
		if (!strcmp (quakePath, q->quakePath))
			return true;
	}

//	q->next = Z_TagMalloc (sizeof(*q), TAGMALLOC_CLIENT_DOWNLOAD);
	q->next = Z_TagMalloc (sizeof(*q), 0);
	q = q->next;

	q->next = NULL;
	q->state = DLQ_STATE_NOT_STARTED;
	Q_strncpyz (q->quakePath, quakePath, sizeof(q->quakePath)-1);

	if (needList)
	{
		//grab the filelist
		CL_QueueHTTPDownload (va("%s.filelist", cl.gamedir));

		//this is a nasty hack to let the server know what we're doing so admins don't
		//get confused by a ton of people stuck in CNCT state. it's assumed the server
		//is running r1q2 if we're even able to do http downloading so hopefully this
		//won't spew an error msg.
	//	MSG_BeginWriting (clc_stringcmd);
	//	MSG_WriteString ("download http\n");
	//	MSG_EndWriting (&cls.netchan.message);
		MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
		MSG_WriteString (&cls.netchan.message, "download http\n");
	}

	//special case for map file lists, i really wanted a server-push mechanism for this, but oh well
	len = strlen (quakePath);
	if (cl_http_filelists->value && len > 4 && !Q_stricmp ((char *)(quakePath + len - 4), ".bsp"))
	{
		char	listPath[MAX_OSPATH];
		char	filePath[MAX_OSPATH];

		Com_sprintf (filePath, sizeof(filePath), "%s/%s", cl.gamedir, quakePath);

		COM_StripExtension (filePath, listPath);
	//	strncat (listPath, ".filelist");
		Q_strncatz (listPath, ".filelist", sizeof(listPath));
		
		CL_QueueHTTPDownload (listPath);
	}

	//if a download entry has made it this far, CL_FinishHTTPDownload is guaranteed to be called.
	pendingCount++;

	return true;
}
Ejemplo n.º 6
0
/**
 * @brief Validate a path supplied by a filelist.
 * @param[in,out] path Pointer to file (path) to download (high bits will be stripped).
 * @sa CL_QueueHTTPDownload
 * @sa CL_ParseFileList
 */
static void CL_CheckAndQueueDownload (char *path)
{
	size_t		length;
	const char	*ext;
	bool	pak;
	bool	gameLocal;

	StripHighBits(path);

	length = strlen(path);

	if (length >= MAX_QPATH)
		return;

	ext = Com_GetExtension(path);
	if (ext == NULL)
		return;

	if (Q_streq(ext, "pk3")) {
		Com_Printf("NOTICE: Filelist is requesting a .pk3 file (%s)\n", path);
		pak = true;
	} else
		pak = false;

	if (!pak &&
			!Q_streq(ext, "bsp") &&
			!Q_streq(ext, "wav") &&
			!Q_streq(ext, "md2") &&
			!Q_streq(ext, "ogg") &&
			!Q_streq(ext, "md3") &&
			!Q_streq(ext, "png") &&
			!Q_streq(ext, "jpg") &&
			!Q_streq(ext, "obj") &&
			!Q_streq(ext, "mat") &&
			!Q_streq(ext, "ump")) {
		Com_Printf("WARNING: Illegal file type '%s' in filelist.\n", path);
		return;
	}

	if (path[0] == '@') {
		if (pak) {
			Com_Printf("WARNING: @ prefix used on a pk3 file (%s) in filelist.\n", path);
			return;
		}
		gameLocal = true;
		path++;
		length--;
	} else
		gameLocal = false;

	if (strstr(path, "..") || !isvalidchar(path[0]) || !isvalidchar(path[length - 1]) || strstr(path, "//") ||
		strchr(path, '\\') || (!pak && !strchr(path, '/')) || (pak && strchr(path, '/'))) {
		Com_Printf("WARNING: Illegal path '%s' in filelist.\n", path);
		return;
	}

	/* by definition pk3s are game-local */
	if (gameLocal || pak) {
		bool exists;

		/* search the user homedir to find the pk3 file */
		if (pak) {
			char gamePath[MAX_OSPATH];
			FILE *f;
			Com_sprintf(gamePath, sizeof(gamePath), "%s/%s", FS_Gamedir(), path);
			f = fopen(gamePath, "rb");
			if (!f)
				exists = false;
			else {
				exists = true;
				fclose(f);
			}
		} else
			exists = FS_CheckFile("%s", path);

		if (!exists) {
			if (CL_QueueHTTPDownload(path)) {
				/* pk3s get bumped to the top and HTTP switches to single downloading.
				 * this prevents someone on 28k dialup trying to do both the main .pk3
				 * and referenced configstrings data at once. */
				if (pak) {
					dlqueue_t** anchor = &cls.downloadQueue;
					while ((*anchor)->next) anchor = &(*anchor)->next;
					/* Remove the last element from the end of the list ... */
					dlqueue_t* const d = *anchor;
					*anchor            = 0;
					/* ... and prepend it to the list. */
					d->next            = cls.downloadQueue;
					cls.downloadQueue  = d;
				}
			}
		}
	} else
		CL_CheckOrDownloadFile(path);
}
Ejemplo n.º 7
0
/*
===============
CL_CheckOrDownloadFile

Returns true if the file exists, otherwise it attempts
to start a download from the server.
===============
*/
qboolean	CL_CheckOrDownloadFile (const char *filename)
{
	FILE *fp;
	char	name[MAX_OSPATH];
	static char lastfilename[MAX_OSPATH] = "\0";


	Q_strncpyz(name, filename, sizeof(name));
	COM_FixPath(name);
	filename = name;

	//r1: don't attempt same file many times
	if (!strcmp (filename, lastfilename))
		return true;

	strcpy (lastfilename, filename);

	if (strstr (filename, ".."))
	{
		Com_Printf ("Refusing to download a path with .. (%s)\n", filename);
		return true;
	}

	if (strchr (filename, ' '))
	{
		Com_Printf ("Refusing to check a path containing spaces (%s)\n", filename);
		return true;
	}

	if (strchr (filename, ':'))
	{
		Com_Printf ("Refusing to check a path containing a colon (%s)\n", filename);
		return true;
	}

	if (FS_LoadFile (filename, NULL) != -1)
	{	// it exists, no need to download
		return true;
	}

#ifdef USE_CURL
	if (CL_QueueHTTPDownload (filename))
	{
		//we return true so that the precache check keeps feeding us more files.
		//since we have multiple HTTP connections we want to minimize latency
		//and be constantly sending requests, not one at a time.
		return true;
	}
#endif

	strcpy (cls.downloadname, filename);

	// download to a temp name, and only rename
	// to the real name when done, so if interrupted
	// a runt file wont be left
	COM_StripExtension (cls.downloadname, cls.downloadtempname);
	strcat (cls.downloadtempname, ".tmp");

//ZOID
	// check to see if we already have a tmp for this file, if so, try to resume
	// open the file if not opened yet
	CL_DownloadFileName(name, sizeof(name), cls.downloadtempname);

//	FS_CreatePath (name);

	fp = fopen (name, "r+b");
	if (fp)
	{ // it exists
		int len;
		fseek(fp, 0, SEEK_END);
		len = ftell(fp);

		cls.download = fp;

		// give the server an offset to start the download
		Com_Printf ("Resuming %s\n", cls.downloadname);

		MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
		
		if (cls.serverProtocol == PROTOCOL_VERSION_R1Q2)
			MSG_WriteString (&cls.netchan.message, va("download \"%s\" %i udp-zlib", cls.downloadname, len));
		else
			MSG_WriteString (&cls.netchan.message, va("download \"%s\" %i", cls.downloadname, len));
	}
	else
	{
		Com_Printf ("Downloading %s\n", cls.downloadname);

		MSG_WriteByte (&cls.netchan.message, clc_stringcmd);

		if (cls.serverProtocol == PROTOCOL_VERSION_R1Q2)
			MSG_WriteString (&cls.netchan.message, va("download \"%s\" 0 udp-zlib", cls.downloadname));
		else
			MSG_WriteString (&cls.netchan.message, va("download \"%s\"", cls.downloadname));
	}

	//cls.downloadnumber++;

	return false;
}