UFO: Alien Invasion
Loading...
Searching...
No Matches
cl_http.cpp
Go to the documentation of this file.
1
13
14/*
15Copyright (C) 1997-2001 Id Software, Inc.
16
17This program is free software; you can redistribute it and/or
18modify it under the terms of the GNU General Public License
19as published by the Free Software Foundation; either version 2
20of the License, or (at your option) any later version.
21
22This program is distributed in the hope that it will be useful,
23but WITHOUT ANY WARRANTY; without even the implied warranty of
24MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
25
26See the GNU General Public License for more details.
27
28You should have received a copy of the GNU General Public License
29along with this program; if not, write to the Free Software
30Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31
32*/
33
34#include "client.h"
35#include "cl_http.h"
37
38#ifndef NO_HTTP
39
43
44enum {
48};
49
50static CURLM *multi = nullptr;
51static int handleCount = 0;
52static int pendingCount = 0;
54static bool downloadingPK3 = false;
55
56static void StripHighBits (char* string)
57{
58 char* p = string;
59
60 while (string[0]) {
61 const unsigned char c = *(string++);
62
63 if (c >= 32 && c <= 127)
64 *p++ = c;
65 }
66
67 p[0] = '\0';
68}
69
70static inline bool isvalidchar (int c)
71{
72 if (!isalnum(c) && c != '_' && c != '-')
73 return false;
74 return true;
75}
76
81static int CL_HTTP_Progress (void* clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
82{
83 dlhandle_t* dl = (dlhandle_t*)clientp;
84
85 dl->position = (unsigned)dlnow;
86
87 /* don't care which download shows as long as something does :) */
88 if (!abortDownloads) {
89 Q_strncpyz(cls.downloadName, dl->queueEntry->ufoPath, sizeof(cls.downloadName));
90 cls.downloadPosition = dl->position;
91
92 if (dltotal > 0.0)
93 cls.downloadPercent = (int)((dlnow / dltotal) * 100.0f);
94 else
95 cls.downloadPercent = 0;
96 }
97
98 return abortDownloads;
99}
100
106static void CL_EscapeHTTPPath (const char* filePath, char* escaped)
107{
108 char *p = escaped;
109
110 size_t len = strlen(filePath);
111 for (int i = 0; i < len; i++) {
112 if (!isalnum(filePath[i]) && filePath[i] != ';' && filePath[i] != '/' &&
113 filePath[i] != '?' && filePath[i] != ':' && filePath[i] != '@' && filePath[i] != '&' &&
114 filePath[i] != '=' && filePath[i] != '+' && filePath[i] != '$' && filePath[i] != ',' &&
115 filePath[i] != '[' && filePath[i] != ']' && filePath[i] != '-' && filePath[i] != '_' &&
116 filePath[i] != '.' && filePath[i] != '!' && filePath[i] != '~' && filePath[i] != '*' &&
117 filePath[i] != '\'' && filePath[i] != '(' && filePath[i] != ')') {
118 sprintf(p, "%%%02x", filePath[i]);
119 p += 3;
120 } else {
121 *p = filePath[i];
122 p++;
123 }
124 }
125 p[0] = 0;
126
127 /* using ./ in a url is legal, but all browsers condense the path and some IDS / request */
128 /* filtering systems act a bit funky if http requests come in with uncondensed paths. */
129 len = strlen(escaped);
130 p = escaped;
131 while ((p = strstr (p, "./"))) {
132 memmove(p, p + 2, len - (p - escaped) - 1);
133 len -= 2;
134 }
135}
136
141{
142 char escapedFilePath[MAX_QPATH * 4];
143 const char* extension = Com_GetExtension(entry->ufoPath);
144
145 /* yet another hack to accomodate filelists, how i wish i could push :(
146 * nullptr file handle indicates filelist. */
147 if (extension != nullptr && Q_streq(extension, "filelist")) {
148 dl->file = nullptr;
149 CL_EscapeHTTPPath(entry->ufoPath, escapedFilePath);
150 } else {
151 char tempFile[MAX_OSPATH];
153 Com_sprintf(dl->filePath, sizeof(dl->filePath), "%s/%s", FS_Gamedir(), entry->ufoPath);
154
155 Com_sprintf(tempFile, sizeof(tempFile), BASEDIRNAME "/%s", entry->ufoPath);
156 CL_EscapeHTTPPath(tempFile, escapedFilePath);
157
158 strcat(dl->filePath, ".tmp");
159
161
162 /* don't bother with http resume... too annoying if server doesn't support it. */
163 dl->file = Sys_Fopen(dl->filePath, "wb");
164 if (!dl->file) {
165 Com_Printf("CL_StartHTTPDownload: Couldn't open %s for writing.\n", dl->filePath);
166 entry->state = DLQ_STATE_DONE;
167 /* CL_RemoveHTTPDownload(entry->ufoPath); */
168 return;
169 }
170 }
171
172 dl->tempBuffer = nullptr;
173 dl->speed = 0;
174 dl->fileSize = 0;
175 dl->position = 0;
176 dl->queueEntry = entry;
177
178 if (!dl->curl)
179 dl->curl = curl_easy_init();
180
181 Com_sprintf(dl->URL, sizeof(dl->URL), "%s%s", cls.downloadServer, escapedFilePath);
182
183 curl_easy_setopt(dl->curl, CURLOPT_ENCODING, "");
184#ifdef PARANOID
185 curl_easy_setopt(dl->curl, CURLOPT_VERBOSE, 1);
186#endif
187 curl_easy_setopt(dl->curl, CURLOPT_NOPROGRESS, 0);
188 if (dl->file) {
189 curl_easy_setopt(dl->curl, CURLOPT_WRITEDATA, dl->file);
190 curl_easy_setopt(dl->curl, CURLOPT_WRITEFUNCTION, nullptr);
191 } else {
192 curl_easy_setopt(dl->curl, CURLOPT_WRITEDATA, dl);
193 curl_easy_setopt(dl->curl, CURLOPT_WRITEFUNCTION, HTTP_Recv);
194 }
195 curl_easy_setopt(dl->curl, CURLOPT_CONNECTTIMEOUT, http_timeout->integer);
196 curl_easy_setopt(dl->curl, CURLOPT_TIMEOUT, http_timeout->integer);
197 curl_easy_setopt(dl->curl, CURLOPT_FAILONERROR, 1);
198 curl_easy_setopt(dl->curl, CURLOPT_PROXY, http_proxy->string);
199 curl_easy_setopt(dl->curl, CURLOPT_FOLLOWLOCATION, 1);
200 curl_easy_setopt(dl->curl, CURLOPT_MAXREDIRS, 5);
201 curl_easy_setopt(dl->curl, CURLOPT_WRITEHEADER, dl);
202 curl_easy_setopt(dl->curl, CURLOPT_HEADERFUNCTION, HTTP_Header);
203 curl_easy_setopt(dl->curl, CURLOPT_XFERINFOFUNCTION, CL_HTTP_Progress);
204 curl_easy_setopt(dl->curl, CURLOPT_PROGRESSDATA, dl);
205 curl_easy_setopt(dl->curl, CURLOPT_USERAGENT, GAME_TITLE " " UFO_VERSION);
206 curl_easy_setopt(dl->curl, CURLOPT_REFERER, cls.downloadReferer);
207 curl_easy_setopt(dl->curl, CURLOPT_URL, dl->URL);
208 curl_easy_setopt(dl->curl, CURLOPT_NOSIGNAL, 1);
209
210 if (curl_multi_add_handle(multi, dl->curl) != CURLM_OK) {
211 Com_Printf("curl_multi_add_handle: error\n");
213 return;
214 }
215
216 handleCount++;
217 /*Com_Printf("started dl: hc = %d\n", handleCount); */
218 Com_Printf("CL_StartHTTPDownload: Fetching %s...\n", dl->URL);
220}
221
225void CL_SetHTTPServer (const char* URL)
226{
228
229 for (dlqueue_t* q = cls.downloadQueue; q;) {
230 dlqueue_t* const del = q;
231 q = q->next;
232 Mem_Free(del);
233 }
234 cls.downloadQueue = 0;
235
236 if (multi)
237 Com_Error(ERR_DROP, "CL_SetHTTPServer: Still have old handle");
238
239 multi = curl_multi_init();
240
243
244 Q_strncpyz(cls.downloadServer, URL, sizeof(cls.downloadServer));
245}
246
250void CL_CancelHTTPDownloads (bool permKill)
251{
252 if (permKill)
254 else
256
257 for (dlqueue_t* q = cls.downloadQueue; q; q = q->next) {
258 if (q->state == DLQ_STATE_NOT_STARTED)
259 q->state = DLQ_STATE_DONE;
260 }
261
263 cls.downloadServer[0] = 0;
264
265 pendingCount = 0;
266}
267
272{
273 for (int i = 0; i < 4; i++) {
274 dlhandle_t* dl = &cls.HTTPHandles[i];
275 if (!dl->queueEntry || dl->queueEntry->state == DLQ_STATE_DONE)
276 return dl;
277 }
278
279 return nullptr;
280}
281
286bool CL_QueueHTTPDownload (const char* ufoPath)
287{
288 /* no http server (or we got booted) */
289 if (!cls.downloadServer[0] || abortDownloads || !cl_http_downloads->integer)
290 return false;
291
292 dlqueue_t** anchor = &cls.downloadQueue;
293 for (; *anchor; anchor = &(*anchor)->next) {
294 /* avoid sending duplicate requests */
295 if (Q_streq(ufoPath, (*anchor)->ufoPath))
296 return true;
297 }
298
300 q->next = nullptr;
302 Q_strncpyz(q->ufoPath, ufoPath, sizeof(q->ufoPath));
303 *anchor = q;
304
305 /* special case for map file lists */
306 if (cl_http_filelists->integer) {
307 const char* extension = Com_GetExtension(ufoPath);
308 if (extension != nullptr && !Q_strcasecmp(extension, "bsp")) {
309 char listPath[MAX_OSPATH];
310 const size_t len = strlen(ufoPath);
311 Com_sprintf(listPath, sizeof(listPath), BASEDIRNAME"/%.*s.filelist", (int)(len - 4), ufoPath);
312 CL_QueueHTTPDownload(listPath);
313 }
314 }
315
316 /* if a download entry has made it this far, CL_FinishHTTPDownload is guaranteed to be called. */
317 pendingCount++;
318
319 return true;
320}
321
329{
330 if (cls.downloadServer[0] == '\0')
331 return false;
332
333 return pendingCount + handleCount;
334}
335
342{
343 static char lastfilename[MAX_OSPATH] = "";
344
345 if (Q_strnull(filename))
346 return true;
347
348 /* r1: don't attempt same file many times */
349 if (Q_streq(filename, lastfilename))
350 return true;
351
352 Q_strncpyz(lastfilename, filename, sizeof(lastfilename));
353
354 if (strstr(filename, "..")) {
355 Com_Printf("Refusing to check a path with .. (%s)\n", filename);
356 return true;
357 }
358
359 if (strchr(filename, ' ')) {
360 Com_Printf("Refusing to check a path containing spaces (%s)\n", filename);
361 return true;
362 }
363
364 if (strchr(filename, ':')) {
365 Com_Printf("Refusing to check a path containing a colon (%s)\n", filename);
366 return true;
367 }
368
369 if (filename[0] == '/') {
370 Com_Printf("Refusing to check a path starting with / (%s)\n", filename);
371 return true;
372 }
373
374 if (FS_LoadFile(filename, nullptr) != -1) {
375 /* it exists, no need to download */
376 return true;
377 }
378
380 return false;
381
382 return true;
383}
384
391static void CL_CheckAndQueueDownload (char* path)
392{
393 StripHighBits(path);
394
395 size_t length = strlen(path);
396
397 if (length >= MAX_QPATH)
398 return;
399
400 const char* ext = Com_GetExtension(path);
401 if (ext == nullptr)
402 return;
403
404 bool pak;
405 if (Q_streq(ext, "pk3")) {
406 Com_Printf("NOTICE: Filelist is requesting a .pk3 file (%s)\n", path);
407 pak = true;
408 } else
409 pak = false;
410
411 if (!pak &&
412 !Q_streq(ext, "bsp") &&
413 !Q_streq(ext, "wav") &&
414 !Q_streq(ext, "md2") &&
415 !Q_streq(ext, "ogg") &&
416 !Q_streq(ext, "md3") &&
417 !Q_streq(ext, "png") &&
418 !Q_streq(ext, "jpg") &&
419 !Q_streq(ext, "webp") &&
420 !Q_streq(ext, "obj") &&
421 !Q_streq(ext, "mat") &&
422 !Q_streq(ext, "ump")) {
423 Com_Printf("WARNING: Illegal file type '%s' in filelist.\n", path);
424 return;
425 }
426
427 bool gameLocal;
428 if (path[0] == '@') {
429 if (pak) {
430 Com_Printf("WARNING: @ prefix used on a pk3 file (%s) in filelist.\n", path);
431 return;
432 }
433 gameLocal = true;
434 path++;
435 length--;
436 } else
437 gameLocal = false;
438
439 if (strstr(path, "..") || !isvalidchar(path[0]) || !isvalidchar(path[length - 1]) || strstr(path, "//") ||
440 strchr(path, '\\') || (!pak && !strchr(path, '/')) || (pak && strchr(path, '/'))) {
441 Com_Printf("WARNING: Illegal path '%s' in filelist.\n", path);
442 return;
443 }
444
445 /* by definition pk3s are game-local */
446 if (gameLocal || pak) {
447 bool exists;
448
449 /* search the user homedir to find the pk3 file */
450 if (pak) {
451 char gamePath[MAX_OSPATH];
452 Com_sprintf(gamePath, sizeof(gamePath), "%s/%s", FS_Gamedir(), path);
453 FILE* f = Sys_Fopen(gamePath, "rb");
454 if (!f)
455 exists = false;
456 else {
457 exists = true;
458 fclose(f);
459 }
460 } else
461 exists = FS_CheckFile("%s", path);
462
463 if (!exists) {
464 if (CL_QueueHTTPDownload(path)) {
465 /* pk3s get bumped to the top and HTTP switches to single downloading.
466 * this prevents someone on 28k dialup trying to do both the main .pk3
467 * and referenced configstrings data at once. */
468 if (pak) {
469 dlqueue_t** anchor = &cls.downloadQueue;
470 while ((*anchor)->next) anchor = &(*anchor)->next;
471 /* Remove the last element from the end of the list ... */
472 dlqueue_t* const d = *anchor;
473 *anchor = 0;
474 /* ... and prepend it to the list. */
475 d->next = cls.downloadQueue;
476 cls.downloadQueue = d;
477 }
478 }
479 }
480 } else
482}
483
488{
489 if (!cl_http_filelists->integer)
490 return;
491
492 char* list = dl->tempBuffer;
493
494 for (;;) {
495 char* p = strchr(list, '\n');
496 if (p) {
497 p[0] = 0;
498 if (list[0])
500 list = p + 1;
501 } else {
502 if (list[0])
504 break;
505 }
506 }
507
508 Mem_Free(dl->tempBuffer);
509 dl->tempBuffer = nullptr;
510}
511
516static void CL_ReVerifyHTTPQueue (void)
517{
518 pendingCount = 0;
519
520 for (dlqueue_t* q = cls.downloadQueue; q; q = q->next) {
521 if (q->state == DLQ_STATE_NOT_STARTED) {
522 if (FS_LoadFile(q->ufoPath, nullptr) != -1)
523 q->state = DLQ_STATE_DONE;
524 else
525 pendingCount++;
526 }
527 }
528}
529
534{
535 for (int i = 0; i < 4; i++) {
536 dlhandle_t* dl = &cls.HTTPHandles[i];
537
538 if (dl->file) {
539 fclose(dl->file);
540 Sys_Remove(dl->filePath);
541 dl->file = nullptr;
542 }
543
544 Mem_Free(dl->tempBuffer);
545 dl->tempBuffer = nullptr;
546
547 if (dl->curl) {
548 if (multi)
549 curl_multi_remove_handle(multi, dl->curl);
550 curl_easy_cleanup(dl->curl);
551 dl->curl = nullptr;
552 }
553
554 dl->queueEntry = nullptr;
555 }
556
557 if (multi) {
558 curl_multi_cleanup(multi);
559 multi = nullptr;
560 }
561}
562
567static void CL_FinishHTTPDownload (void)
568{
569 int messagesInQueue;
570 do {
571 CURLMsg* msg = curl_multi_info_read(multi, &messagesInQueue);
572 dlhandle_t* dl = nullptr;
573
574 if (!msg) {
575 Com_Printf("CL_FinishHTTPDownload: Odd, no message for us...\n");
576 return;
577 }
578
579 if (msg->msg != CURLMSG_DONE) {
580 Com_Printf("CL_FinishHTTPDownload: Got some weird message...\n");
581 continue;
582 }
583
584 CURL* curl = msg->easy_handle;
585
586 /* curl doesn't provide reverse-lookup of the void* ptr, so search for it */
587 for (int i = 0; i < 4; i++) {
588 if (cls.HTTPHandles[i].curl == curl) {
589 dl = &cls.HTTPHandles[i];
590 break;
591 }
592 }
593
594 if (!dl)
595 Com_Error(ERR_DROP, "CL_FinishHTTPDownload: Handle not found");
596
597 /* we mark everything as done even if it errored to prevent multiple attempts. */
599
600 /* filelist processing is done on read */
601 bool isFile;
602 if (dl->file)
603 isFile = true;
604 else
605 isFile = false;
606
607 if (isFile) {
608 fclose(dl->file);
609 dl->file = nullptr;
610 }
611
612 /* might be aborted */
613 if (pendingCount)
614 pendingCount--;
615 handleCount--;
616 /* Com_Printf("finished dl: hc = %d\n", handleCount); */
617 cls.downloadName[0] = 0;
618 cls.downloadPosition = 0;
619
620 CURLcode result = msg->data.result;
621
622 long responseCode;
623 double timeTaken;
624 curl_off_t fileSize;
625 char tempName[MAX_OSPATH];
626 switch (result) {
627 /* for some reason curl returns CURLE_OK for a 404... */
628 case CURLE_HTTP_RETURNED_ERROR:
629 case CURLE_OK:
630 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode);
631 if (responseCode == 404) {
632 const char* extension = Com_GetExtension(dl->queueEntry->ufoPath);
633 if (extension != nullptr && Q_streq(extension, "pk3"))
634 downloadingPK3 = false;
635
636 if (isFile)
638 Com_Printf("HTTP(%s): 404 File Not Found [%d remaining files]\n", dl->queueEntry->ufoPath, pendingCount);
639 curl_easy_getinfo(curl, CURLINFO_SIZE_DOWNLOAD_T, &fileSize);
640 if (fileSize > 512) {
641 /* ick */
642 isFile = false;
643 result = CURLE_FILESIZE_EXCEEDED;
644 Com_Printf("Oversized 404 body received (%d bytes), aborting HTTP downloading.\n", (int)fileSize);
645 } else {
646 curl_multi_remove_handle(multi, dl->curl);
647 continue;
648 }
649 } else if (responseCode == 200) {
650 if (!isFile && !abortDownloads)
652 break;
653 }
654
655 /* every other code is treated as fatal, fallthrough here */
656
657 /* fatal error, disable http */
658 case CURLE_COULDNT_RESOLVE_HOST:
659 case CURLE_COULDNT_CONNECT:
660 case CURLE_COULDNT_RESOLVE_PROXY:
661 if (isFile)
663 Com_Printf("Fatal HTTP error: %s\n", curl_easy_strerror(result));
664 curl_multi_remove_handle(multi, dl->curl);
665 if (abortDownloads)
666 continue;
668 continue;
669 default:
670 //i = strlen(dl->queueEntry->ufoPath);
671 if (Q_streq(dl->queueEntry->ufoPath + strlen(dl->queueEntry->ufoPath) - 4, ".pk3"))
672 downloadingPK3 = false;
673 if (isFile)
675 Com_Printf("HTTP download failed: %s\n", curl_easy_strerror(result));
676 curl_multi_remove_handle(multi, dl->curl);
677 continue;
678 }
679
680 if (isFile) {
681 /* rename the temp file */
682 Com_sprintf(tempName, sizeof(tempName), "%s/%s", FS_Gamedir(), dl->queueEntry->ufoPath);
683
684 if (!FS_RenameFile(dl->filePath, tempName, false))
685 Com_Printf("Failed to rename %s for some odd reason...", dl->filePath);
686
687 /* a pk3 file is very special... */
688 int i = strlen(tempName);
689 if (Q_streq(tempName + i - 4, ".pk3")) {
690 FS_RestartFilesystem(nullptr);
692 downloadingPK3 = false;
693 }
694 }
695
696 /* show some stats */
697 curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &timeTaken);
698 curl_easy_getinfo(curl, CURLINFO_SIZE_DOWNLOAD_T, &fileSize);
699
705 curl_multi_remove_handle(multi, dl->curl);
706
707 Com_Printf("HTTP(%s): %ld bytes, %.2fkB/sec [%d remaining files]\n",
708 dl->queueEntry->ufoPath, fileSize, (fileSize / 1024.0) / timeTaken, pendingCount);
709 } while (messagesInQueue > 0);
710
711 if (handleCount == 0) {
715 cls.downloadServer[0] = 0;
716 }
717
718 /* done current batch, see if we have more to dl - maybe a .bsp needs downloaded */
719 if (cls.state == ca_connected && !CL_PendingHTTPDownloads())
721}
722
727static void CL_StartNextHTTPDownload (void)
728{
729 for (dlqueue_t* q = cls.downloadQueue; q; q = q->next) {
730 if (q->state == DLQ_STATE_NOT_STARTED) {
732 if (!dl)
733 return;
734
736
737 /* ugly hack for pk3 file single downloading */
738 const size_t len = strlen(q->ufoPath);
739 if (len > 4 && !Q_strcasecmp(q->ufoPath + len - 4, ".pk3"))
740 downloadingPK3 = true;
741
742 break;
743 }
744 }
745}
746
754{
755 CURLMcode ret;
756
757 if (!cls.downloadServer[0])
758 return;
759
760 /* Com_Printf("handle %d, pending %d\n", handleCount, pendingCount); */
761
762 /* not enough downloads running, queue some more! */
766
767 do {
768 int newHandleCount;
769 ret = curl_multi_perform(multi, &newHandleCount);
770 if (newHandleCount < handleCount) {
771 /* Com_Printf("runnd dl: hc = %d, nc = %d\n", handleCount, newHandleCount); */
772 /* hmm, something either finished or errored out. */
774 handleCount = newHandleCount;
775 }
776 } while (ret == CURLM_CALL_MULTI_PERFORM);
777
778 if (ret != CURLM_OK) {
779 Com_Printf("curl_multi_perform error. Aborting HTTP downloads.\n");
781 }
782
783 /* not enough downloads running, queue some more! */
787}
788
790{
791 cl_http_filelists = Cvar_Get("cl_http_filelists", "1");
792 cl_http_downloads = Cvar_Get("cl_http_downloads", "1", 0, "Try to download files via http");
793 cl_http_max_connections = Cvar_Get("cl_http_max_connections", "1");
794}
795#else
796void CL_CancelHTTPDownloads(bool permKill) {}
797bool CL_QueueHTTPDownload(const char* ufoPath) {return false;}
798void CL_RunHTTPDownloads(void) {}
799bool CL_PendingHTTPDownloads(void) {return false;}
800void CL_SetHTTPServer(const char* URL) {}
801void CL_HTTP_Cleanup(void) {}
802void CL_RequestNextDownload(void) {}
803bool CL_CheckOrDownloadFile(const char* filename) {return false;}
804
805void HTTP_InitStartup(void){}
806#endif
bool CL_CheckOrDownloadFile(const char *filename)
Definition cl_http.cpp:341
static void StripHighBits(char *string)
Definition cl_http.cpp:56
static void CL_CheckAndQueueDownload(char *path)
Validate a path supplied by a filelist.
Definition cl_http.cpp:391
bool CL_PendingHTTPDownloads(void)
See if we're still busy with some downloads. Called by precacher just before it loads the map since w...
Definition cl_http.cpp:328
static int pendingCount
Definition cl_http.cpp:52
static bool isvalidchar(int c)
Definition cl_http.cpp:70
void CL_RunHTTPDownloads(void)
This calls curl_multi_perform do actually do stuff. Called every frame while connecting to minimise l...
Definition cl_http.cpp:753
static cvar_t * cl_http_filelists
Definition cl_http.cpp:41
static int handleCount
Definition cl_http.cpp:51
static dlhandle_t * CL_GetFreeDLHandle(void)
Find a free download handle to start another queue entry on.
Definition cl_http.cpp:271
static int CL_HTTP_Progress(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
libcurl callback to update progress info. Mainly just used as a way to cancel the transfer if require...
Definition cl_http.cpp:81
void CL_HTTP_Cleanup(void)
UFO is exiting or we're changing servers. Clean up.
Definition cl_http.cpp:533
static int abortDownloads
Definition cl_http.cpp:53
static void CL_StartHTTPDownload(dlqueue_t *entry, dlhandle_t *dl)
Actually starts a download by adding it to the curl multi handle.
Definition cl_http.cpp:140
void CL_CancelHTTPDownloads(bool permKill)
Cancel all downloads and nuke the queue.
Definition cl_http.cpp:250
static bool downloadingPK3
Definition cl_http.cpp:54
@ HTTPDL_ABORT_SOFT
Definition cl_http.cpp:46
@ HTTPDL_ABORT_NONE
Definition cl_http.cpp:45
@ HTTPDL_ABORT_HARD
Definition cl_http.cpp:47
static CURLM * multi
Definition cl_http.cpp:50
static void CL_ParseFileList(dlhandle_t *dl)
A filelist is in memory, scan and validate it and queue up the files.
Definition cl_http.cpp:487
void CL_SetHTTPServer(const char *URL)
A new server is specified, so we nuke all our state.
Definition cl_http.cpp:225
static void CL_FinishHTTPDownload(void)
A download finished, find out what it was, whether there were any errors and if so,...
Definition cl_http.cpp:567
bool CL_QueueHTTPDownload(const char *ufoPath)
Called from the precache check to queue a download.
Definition cl_http.cpp:286
static cvar_t * cl_http_max_connections
Definition cl_http.cpp:42
static cvar_t * cl_http_downloads
Definition cl_http.cpp:40
static void CL_EscapeHTTPPath(const char *filePath, char *escaped)
Properly escapes a path with HTTP encoding. libcurl's function seems to treat '/' and such as illegal...
Definition cl_http.cpp:106
static void CL_ReVerifyHTTPQueue(void)
A pk3 file just downloaded, let's see if we can remove some stuff from the queue which is in the ....
Definition cl_http.cpp:516
void HTTP_InitStartup(void)
Definition cl_http.cpp:789
static void CL_StartNextHTTPDownload(void)
Start another HTTP download if possible.
Definition cl_http.cpp:727
cURL header
void CL_RequestNextDownload(void)
Definition cl_main.cpp:602
client_static_t cls
Definition cl_main.cpp:83
@ ca_connected
Definition cl_shared.h:79
Primary header for client.
cvar_t * http_proxy
Definition common.cpp:47
cvar_t * http_timeout
Definition common.cpp:48
void Com_Error(int code, const char *fmt,...)
Definition common.cpp:459
void Com_Printf(const char *const fmt,...)
Definition common.cpp:428
#define GAME_TITLE
Definition common.h:37
#define ERR_DROP
Definition common.h:211
#define UFO_VERSION
Definition common.h:36
cvar_t * Cvar_Get(const char *var_name, const char *var_value, int flags, const char *desc)
Init or return a cvar.
Definition cvar.cpp:342
void FS_CreatePath(const char *path)
Creates any directories needed to store the given filename.
Definition files.cpp:117
void FS_RemoveFile(const char *osPath)
Definition files.cpp:1692
int FS_CheckFile(const char *fmt,...)
Just returns the filelength and -1 if the file wasn't found.
Definition files.cpp:298
int FS_LoadFile(const char *path, byte **buffer)
Filenames are relative to the quake search path.
Definition files.cpp:384
void FS_RestartFilesystem(const char *gamedir)
Restart the filesystem (reload all pk3 files).
Definition files.cpp:1643
bool FS_RenameFile(const char *from, const char *to, bool relative)
Renames a file.
Definition files.cpp:1709
const char * FS_Gamedir(void)
Called to find where to write a file (savegames, etc).
Definition files.cpp:68
#define MAX_OSPATH
Definition filesys.h:44
#define BASEDIRNAME
Definition filesys.h:34
#define MAX_QPATH
Definition filesys.h:40
size_t HTTP_Recv(void *ptr, size_t size, size_t nmemb, void *stream)
libcurl callback for HTTP_GetURL
Definition http.cpp:154
size_t HTTP_Header(void *ptr, size_t size, size_t nmemb, void *stream)
libcurl callback to update header info.
Definition http.cpp:126
@ DLQ_STATE_RUNNING
Definition http.h:36
@ DLQ_STATE_NOT_STARTED
Definition http.h:35
@ DLQ_STATE_DONE
Definition http.h:37
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
const char * filename
Definition ioapi.h:41
#define Mem_Free(ptr)
Definition mem.h:35
#define Mem_AllocType(type)
Definition mem.h:39
QGL_EXTERN GLuint GLchar GLuint * len
Definition r_gl.h:99
QGL_EXTERN GLuint GLsizei GLsizei * length
Definition r_gl.h:110
QGL_EXTERN GLfloat f
Definition r_gl.h:114
QGL_EXTERN GLint i
Definition r_gl.h:113
#define Q_strcasecmp(a, b)
Definition shared.h:131
#define Q_streq(a, b)
Definition shared.h:136
bool Q_strnull(const char *string)
Definition shared.h:138
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition shared.cpp:457
const char * Com_GetExtension(const char *path)
Definition shared.cpp:282
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition shared.cpp:494
This is a cvar definition. Cvars can be user modified and used in our menus e.g.
Definition cvar.h:71
dlqueue_t * queueEntry
Definition http.h:50
size_t fileSize
Definition http.h:51
char URL[576]
Definition http.h:54
char filePath[MAX_OSPATH]
Definition http.h:48
double speed
Definition http.h:53
FILE * file
Definition http.h:49
char * tempBuffer
Definition http.h:55
size_t position
Definition http.h:52
CURL * curl
Definition http.h:47
char ufoPath[MAX_QPATH]
Definition http.h:42
dlq_state state
Definition http.h:43
struct dlqueue_s * next
Definition http.h:41
FILE * Sys_Fopen(const char *filename, const char *mode)
int Sys_Remove(const char *filename)
#define FILE