Ejemplo n.º 1
0
/**
 * @return @c true if are a compatible client and nothing else must be downloaded or no downloads are still running,
 * @c false if the start of the match must get a little bit postponed (running downloads).
 * @note throws ERR_DISCONNECT if we are not compatible to the server
 */
static bool CL_CanMultiplayerStart (void)
{
	const int day = CL_GetConfigStringInteger(CS_LIGHTMAP);
	const char* serverVersion = CL_GetConfigString(CS_VERSION);

	/* checksum doesn't match with the one the server gave us via configstring */
	if (!Q_streq(UFO_VERSION, serverVersion)) {
		Com_sprintf(popupText, sizeof(popupText), _("Local game version (%s) differs from the server version (%s)"), UFO_VERSION, serverVersion);
		UI_Popup(_("Error"), popupText);
		Com_Error(ERR_DISCONNECT, "Local game version (%s) differs from the server version (%s)", UFO_VERSION, serverVersion);
	/* amount of objects from script files doesn't match */
	} else if (csi.numODs != CL_GetConfigStringInteger(CS_OBJECTAMOUNT)) {
		UI_Popup(_("Error"), _("Script files are not the same"));
		Com_Error(ERR_DISCONNECT, "Script files are not the same");
	}

	/* activate the map loading screen for multiplayer, too */
	SCR_BeginLoadingPlaque();

	/* check download */
	if (cls.downloadMaps) { /* confirm map */
		if (CL_DownloadMap(CL_GetConfigString(CS_NAME)))
			return false;
		cls.downloadMaps = false;
	}

	/* map might still be downloading? */
	if (CL_PendingHTTPDownloads())
		return false;

	if (Com_GetScriptChecksum() != CL_GetConfigStringInteger(CS_UFOCHECKSUM))
		Com_Printf("You are using modified ufo script files - might produce problems\n");

	CM_LoadMap(CL_GetConfigString(CS_TILES), day, CL_GetConfigString(CS_POSITIONS), CL_GetConfigString(CS_ENTITYSTRING), cl.mapData, cl.mapTiles);

#if 0
	if (cl.mapData->mapChecksum != CL_GetConfigStringInteger(CS_MAPCHECKSUM)) {
		UI_Popup(_("Error"), _("Local map version differs from server"));
		Com_Error(ERR_DISCONNECT, "Local map version differs from server: %u != '%i'",
			cl.mapData->mapChecksum, CL_GetConfigStringInteger(CS_MAPCHECKSUM));
	}
#endif

	return true;
}
Ejemplo n.º 2
0
/*
===============
CL_FinishHTTPDownload

A download finished, find out what it was, whether there were any errors and
if so, how severe. If none, rename file and other such stuff.
===============
*/
static void CL_FinishHTTPDownload (void)
{
	size_t		i;
	int			msgs_in_queue;
	CURLMsg		*msg;
	CURLcode	result;
	dlhandle_t	*dl;
	CURL		*curl;
	long		responseCode;
	double		timeTaken;
	double		fileSize;
	char		tempName[MAX_OSPATH];
	qboolean	isFile;

	do
	{
		msg = curl_multi_info_read (multi, &msgs_in_queue);

		if (!msg)
		{
			Com_Printf ("CL_FinishHTTPDownload: Odd, no message for us...\n");
			return;
		}

		if (msg->msg != CURLMSG_DONE)
		{
			Com_Printf ("CL_FinishHTTPDownload: Got some weird message...\n");
			continue;
		}

		curl = msg->easy_handle;

		// curl doesn't provide reverse-lookup of the void * ptr, so search for it
		for (i = 0; i < 4; i++)
		{
			if (cls.HTTPHandles[i].curl == curl)
			{
				dl = &cls.HTTPHandles[i];
				break;
			}
		}

		if (i == 4)
			Com_Error (ERR_DROP, "CL_FinishHTTPDownload: Handle not found");

		// we mark everything as done even if it errored to prevent multiple
		// attempts.
		dl->queueEntry->state = DLQ_STATE_DONE;

		//filelist processing is done on read
		if (dl->file)
			isFile = true;
		else
			isFile = false;

		if (isFile)
		{
			fclose (dl->file);
			dl->file = NULL;
		}

		//might be aborted
		if (pendingCount)
			pendingCount--;
		handleCount--;
		//Com_Printf ("finished dl: hc = %d\n", LOG_GENERAL, handleCount);
		cls.downloadname[0] = 0;
		cls.downloadposition = 0;

		result = msg->data.result;

		switch (result)
		{
			// for some reason curl returns CURLE_OK for a 404...
			case CURLE_HTTP_RETURNED_ERROR:
			case CURLE_OK:
			
				curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &responseCode);
				if (responseCode == 404)
				{
					i = strlen (dl->queueEntry->quakePath);
					if ( !strcmp (dl->queueEntry->quakePath + i - 4, ".pak")
						|| !strcmp (dl->queueEntry->quakePath + i - 4, ".pk3") )
						downloading_pak = false;

					if (isFile)
						remove (dl->filePath);
					Com_Printf ("HTTP(%s): 404 File Not Found [%d remaining files]\n", dl->queueEntry->quakePath, pendingCount);
					curl_easy_getinfo (curl, CURLINFO_SIZE_DOWNLOAD, &fileSize);
					if (fileSize > 512)
					{
						// ick
						isFile = false;
						result = CURLE_FILESIZE_EXCEEDED;
						Com_Printf ("Oversized 404 body received (%d bytes), aborting HTTP downloading.\n", (int)fileSize);
					}
					else
					{
						curl_multi_remove_handle (multi, dl->curl);
						// Knightmare- fall back to UDP download for this map if failure on .bsp
						if ( !strncmp(dl->queueEntry->quakePath, "maps/", 5) && !strcmp(dl->queueEntry->quakePath + i - 4, ".bsp") )
						{
							Com_Printf ("HTTP: failed to download %s, falling back to UDP until next map.\n", dl->queueEntry->quakePath);
							thisMapAbort = true;
							CL_CancelHTTPDownloads (false);
							CL_ResetPrecacheCheck ();
						}
						// end Knightmare
						continue;
					}
				}
				else if (responseCode == 200)
				{
					if (!isFile && !abortDownloads)
						CL_ParseFileList (dl);
					break;
				}

				//every other code is treated as fatal, fallthrough here
				Com_Printf ("Bad HTTP response code %d for %s, aborting HTTP downloading.\n", responseCode, dl->queueEntry->quakePath);

			//fatal error, disable http
			case CURLE_COULDNT_RESOLVE_HOST:
			case CURLE_COULDNT_CONNECT:
			case CURLE_COULDNT_RESOLVE_PROXY:
				if (isFile)
					remove (dl->filePath);
			//	Com_Printf ("Fatal HTTP error: %s\n", curl_easy_strerror (result));
				Com_Printf ("Fatal HTTP error: %s\n", CURL_ERROR(result));
				curl_multi_remove_handle (multi, dl->curl);
				if (abortDownloads)
					continue;
				CL_CancelHTTPDownloads (true);
				continue;
			default:
				i = strlen (dl->queueEntry->quakePath);
				if ( !strcmp (dl->queueEntry->quakePath + i - 4, ".pak") || !strcmp (dl->queueEntry->quakePath + i - 4, ".pk3") )
					downloading_pak = false;
				if (isFile)
					remove (dl->filePath);
			//	Com_Printf ("HTTP download failed: %s\n", curl_easy_strerror (result));
				Com_Printf ("HTTP download failed: %s\n", CURL_ERROR(result));
				curl_multi_remove_handle (multi, dl->curl);
				continue;
		}

		if (isFile)
		{
			//rename the temp file
			Com_sprintf (tempName, sizeof(tempName), "%s/%s", FS_Gamedir(), dl->queueEntry->quakePath);

			if (rename (dl->filePath, tempName))
				Com_Printf ("Failed to rename %s for some odd reason...", dl->filePath);

			//a pak file is very special...
			i = strlen (tempName);
			if ( !strcmp (tempName + i - 4, ".pak") || !strcmp (tempName + i - 4, ".pk3") )
			{
			//	FS_FlushCache ();
			//	FS_ReloadPAKs ();
				// Knightmare- just add the pk3/ pak file
				if (!strcmp (tempName + i - 4, ".pk3")) 
					FS_AddPK3File (tempName);
				else
					FS_AddPAKFile (tempName);

				CL_ReVerifyHTTPQueue ();
				downloading_pak = false;
			}
		}

		//show some stats
		curl_easy_getinfo (curl, CURLINFO_TOTAL_TIME, &timeTaken);
		curl_easy_getinfo (curl, CURLINFO_SIZE_DOWNLOAD, &fileSize);

		//FIXME:
		//technically i shouldn't need to do this as curl will auto reuse the
		//existing handle when you change the URL. however, the handleCount goes
		//all weird when reusing a download slot in this way. if you can figure
		//out why, please let me know.
		curl_multi_remove_handle (multi, dl->curl);

		Com_Printf ("HTTP(%s): %.f bytes, %.2fkB/sec [%d remaining files]\n", dl->queueEntry->quakePath, fileSize, (fileSize / 1024.0) / timeTaken, pendingCount);
	} while (msgs_in_queue > 0);

//	FS_FlushCache ();

	if (handleCount == 0)
	{
		if (abortDownloads == HTTPDL_ABORT_SOFT)
			abortDownloads = HTTPDL_ABORT_NONE;
		else if (abortDownloads == HTTPDL_ABORT_HARD) {
			// FS: Added because Whale's Weapons HTTP server rejects you after a lot of 404s.  Then you lose HTTP until a hard reconnect.
			Q_strncpyz(cls.downloadServerRetry, cls.downloadServer, sizeof(cls.downloadServerRetry)); 
			cls.downloadServer[0] = 0;
		}
	}

	// done current batch, see if we have more to dl - maybe a .bsp needs downloaded
	if (cls.state == ca_connected && !CL_PendingHTTPDownloads())
		CL_RequestNextDownload ();
}
Ejemplo n.º 3
0
/**
 * @brief A download finished, find out what it was, whether there were any errors and
 * if so, how severe. If none, rename file and other such stuff.
 */
static void CL_FinishHTTPDownload (void)
{
	int messagesInQueue, i;
	CURLcode result;
	CURL *curl;
	long responseCode;
	double timeTaken, fileSize;
	char tempName[MAX_OSPATH];
	bool isFile;

	do {
		CURLMsg *msg = curl_multi_info_read(multi, &messagesInQueue);
		dlhandle_t *dl = NULL;

		if (!msg) {
			Com_Printf("CL_FinishHTTPDownload: Odd, no message for us...\n");
			return;
		}

		if (msg->msg != CURLMSG_DONE) {
			Com_Printf("CL_FinishHTTPDownload: Got some weird message...\n");
			continue;
		}

		curl = msg->easy_handle;

		/* curl doesn't provide reverse-lookup of the void * ptr, so search for it */
		for (i = 0; i < 4; i++) {
			if (cls.HTTPHandles[i].curl == curl) {
				dl = &cls.HTTPHandles[i];
				break;
			}
		}

		if (!dl)
			Com_Error(ERR_DROP, "CL_FinishHTTPDownload: Handle not found");

		/* we mark everything as done even if it errored to prevent multiple attempts. */
		dl->queueEntry->state = DLQ_STATE_DONE;

		/* filelist processing is done on read */
		if (dl->file)
			isFile = true;
		else
			isFile = false;

		if (isFile) {
			fclose(dl->file);
			dl->file = NULL;
		}

		/* might be aborted */
		if (pendingCount)
			pendingCount--;
		handleCount--;
		/* Com_Printf("finished dl: hc = %d\n", handleCount); */
		cls.downloadName[0] = 0;
		cls.downloadPosition = 0;

		result = msg->data.result;

		switch (result) {
		/* for some reason curl returns CURLE_OK for a 404... */
		case CURLE_HTTP_RETURNED_ERROR:
		case CURLE_OK:
			curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode);
			if (responseCode == 404) {
				const char *extension = Com_GetExtension(dl->queueEntry->ufoPath);
				if (extension != NULL && Q_streq(extension, "pk3"))
					downloadingPK3 = false;

				if (isFile)
					FS_RemoveFile(dl->filePath);
				Com_Printf("HTTP(%s): 404 File Not Found [%d remaining files]\n", dl->queueEntry->ufoPath, pendingCount);
				curl_easy_getinfo(curl, CURLINFO_SIZE_DOWNLOAD, &fileSize);
				if (fileSize > 512) {
					/* ick */
					isFile = false;
					result = CURLE_FILESIZE_EXCEEDED;
					Com_Printf("Oversized 404 body received (%d bytes), aborting HTTP downloading.\n", (int)fileSize);
				} else {
					curl_multi_remove_handle(multi, dl->curl);
					continue;
				}
			} else if (responseCode == 200) {
				if (!isFile && !abortDownloads)
					CL_ParseFileList(dl);
				break;
			}

			/* every other code is treated as fatal, fallthrough here */

		/* fatal error, disable http */
		case CURLE_COULDNT_RESOLVE_HOST:
		case CURLE_COULDNT_CONNECT:
		case CURLE_COULDNT_RESOLVE_PROXY:
			if (isFile)
				FS_RemoveFile(dl->filePath);
			Com_Printf("Fatal HTTP error: %s\n", curl_easy_strerror(result));
			curl_multi_remove_handle(multi, dl->curl);
			if (abortDownloads)
				continue;
			CL_CancelHTTPDownloads(true);
			continue;
		default:
			i = strlen(dl->queueEntry->ufoPath);
			if (Q_streq(dl->queueEntry->ufoPath + i - 4, ".pk3"))
				downloadingPK3 = false;
			if (isFile)
				FS_RemoveFile(dl->filePath);
			Com_Printf("HTTP download failed: %s\n", curl_easy_strerror(result));
			curl_multi_remove_handle(multi, dl->curl);
			continue;
		}

		if (isFile) {
			/* rename the temp file */
			Com_sprintf(tempName, sizeof(tempName), "%s/%s", FS_Gamedir(), dl->queueEntry->ufoPath);

			if (!FS_RenameFile(dl->filePath, tempName, false))
				Com_Printf("Failed to rename %s for some odd reason...", dl->filePath);

			/* a pk3 file is very special... */
			i = strlen(tempName);
			if (Q_streq(tempName + i - 4, ".pk3")) {
				FS_RestartFilesystem(NULL);
				CL_ReVerifyHTTPQueue();
				downloadingPK3 = false;
			}
		}

		/* show some stats */
		curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &timeTaken);
		curl_easy_getinfo(curl, CURLINFO_SIZE_DOWNLOAD, &fileSize);

		/** @todo
		 * technically i shouldn't need to do this as curl will auto reuse the
		 * existing handle when you change the URL. however, the handleCount goes
		 * all weird when reusing a download slot in this way. if you can figure
		 * out why, please let me know. */
		curl_multi_remove_handle(multi, dl->curl);

		Com_Printf("HTTP(%s): %.f bytes, %.2fkB/sec [%d remaining files]\n",
			dl->queueEntry->ufoPath, fileSize, (fileSize / 1024.0) / timeTaken, pendingCount);
	} while (messagesInQueue > 0);

	if (handleCount == 0) {
		if (abortDownloads == HTTPDL_ABORT_SOFT)
			abortDownloads = HTTPDL_ABORT_NONE;
		else if (abortDownloads == HTTPDL_ABORT_HARD)
			cls.downloadServer[0] = 0;
	}

	/* done current batch, see if we have more to dl - maybe a .bsp needs downloaded */
	if (cls.state == ca_connected && !CL_PendingHTTPDownloads())
		CL_RequestNextDownload();
}