📄 downloader.c
字号:
void *usr_cbk, GF_Err *e){ GF_DownloadSession *sess; *e = GF_OK; if (gf_dm_is_local(dm, url)) return NULL; if (!gf_dm_can_handle_url(dm, url)) { *e = GF_NOT_SUPPORTED; return NULL; } if (!user_io) { *e = GF_BAD_PARAM; return NULL; } sess = (GF_DownloadSession *)malloc(sizeof(GF_DownloadSession)); memset((void *)sess, 0, sizeof(GF_DownloadSession)); sess->flags = dl_flags; sess->user_proc = user_io; sess->usr_cbk = usr_cbk; sess->dm = dm; gf_list_add(dm->sessions, sess); *e = gf_dm_setup_from_url(sess, url); if (*e) { gf_dm_sess_del(sess); return NULL; } if (!(sess->flags & GF_NETIO_SESSION_NOT_THREADED) ) { sess->th = gf_th_new(); sess->mx = gf_mx_new(); gf_th_run(sess->th, gf_dm_session_thread, sess); } sess->num_retry = SESSION_RETRY_COUNT; return sess;}static GF_Err gf_dm_read_data(GF_DownloadSession *sess, char *data, u32 data_size, u32 *out_read){ GF_Err e; #ifdef GPAC_HAS_SSL if (sess->ssl) { u32 size = SSL_read(sess->ssl, data, data_size); e = GF_OK; data[size] = 0; if (!size) e = GF_IP_NETWORK_EMPTY; *out_read = size; } else #endif e = gf_sk_receive(sess->sock, data, data_size, 0, out_read); return e;}#ifdef GPAC_HAS_SSL/*pattern comp taken from wget*/#define ASTERISK_EXCLUDES_DOT /* mandated by rfc2818 */#define TOLOWER(x) ('A' <= (x) && (x) <= 'Z' ? (x) - 32 : (x))static Bool pattern_match(const char *pattern, const char *string){ const char *p = pattern, *n = string; char c; for (; (c = TOLOWER (*p++)) != '\0'; n++) { if (c == '*') { for (c = TOLOWER (*p); c == '*'; c = TOLOWER (*++p)) ; for (; *n != '\0'; n++) if (TOLOWER (*n) == c && pattern_match (p, n)) return 1;#ifdef ASTERISK_EXCLUDES_DOT else if (*n == '.') return 0;#endif return c == '\0'; } else { if (c != TOLOWER (*n)) return 0; } } return *n == '\0';}#undef TOLOWER#endifstatic void gf_dm_connect(GF_DownloadSession *sess){ GF_Err e; u16 proxy_port = 0; const char *proxy; if (!sess->sock) { //sess->num_retry = 40; sess->sock = gf_sk_new(GF_SOCK_TYPE_TCP); } /*connect*/ sess->status = GF_NETIO_SETUP; gf_dm_sess_notify_state(sess, sess->status, GF_OK); /*PROXY setup*/ proxy = gf_cfg_get_key(sess->dm->cfg, "HTTPProxy", "Enabled"); if (proxy && !strcmp(proxy, "yes")) { proxy = gf_cfg_get_key(sess->dm->cfg, "HTTPProxy", "Port"); proxy_port = proxy ? atoi(proxy) : 80; proxy = gf_cfg_get_key(sess->dm->cfg, "HTTPProxy", "Name"); } else { proxy = NULL; } if (proxy) { e = gf_sk_connect(sess->sock, (char *) proxy, proxy_port); } else { e = gf_sk_connect(sess->sock, sess->server_name, sess->port); } /*retry*/ if ((e == GF_IP_SOCK_WOULD_BLOCK) && sess->num_retry) { sess->status = GF_NETIO_SETUP; sess->num_retry--; return; } /*failed*/ if (e) { sess->status = GF_NETIO_STATE_ERROR; sess->last_error = e; gf_dm_sess_notify_state(sess, sess->status, e); return; } sess->status = GF_NETIO_CONNECTED; gf_dm_sess_notify_state(sess, GF_NETIO_CONNECTED, GF_OK); gf_sk_set_block_mode(sess->sock, 1); gf_dm_configure_cache(sess);#ifdef GPAC_HAS_SSL /*socket is connected, configure SSL layer*/ if (!sess->ssl && sess->dm->ssl_ctx && (sess->flags & GF_DOWNLOAD_SESSION_USE_SSL)) { int ret; long vresult; char common_name[256]; X509 *cert; Bool success = 1; sess->ssl = SSL_new(sess->dm->ssl_ctx); SSL_set_fd(sess->ssl, gf_sk_get_handle(sess->sock)); SSL_set_connect_state(sess->ssl); ret = SSL_connect(sess->ssl); assert(ret>0); cert = SSL_get_peer_certificate(sess->ssl); /*if we have a cert, check it*/ if (cert) { vresult = SSL_get_verify_result(sess->ssl); if (vresult != X509_V_OK) success = 0; else { common_name[0] = 0; X509_NAME_get_text_by_NID(X509_get_subject_name(cert), NID_commonName, common_name, sizeof (common_name)); if (!pattern_match(common_name, sess->server_name)) success = 0; } X509_free(cert); if (!success) { gf_dm_disconnect(sess); sess->status = GF_NETIO_STATE_ERROR; sess->last_error = GF_AUTHENTICATION_FAILURE; gf_dm_sess_notify_state(sess, sess->status, sess->last_error); } } }#endif}const char *gf_dm_sess_mime_type(GF_DownloadSession *sess){ Bool go; u32 flags = sess->flags; sess->flags |= GF_NETIO_SESSION_NOT_CACHED; go = 1; while (go) { switch (sess->status) { /*setup download*/ case GF_NETIO_SETUP: gf_dm_connect(sess); break; case GF_NETIO_WAIT_FOR_REPLY: gf_sleep(20); case GF_NETIO_CONNECTED: sess->do_requests(sess); break; case GF_NETIO_DATA_EXCHANGE: case GF_NETIO_DISCONNECTED: case GF_NETIO_STATE_ERROR: go = 0; break; } } sess->flags = flags; if (sess->status==GF_NETIO_STATE_ERROR) return NULL; return sess->mime_type;}GF_DownloadManager *gf_dm_new(GF_Config *cfg){ const char *opt; GF_DownloadManager *dm; if (!cfg) return NULL; GF_SAFEALLOC(dm, GF_DownloadManager); dm->sessions = gf_list_new(); dm->cfg = cfg; opt = gf_cfg_get_key(cfg, "General", "CacheDirectory"); if (opt) { if (opt[strlen(opt)-1] != GF_PATH_SEPARATOR) { dm->cache_directory = (char *) malloc(sizeof(char)* (strlen(opt)+2)); sprintf(dm->cache_directory, "%s%c", opt, GF_PATH_SEPARATOR); } else { dm->cache_directory = strdup(opt); } }#ifdef GPAC_HAS_SSL ssl_init(dm, 0);#endif return dm;}void gf_dm_set_auth_callback(GF_DownloadManager *dm, Bool (*GetUserPassword)(void *usr_cbk, const char *site_url, char *usr_name, char *password), void *usr_cbk){ if (dm) { dm->GetUserPassword = GetUserPassword; dm->usr_cbk = usr_cbk; }}void gf_dm_del(GF_DownloadManager *dm){ /*destroy all pending sessions*/ while (gf_list_count(dm->sessions)) { GF_DownloadSession *sess = (GF_DownloadSession *) gf_list_get(dm->sessions, 0); gf_dm_sess_del(sess); } gf_list_del(dm->sessions); free(dm->cache_directory);#ifdef GPAC_HAS_SSL if (dm->ssl_ctx) SSL_CTX_free(dm->ssl_ctx);#endif free(dm);}static GFINLINE void gf_dm_data_recieved(GF_DownloadSession *sess, char *data, u32 nbBytes){ GF_NETIO_Parameter par; u32 runtime, rcv; rcv = nbBytes; if (! (sess->flags & GF_NETIO_SESSION_NOT_CACHED)) { if (sess->cache) { fwrite(data, nbBytes, 1, sess->cache); fflush(sess->cache); } sess->bytes_done += nbBytes; /*if not threaded don't signal data to user*/ if (sess->th) { par.msg_type = GF_NETIO_DATA_EXCHANGE; par.error = GF_OK; par.data = NULL; par.size = nbBytes; gf_dm_sess_user_io(sess, &par); } } else if (sess->icy_metaint) { while (nbBytes) { if (sess->icy_bytes == sess->icy_metaint) { sess->icy_count = 1 + 16* (u8) data[0]; /*skip icy metadata*/ if (sess->icy_count >= nbBytes) { sess->icy_count -= nbBytes; nbBytes = 0; } else { if (sess->icy_count > 1) { GF_NETIO_Parameter par; char szData[4096]; memcpy(szData, data+1, sess->icy_count-1); szData[sess->icy_count] = 0; par.error = 0; par.msg_type = GF_NETIO_PARSE_HEADER; par.name = "icy-meta"; par.value = szData; gf_dm_sess_user_io(sess, &par); } nbBytes -= sess->icy_count; data += sess->icy_count; sess->icy_count = 0; sess->icy_bytes = 0; } } else { u32 left = sess->icy_metaint - sess->icy_bytes; if (left > nbBytes) { left = nbBytes; sess->icy_bytes += left; nbBytes = 0; } else { sess->icy_bytes = sess->icy_metaint; nbBytes -= left; } par.msg_type = GF_NETIO_DATA_EXCHANGE; par.error = GF_OK; par.data = data; par.size = left; gf_dm_sess_user_io(sess, &par); data += left; } } } else { sess->bytes_done += nbBytes; /*if not threaded don't signal data to user*/ if (sess->th) { par.msg_type = GF_NETIO_DATA_EXCHANGE; par.error = GF_OK; par.data = data; par.size = nbBytes; gf_dm_sess_user_io(sess, &par); } } if (sess->total_size && (sess->bytes_done == sess->total_size)) { gf_dm_disconnect(sess); par.msg_type = GF_NETIO_DATA_TRANSFERED; par.error = GF_OK; gf_dm_sess_user_io(sess, &par); return; } /*update state if not done*/ if (rcv) { sess->bytes_in_wnd += rcv; runtime = gf_sys_clock() - sess->window_start; if (!runtime) { sess->bytes_per_sec = 0; } else { sess->bytes_per_sec = (1000 * (sess->bytes_in_wnd)) / runtime; if (runtime>1000) { sess->window_start += runtime/2; sess->bytes_in_wnd = sess->bytes_per_sec / 2; } } }}GF_EXPORTGF_Err gf_dm_sess_fetch_data(GF_DownloadSession *sess, char *buffer, u32 buffer_size, u32 *read_size){ GF_Err e; if (sess->cache || !buffer || !buffer_size) return GF_BAD_PARAM; if (sess->th) return GF_BAD_PARAM; if (sess->status == GF_NETIO_DISCONNECTED) return GF_EOS; if (sess->status > GF_NETIO_DATA_TRANSFERED) return GF_BAD_PARAM; *read_size = 0; if (sess->status == GF_NETIO_DATA_TRANSFERED) return GF_EOS; if (sess->status == GF_NETIO_SETUP) { gf_dm_connect(sess); return GF_OK; } else if (sess->status < GF_NETIO_DATA_EXCHANGE) { sess->do_requests(sess); return GF_OK; } /*we're running but we had data previously*/ if (sess->init_data) { memcpy(buffer, sess->init_data, sizeof(char)*sess->init_data_size); *read_size = sess->init_data_size; free(sess->init_data); sess->init_data = NULL; sess->init_data_size = 0; return GF_OK; } e = gf_dm_read_data(sess, buffer, buffer_size, read_size); if (e) return e; gf_dm_data_recieved(sess, buffer, *read_size); return GF_OK;}GF_EXPORTGF_Err gf_dm_sess_get_stats(GF_DownloadSession * sess, const char **server, const char **path, u32 *total_size, u32 *bytes_done, u32 *bytes_per_sec, u32 *net_status){ if (!sess) return GF_BAD_PARAM; if (server) *server = sess->server_name; if (path) *path = sess->remote_path; if (total_size) *total_size = sess->total_size; if (bytes_done) *bytes_done = sess->bytes_done; if (bytes_per_sec) *bytes_per_sec = sess->bytes_per_sec; if (net_status) *net_status = sess->status; if (sess->status == GF_NETIO_DISCONNECTED) return GF_EOS; else if (sess->status == GF_NETIO_STATE_ERROR) return GF_SERVICE_ERROR; return GF_OK;}GF_EXPORTconst char *gf_dm_sess_get_cache_name(GF_DownloadSession * sess){ if (!sess) return NULL; return sess->cache_name;}void gf_dm_sess_abort(GF_DownloadSession * sess){ if (sess->mx) { gf_mx_p(sess->mx); gf_dm_disconnect(sess); sess->status = GF_NETIO_STATE_ERROR; gf_mx_v(sess->mx); } else { gf_dm_disconnect(sess); }}void *gf_dm_sess_get_private(GF_DownloadSession * sess){ return sess ? sess->ext : NULL;}void gf_dm_sess_set_private(GF_DownloadSession * sess, void *private_data){ if (sess) sess->ext = private_data;}/* HTTP(S) stuff*/static GFINLINE u32 http_skip_space(char *val){ u32 ret = 0; while (val[ret] == ' ') ret+=1; return ret;}static GFINLINE char *http_is_header(char *line, char *header_name){ char *res; if (strnicmp(line, header_name, strlen(header_name))) return NULL; res = line + strlen(header_name); while ((res[0] == ':') || (res[0] == ' ')) res+=1; return res;}void http_do_requests(GF_DownloadSession *sess){ GF_Err e; Bool is_ice; GF_NETIO_Parameter par; char sHTTP[GF_DOWNLOAD_BUFFER_SIZE]; char buf[1024]; char comp[400]; char *new_location; char *hdr, *hdr_val; u32 bytesRead, res; s32 LinePos, Pos; u32 rsp_code, ContentLength, first_byte, last_byte, total_size, range, no_range; s32 BodyStart; /*sent HTTP request*/ if (sess->status==GF_NETIO_CONNECTED) { char range_buf[1024]; char pass_buf[1024]; const char *user_agent;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -