//parse all fields in the header GF_Err RTSP_ParseResponseHeader(GF_RTSPSession *sess, GF_RTSPResponse *rsp, u32 BodyStart) { char LineBuffer[1024]; char ValBuf[400]; char *buffer; s32 Pos, ret; u32 Size; Size = sess->CurrentSize - sess->CurrentPos; buffer = sess->TCPBuffer + sess->CurrentPos; //parse first line ret = gf_token_get_line(buffer, 0, Size, LineBuffer, 1024); if (ret < 0) return GF_REMOTE_SERVICE_ERROR; //RTSP/1.0 Pos = gf_token_get(LineBuffer, 0, " \t\r\n", ValBuf, 400); if (Pos <= 0) return GF_REMOTE_SERVICE_ERROR; if (strcmp(ValBuf, GF_RTSP_VERSION)) return GF_SERVICE_ERROR; //CODE Pos = gf_token_get(LineBuffer, Pos, " \t\r\n", ValBuf, 400); if (Pos <= 0) return GF_REMOTE_SERVICE_ERROR; rsp->ResponseCode = atoi(ValBuf); //string info Pos = gf_token_get(LineBuffer, Pos, "\t\r\n", ValBuf, 400); if (Pos > 0) rsp->ResponseInfo = gf_strdup(ValBuf); return gf_rtsp_parse_header(buffer + ret, Size - ret, BodyStart, NULL, rsp); }
GF_Err RTSP_ParseCommandHeader(GF_RTSPSession *sess, GF_RTSPCommand *com, u32 BodyStart) { char LineBuffer[1024]; char ValBuf[1024]; char *buffer; s32 Pos, ret; u32 Size; Size = sess->CurrentSize - sess->CurrentPos; buffer = sess->TCPBuffer + sess->CurrentPos; //by default the command is wrong ;) com->StatusCode = NC_RTSP_Bad_Request; //parse first line ret = gf_token_get_line(buffer, 0, Size, LineBuffer, 1024); if (ret < 0) return GF_REMOTE_SERVICE_ERROR; //method Pos = gf_token_get(LineBuffer, 0, " \t\r\n", ValBuf, 1024); if (Pos <= 0) return GF_OK; com->method = gf_strdup((const char *) ValBuf); //URL Pos = gf_token_get(LineBuffer, Pos, " \t\r\n", ValBuf, 1024); if (Pos <= 0) return GF_OK; com->service_name = gf_strdup(ValBuf); //RTSP version Pos = gf_token_get(LineBuffer, Pos, "\t\r\n", ValBuf, 1024); if (Pos <= 0) return GF_OK; if (strcmp(ValBuf, GF_RTSP_VERSION)) { com->StatusCode = NC_RTSP_RTSP_Version_Not_Supported; return GF_OK; } com->StatusCode = NC_RTSP_OK; return gf_rtsp_parse_header(buffer + ret, Size - ret, BodyStart, com, NULL); }
GF_Err gf_rtsp_parse_header(char *buffer, u32 BufferSize, u32 BodyStart, GF_RTSPCommand *com, GF_RTSPResponse *rsp) { char LineBuffer[1024]; char HeaderBuf[100], ValBuf[1024], temp[400]; s32 Pos, LinePos; u32 HeaderLine; //then parse the full header LinePos = 0; strcpy(HeaderBuf, ""); while (1) { HeaderLine = 0; LinePos = gf_token_get_line(buffer, LinePos, BufferSize, LineBuffer, 1024); if (LinePos <= 0) return GF_REMOTE_SERVICE_ERROR; //extract field header and value. Warning: some params (transport, ..) may be on several lines Pos = gf_token_get(LineBuffer, 0, ":\r\n", temp, 400); //end of header if (Pos <= 0) { HeaderLine = 2; } //this is a header else if (LineBuffer[0] != ' ') { HeaderLine = 1; } else { Pos = gf_token_get(LineBuffer, 0, ", \r\n", temp, 400); //end of header - process any pending one if (Pos <= 0) { HeaderLine = 2; } else { //n-line value - append strcat(ValBuf, "\r\n"); strcat(ValBuf, temp); continue; } } //process current value if (HeaderLine && strlen(HeaderBuf)) { if (rsp) { gf_rtsp_set_response_value(rsp, HeaderBuf, ValBuf); } else { gf_rtsp_set_command_value(com, HeaderBuf, ValBuf); } } //done with the header if ( (HeaderLine == 2) || ((u32) LinePos >= BodyStart) ) return GF_OK; //process current line strcpy(HeaderBuf, temp); //skip ':' Pos += 1; //a server should normally reply with a space, but check it if (LineBuffer[Pos] == ' ') Pos += 1; /*!! empty value !! - DSS may send these for CSeq if something goes wrong*/ if (!strcmp(LineBuffer+Pos, "\r\n")) { HeaderBuf[0] = 0; continue; } Pos = gf_token_get(LineBuffer, Pos, "\r\n", ValBuf, 400); if (Pos <= 0) break; } //if we get here we haven't reached the BodyStart return GF_REMOTE_SERVICE_ERROR; }
GF_EXPORT GF_Err gf_sdp_info_parse(GF_SDPInfo *sdp, char *sdp_text, u32 text_size) { GF_SDPBandwidth *bw; GF_SDPConnection *conn; GF_SDPMedia *media; GF_SDPTiming *timing; u32 i; s32 pos, LinePos; char LineBuf[3000], comp[3000]; media = NULL; timing = NULL; if (!sdp) return GF_BAD_PARAM; //Clean SDP info gf_sdp_info_reset(sdp); LinePos = 0; while (1) { LinePos = gf_token_get_line(sdp_text, LinePos, text_size, LineBuf, 3000); if (LinePos <= 0) break; if (!strcmp(LineBuf, "\r\n") || !strcmp(LineBuf, "\n") || !strcmp(LineBuf, "\r")) continue; switch (LineBuf[0]) { case 'v': pos = gf_token_get(LineBuf, 2, "\t\r\n", comp, 3000); sdp->Version = atoi(comp); break; case 'o': pos = gf_token_get(LineBuf, 2, " \t\r\n", comp, 3000); sdp->o_username = gf_strdup(comp); pos = gf_token_get(LineBuf, pos, " \t\r\n", comp, 3000); sdp->o_session_id = gf_strdup(comp); pos = gf_token_get(LineBuf, pos, " \t\r\n", comp, 3000); sdp->o_version = gf_strdup(comp); pos = gf_token_get(LineBuf, pos, " \t\r\n", comp, 3000); sdp->o_net_type = gf_strdup(comp); pos = gf_token_get(LineBuf, pos, " \t\r\n", comp, 3000); sdp->o_add_type = gf_strdup(comp); pos = gf_token_get(LineBuf, pos, " \t\r\n", comp, 3000); sdp->o_address = gf_strdup(comp); break; case 's': pos = gf_token_get(LineBuf, 2, "\t\r\n", comp, 3000); sdp->s_session_name = gf_strdup(comp); break; case 'i': pos = gf_token_get(LineBuf, 2, "\t\r\n", comp, 3000); sdp->i_description = gf_strdup(comp); break; case 'u': pos = gf_token_get(LineBuf, 2, "\t\r\n", comp, 3000); sdp->u_uri = gf_strdup(comp); break; case 'e': pos = gf_token_get(LineBuf, 2, "\t\r\n", comp, 3000); sdp->e_email = gf_strdup(comp); break; case 'p': pos = gf_token_get(LineBuf, 2, "\t\r\n", comp, 3000); sdp->p_phone = gf_strdup(comp); break; case 'c': //if at session level, only 1 is allowed for all SDP if (sdp->c_connection) break; conn = gf_sdp_conn_new(); pos = gf_token_get(LineBuf, 2, " \t\r\n", comp, 3000); conn->net_type = gf_strdup(comp); pos = gf_token_get(LineBuf, pos, " \t\r\n", comp, 3000); conn->add_type = gf_strdup(comp); pos = gf_token_get(LineBuf, pos, " /\r\n", comp, 3000); conn->host = gf_strdup(comp); if (gf_sk_is_multicast_address(conn->host)) { //a valid SDP will have TTL if address is multicast pos = gf_token_get(LineBuf, pos, "/\r\n", comp, 3000); if (pos > 0) { conn->TTL = atoi(comp); //multiple address indication is only valid for media pos = gf_token_get(LineBuf, pos, "/\r\n", comp, 3000); } if (pos > 0) { if (!media) { gf_sdp_conn_del(conn); break; } conn->add_count = atoi(comp); } } if (!media) sdp->c_connection = conn; else gf_list_add(media->Connections, conn); break; case 'b': pos = gf_token_get(LineBuf, 2, ":\r\n", comp, 3000); if (strcmp(comp, "CT") && strcmp(comp, "AS") && (comp[0] != 'X')) break; bw = (GF_SDPBandwidth*)gf_malloc(sizeof(GF_SDPBandwidth)); bw->name = gf_strdup(comp); pos = gf_token_get(LineBuf, pos, ":\r\n", comp, 3000); bw->value = atoi(comp); if (media) { gf_list_add(media->Bandwidths, bw); } else { gf_list_add(sdp->b_bandwidth, bw); } break; case 't': if (media) break; //create a new time structure for each entry GF_SAFEALLOC(timing, GF_SDPTiming); pos = gf_token_get(LineBuf, 2, " \t\r\n", comp, 3000); timing->StartTime = atoi(comp); pos = gf_token_get(LineBuf, pos, "\r\n", comp, 3000); timing->StopTime = atoi(comp); gf_list_add(sdp->Timing, timing); break; case 'r': if (media) break; pos = gf_token_get(LineBuf, 2, " \t\r\n", comp, 3000); timing->RepeatInterval = SDP_MakeSeconds(comp); pos = gf_token_get(LineBuf, pos, " \t\r\n", comp, 3000); timing->ActiveDuration = SDP_MakeSeconds(comp); while (1) { pos = gf_token_get(LineBuf, pos, " \t\r\n", comp, 3000); if (pos <= 0) break; timing->OffsetFromStart[timing->NbRepeatOffsets] = SDP_MakeSeconds(comp); timing->NbRepeatOffsets += 1; } break; case 'z': if (media) break; pos = 2; while (1) { pos = gf_token_get(LineBuf, pos, " \t\r\n", comp, 3000); if (pos <= 0) break; timing->AdjustmentTime[timing->NbZoneOffsets] = atoi(comp); pos = gf_token_get(LineBuf, pos, " \t\r\n", comp, 3000); timing->AdjustmentOffset[timing->NbZoneOffsets] = SDP_MakeSeconds(comp); timing->NbZoneOffsets += 1; } break; case 'k': pos = gf_token_get(LineBuf, 2, ":\t\r\n", comp, 3000); if (media) { media->k_method = gf_strdup(comp); } else { sdp->k_method = gf_strdup(comp); } pos = gf_token_get(LineBuf, pos, ":\r\n", comp, 3000); if (pos > 0) { if (media) { media->k_key = gf_strdup(comp); } else { sdp->k_key = gf_strdup(comp); } } break; case 'a': SDP_ParseAttribute(sdp, LineBuf+2, media); break; case 'm': pos = gf_token_get(LineBuf, 2, " \t\r\n", comp, 3000); if (strcmp(comp, "audio") && strcmp(comp, "data") && strcmp(comp, "control") && strcmp(comp, "video") && strcmp(comp, "text") && strcmp(comp, "application")) { return GF_SERVICE_ERROR; } media = gf_sdp_media_new(); //media type if (!strcmp(comp, "video")) media->Type = 1; else if (!strcmp(comp, "audio")) media->Type = 2; else if (!strcmp(comp, "text")) media->Type = 3; else if (!strcmp(comp, "data")) media->Type = 4; else if (!strcmp(comp, "control")) media->Type = 5; else media->Type = 0; //port numbers gf_token_get(LineBuf, pos, " ", comp, 3000); if (!strstr(comp, "/")) { pos = gf_token_get(LineBuf, pos, " \r\n", comp, 3000); media->PortNumber = atoi(comp); media->NumPorts = 0; } else { pos = gf_token_get(LineBuf, pos, " /\r\n", comp, 3000); media->PortNumber = atoi(comp); pos = gf_token_get(LineBuf, pos, " \r\n", comp, 3000); media->NumPorts = atoi(comp); } //transport Profile pos = gf_token_get(LineBuf, pos, " \r\n", comp, 3000); media->Profile = gf_strdup(comp); pos = gf_token_get(LineBuf, pos, " \r\n", comp, 3000); media->fmt_list = gf_strdup(comp); gf_list_add(sdp->media_desc, media); break; } } //finally rewrite the fmt_list for all media, and remove dynamic payloads //from the list i=0; while ((media = (GF_SDPMedia*)gf_list_enum(sdp->media_desc, &i))) { pos = 0; LinePos = 1; strcpy(LineBuf, ""); while (1) { if (!media->fmt_list) break; pos = gf_token_get(media->fmt_list, pos, " ", comp, 3000); if (pos <= 0) break; if (!SDP_IsDynamicPayload(media, comp)) { if (!LinePos) { strcat(LineBuf, " "); } else { LinePos = 0; } strcat(LineBuf, comp); } gf_free(media->fmt_list); media->fmt_list = NULL; if (strlen(LineBuf)) { media->fmt_list = gf_strdup(LineBuf); } } } return GF_OK; }
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; u32 size; Bool has_accept, has_connection, has_range, has_agent; /*setup authentification*/ strcpy(pass_buf, ""); if (sess->user) { if (!sess->passwd) { char szUSR[50], szPASS[50]; strcpy(szUSR, sess->user); strcpy(szPASS, ""); /*failed getting pass*/ if (!sess->dm->GetUserPassword || !sess->dm->GetUserPassword(sess->dm->usr_cbk, sess->server_name, szUSR, szPASS)) { sess->status = GF_NETIO_STATE_ERROR; return; } sess->passwd = strdup(szPASS); } sprintf(pass_buf, "%s:%s", sess->user, sess->passwd); size = gf_base64_encode(pass_buf, strlen(pass_buf), range_buf, 1024); range_buf[size] = 0; sprintf(pass_buf, "Authorization: Basic %s", range_buf); } /*MIX2005 KMS project*/ #if 0 if (strstr(sess->remote_path, "getKey.php?")) { char *sLogin, *sPass; sLogin = gf_cfg_get_key(sess->dm->cfg, "General", "KMS_User"); sPass = gf_cfg_get_key(sess->dm->cfg, "General", "KMS_Password"); if (!sLogin) sLogin = "******"; if (!sPass) sPass = "******"; sprintf(https_get_buffer, "%s&login=%s&password=%s", sess->remote_path, sLogin, sPass); } #endif user_agent = gf_cfg_get_key(sess->dm->cfg, "Downloader", "UserAgent"); if (!user_agent) user_agent = GF_DOWNLOAD_AGENT_NAME; par.error = 0; par.msg_type = GF_NETIO_GET_METHOD; par.name = NULL; gf_dm_sess_user_io(sess, &par); if (par.name) { if (!strcmp(par.name, "GET")) sess->http_read_type = 0; else if (!strcmp(par.name, "HEAD")) sess->http_read_type = 1; else sess->http_read_type = 2; } else { sess->http_read_type = 0; } sprintf(sHTTP, "%s %s HTTP/1.0\r\nHost: %s\r\n" , par.name ? par.name : "GET", sess->remote_path, sess->server_name); /*signal we support title streaming*/ if (!strcmp(sess->remote_path, "/")) strcat(sHTTP, "icy-metadata:1\r\n"); /*get all headers*/ has_agent = has_accept = has_connection = has_range = 0; while (1) { par.msg_type = GF_NETIO_GET_HEADER; par.name = NULL; par.value = NULL; gf_dm_sess_user_io(sess, &par); if (!par.name) break; strcat(sHTTP, par.name); strcat(sHTTP, ": "); strcat(sHTTP, par.value); strcat(sHTTP, "\r\n"); if (!strcmp(par.name, "Accept")) has_accept = 1; else if (!strcmp(par.name, "Connection")) has_connection = 1; else if (!strcmp(par.name, "Range")) has_range = 1; else if (!strcmp(par.name, "User-Agent")) has_agent = 1; } if (!has_agent) { strcat(sHTTP, "User-Agent: "); strcat(sHTTP, user_agent); strcat(sHTTP, "\r\n"); } if (!has_accept) strcat(sHTTP, "Accept: */*\r\n"); if (!has_connection) strcat(sHTTP, "Connection: Keep-Alive\r\n"); if (!has_range && sess->cache_start_size) { sprintf(range_buf, "Range: bytes=%d-\r\n", sess->cache_start_size); strcat(sHTTP, range_buf); } if (strlen(pass_buf)) { strcat(sHTTP, pass_buf); strcat(sHTTP, "\r\n"); } if (sess->flags & GF_DOWNLOAD_IS_ICY) strcat(sHTTP, "Icy-Metadata: 1\r\n"); par.msg_type = GF_NETIO_GET_CONTENT; par.data = NULL; par.size = 0; gf_dm_sess_user_io(sess, &par); if (par.data && par.size) { sprintf(range_buf, "Content-Length: %d\r\n", par.size); strcat(sHTTP, range_buf); } strcat(sHTTP, "\r\n"); #ifdef GPAC_HAS_SSL if (sess->ssl) { e = GF_IP_NETWORK_FAILURE; if (!SSL_write(sess->ssl, sHTTP, strlen(sHTTP))) e = GF_OK; } else #endif e = gf_sk_send(sess->sock, sHTTP, strlen(sHTTP)); GF_LOG(GF_LOG_DEBUG, GF_LOG_NETWORK, ("[HTTP] %s\n\n", sHTTP)); if (e) { sess->status = GF_NETIO_STATE_ERROR; sess->last_error = e; gf_dm_sess_notify_state(sess, GF_NETIO_STATE_ERROR, e); return; } if (par.size && par.data) { u32 done = 0; while (done<par.size) { #ifdef GPAC_HAS_SSL if (sess->ssl) { e = GF_IP_NETWORK_FAILURE; if (!SSL_write(sess->ssl, par.data+done, par.size-done)) e = GF_OK; } else #endif e = gf_sk_send(sess->sock, par.data+done, par.size-done); if (e) { sess->status = GF_NETIO_STATE_ERROR; sess->last_error = e; gf_dm_sess_notify_state(sess, GF_NETIO_STATE_ERROR, e); return; } } } sess->status = GF_NETIO_WAIT_FOR_REPLY; gf_dm_sess_notify_state(sess, GF_NETIO_WAIT_FOR_REPLY, GF_OK); return; } /*process HTTP request*/ if (sess->status == GF_NETIO_WAIT_FOR_REPLY) { bytesRead = res = 0; new_location = NULL; while (1) { e = gf_dm_read_data(sess, sHTTP + bytesRead, GF_DOWNLOAD_BUFFER_SIZE - bytesRead, &res); switch (e) { case GF_IP_NETWORK_EMPTY: if (!bytesRead) return; continue; /*socket has been closed while configuring, retry (not sure if the server got the GET)*/ case GF_IP_CONNECTION_CLOSED: gf_dm_disconnect(sess); if (sess->num_retry) sess->status = GF_NETIO_SETUP; else { sess->last_error = e; sess->status = GF_NETIO_STATE_ERROR; } return; case GF_OK: if (!res) return; break; default: goto exit; } bytesRead += res; /*locate body start*/ BodyStart = gf_token_find(sHTTP, 0, bytesRead, "\r\n\r\n"); if (BodyStart <= 0) { BodyStart=0; continue; } BodyStart += 4; break; } if (bytesRead < 0) { e = GF_REMOTE_SERVICE_ERROR; goto exit; } if (!BodyStart) BodyStart = bytesRead; sHTTP[BodyStart-1] = 0; GF_LOG(GF_LOG_DEBUG, GF_LOG_NETWORK, ("[HTTP] %s\n\n", sHTTP)); LinePos = gf_token_get_line(sHTTP, 0, bytesRead, buf, 1024); Pos = gf_token_get(buf, 0, " \t\r\n", comp, 400); if (sess->mime_type) free(sess->mime_type); sess->mime_type = NULL; is_ice = 0; if (!strncmp("ICY", comp, 4)) { is_ice = 1; /*be prepared not to recieve any mime type from ShoutCast servers*/ sess->mime_type = strdup("audio/mpeg"); } else if ((strncmp("HTTP", comp, 4) != 0)) { e = GF_REMOTE_SERVICE_ERROR; goto exit; } Pos = gf_token_get(buf, Pos, " ", comp, 400); if (Pos <= 0) { e = GF_REMOTE_SERVICE_ERROR; goto exit; } rsp_code = (u32) atoi(comp); Pos = gf_token_get(buf, Pos, " \r\n", comp, 400); no_range = range = ContentLength = first_byte = last_byte = total_size = 0; //parse header while (1) { char *sep, *hdr_sep; if ( (u32) LinePos + 4 > BodyStart) break; LinePos = gf_token_get_line(sHTTP, LinePos , bytesRead, buf, 1024); if (LinePos < 0) break; hdr_sep = NULL; hdr_val = NULL; hdr = buf; sep = strchr(buf, ':'); if (sep) { sep[0]=0; hdr_val = sep+1; while (hdr_val[0]==' ') hdr_val++; hdr_sep = strrchr(hdr_val, '\r'); if (hdr_sep) hdr_sep[0] = 0; } par.error = 0; par.msg_type = GF_NETIO_PARSE_HEADER; par.name = hdr; par.value = hdr_val; gf_dm_sess_user_io(sess, &par); if (!stricmp(hdr, "Content-Length") ) ContentLength = (u32) atoi(hdr_val); else if (!stricmp(hdr, "Content-Type")) { if (sess->mime_type) free(sess->mime_type); sess->mime_type = strdup(hdr_val); while (1) { u32 len = strlen(sess->mime_type); char c = len ? sess->mime_type[len-1] : 0; if ((c=='\r') || (c=='\n')) { sess->mime_type[len-1] = 0; } else { break; } } hdr = strchr(sess->mime_type, ';'); if (hdr) hdr[0] = 0; } else if (!stricmp(hdr, "Content-Range")) { range = 1; if (!strncmp(hdr_val, "bytes", 5)) { hdr_val += 5; if (hdr_val[0] == ':') hdr_val += 1; hdr_val += http_skip_space(hdr_val); if (hdr_val[0] == '*') { sscanf(hdr_val, "*/%d", &total_size); } else { sscanf(hdr_val, "%d-%d/%d", &first_byte, &last_byte, &total_size); } } } else if (!stricmp(hdr, "Accept-Ranges")) { if (strstr(hdr_val, "none")) no_range = 1; } else if (!stricmp(hdr, "Location")) new_location = strdup(hdr_val); else if (!stricmp(hdr, "icy-metaint")) sess->icy_metaint = atoi(hdr_val); else if (!stricmp(hdr, "ice") || !stricmp(hdr, "icy") ) is_ice = 1; if (sep) sep[0]=':'; if (hdr_sep) hdr_sep[0] = '\r'; } if (no_range) first_byte = 0; if (sess->cache_start_size) { if (total_size && (sess->cache_start_size >= total_size) ) { rsp_code = 200; ContentLength = total_size; } if (ContentLength && (sess->cache_start_size == ContentLength) ) rsp_code = 200; } par.msg_type = GF_NETIO_PARSE_REPLY; par.error = GF_OK; par.reply = rsp_code; par.value = comp; switch (rsp_code) { case 200: case 201: case 202: case 206: gf_dm_sess_user_io(sess, &par); e = GF_OK; break; /*redirection: extract the new location*/ case 301: case 302: if (!new_location || !strlen(new_location) ) { gf_dm_sess_user_io(sess, &par); e = GF_URL_ERROR; goto exit; } while ( (new_location[strlen(new_location)-1] == '\n') || (new_location[strlen(new_location)-1] == '\r') ) new_location[strlen(new_location)-1] = 0; /*reset and reconnect*/ gf_dm_disconnect(sess); sess->status = GF_NETIO_SETUP; e = gf_dm_setup_from_url(sess, new_location); if (e) { sess->status = GF_NETIO_STATE_ERROR; sess->last_error = e; gf_dm_sess_notify_state(sess, sess->status, e); return; } return; case 404: case 416: /*try without cache (some servers screw up when content-length is specified)*/ if (sess->cache_start_size) { gf_dm_disconnect(sess); sess->status = GF_NETIO_SETUP; return; } else if (is_ice && !(sess->flags & GF_DOWNLOAD_IS_ICY)) { gf_dm_disconnect(sess); sess->status = GF_NETIO_SETUP; sess->flags |= GF_DOWNLOAD_IS_ICY; return; } gf_dm_sess_user_io(sess, &par); e = GF_URL_ERROR; goto exit; case 503: default: gf_dm_sess_user_io(sess, &par); e = GF_REMOTE_SERVICE_ERROR; goto exit; } /*head*/ if (sess->http_read_type==1) { gf_dm_disconnect(sess); gf_dm_sess_notify_state(sess, GF_NETIO_DATA_TRANSFERED, GF_OK); sess->status = GF_NETIO_DISCONNECTED; sess->http_read_type = 0; return; } if (!ContentLength && sess->mime_type && strstr(sess->mime_type, "ogg")) is_ice = 1; /*some servers may reply without content length, but we MUST have it*/ // if (!is_ice && !ContentLength) e = GF_REMOTE_SERVICE_ERROR; if (e) goto exit; /*force disabling cache (no content length)*/ if (is_ice) { sess->flags |= GF_NETIO_SESSION_NOT_CACHED; if (sess->mime_type && !stricmp(sess->mime_type, "video/nsv")) { free(sess->mime_type); sess->mime_type = strdup("audio/aac"); } } /*done*/ if (sess->cache_start_size && ( (total_size && sess->cache_start_size >= total_size) || (sess->cache_start_size == ContentLength)) ) { sess->total_size = sess->bytes_done = sess->cache_start_size; /*disconnect*/ gf_dm_disconnect(sess); BodyStart = bytesRead; gf_dm_sess_notify_state(sess, GF_NETIO_DATA_TRANSFERED, GF_OK); } else if (sess->flags & GF_DOWNLOAD_IS_ICY) { sess->icy_bytes = 0; sess->status = GF_NETIO_DATA_EXCHANGE; } /*we don't expect anything*/ else if (!ContentLength && sess->http_read_type) { gf_dm_disconnect(sess); gf_dm_sess_notify_state(sess, GF_NETIO_DATA_TRANSFERED, GF_OK); sess->status = GF_NETIO_DISCONNECTED; sess->http_read_type = 0; } /*no range header, Accep-Ranges deny or dumb server : restart*/ else if (!range || !first_byte || (first_byte != sess->cache_start_size) ) { sess->cache_start_size = sess->bytes_done = 0; sess->total_size = ContentLength; if (! (sess->flags & GF_NETIO_SESSION_NOT_CACHED) ) { sess->cache = fopen(sess->cache_name, "wb"); if (!sess->cache) { e = GF_IO_ERR; goto exit; } } sess->status = GF_NETIO_DATA_EXCHANGE; } /*resume*/ else { sess->total_size = ContentLength + sess->cache_start_size; if (! (sess->flags & GF_NETIO_SESSION_NOT_CACHED) ) { sess->cache = fopen(sess->cache_name, "ab"); if (!sess->cache) { e = GF_IO_ERR; goto exit; } } sess->status = GF_NETIO_DATA_EXCHANGE; sess->bytes_done = sess->cache_start_size; } sess->window_start = sess->start_time = gf_sys_clock(); sess->bytes_in_wnd = 0; //we may have existing data in this buffer ... if (!e && (BodyStart < (u32) bytesRead)) { gf_dm_data_recieved(sess, sHTTP + BodyStart, bytesRead - BodyStart); /*store data if no callbacks or cache*/ if (sess->flags & GF_NETIO_SESSION_NOT_CACHED) { if (sess->init_data) free(sess->init_data); sess->init_data_size = bytesRead - BodyStart; sess->init_data = (char *) malloc(sizeof(char) * sess->init_data_size); memcpy(sess->init_data, sHTTP+BodyStart, sess->init_data_size); } } exit: if (e) { gf_dm_disconnect(sess); sess->status = GF_NETIO_STATE_ERROR; sess->last_error = e; gf_dm_sess_notify_state(sess, sess->status, e); } return; } /*fetch data*/ while (1) { u32 size; #if 1 if (sess->limit_data_rate && sess->bytes_per_sec) { if (sess->bytes_per_sec>sess->limit_data_rate) { /*update state*/ u32 runtime = gf_sys_clock() - sess->window_start; sess->bytes_per_sec = (1000 * (sess->bytes_in_wnd)) / runtime; if (sess->bytes_per_sec > sess->limit_data_rate) return; } } #endif e = gf_dm_read_data(sess, sHTTP, GF_DOWNLOAD_BUFFER_SIZE, &size); if (!size || e == GF_IP_NETWORK_EMPTY) { if (!sess->total_size && (gf_sys_clock() - sess->window_start > 1000)) { sess->total_size = sess->bytes_done; gf_dm_sess_notify_state(sess, GF_NETIO_DATA_TRANSFERED, GF_OK); } return; } if (e) { gf_dm_disconnect(sess); sess->last_error = e; gf_dm_sess_notify_state(sess, sess->status, e); return; } gf_dm_data_recieved(sess, sHTTP, size); /*socket empty*/ if (size < GF_DOWNLOAD_BUFFER_SIZE) return; } }