Quake II RTX doxygen  1.0 dev
http.c File Reference
#include "client.h"
#include <curl/curl.h>

Go to the source code of this file.

Classes

struct  dlhandle_t
 

Macros

#define MAX_DLSIZE   0x100000
 
#define MIN_DLSIZE   0x8000
 

Functions

static int progress_func (void *clientp, double dltotal, double dlnow, double ultotal, double ulnow)
 
static size_t recv_func (void *ptr, size_t size, size_t nmemb, void *stream)
 
static void escape_path (const char *path, char *escaped)
 
static const char * http_strerror (int response)
 
static const char * http_gamedir (void)
 
static void start_download (dlqueue_t *entry, dlhandle_t *dl)
 
void HTTP_CleanupDownloads (void)
 
void HTTP_Init (void)
 
void HTTP_Shutdown (void)
 
void HTTP_SetServer (const char *url)
 
qerror_t HTTP_QueueDownload (const char *path, dltype_t type)
 
static void check_and_queue_download (char *path)
 
static void parse_file_list (dlhandle_t *dl)
 
static void rescan_queue (void)
 
static void abort_downloads (void)
 
static dlhandle_tfind_handle (CURL *curl)
 
static qboolean finish_download (void)
 
static dlhandle_tget_free_handle (void)
 
static void start_next_download (void)
 
void HTTP_RunDownloads (void)
 

Variables

static cvar_t * cl_http_downloads
 
static cvar_t * cl_http_filelists
 
static cvar_t * cl_http_max_connections
 
static cvar_t * cl_http_proxy
 
static cvar_t * cl_http_default_url
 
static dlhandle_t download_handles [4]
 
static char download_server [512]
 
static char download_referer [32]
 
static qboolean download_default_repo
 
static qboolean curl_initialized
 
static CURLM * curl_multi
 
static int curl_handles
 

Macro Definition Documentation

◆ MAX_DLSIZE

#define MAX_DLSIZE   0x100000

Definition at line 37 of file http.c.

◆ MIN_DLSIZE

#define MIN_DLSIZE   0x8000

Definition at line 38 of file http.c.

Function Documentation

◆ abort_downloads()

static void abort_downloads ( void  )
static

Definition at line 701 of file http.c.

702 {
703  dlqueue_t *q;
704 
706 
707  cls.download.current = NULL;
708  cls.download.percent = 0;
709  cls.download.position = 0;
710 
711  FOR_EACH_DLQ(q) {
712  if (q->state != DL_DONE && q->type >= DL_LIST)
714  else if (q->state == DL_RUNNING)
715  q->state = DL_PENDING;
716  }
717 
720 }

Referenced by finish_download(), and HTTP_RunDownloads().

◆ check_and_queue_download()

static void check_and_queue_download ( char *  path)
static

Definition at line 579 of file http.c.

580 {
581  size_t len;
582  char *ext;
583  dltype_t type;
584  unsigned flags;
585  int valid;
586 
587  len = strlen(path);
588  if (len >= MAX_QPATH)
589  return;
590 
591  ext = strrchr(path, '.');
592  if (!ext)
593  return;
594 
595  ext++;
596  if (!ext[0])
597  return;
598 
599  Q_strlwr(ext);
600 
601  if (!strcmp(ext, "pak") || !strcmp(ext, "pkz")) {
602  Com_Printf("[HTTP] Filelist is requesting a .%s file '%s'\n", ext, path);
603  type = DL_PAK;
604  } else {
605  type = DL_OTHER;
607  Com_WPrintf("[HTTP] Illegal file type '%s' in filelist.\n", path);
608  return;
609  }
610  }
611 
612  if (path[0] == '@') {
613  if (type == DL_PAK) {
614  Com_WPrintf("[HTTP] '@' prefix used on a pak file '%s' in filelist.\n", path);
615  return;
616  }
617  flags = FS_PATH_GAME;
618  path++;
619  len--;
620  } else if (type == DL_PAK) {
621  //by definition paks are game-local
622  flags = FS_PATH_GAME | FS_TYPE_REAL;
623  } else {
624  flags = 0;
625  }
626 
627  len = FS_NormalizePath(path, path);
628  if (len == 0)
629  return;
630 
631  valid = FS_ValidatePath(path);
632 
633  if (valid == PATH_INVALID ||
634  !Q_ispath(path[0]) ||
635  !Q_ispath(path[len - 1]) ||
636  strstr(path, "..") ||
637  (type == DL_OTHER && !strchr(path, '/')) ||
638  (type == DL_PAK && strchr(path, '/'))) {
639  Com_WPrintf("[HTTP] Illegal path '%s' in filelist.\n", path);
640  return;
641  }
642 
643  if (FS_FileExistsEx(path, flags))
644  return;
645 
646  if (valid == PATH_MIXED_CASE)
647  Q_strlwr(path);
648 
649  if (CL_IgnoreDownload(path))
650  return;
651 
652  CL_QueueDownload(path, type);
653 }

Referenced by parse_file_list().

◆ escape_path()

static void escape_path ( const char *  path,
char *  escaped 
)
static

Definition at line 152 of file http.c.

153 {
154  static const char allowed[] = ";/?:@&=+$,[]-_.!~*'()";
155  int c;
156  char *p;
157 
158  p = escaped;
159  while (*path) {
160  c = *path++;
161  if (!Q_isalnum(c) && !strchr(allowed, c)) {
162  sprintf(p, "%%%02x", c);
163  p += 3;
164  } else {
165  *p++ = c;
166  }
167  }
168  *p = 0;
169 }

Referenced by start_download().

◆ find_handle()

static dlhandle_t* find_handle ( CURL *  curl)
static

Definition at line 723 of file http.c.

724 {
725  size_t i;
726  dlhandle_t *dl;
727 
728  for (i = 0; i < 4; i++) {
729  dl = &download_handles[i];
730  if (dl->curl == curl) {
731  return dl;
732  }
733  }
734 
735  Com_Error(ERR_FATAL, "CURL handle not found for CURLMSG_DONE");
736  return NULL;
737 }

Referenced by finish_download().

◆ finish_download()

static qboolean finish_download ( void  )
static

Definition at line 741 of file http.c.

742 {
743  int msgs_in_queue;
744  CURLMsg *msg;
745  CURLcode result;
746  dlhandle_t *dl;
747  CURL *curl;
748  long response;
749  double sec, bytes;
750  char size[16], speed[16];
751  char temp[MAX_OSPATH];
752  qboolean fatal_error = qfalse;
753  const char *err;
754  print_type_t level;
755 
756  do {
757  msg = curl_multi_info_read(curl_multi, &msgs_in_queue);
758  if (!msg)
759  break;
760 
761  if (msg->msg != CURLMSG_DONE)
762  continue;
763 
764  curl = msg->easy_handle;
765  dl = find_handle(curl);
766 
767  cls.download.current = NULL;
768  cls.download.percent = 0;
769  cls.download.position = 0;
770 
771  //filelist processing is done on read
772  if (dl->file) {
773  fclose(dl->file);
774  dl->file = NULL;
775  }
776 
777  curl_handles--;
778 
779  result = msg->data.result;
780 
781  switch (result) {
782  //for some reason curl returns CURLE_OK for a 404...
783  case CURLE_HTTP_RETURNED_ERROR:
784  case CURLE_OK:
785  curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
786  if (result == CURLE_OK && response == 200) {
787  //success
788  break;
789  }
790 
791  err = http_strerror(response);
792 
793  //404 is non-fatal unless accessing default repository
794  if (response == 404 && (!download_default_repo || !dl->path[0])) {
795  level = PRINT_ALL;
796  goto fail1;
797  }
798 
799  //every other code is treated as fatal
800  //not marking download as done since
801  //we are falling back to UDP
802  level = PRINT_ERROR;
803  fatal_error = qtrue;
804  goto fail2;
805 
806  case CURLE_COULDNT_RESOLVE_HOST:
807  case CURLE_COULDNT_CONNECT:
808  case CURLE_COULDNT_RESOLVE_PROXY:
809  //connection problems are fatal
810  err = curl_easy_strerror(result);
811  level = PRINT_ERROR;
812  fatal_error = qtrue;
813  goto fail2;
814 
815  default:
816  err = curl_easy_strerror(result);
817  level = PRINT_WARNING;
818 fail1:
819  //we mark download as done even if it errored
820  //to prevent multiple attempts.
822 fail2:
824  "[HTTP] %s [%s] [%d remaining file%s]\n",
825  dl->queue->path, err, cls.download.pending,
826  cls.download.pending == 1 ? "" : "s");
827  if (dl->path[0]) {
828  remove(dl->path);
829  dl->path[0] = 0;
830  }
831  if (dl->buffer) {
832  Z_Free(dl->buffer);
833  dl->buffer = NULL;
834  }
835  if (dl->multi_added) {
836  //remove the handle and mark it as such
837  curl_multi_remove_handle(curl_multi, curl);
838  dl->multi_added = qfalse;
839  }
840  continue;
841  }
842 
843  //mark as done
845 
846  //show some stats
847  curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &sec);
848  curl_easy_getinfo(curl, CURLINFO_SIZE_DOWNLOAD, &bytes);
849  if (sec < 0.001)
850  sec = 0.001;
851  Com_FormatSizeLong(size, sizeof(size), bytes);
852  Com_FormatSizeLong(speed, sizeof(speed), bytes / sec);
853 
854  if (dl->multi_added) {
855  //remove the handle and mark it as such
856  curl_multi_remove_handle(curl_multi, curl);
857  dl->multi_added = qfalse;
858  }
859 
860  Com_Printf("[HTTP] %s [%s, %s/sec] [%d remaining file%s]\n",
861  dl->queue->path, size, speed, cls.download.pending,
862  cls.download.pending == 1 ? "" : "s");
863 
864  if (dl->path[0]) {
865  //rename the temp file
866  Q_snprintf(temp, sizeof(temp), "%s/%s", fs_gamedir, dl->queue->path);
867 
868  if (rename(dl->path, temp))
869  Com_EPrintf("[HTTP] Failed to rename '%s' to '%s': %s\n",
870  dl->path, dl->queue->path, strerror(errno));
871  dl->path[0] = 0;
872 
873  //a pak file is very special...
874  if (dl->queue->type == DL_PAK) {
875  CL_RestartFilesystem(qfalse);
876  rescan_queue();
877  }
878  } else if (!fatal_error) {
879  parse_file_list(dl);
880  }
881  } while (msgs_in_queue > 0);
882 
883  //fatal error occured, disable HTTP
884  if (fatal_error) {
885  abort_downloads();
886  return qfalse;
887  }
888 
889  // see if we have more to dl
891  return qtrue;
892 }

Referenced by HTTP_RunDownloads().

◆ get_free_handle()

static dlhandle_t* get_free_handle ( void  )
static

Definition at line 895 of file http.c.

896 {
897  dlhandle_t *dl;
898  int i;
899 
900  for (i = 0; i < 4; i++) {
901  dl = &download_handles[i];
902  if (!dl->queue || dl->queue->state == DL_DONE)
903  return dl;
904  }
905 
906  return NULL;
907 }

Referenced by start_next_download().

◆ HTTP_CleanupDownloads()

void HTTP_CleanupDownloads ( void  )

Definition at line 386 of file http.c.

387 {
388  dlhandle_t *dl;
389  int i;
390 
391  download_server[0] = 0;
392  download_referer[0] = 0;
393  download_default_repo = qfalse;
394 
395  curl_handles = 0;
396 
397  for (i = 0; i < 4; i++) {
398  dl = &download_handles[i];
399 
400  if (dl->file) {
401  fclose(dl->file);
402  remove(dl->path);
403  dl->file = NULL;
404  }
405 
406  if (dl->buffer) {
407  Z_Free(dl->buffer);
408  dl->buffer = NULL;
409  }
410 
411  if (dl->curl) {
412  if (curl_multi && dl->multi_added)
413  curl_multi_remove_handle(curl_multi, dl->curl);
414  curl_easy_cleanup(dl->curl);
415  dl->curl = NULL;
416  }
417 
418  dl->queue = NULL;
419  dl->multi_added = qfalse;
420  }
421 
422  if (curl_multi) {
423  curl_multi_cleanup(curl_multi);
424  curl_multi = NULL;
425  }
426 }

Referenced by abort_downloads(), CL_CleanupDownloads(), and HTTP_Shutdown().

◆ http_gamedir()

static const char* http_gamedir ( void  )
static

Definition at line 214 of file http.c.

215 {
216  if (*fs_game->string)
217  return fs_game->string;
218 
219  return BASEGAME;
220 }

Referenced by HTTP_QueueDownload(), and start_download().

◆ HTTP_Init()

void HTTP_Init ( void  )

Definition at line 436 of file http.c.

437 {
438  cl_http_downloads = Cvar_Get("cl_http_downloads", "1", 0);
439  cl_http_filelists = Cvar_Get("cl_http_filelists", "1", 0);
440  cl_http_max_connections = Cvar_Get("cl_http_max_connections", "2", 0);
441  //cl_http_max_connections->changed = _cl_http_max_connections_changed;
442  cl_http_proxy = Cvar_Get("cl_http_proxy", "", 0);
443  cl_http_default_url = Cvar_Get("cl_http_default_url", "", 0);
444 
445 #ifdef _DEBUG
446  cl_http_debug = Cvar_Get("cl_http_debug", "0", 0);
447 #endif
448 
449 #if USE_UI
450  cl_http_blocking_timeout = Cvar_Get("cl_http_blocking_timeout", "15", 0);
451 #endif
452 
453  curl_global_init(CURL_GLOBAL_NOTHING);
454  curl_initialized = qtrue;
455  Com_DPrintf("%s initialized.\n", curl_version());
456 }

Referenced by CL_Init().

◆ HTTP_QueueDownload()

qerror_t HTTP_QueueDownload ( const char *  path,
dltype_t  type 
)

Definition at line 530 of file http.c.

531 {
532  size_t len;
533  qboolean need_list;
534  char temp[MAX_QPATH];
535  qerror_t ret;
536 
537  // no http server (or we got booted)
538  if (!curl_multi)
539  return Q_ERR_NOSYS;
540 
541  // first download queued, so we want the mod filelist
542  need_list = LIST_EMPTY(&cls.download.queue);
543 
544  ret = CL_QueueDownload(path, type);
545  if (ret)
546  return ret;
547 
548  if (!cl_http_filelists->integer)
549  return Q_ERR_SUCCESS;
550 
551  if (need_list) {
552  //grab the filelist
553  len = Q_snprintf(temp, sizeof(temp), "%s.filelist", http_gamedir());
554  if (len < sizeof(temp))
555  CL_QueueDownload(temp, DL_LIST);
556 
557  //this is a nasty hack to let the server know what we're doing so admins don't
558  //get confused by a ton of people stuck in CNCT state. it's assumed the server
559  //is running r1q2 if we're even able to do http downloading so hopefully this
560  //won't spew an error msg.
562  CL_ClientCommand("download http\n");
563  }
564 
565  //special case for map file lists, i really wanted a server-push mechanism for this, but oh well
566  len = strlen(path);
567  if (len > 4 && !Q_stricmp(path + len - 4, ".bsp")) {
568  len = Q_snprintf(temp, sizeof(temp), "%s/%s", http_gamedir(), path);
569  if (len < sizeof(temp) - 5) {
570  memcpy(temp + len - 4, ".filelist", 10);
571  CL_QueueDownload(temp, DL_LIST);
572  }
573  }
574 
575  return Q_ERR_SUCCESS;
576 }

Referenced by check_file_len().

◆ HTTP_RunDownloads()

void HTTP_RunDownloads ( void  )

Definition at line 941 of file http.c.

942 {
943  int new_count;
944  CURLMcode ret;
945 
946  if (!curl_multi)
947  return;
948 
950 
951  do {
952  ret = curl_multi_perform(curl_multi, &new_count);
953  if (new_count < curl_handles) {
954  //hmm, something either finished or errored out.
955  if (!finish_download())
956  return; //aborted
957  curl_handles = new_count;
958  }
959  } while (ret == CURLM_CALL_MULTI_PERFORM);
960 
961  if (ret != CURLM_OK) {
962  Com_EPrintf("[HTTP] Error running downloads: %s.\n",
963  curl_multi_strerror(ret));
964  abort_downloads();
965  return;
966  }
967 
969 }

Referenced by CL_ProcessEvents().

◆ HTTP_SetServer()

void HTTP_SetServer ( const char *  url)

Definition at line 477 of file http.c.

478 {
479  if (curl_multi) {
480  Com_EPrintf("[HTTP] Set server without cleanup?\n");
481  return;
482  }
483 
484  // ignore on the local server
485  if (NET_IsLocalAddress(&cls.serverAddress))
486  return;
487 
488  // ignore if downloads are permanently disabled
489  if (allow_download->integer == -1)
490  return;
491 
492  // ignore if HTTP downloads are disabled
493  if (cl_http_downloads->integer == 0)
494  return;
495 
496  // use default URL for servers that don't specify one. treat 404 from
497  // default repository as fatal error and revert to UDP downloading.
498  if (!url) {
499  url = cl_http_default_url->string;
500  download_default_repo = qtrue;
501  } else {
502  download_default_repo = qfalse;
503  }
504 
505  if (!*url)
506  return;
507 
508  if (strncmp(url, "http://", 7)) {
509  Com_Printf("[HTTP] Ignoring download server URL with non-HTTP schema.\n");
510  return;
511  }
512 
513  curl_multi = curl_multi_init();
514 
517  "quake2://%s", NET_AdrToString(&cls.serverAddress));
518 
519  Com_Printf("[HTTP] Download server at %s\n", download_server);
520 }

Referenced by CL_ConnectionlessPacket().

◆ HTTP_Shutdown()

void HTTP_Shutdown ( void  )

Definition at line 458 of file http.c.

459 {
460  if (!curl_initialized)
461  return;
462 
464 
465  curl_global_cleanup();
466  curl_initialized = qfalse;
467 }

Referenced by CL_Shutdown().

◆ http_strerror()

static const char* http_strerror ( int  response)
static

Definition at line 172 of file http.c.

173 {
174  static char buffer[32];
175 
176  //common codes
177  switch (response) {
178  case 200:
179  return "200 OK";
180  case 401:
181  return "401 Unauthorized";
182  case 403:
183  return "403 Forbidden";
184  case 404:
185  return "404 Not Found";
186  case 500:
187  return "500 Internal Server Error";
188  case 503:
189  return "503 Service Unavailable";
190  }
191 
192  if (response < 100 || response >= 600) {
193  Q_snprintf(buffer, sizeof(buffer), "%d <bad code>", response);
194  return buffer;
195  }
196 
197  //generic classes
198  if (response < 200) {
199  Q_snprintf(buffer, sizeof(buffer), "%d Informational", response);
200  } else if (response < 300) {
201  Q_snprintf(buffer, sizeof(buffer), "%d Success", response);
202  } else if (response < 400) {
203  Q_snprintf(buffer, sizeof(buffer), "%d Redirection", response);
204  } else if (response < 500) {
205  Q_snprintf(buffer, sizeof(buffer), "%d Client Error", response);
206  } else {
207  Q_snprintf(buffer, sizeof(buffer), "%d Server Error", response);
208  }
209 
210  return buffer;
211 }

Referenced by finish_download().

◆ parse_file_list()

static void parse_file_list ( dlhandle_t dl)
static

Definition at line 656 of file http.c.

657 {
658  char *list;
659  char *p;
660 
661  if (!dl->buffer)
662  return;
663 
664  if (cl_http_filelists->integer) {
665  list = dl->buffer;
666  while (*list) {
667  p = strchr(list, '\n');
668  if (p) {
669  if (p > list && *(p - 1) == '\r')
670  *(p - 1) = 0;
671  *p = 0;
672  }
673 
674  if (*list)
676 
677  if (!p)
678  break;
679  list = p + 1;
680  }
681  }
682 
683  Z_Free(dl->buffer);
684  dl->buffer = NULL;
685 }

Referenced by finish_download().

◆ progress_func()

static int progress_func ( void clientp,
double  dltotal,
double  dlnow,
double  ultotal,
double  ulnow 
)
static

Definition at line 78 of file http.c.

79 {
80  dlhandle_t *dl = (dlhandle_t *)clientp;
81 
82  //don't care which download shows as long as something does :)
83  cls.download.current = dl->queue;
84 
85  if (dltotal)
86  cls.download.percent = (int)((dlnow / dltotal) * 100.0);
87  else
88  cls.download.percent = 0;
89 
90  cls.download.position = (int)dlnow;
91 
92  return 0;
93 }

Referenced by start_download().

◆ recv_func()

static size_t recv_func ( void ptr,
size_t  size,
size_t  nmemb,
void stream 
)
static

Definition at line 96 of file http.c.

97 {
98  dlhandle_t *dl = (dlhandle_t *)stream;
99  size_t new_size, bytes;
100 
101  if (!nmemb)
102  return 0;
103 
104  if (size > SIZE_MAX / nmemb)
105  goto oversize;
106 
107  if (dl->position > MAX_DLSIZE)
108  goto oversize;
109 
110  bytes = size * nmemb;
111  if (bytes >= MAX_DLSIZE - dl->position)
112  goto oversize;
113 
114  // grow buffer in MIN_DLSIZE chunks. +1 for NUL.
115  new_size = (dl->position + bytes + MIN_DLSIZE) & ~(MIN_DLSIZE - 1);
116  if (new_size > dl->size) {
117  dl->size = new_size;
118  dl->buffer = Z_Realloc(dl->buffer, new_size);
119  }
120 
121  memcpy(dl->buffer + dl->position, ptr, bytes);
122  dl->position += bytes;
123  dl->buffer[dl->position] = 0;
124 
125  return bytes;
126 
127 oversize:
128  Com_DPrintf("[HTTP] Oversize file while trying to download '%s'\n", dl->url);
129  return 0;
130 }

Referenced by start_download().

◆ rescan_queue()

static void rescan_queue ( void  )
static

Definition at line 689 of file http.c.

690 {
691  dlqueue_t *q;
692 
693  FOR_EACH_DLQ(q) {
694  if (q->state == DL_PENDING && q->type < DL_LIST && FS_FileExists(q->path))
696  }
697 }

Referenced by finish_download().

◆ start_download()

static void start_download ( dlqueue_t entry,
dlhandle_t dl 
)
static

Definition at line 223 of file http.c.

224 {
225  size_t len;
226  char temp[MAX_QPATH];
227  char escaped[MAX_QPATH * 4];
228  CURLMcode ret;
229  qerror_t err;
230 
231  //yet another hack to accomodate filelists, how i wish i could push :(
232  //NULL file handle indicates filelist.
233  if (entry->type == DL_LIST) {
234  dl->file = NULL;
235  dl->path[0] = 0;
236  //filelist paths are absolute
237  escape_path(entry->path, escaped);
238  } else {
239  len = Q_snprintf(dl->path, sizeof(dl->path), "%s/%s.tmp", fs_gamedir, entry->path);
240  if (len >= sizeof(dl->path)) {
241  Com_EPrintf("[HTTP] Refusing oversize temporary file path.\n");
242  goto fail;
243  }
244 
245  //prepend quake path with gamedir
246  len = Q_snprintf(temp, sizeof(temp), "%s/%s", http_gamedir(), entry->path);
247  if (len >= sizeof(temp)) {
248  Com_EPrintf("[HTTP] Refusing oversize server file path.\n");
249  goto fail;
250  }
251  escape_path(temp, escaped);
252 
253  err = FS_CreatePath(dl->path);
254  if (err < 0) {
255  Com_EPrintf("[HTTP] Couldn't create path to '%s': %s\n", dl->path, Q_ErrorString(err));
256  goto fail;
257  }
258 
259  //don't bother with http resume... too annoying if server doesn't support it.
260  dl->file = fopen(dl->path, "wb");
261  if (!dl->file) {
262  Com_EPrintf("[HTTP] Couldn't open '%s' for writing: %s\n", dl->path, strerror(errno));
263  goto fail;
264  }
265  }
266 
267  len = Q_snprintf(dl->url, sizeof(dl->url), "%s%s", download_server, escaped);
268  if (len >= sizeof(dl->url)) {
269  Com_EPrintf("[HTTP] Refusing oversize download URL.\n");
270  goto fail;
271  }
272 
273  dl->buffer = NULL;
274  dl->size = 0;
275  dl->position = 0;
276  dl->queue = entry;
277  if (!dl->curl)
278  dl->curl = curl_easy_init();
279 
280  curl_easy_setopt(dl->curl, CURLOPT_ENCODING, "");
281 #ifdef _DEBUG
282  if (cl_http_debug->integer) {
283  curl_easy_setopt(dl->curl, CURLOPT_DEBUGFUNCTION, debug_func);
284  curl_easy_setopt(dl->curl, CURLOPT_VERBOSE, 1);
285  }
286 #endif
287  curl_easy_setopt(dl->curl, CURLOPT_NOPROGRESS, 0);
288  if (dl->file) {
289  curl_easy_setopt(dl->curl, CURLOPT_WRITEDATA, dl->file);
290  curl_easy_setopt(dl->curl, CURLOPT_WRITEFUNCTION, NULL);
291  } else {
292  curl_easy_setopt(dl->curl, CURLOPT_WRITEDATA, dl);
293  curl_easy_setopt(dl->curl, CURLOPT_WRITEFUNCTION, recv_func);
294  }
295  curl_easy_setopt(dl->curl, CURLOPT_FAILONERROR, 1);
296  curl_easy_setopt(dl->curl, CURLOPT_PROXY, cl_http_proxy->string);
297  curl_easy_setopt(dl->curl, CURLOPT_FOLLOWLOCATION, 1);
298  curl_easy_setopt(dl->curl, CURLOPT_MAXREDIRS, 5);
299  curl_easy_setopt(dl->curl, CURLOPT_PROGRESSFUNCTION, progress_func);
300  curl_easy_setopt(dl->curl, CURLOPT_PROGRESSDATA, dl);
301  curl_easy_setopt(dl->curl, CURLOPT_USERAGENT, com_version->string);
302  curl_easy_setopt(dl->curl, CURLOPT_REFERER, download_referer);
303  curl_easy_setopt(dl->curl, CURLOPT_URL, dl->url);
304 
305  ret = curl_multi_add_handle(curl_multi, dl->curl);
306  if (ret != CURLM_OK) {
307  Com_EPrintf("[HTTP] Failed to add download handle: %s\n",
308  curl_multi_strerror(ret));
309 fail:
310  CL_FinishDownload(entry);
311 
312  // see if we have more to dl
314  return;
315  }
316 
317  Com_DPrintf("[HTTP] Fetching %s...\n", dl->url);
318  entry->state = DL_RUNNING;
319  dl->multi_added = qtrue;
320  curl_handles++;
321 }

Referenced by start_next_download().

◆ start_next_download()

static void start_next_download ( void  )
static

Definition at line 910 of file http.c.

911 {
912  dlqueue_t *q;
913 
915  return;
916  }
917 
918  //not enough downloads running, queue some more!
919  FOR_EACH_DLQ(q) {
920  if (q->state == DL_RUNNING) {
921  if (q->type == DL_PAK)
922  break; // hack for pak file single downloading
923  } else if (q->state == DL_PENDING) {
924  dlhandle_t *dl = get_free_handle();
925  if (dl)
926  start_download(q, dl);
927  break;
928  }
929  }
930 }

Referenced by HTTP_RunDownloads().

Variable Documentation

◆ cl_http_default_url

cvar_t* cl_http_default_url
static

Definition at line 26 of file http.c.

Referenced by HTTP_Init(), and HTTP_SetServer().

◆ cl_http_downloads

cvar_t* cl_http_downloads
static

Definition at line 22 of file http.c.

Referenced by HTTP_Init(), and HTTP_SetServer().

◆ cl_http_filelists

cvar_t* cl_http_filelists
static

Definition at line 23 of file http.c.

Referenced by HTTP_Init(), HTTP_QueueDownload(), and parse_file_list().

◆ cl_http_max_connections

cvar_t* cl_http_max_connections
static

Definition at line 24 of file http.c.

Referenced by HTTP_Init(), and start_next_download().

◆ cl_http_proxy

cvar_t* cl_http_proxy
static

Definition at line 25 of file http.c.

Referenced by HTTP_Init(), and start_download().

◆ curl_handles

int curl_handles
static

◆ curl_initialized

qboolean curl_initialized
static

Definition at line 57 of file http.c.

Referenced by HTTP_Init(), and HTTP_Shutdown().

◆ curl_multi

CURLM* curl_multi
static

◆ download_default_repo

qboolean download_default_repo
static

Definition at line 55 of file http.c.

Referenced by finish_download(), HTTP_CleanupDownloads(), HTTP_QueueDownload(), and HTTP_SetServer().

◆ download_handles

dlhandle_t download_handles[4]
static

Definition at line 52 of file http.c.

Referenced by find_handle(), get_free_handle(), and HTTP_CleanupDownloads().

◆ download_referer

char download_referer[32]
static

Definition at line 54 of file http.c.

Referenced by HTTP_CleanupDownloads(), HTTP_SetServer(), and start_download().

◆ download_server

char download_server[512]
static

Definition at line 53 of file http.c.

Referenced by HTTP_CleanupDownloads(), HTTP_SetServer(), and start_download().

parse_file_list
static void parse_file_list(dlhandle_t *dl)
Definition: http.c:656
dlhandle_t::curl
CURL * curl
Definition: http.c:41
cl_http_downloads
static cvar_t * cl_http_downloads
Definition: http.c:22
NET_AdrToString
char * NET_AdrToString(const netadr_t *a)
Definition: net.c:257
dlqueue_t
Definition: client.h:367
Q_snprintf
size_t Q_snprintf(char *dest, size_t size, const char *fmt,...)
Definition: shared.c:846
Com_FormatSizeLong
size_t Com_FormatSizeLong(char *dest, size_t destsize, off_t bytes)
Definition: utils.c:482
DL_OTHER
@ DL_OTHER
Definition: client.h:351
CL_CheckDownloadExtension
qboolean CL_CheckDownloadExtension(const char *ext)
Definition: download.c:494
CL_IgnoreDownload
qboolean CL_IgnoreDownload(const char *path)
Definition: download.c:95
curl_handles
static int curl_handles
Definition: http.c:59
start_download
static void start_download(dlqueue_t *entry, dlhandle_t *dl)
Definition: http.c:223
curl_initialized
static qboolean curl_initialized
Definition: http.c:57
HTTP_CleanupDownloads
void HTTP_CleanupDownloads(void)
Definition: http.c:386
Cvar_Get
cvar_t * Cvar_Get(const char *var_name, const char *var_value, int flags)
Definition: cvar.c:257
Q_ErrorString
const char * Q_ErrorString(qerror_t error)
Definition: error.c:51
finish_download
static qboolean finish_download(void)
Definition: http.c:741
cl_http_max_connections
static cvar_t * cl_http_max_connections
Definition: http.c:24
dltype_t
dltype_t
Definition: client.h:349
http_strerror
static const char * http_strerror(int response)
Definition: http.c:172
dlhandle_t::position
size_t position
Definition: http.c:46
ext
char ext[4]
Definition: images.c:657
start_next_download
static void start_next_download(void)
Definition: http.c:910
recv_func
static size_t recv_func(void *ptr, size_t size, size_t nmemb, void *stream)
Definition: http.c:96
check_and_queue_download
static void check_and_queue_download(char *path)
Definition: http.c:579
CL_FinishDownload
void CL_FinishDownload(dlqueue_t *q)
Definition: download.c:115
FS_ValidatePath
int FS_ValidatePath(const char *s)
Definition: files.c:271
rescan_queue
static void rescan_queue(void)
Definition: http.c:689
http_gamedir
static const char * http_gamedir(void)
Definition: http.c:214
com_version
cvar_t * com_version
Definition: common.c:84
download_server
static char download_server[512]
Definition: http.c:53
Com_Error
void Com_Error(error_type_t type, const char *fmt,...)
Definition: g_main.c:258
download_referer
static char download_referer[32]
Definition: http.c:54
client_static_s::current
dlqueue_t * current
Definition: client.h:440
cl_http_filelists
static cvar_t * cl_http_filelists
Definition: http.c:23
dlhandle_t::multi_added
qboolean multi_added
Definition: http.c:49
dlhandle_t
Definition: http.c:40
Z_Free
void Z_Free(void *ptr)
Definition: zone.c:147
get_free_handle
static dlhandle_t * get_free_handle(void)
Definition: http.c:895
DL_DONE
@ DL_DONE
Definition: client.h:364
download_default_repo
static qboolean download_default_repo
Definition: http.c:55
dlqueue_t::state
dlstate_t state
Definition: client.h:370
find_handle
static dlhandle_t * find_handle(CURL *curl)
Definition: http.c:723
fs_game
cvar_t * fs_game
Definition: files.c:202
escape_path
static void escape_path(const char *path, char *escaped)
Definition: http.c:152
client_static_s::pending
int pending
Definition: client.h:439
dlhandle_t::url
char url[576]
Definition: http.c:47
Q_strlcpy
size_t Q_strlcpy(char *dst, const char *src, size_t size)
Definition: shared.c:715
Com_LPrintf
void Com_LPrintf(print_type_t type, const char *fmt,...)
Definition: g_main.c:242
client_static_s::percent
int percent
Definition: client.h:441
CL_StartNextDownload
void CL_StartNextDownload(void)
Definition: download.c:294
dlqueue_t::path
char path[1]
Definition: client.h:371
MAX_DLSIZE
#define MAX_DLSIZE
Definition: http.c:37
dlhandle_t::queue
dlqueue_t * queue
Definition: http.c:44
dlhandle_t::path
char path[MAX_OSPATH]
Definition: http.c:42
cls
client_static_t cls
Definition: main.c:98
FOR_EACH_DLQ
#define FOR_EACH_DLQ(q)
Definition: client.h:344
c
statCounters_t c
Definition: main.c:30
DL_RUNNING
@ DL_RUNNING
Definition: client.h:363
client_static_s::queue
list_t queue
Definition: client.h:438
CL_RestartFilesystem
void CL_RestartFilesystem(qboolean total)
Definition: main.c:2418
CL_RequestNextDownload
void CL_RequestNextDownload(void)
Definition: download.c:735
client_static_s::download
struct client_static_s::@2 download
curl_multi
static CURLM * curl_multi
Definition: http.c:58
level
level_locals_t level
Definition: g_main.c:22
dlhandle_t::buffer
char * buffer
Definition: http.c:48
cl_http_default_url
static cvar_t * cl_http_default_url
Definition: http.c:26
err
int err
Definition: win.h:24
allow_download
cvar_t * allow_download
Definition: common.c:105
progress_func
static int progress_func(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow)
Definition: http.c:78
abort_downloads
static void abort_downloads(void)
Definition: http.c:701
DL_PENDING
@ DL_PENDING
Definition: client.h:362
msg
const char * msg
Definition: win.h:25
CL_ClientCommand
void CL_ClientCommand(const char *string)
Definition: main.c:299
FS_CreatePath
qerror_t FS_CreatePath(char *path)
Definition: files.c:605
client_static_s::serverAddress
netadr_t serverAddress
Definition: client.h:409
CL_QueueDownload
qerror_t CL_QueueDownload(const char *path, dltype_t type)
Definition: download.c:49
int
CONST PIXELFORMATDESCRIPTOR int
Definition: wgl.c:26
cl_http_proxy
static cvar_t * cl_http_proxy
Definition: http.c:25
dlqueue_t::type
dltype_t type
Definition: client.h:369
Z_Realloc
void * Z_Realloc(void *ptr, size_t size)
Definition: zone.c:178
fs_gamedir
char fs_gamedir[MAX_OSPATH]
Definition: files.c:171
client_static_s::position
int position
Definition: client.h:442
download_handles
static dlhandle_t download_handles[4]
Definition: http.c:52
FS_NormalizePath
size_t FS_NormalizePath(char *out, const char *in)
Definition: files.c:331
dlhandle_t::size
size_t size
Definition: http.c:45
MIN_DLSIZE
#define MIN_DLSIZE
Definition: http.c:38
dlhandle_t::file
FILE * file
Definition: http.c:43