static TinyRet UpnpDeviceParser_SetURLBase(UpnpDevice *thiz, const char *deviceUrl) { TinyRet ret = TINY_RET_OK; RETURN_VAL_IF_FAIL(thiz, TINY_RET_E_ARG_NULL); RETURN_VAL_IF_FAIL(deviceUrl, TINY_RET_E_ARG_NULL); do { char url_base[TINY_URL_LEN]; char ip[TINY_IP_LEN]; uint16_t port = 0; char uri[512]; memset(ip, 0, TINY_IP_LEN); memset(uri, 0, 512); ret = url_split(deviceUrl, ip, TINY_IP_LEN, &port, uri, 512); if (RET_FAILED(ret)) { break; } tiny_snprintf(url_base, TINY_URL_LEN, "http://%s:%d", ip, port); UpnpDevice_SetURLBase(thiz, url_base); } while (0); return ret; }
void webpopup_finalize_result(webpopup_result_t *wr) { if(wr->wr_trapped.url != NULL) { char hn[256]; char path[4096]; TRACE(TRACE_DEBUG, "webpopup", "Trapped URL: %s", wr->wr_trapped.url); url_split(NULL, 0, NULL, 0, hn, sizeof(hn), &wr->wr_trapped.port, path, sizeof(path), wr->wr_trapped.url); wr->wr_trapped.hostname = strdup(hn); wr->wr_trapped.path = strdup(path); char *k = strchr(wr->wr_trapped.path, '?'); while(k) { *k++ = 0; char *v = strchr(k, '='); int kl, vl = 0; char *n = strchr(k, '&'); if(v == NULL) { if(n == NULL) { kl = strlen(k); } else { kl = n - k; } } else { kl = v - k; v++; if(n == NULL) { vl = strlen(v); } else { vl = n - v; } } http_header_t *hh = malloc(sizeof(http_header_t)); hh->hh_key = malloc(kl+1); memcpy(hh->hh_key, k, kl); hh->hh_key[kl] = 0; if(v != NULL) { hh->hh_value = malloc(vl+1); memcpy(hh->hh_value, v, vl); hh->hh_value[vl] = 0; } k = n; LIST_INSERT_HEAD(&wr->wr_trapped.qargs, hh, hh_link); } } }
/* return zero if error */ static uint32 open(const char *uri, int flags, int udp) { char hostname[128]; char options[128]; int port; TCPContext *s; int sock = -1; struct sockaddr_in sa; int res; //h->is_streamed = 1; if (flags & O_DIR) return 0; s = malloc(sizeof(TCPContext)); if (!s) { return 0; } /* fill the dest addr */ /* needed in any case to build the host string */ url_split(NULL, 0, hostname, sizeof(hostname), &port, options, sizeof(options), uri); if (port < 0) port = 80; // printf("TCP : addr '%s' port %d\n", hostname, port); sa.sin_family = AF_INET; sa.sin_port = htons(port); if (dns(hostname, &sa.sin_addr.s_addr)) goto fail; sock = socket(PF_INET, udp? SOCK_DGRAM:SOCK_STREAM, 0); if (sock < 0) goto fail; res = connect(sock, &sa, sizeof(sa)); //printf("connect --> %d\n", res); if (res) goto fail; s->socket = sock; s->pos = 0; s->stream = strstr(options, "<stream>"); return (uint32) s; fail: if (sock >= 0) close(sock); free(s); return 0; }
int udp_ipv6_set_remote_url(URLContext *h, const char *uri) { UDPContext *s = h->priv_data; char hostname[256]; int port; struct addrinfo *res0; url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri); res0 = udp_ipv6_resolve_host(hostname, port, SOCK_DGRAM, AF_UNSPEC, 0); if (res0 == 0) return AVERROR_IO; memcpy(&s->dest_addr, res0->ai_addr, res0->ai_addrlen); s->dest_addr_len = res0->ai_addrlen; freeaddrinfo(res0); return 0; }
/** * If no filename is given to av_open_input_file because you want to * get the local port first, then you must call this function to set * the remote server address. * * url syntax: udp://host:port[?option=val...] * option: 'multicast=1' : enable multicast * 'ttl=n' : set the ttl value (for multicast only) * 'localport=n' : set the local port * 'pkt_size=n' : set max packet size * * @param s1 media file context * @param uri of the remote server * @return zero if no error. */ int udp_set_remote_url(URLContext *h, const char *uri) { UDPContext *s = h->priv_data; char hostname[256]; int port; url_split(NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri); /* set the destination address */ if (resolve_host(&s->dest_addr.sin_addr, hostname) < 0) return AVERROR_IO; s->dest_addr.sin_family = AF_INET; s->dest_addr.sin_port = htons(port); return 0; }
/** * If no filename is given to av_open_input_file because you want to * get the local port first, then you must call this function to set * the remote server address. * * url syntax: udp://host:port[?option=val...] * option: 'ttl=n' : set the ttl value (for multicast only) * 'localport=n' : set the local port * 'pkt_size=n' : set max packet size * 'reuse=1' : enable reusing the socket * * @param s1 media file context * @param uri of the remote server * @return zero if no error. */ int udp_set_remote_url(URLContext *h, const char *uri) { UDPContext *s = h->priv_data; char hostname[256]; int port; url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri); /* set the destination address */ s->dest_addr_len = udp_set_url(&s->dest_addr, hostname, port); if (s->dest_addr_len < 0) { return AVERROR(EIO); } s->is_multicast = is_multicast_address(&s->dest_addr); return 0; }
/** * If no filename is given to av_open_input_file because you want to * get the local port first, then you must call this function to set * the remote server address. * * @param s1 media file context * @param uri of the remote server * @return zero if no error. */ int rtp_set_remote_url(URLContext *h, const char *uri) { RTPContext *s = h->priv_data; char hostname[256]; int port; char buf[1024]; char path[1024]; url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, path, sizeof(path), uri); snprintf(buf, sizeof(buf), "udp://%s:%d%s", hostname, port, path); udp_set_remote_url(s->rtp_hd, buf); snprintf(buf, sizeof(buf), "udp://%s:%d%s", hostname, port + 1, path); udp_set_remote_url(s->rtcp_hd, buf); return 0; }
/** * If no filename is given to av_open_input_file because you want to * get the local port first, then you must call this function to set * the remote server address. * * url syntax: udp://host:port[?option=val...] * option: 'multicast=1' : enable multicast * 'ttl=n' : set the ttl value (for multicast only) * 'localport=n' : set the local port * 'pkt_size=n' : set max packet size * 'reuse=1' : enable reusing the socket * * @param s1 media file context * @param uri of the remote server * @return zero if no error. */ int udp_set_remote_url(URLContext *h, const char *uri) { #ifdef CONFIG_IPV6 return udp_ipv6_set_remote_url(h, uri); #else UDPContext *s = h->priv_data; char hostname[256]; int port; url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri); /* set the destination address */ if (resolve_host(&s->dest_addr.sin_addr, hostname) < 0) return AVERROR(EIO); s->dest_addr.sin_family = AF_INET; s->dest_addr.sin_port = htons(port); return 0; #endif }
/* return non zero if error */ static int http_open_cnx(URLContext *h) { const char *path, *proxy_path; char hostname[1024], hoststr[1024]; char auth[1024]; char path1[1024]; char buf[1024]; int port, use_proxy, err, location_changed = 0, redirects = 0; HTTPContext *s = h->priv_data; URLContext *hd = NULL; proxy_path = getenv("http_proxy"); use_proxy = (proxy_path != NULL) && !getenv("no_proxy") && av_strstart(proxy_path, "http://", NULL); /* fill the dest addr */ redo: /* needed in any case to build the host string */ url_split(NULL, 0, auth, sizeof(auth), hostname, sizeof(hostname), &port, path1, sizeof(path1), s->location); if (port > 0) { snprintf(hoststr, sizeof(hoststr), "%s:%d", hostname, port); } else { av_strlcpy(hoststr, hostname, sizeof(hoststr)); } if (use_proxy) { url_split(NULL, 0, auth, sizeof(auth), hostname, sizeof(hostname), &port, NULL, 0, proxy_path); path = s->location; } else { if (path1[0] == '\0') path = "/"; else path = path1; } if (port < 0) port = 80; snprintf(buf, sizeof(buf), "tcp://%s:%d", hostname, port); err = url_open(&hd, buf, URL_RDWR); if (err < 0) goto fail; s->hd = hd; if (http_connect(h, path, hoststr, auth, &location_changed) < 0) goto fail; if ((s->http_code == 302 || s->http_code == 303) && location_changed == 1) { /* url moved, get next */ url_close(hd); if (redirects++ >= MAX_REDIRECTS) return AVERROR(EIO); location_changed = 0; goto redo; } return 0; fail: if (hd) url_close(hd); return AVERROR(EIO); }
static int rtsp_read_header(AVFormatContext *s, AVFormatParameters *ap) { RTSPState *rt = s->priv_data; char host[1024], path[1024], tcpname[1024], cmd[2048]; URLContext *rtsp_hd; int port, i, j, ret, err; RTSPHeader reply1, *reply = &reply1; unsigned char *content = NULL; RTSPStream *rtsp_st; int protocol_mask; AVStream *st; /* extract hostname and port */ url_split(NULL, 0, NULL, 0, host, sizeof(host), &port, path, sizeof(path), s->filename); if (port < 0) port = RTSP_DEFAULT_PORT; /* open the tcp connexion */ snprintf(tcpname, sizeof(tcpname), "tcp://%s:%d", host, port); if (url_open(&rtsp_hd, tcpname, URL_RDWR) < 0) return AVERROR_IO; rt->rtsp_hd = rtsp_hd; rt->seq = 0; /* describe the stream */ snprintf(cmd, sizeof(cmd), "DESCRIBE %s RTSP/1.0\r\n" "Accept: application/sdp\r\n", s->filename); rtsp_send_cmd(s, cmd, reply, &content); if (!content) { err = AVERROR_INVALIDDATA; goto fail; } if (reply->status_code != RTSP_STATUS_OK) { err = AVERROR_INVALIDDATA; goto fail; } /* now we got the SDP description, we parse it */ ret = sdp_parse(s, (const char *)content); av_freep(&content); if (ret < 0) { err = AVERROR_INVALIDDATA; goto fail; } protocol_mask = rtsp_default_protocols; /* for each stream, make the setup request */ /* XXX: we assume the same server is used for the control of each RTSP stream */ for(j = RTSP_RTP_PORT_MIN, i = 0; i < rt->nb_rtsp_streams; ++i) { char transport[2048]; rtsp_st = rt->rtsp_streams[i]; /* compute available transports */ transport[0] = '\0'; /* RTP/UDP */ if (protocol_mask & (1 << RTSP_PROTOCOL_RTP_UDP)) { char buf[256]; /* first try in specified port range */ if (RTSP_RTP_PORT_MIN != 0) { while(j <= RTSP_RTP_PORT_MAX) { snprintf(buf, sizeof(buf), "rtp://?localport=%d", j); if (url_open(&rtsp_st->rtp_handle, buf, URL_RDONLY) == 0) { j += 2; /* we will use two port by rtp stream (rtp and rtcp) */ goto rtp_opened; } } } /* then try on any port ** if (url_open(&rtsp_st->rtp_handle, "rtp://", URL_RDONLY) < 0) { ** err = AVERROR_INVALIDDATA; ** goto fail; ** } */ rtp_opened: port = rtp_get_local_port(rtsp_st->rtp_handle); if (transport[0] != '\0') pstrcat(transport, sizeof(transport), ","); snprintf(transport + strlen(transport), sizeof(transport) - strlen(transport) - 1, "RTP/AVP/UDP;unicast;client_port=%d-%d", port, port + 1); } /* RTP/TCP */ else if (protocol_mask & (1 << RTSP_PROTOCOL_RTP_TCP)) { if (transport[0] != '\0') pstrcat(transport, sizeof(transport), ","); snprintf(transport + strlen(transport), sizeof(transport) - strlen(transport) - 1, "RTP/AVP/TCP"); } else if (protocol_mask & (1 << RTSP_PROTOCOL_RTP_UDP_MULTICAST)) { if (transport[0] != '\0') pstrcat(transport, sizeof(transport), ","); snprintf(transport + strlen(transport), sizeof(transport) - strlen(transport) - 1, "RTP/AVP/UDP;multicast"); } snprintf(cmd, sizeof(cmd), "SETUP %s RTSP/1.0\r\n" "Transport: %s\r\n", rtsp_st->control_url, transport); rtsp_send_cmd(s, cmd, reply, NULL); if (reply->status_code != RTSP_STATUS_OK || reply->nb_transports != 1) { err = AVERROR_INVALIDDATA; goto fail; } /* XXX: same protocol for all streams is required */ if (i > 0) { if (reply->transports[0].protocol != rt->protocol) { err = AVERROR_INVALIDDATA; goto fail; } } else { rt->protocol = reply->transports[0].protocol; } /* close RTP connection if not choosen */ if (reply->transports[0].protocol != RTSP_PROTOCOL_RTP_UDP && (protocol_mask & (1 << RTSP_PROTOCOL_RTP_UDP))) { url_close(rtsp_st->rtp_handle); rtsp_st->rtp_handle = NULL; } switch(reply->transports[0].protocol) { case RTSP_PROTOCOL_RTP_TCP: rtsp_st->interleaved_min = reply->transports[0].interleaved_min; rtsp_st->interleaved_max = reply->transports[0].interleaved_max; break; case RTSP_PROTOCOL_RTP_UDP: { char url[1024]; /* XXX: also use address if specified */ snprintf(url, sizeof(url), "rtp://%s:%d", host, reply->transports[0].server_port_min); if (rtp_set_remote_url(rtsp_st->rtp_handle, url) < 0) { err = AVERROR_INVALIDDATA; goto fail; } } break; case RTSP_PROTOCOL_RTP_UDP_MULTICAST: { char url[1024]; int ttl; ttl = reply->transports[0].ttl; if (!ttl) ttl = 16; snprintf(url, sizeof(url), "rtp://%s:%d?multicast=1&ttl=%d", host, reply->transports[0].server_port_min, ttl); if (url_open(&rtsp_st->rtp_handle, url, URL_RDONLY) < 0) { err = AVERROR_INVALIDDATA; goto fail; } } break; } /* open the RTP context */ st = NULL; if (rtsp_st->stream_index >= 0) st = s->streams[rtsp_st->stream_index]; if (!st) s->ctx_flags |= AVFMTCTX_NOHEADER; rtsp_st->rtp_ctx = rtp_parse_open(s, st, rtsp_st->sdp_payload_type, &rtsp_st->rtp_payload_data); if (!rtsp_st->rtp_ctx) { err = AVERROR_NOMEM; goto fail; } } /* use callback if available to extend setup */ if (ff_rtsp_callback) { if (ff_rtsp_callback(RTSP_ACTION_CLIENT_SETUP, rt->session_id, NULL, 0, rt->last_reply) < 0) { err = AVERROR_INVALIDDATA; goto fail; } } rt->state = RTSP_STATE_IDLE; rt->seek_timestamp = 0; /* default is to start stream at position zero */ if (ap->initial_pause) { /* do not start immediately */ } else { if (rtsp_read_play(s) < 0) { err = AVERROR_INVALIDDATA; goto fail; } } return 0; fail: rtsp_close_streams(rt); av_freep(&content); url_close(rt->rtsp_hd); return err; }
static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1, int letter, const char *buf) { RTSPState *rt = s->priv_data; char buf1[64], st_type[64]; const char *p; int codec_type, payload_type, i; AVStream *st; RTSPStream *rtsp_st; struct in_addr sdp_ip; int ttl; #ifdef DEBUG printf("sdp: %c='%s'\n", letter, buf); #endif p = buf; switch(letter) { case 'c': get_word(buf1, sizeof(buf1), &p); if (strcmp(buf1, "IN") != 0) return; get_word(buf1, sizeof(buf1), &p); if (strcmp(buf1, "IP4") != 0) return; get_word_sep(buf1, sizeof(buf1), "/", &p); if (inet_aton(buf1, &sdp_ip) == 0) return; ttl = 16; if (*p == '/') { p++; get_word_sep(buf1, sizeof(buf1), "/", &p); ttl = atoi(buf1); } if (s->nb_streams == 0) { s1->default_ip = sdp_ip; s1->default_ttl = ttl; } else { st = s->streams[s->nb_streams - 1]; rtsp_st = st->priv_data; rtsp_st->sdp_ip = sdp_ip; rtsp_st->sdp_ttl = ttl; } break; case 's': pstrcpy(s->title, sizeof(s->title), p); break; case 'i': if (s->nb_streams == 0) { pstrcpy(s->comment, sizeof(s->comment), p); break; } break; case 'm': /* new stream */ get_word(st_type, sizeof(st_type), &p); if (!strcmp(st_type, "audio")) { codec_type = CODEC_TYPE_AUDIO; } else if (!strcmp(st_type, "video")) { codec_type = CODEC_TYPE_VIDEO; } else { return; } rtsp_st = av_mallocz(sizeof(RTSPStream)); if (!rtsp_st) return; rtsp_st->stream_index = -1; dynarray_add(&rt->rtsp_streams, &rt->nb_rtsp_streams, rtsp_st); rtsp_st->sdp_ip = s1->default_ip; rtsp_st->sdp_ttl = s1->default_ttl; get_word(buf1, sizeof(buf1), &p); /* port */ rtsp_st->sdp_port = atoi(buf1); get_word(buf1, sizeof(buf1), &p); /* protocol (ignored) */ /* XXX: handle list of formats */ get_word(buf1, sizeof(buf1), &p); /* format list */ rtsp_st->sdp_payload_type = atoi(buf1); if (!strcmp(AVRtpPayloadTypes[rtsp_st->sdp_payload_type].enc_name, "MP2T")) { /* no corresponding stream */ } else { st = av_new_stream(s, 0); if (!st) return; st->priv_data = rtsp_st; rtsp_st->stream_index = st->index; st->codec->codec_type = codec_type; if (rtsp_st->sdp_payload_type < RTP_PT_PRIVATE) { /* if standard payload type, we can find the codec right now */ rtp_get_codec_info(st->codec, rtsp_st->sdp_payload_type); } } /* put a default control url */ pstrcpy(rtsp_st->control_url, sizeof(rtsp_st->control_url), s->filename); break; case 'a': if (strstart(p, "control:", &p) && s->nb_streams > 0) { char proto[32]; /* get the control url */ st = s->streams[s->nb_streams - 1]; rtsp_st = st->priv_data; /* XXX: may need to add full url resolution */ url_split(proto, sizeof(proto), NULL, 0, NULL, 0, NULL, NULL, 0, p); if (proto[0] == '\0') { /* relative control URL */ pstrcat(rtsp_st->control_url, sizeof(rtsp_st->control_url), "/"); pstrcat(rtsp_st->control_url, sizeof(rtsp_st->control_url), p); } else { pstrcpy(rtsp_st->control_url, sizeof(rtsp_st->control_url), p); } } else if (strstart(p, "rtpmap:", &p)) { /* NOTE: rtpmap is only supported AFTER the 'm=' tag */ get_word(buf1, sizeof(buf1), &p); payload_type = atoi(buf1); for(i = 0; i < s->nb_streams;i++) { st = s->streams[i]; rtsp_st = st->priv_data; if (rtsp_st->sdp_payload_type == payload_type) { sdp_parse_rtpmap(st->codec, payload_type, p); } } } else if (strstart(p, "fmtp:", &p)) { /* NOTE: fmtp is only supported AFTER the 'a=rtpmap:xxx' tag */ get_word(buf1, sizeof(buf1), &p); payload_type = atoi(buf1); for(i = 0; i < s->nb_streams;i++) { st = s->streams[i]; rtsp_st = st->priv_data; if (rtsp_st->sdp_payload_type == payload_type) { sdp_parse_fmtp(st, p); } } } break; } }
/* return non zero if error */ static int udp_open(URLContext *h, const char *uri, int flags) { char hostname[1024]; int port, udp_fd = -1, tmp; UDPContext *s = NULL; int is_output; const char *p; char buf[256]; #ifndef CONFIG_IPV6 struct sockaddr_in my_addr, my_addr1; int len; #endif h->is_streamed = 1; h->max_packet_size = 1472; is_output = (flags & URL_WRONLY); s = av_malloc(sizeof(UDPContext)); if (!s) return -ENOMEM; h->priv_data = s; s->ttl = 16; s->is_multicast = 0; s->local_port = 0; p = strchr(uri, '?'); if (p) { s->is_multicast = find_info_tag(buf, sizeof(buf), "multicast", p); if (find_info_tag(buf, sizeof(buf), "ttl", p)) { s->ttl = strtol(buf, NULL, 10); } if (find_info_tag(buf, sizeof(buf), "localport", p)) { s->local_port = strtol(buf, NULL, 10); } if (find_info_tag(buf, sizeof(buf), "pkt_size", p)) { h->max_packet_size = strtol(buf, NULL, 10); } } /* fill the dest addr */ url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri); /* XXX: fix url_split */ if (hostname[0] == '\0' || hostname[0] == '?') { /* only accepts null hostname if input */ if (s->is_multicast || (flags & URL_WRONLY)) goto fail; } else { udp_set_remote_url(h, uri); } #ifndef CONFIG_IPV6 udp_fd = socket(PF_INET, SOCK_DGRAM, 0); if (udp_fd < 0) goto fail; my_addr.sin_family = AF_INET; my_addr.sin_addr.s_addr = htonl (INADDR_ANY); if (s->is_multicast && !(h->flags & URL_WRONLY)) { /* special case: the bind must be done on the multicast address port */ my_addr.sin_port = s->dest_addr.sin_port; } else { my_addr.sin_port = htons(s->local_port); } /* the bind is needed to give a port to the socket now */ if (bind(udp_fd,(struct sockaddr *)&my_addr, sizeof(my_addr)) < 0) goto fail; len = sizeof(my_addr1); getsockname(udp_fd, (struct sockaddr *)&my_addr1, &len); s->local_port = ntohs(my_addr1.sin_port); #ifndef CONFIG_BEOS_NETSERVER if (s->is_multicast) { if (h->flags & URL_WRONLY) { /* output */ if (setsockopt(udp_fd, IPPROTO_IP, IP_MULTICAST_TTL, &s->ttl, sizeof(s->ttl)) < 0) { perror("IP_MULTICAST_TTL"); goto fail; } } else { /* input */ memset(&s->mreq, 0, sizeof(s->mreq)); s->mreq.imr_multiaddr = s->dest_addr.sin_addr; s->mreq.imr_interface.s_addr = htonl (INADDR_ANY); if (setsockopt(udp_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &s->mreq, sizeof(s->mreq)) < 0) { perror("rtp: IP_ADD_MEMBERSHIP"); goto fail; } } } #endif #else if (s->is_multicast && !(h->flags & URL_WRONLY)) s->local_port = port; udp_fd = udp_ipv6_set_local(h); if (udp_fd < 0) goto fail; #ifndef CONFIG_BEOS_NETSERVER if (s->is_multicast) { if (h->flags & URL_WRONLY) { if (udp_ipv6_set_multicast_ttl(udp_fd, s->ttl, (struct sockaddr *)&s->dest_addr) < 0) goto fail; } else { if (udp_ipv6_join_multicast_group(udp_fd, (struct sockaddr *)&s->dest_addr) < 0) goto fail; } } #endif #endif if (is_output) { /* limit the tx buf size to limit latency */ tmp = UDP_TX_BUF_SIZE; if (setsockopt(udp_fd, SOL_SOCKET, SO_SNDBUF, &tmp, sizeof(tmp)) < 0) { perror("setsockopt sndbuf"); goto fail; } } s->udp_fd = udp_fd; return 0; fail: if (udp_fd >= 0) #ifdef CONFIG_BEOS_NETSERVER closesocket(udp_fd); #else close(udp_fd); #endif av_free(s); return AVERROR_IO; }
/* return non zero if error */ static int http_open(URLContext *h, const char *uri, int flags) { const char *path, *proxy_path; char hostname[1024], hoststr[1024]; char auth[1024]; char path1[1024]; char buf[1024]; int port, use_proxy, err; HTTPContext *s; URLContext *hd = NULL; h->is_streamed = 1; s = av_malloc(sizeof(HTTPContext)); if (!s) { return -ENOMEM; } h->priv_data = s; proxy_path = getenv("http_proxy"); use_proxy = (proxy_path != NULL) && !getenv("no_proxy") && strstart(proxy_path, "http://", NULL); /* fill the dest addr */ redo: /* needed in any case to build the host string */ url_split(NULL, 0, auth, sizeof(auth), hostname, sizeof(hostname), &port, path1, sizeof(path1), uri); if (port > 0) { snprintf(hoststr, sizeof(hoststr), "%s:%d", hostname, port); } else { pstrcpy(hoststr, sizeof(hoststr), hostname); } if (use_proxy) { url_split(NULL, 0, auth, sizeof(auth), hostname, sizeof(hostname), &port, NULL, 0, proxy_path); path = uri; } else { if (path1[0] == '\0') path = "/"; else path = path1; } if (port < 0) port = 80; snprintf(buf, sizeof(buf), "tcp://%s:%d", hostname, port); err = url_open(&hd, buf, URL_RDWR); if (err < 0) goto fail; s->hd = hd; if (http_connect(h, path, hoststr, auth) < 0) goto fail; if (s->http_code == 303 && s->location[0] != '\0') { /* url moved, get next */ uri = s->location; url_close(hd); goto redo; } return 0; fail: if (hd) url_close(hd); av_free(s); return AVERROR_IO; }
/* return non zero if error */ static int tcp_open(URLContext *h, const char *uri, int flags) { struct sockaddr_in dest_addr; int port, fd = -1; TCPContext *s = NULL; fd_set wfds; int fd_max, ret; struct timeval tv; socklen_t optlen; char hostname[1024],proto[1024],path[1024]; if(!ff_network_init()) return AVERROR(EIO); url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port, path, sizeof(path), uri); if (strcmp(proto,"tcp") || port <= 0 || port >= 65536) return AVERROR(EINVAL); dest_addr.sin_family = AF_INET; dest_addr.sin_port = htons(port); if (resolve_host(&dest_addr.sin_addr, hostname) < 0) return AVERROR(EIO); fd = socket(AF_INET, SOCK_STREAM, 0); if (fd < 0) return AVERROR(EIO); ff_socket_nonblock(fd, 1); redo: ret = connect(fd, (struct sockaddr *)&dest_addr, sizeof(dest_addr)); if (ret < 0) { if (ff_neterrno() == FF_NETERROR(EINTR)) goto redo; if (ff_neterrno() != FF_NETERROR(EINPROGRESS) && ff_neterrno() != FF_NETERROR(EAGAIN)) goto fail; /* wait until we are connected or until abort */ for(;;) { if (url_interrupt_cb()) { ret = AVERROR(EINTR); goto fail1; } fd_max = fd; FD_ZERO(&wfds); FD_SET(fd, &wfds); tv.tv_sec = 0; tv.tv_usec = 100 * 1000; ret = select(fd_max + 1, NULL, &wfds, NULL, &tv); if (ret > 0 && FD_ISSET(fd, &wfds)) break; } /* test error */ optlen = sizeof(ret); getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen); if (ret != 0) goto fail; } s = av_malloc(sizeof(TCPContext)); if (!s) return AVERROR(ENOMEM); h->priv_data = s; h->is_streamed = 1; s->fd = fd; return 0; fail: ret = AVERROR(EIO); fail1: if (fd >= 0) closesocket(fd); return ret; }
static int rtsp_read_header(AVFormatContext *s, AVFormatParameters *ap) { RTSPState *rt = s->priv_data; char host[1024], path[1024], tcpname[1024], cmd[2048], *option_list, *option; URLContext *rtsp_hd; int port, ret, err; RTSPHeader reply1, *reply = &reply1; unsigned char *content = NULL; int protocol_mask = 0; /* extract hostname and port */ url_split(NULL, 0, NULL, 0, host, sizeof(host), &port, path, sizeof(path), s->filename); if (port < 0) port = RTSP_DEFAULT_PORT; /* search for options */ option_list = strchr(path, '?'); if (option_list) { /* remove the options from the path */ *option_list++ = 0; while(option_list) { /* move the option pointer */ option = option_list; option_list = strchr(option_list, '&'); if (option_list) *(option_list++) = 0; /* handle the options */ if (strcmp(option, "udp") == 0) protocol_mask = (1<< RTSP_PROTOCOL_RTP_UDP); else if (strcmp(option, "multicast") == 0) protocol_mask = (1<< RTSP_PROTOCOL_RTP_UDP_MULTICAST); else if (strcmp(option, "tcp") == 0) protocol_mask = (1<< RTSP_PROTOCOL_RTP_TCP); } } if (!protocol_mask) protocol_mask = (1 << RTSP_PROTOCOL_RTP_LAST) - 1; /* open the tcp connexion */ snprintf(tcpname, sizeof(tcpname), "tcp://%s:%d", host, port); if (url_open(&rtsp_hd, tcpname, URL_RDWR) < 0) return AVERROR(EIO); rt->rtsp_hd = rtsp_hd; rt->seq = 0; /* describe the stream */ snprintf(cmd, sizeof(cmd), "DESCRIBE %s RTSP/1.0\r\n" "Accept: application/sdp\r\n", s->filename); rtsp_send_cmd(s, cmd, reply, &content); if (!content) { err = AVERROR_INVALIDDATA; goto fail; } if (reply->status_code != RTSP_STATUS_OK) { err = AVERROR_INVALIDDATA; goto fail; } /* now we got the SDP description, we parse it */ ret = sdp_parse(s, (const char *)content); av_freep(&content); if (ret < 0) { err = AVERROR_INVALIDDATA; goto fail; } do { int protocol = ff_log2_tab[protocol_mask & ~(protocol_mask - 1)]; err = make_setup_request(s, host, port, protocol); if (err < 0) goto fail; protocol_mask &= ~(1 << protocol); if (protocol_mask == 0 && err == 1) { err = AVERROR(FF_NETERROR(EPROTONOSUPPORT)); goto fail; } } while (err); rt->state = RTSP_STATE_IDLE; rt->seek_timestamp = 0; /* default is to start stream at position zero */ if (ap->initial_pause) { /* do not start immediately */ } else { if (rtsp_read_play(s) < 0) { err = AVERROR_INVALIDDATA; goto fail; } } return 0; fail: rtsp_close_streams(rt); av_freep(&content); url_close(rt->rtsp_hd); return err; }
static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1, int letter, const char *buf) { RTSPState *rt = s->priv_data; char buf1[64], st_type[64]; const char *p; int codec_type, payload_type, i; AVStream *st; RTSPStream *rtsp_st; struct in_addr sdp_ip; int ttl; #ifdef DEBUG printf("sdp: %c='%s'\n", letter, buf); #endif p = buf; switch(letter) { case 'c': get_word(buf1, sizeof(buf1), &p); if (strcmp(buf1, "IN") != 0) return; get_word(buf1, sizeof(buf1), &p); if (strcmp(buf1, "IP4") != 0) return; get_word_sep(buf1, sizeof(buf1), "/", &p); if (inet_aton(buf1, &sdp_ip) == 0) return; ttl = 16; if (*p == '/') { p++; get_word_sep(buf1, sizeof(buf1), "/", &p); ttl = atoi(buf1); } if (s->nb_streams == 0) { s1->default_ip = sdp_ip; s1->default_ttl = ttl; } else { st = s->streams[s->nb_streams - 1]; rtsp_st = st->priv_data; rtsp_st->sdp_ip = sdp_ip; rtsp_st->sdp_ttl = ttl; } break; case 's': av_strlcpy(s->title, p, sizeof(s->title)); break; case 'i': if (s->nb_streams == 0) { av_strlcpy(s->comment, p, sizeof(s->comment)); break; } break; case 'm': /* new stream */ get_word(st_type, sizeof(st_type), &p); if (!strcmp(st_type, "audio")) { codec_type = CODEC_TYPE_AUDIO; } else if (!strcmp(st_type, "video")) { codec_type = CODEC_TYPE_VIDEO; } else { return; } rtsp_st = av_mallocz(sizeof(RTSPStream)); if (!rtsp_st) return; rtsp_st->stream_index = -1; dynarray_add(&rt->rtsp_streams, &rt->nb_rtsp_streams, rtsp_st); rtsp_st->sdp_ip = s1->default_ip; rtsp_st->sdp_ttl = s1->default_ttl; get_word(buf1, sizeof(buf1), &p); /* port */ rtsp_st->sdp_port = atoi(buf1); get_word(buf1, sizeof(buf1), &p); /* protocol (ignored) */ /* XXX: handle list of formats */ get_word(buf1, sizeof(buf1), &p); /* format list */ rtsp_st->sdp_payload_type = atoi(buf1); if (!strcmp(ff_rtp_enc_name(rtsp_st->sdp_payload_type), "MP2T")) { /* no corresponding stream */ } else { st = av_new_stream(s, 0); if (!st) return; st->priv_data = rtsp_st; rtsp_st->stream_index = st->index; st->codec->codec_type = codec_type; if (rtsp_st->sdp_payload_type < RTP_PT_PRIVATE) { /* if standard payload type, we can find the codec right now */ rtp_get_codec_info(st->codec, rtsp_st->sdp_payload_type); } } /* put a default control url */ av_strlcpy(rtsp_st->control_url, s->filename, sizeof(rtsp_st->control_url)); break; case 'a': if (av_strstart(p, "control:", &p) && s->nb_streams > 0) { char proto[32]; /* get the control url */ st = s->streams[s->nb_streams - 1]; rtsp_st = st->priv_data; /* XXX: may need to add full url resolution */ url_split(proto, sizeof(proto), NULL, 0, NULL, 0, NULL, NULL, 0, p); if (proto[0] == '\0') { /* relative control URL */ av_strlcat(rtsp_st->control_url, "/", sizeof(rtsp_st->control_url)); av_strlcat(rtsp_st->control_url, p, sizeof(rtsp_st->control_url)); } else { av_strlcpy(rtsp_st->control_url, p, sizeof(rtsp_st->control_url)); } } else if (av_strstart(p, "rtpmap:", &p)) { /* NOTE: rtpmap is only supported AFTER the 'm=' tag */ get_word(buf1, sizeof(buf1), &p); payload_type = atoi(buf1); for(i = 0; i < s->nb_streams;i++) { st = s->streams[i]; rtsp_st = st->priv_data; if (rtsp_st->sdp_payload_type == payload_type) { sdp_parse_rtpmap(st->codec, rtsp_st, payload_type, p); } } } else if (av_strstart(p, "fmtp:", &p)) { /* NOTE: fmtp is only supported AFTER the 'a=rtpmap:xxx' tag */ get_word(buf1, sizeof(buf1), &p); payload_type = atoi(buf1); for(i = 0; i < s->nb_streams;i++) { st = s->streams[i]; rtsp_st = st->priv_data; if (rtsp_st->sdp_payload_type == payload_type) { if(rtsp_st->dynamic_handler && rtsp_st->dynamic_handler->parse_sdp_a_line) { if(!rtsp_st->dynamic_handler->parse_sdp_a_line(st, rtsp_st->dynamic_protocol_context, buf)) { sdp_parse_fmtp(st, p); } } else { sdp_parse_fmtp(st, p); } } } } else if(av_strstart(p, "framesize:", &p)) { // let dynamic protocol handlers have a stab at the line. get_word(buf1, sizeof(buf1), &p); payload_type = atoi(buf1); for(i = 0; i < s->nb_streams;i++) { st = s->streams[i]; rtsp_st = st->priv_data; if (rtsp_st->sdp_payload_type == payload_type) { if(rtsp_st->dynamic_handler && rtsp_st->dynamic_handler->parse_sdp_a_line) { rtsp_st->dynamic_handler->parse_sdp_a_line(st, rtsp_st->dynamic_protocol_context, buf); } } } } else if(av_strstart(p, "range:", &p)) { int64_t start, end; // this is so that seeking on a streamed file can work. rtsp_parse_range_npt(p, &start, &end); s->start_time= start; s->duration= (end==AV_NOPTS_VALUE)?AV_NOPTS_VALUE:end-start; // AV_NOPTS_VALUE means live broadcast (and can't seek) } else if (s->nb_streams > 0) { rtsp_st = s->streams[s->nb_streams - 1]->priv_data; if (rtsp_st->dynamic_handler && rtsp_st->dynamic_handler->parse_sdp_a_line) rtsp_st->dynamic_handler->parse_sdp_a_line(s->streams[s->nb_streams - 1], rtsp_st->dynamic_protocol_context, buf); } break; } }
/* * url syntax: rtp://host:port[?option=val...] * option: 'multicast=1' : enable multicast * 'ttl=n' : set the ttl value (for multicast only) * 'localport=n' : set the local port to n * */ static int rtp_open(URLContext *h, const char *uri, int flags) { RTPContext *s; int port, is_output, is_multicast, ttl, local_port; char hostname[256]; char buf[1024]; char path[1024]; const char *p; is_output = (flags & URL_WRONLY); s = av_mallocz(sizeof(RTPContext)); if (!s) return AVERROR(ENOMEM); h->priv_data = s; url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, path, sizeof(path), uri); /* extract parameters */ is_multicast = 0; ttl = -1; local_port = -1; p = strchr(uri, '?'); if (p) { is_multicast = find_info_tag(buf, sizeof(buf), "multicast", p); if (find_info_tag(buf, sizeof(buf), "ttl", p)) { ttl = strtol(buf, NULL, 10); } if (find_info_tag(buf, sizeof(buf), "localport", p)) { local_port = strtol(buf, NULL, 10); } } build_udp_url(buf, sizeof(buf), hostname, port, local_port, is_multicast, ttl); if (url_open(&s->rtp_hd, buf, flags) < 0) goto fail; local_port = udp_get_local_port(s->rtp_hd); /* XXX: need to open another connexion if the port is not even */ /* well, should suppress localport in path */ build_udp_url(buf, sizeof(buf), hostname, port + 1, local_port + 1, is_multicast, ttl); if (url_open(&s->rtcp_hd, buf, flags) < 0) goto fail; /* just to ease handle access. XXX: need to suppress direct handle access */ s->rtp_fd = udp_get_file_handle(s->rtp_hd); s->rtcp_fd = udp_get_file_handle(s->rtcp_hd); h->max_packet_size = url_get_max_packet_size(s->rtp_hd); h->is_streamed = 1; return 0; fail: if (s->rtp_hd) url_close(s->rtp_hd); if (s->rtcp_hd) url_close(s->rtcp_hd); av_free(s); return AVERROR_IO; }
/* return zero if error */ static uint32 http_open(vfs_handler_t * dummy, const char *uri, int flags) { const char *path, *proxy_path; char hostname[128]; char path1[256]; int port, use_proxy, err; HTTPContext *s; file_t hd = -1; int wait = 0; if (flags & O_DIR) return 0; //h->is_streamed = 1; s = malloc(sizeof(HTTPContext)); if (!s) { return 0; } /* proxy_path = getenv("http_proxy"); */ /* use_proxy = (proxy_path != NULL) && !getenv("no_proxy") && */ /* strstart(proxy_path, "http://", NULL); */ use_proxy = 0; s->nb_header_entries = 0; /* fill the dest addr */ redo: /* needed in any case to build the host string */ url_split(NULL, 0, hostname, sizeof(hostname), &port, path1, sizeof(path1), uri); if (port > 0) { snprintf(s->hoststr, sizeof(s->hoststr), "%s:%d", hostname, port); } else { pstrcpy(s->hoststr, sizeof(s->hoststr), hostname); } if (use_proxy) { url_split(NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, proxy_path); path = uri; } else { if (path1[0] == '\0') path = "/"; else path = path1; } if (port < 0) port = 80; snprintf(s->location, sizeof(s->location), "/tcp/%s:%d", hostname, port); //printf("HTTPFS : opening '%s' '%s'\n", s->location, path); redo2: hd = fs_open(s->location, O_RDWR); err = hd >= 0? 0:-1; // err = url_open(&hd, buf, URL_RDWR); if (err < 0) goto fail; s->hd = hd; strcpy(s->path, path); s->flags = flags; if (http_connect(s, path, s->hoststr, flags, wait) < 0) { if (0&&wait <= 2000) { /* try again with a sleep */ wait += 1000; fs_close(hd); hd = -1; goto redo2; } goto fail; } if ((s->http_code == 303 || s->http_code == 302) && s->location[0] != '\0') { /* url moved, get next */ uri = s->location+6; #ifdef DEBUG printf("URL moved get next '%s'\n", uri); #endif fs_close(hd); hd = -1; //wait = 4000; goto redo; } if (s->http_code != 200) goto fail; return (uint32) s; fail: hdr_clear(s); if (hd>=0) fs_close(hd); free(s); return 0; }
/* return non zero if error */ static int udp_open(URLContext *h, const char *uri, int flags) { char hostname[1024]; int port, udp_fd = -1, tmp, bind_ret = -1; UDPContext *s = NULL; int is_output; const char *p; char buf[256]; #if !CONFIG_IPV6 struct sockaddr_in my_addr; #else struct sockaddr_storage my_addr; #endif int len; h->is_streamed = 1; h->max_packet_size = 1472; is_output = (flags & URL_WRONLY); if(!ff_network_init()) return AVERROR(EIO); s = av_mallocz(sizeof(UDPContext)); if (!s) return AVERROR(ENOMEM); h->priv_data = s; s->ttl = 16; s->buffer_size = is_output ? UDP_TX_BUF_SIZE : UDP_MAX_PKT_SIZE; p = strchr(uri, '?'); if (p) { s->reuse_socket = find_info_tag(buf, sizeof(buf), "reuse", p); if (find_info_tag(buf, sizeof(buf), "ttl", p)) { s->ttl = strtol(buf, NULL, 10); } if (find_info_tag(buf, sizeof(buf), "localport", p)) { s->local_port = strtol(buf, NULL, 10); } if (find_info_tag(buf, sizeof(buf), "pkt_size", p)) { h->max_packet_size = strtol(buf, NULL, 10); } if (find_info_tag(buf, sizeof(buf), "buffer_size", p)) { s->buffer_size = strtol(buf, NULL, 10); } } /* fill the dest addr */ url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri); /* XXX: fix url_split */ if (hostname[0] == '\0' || hostname[0] == '?') { /* only accepts null hostname if input */ if (flags & URL_WRONLY) goto fail; } else { udp_set_remote_url(h, uri); } if (s->is_multicast && !(h->flags & URL_WRONLY)) s->local_port = port; udp_fd = udp_socket_create(s, &my_addr, &len); if (udp_fd < 0) goto fail; if (s->reuse_socket) if (setsockopt (udp_fd, SOL_SOCKET, SO_REUSEADDR, &(s->reuse_socket), sizeof(s->reuse_socket)) != 0) goto fail; /* the bind is needed to give a port to the socket now */ /* if multicast, try the multicast address bind first */ if (s->is_multicast && !(h->flags & URL_WRONLY)) { bind_ret = bind(udp_fd,(struct sockaddr *)&s->dest_addr, len); } /* bind to the local address if not multicast or if the multicast * bind failed */ if (bind_ret < 0 && bind(udp_fd,(struct sockaddr *)&my_addr, len) < 0) goto fail; len = sizeof(my_addr); getsockname(udp_fd, (struct sockaddr *)&my_addr, &len); s->local_port = udp_port(&my_addr, len); if (s->is_multicast) { if (h->flags & URL_WRONLY) { /* output */ if (udp_set_multicast_ttl(udp_fd, s->ttl, (struct sockaddr *)&s->dest_addr) < 0) goto fail; } else { /* input */ if (udp_join_multicast_group(udp_fd, (struct sockaddr *)&s->dest_addr) < 0) goto fail; } } if (is_output) { /* limit the tx buf size to limit latency */ tmp = s->buffer_size; if (setsockopt(udp_fd, SOL_SOCKET, SO_SNDBUF, &tmp, sizeof(tmp)) < 0) { av_log(NULL, AV_LOG_ERROR, "setsockopt(SO_SNDBUF): %s\n", strerror(errno)); goto fail; } } else { /* set udp recv buffer size to the largest possible udp packet size to * avoid losing data on OSes that set this too low by default. */ tmp = s->buffer_size; if (setsockopt(udp_fd, SOL_SOCKET, SO_RCVBUF, &tmp, sizeof(tmp)) < 0) { av_log(NULL, AV_LOG_WARNING, "setsockopt(SO_RECVBUF): %s\n", strerror(errno)); } /* make the socket non-blocking */ ff_socket_nonblock(udp_fd, 1); } s->udp_fd = udp_fd; return 0; fail: if (udp_fd >= 0) closesocket(udp_fd); av_free(s); return AVERROR(EIO); }
/* return non zero if error */ static int tcp_open(URLContext *h, const char *uri, int flags) { struct sockaddr_in dest_addr; char hostname[1024], *q; int port, fd = -1; TCPContext *s; const char *p; fd_set wfds; int fd_max, ret; struct timeval tv; socklen_t optlen; char proto[1024],path[1024],tmp[1024]; // PETR: protocol and path strings url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port, path, sizeof(path), uri); // PETR: use url_split if (strcmp(proto,"tcp")) goto fail; // PETR: check protocol if ((q = strchr(hostname,'@'))) { strcpy(tmp,q+1); strcpy(hostname,tmp); } // PETR: take only the part after '@' for tcp protocol s = av_malloc(sizeof(TCPContext)); if (!s) return -ENOMEM; h->priv_data = s; if (port <= 0 || port >= 65536) goto fail; dest_addr.sin_family = AF_INET; dest_addr.sin_port = htons(port); if (resolve_host(&dest_addr.sin_addr, hostname) < 0) goto fail; fd = socket(PF_INET, SOCK_STREAM, 0); if (fd < 0) goto fail; fcntl(fd, F_SETFL, O_NONBLOCK); redo: ret = connect(fd, (struct sockaddr *)&dest_addr, sizeof(dest_addr)); if (ret < 0) { if (errno == EINTR) goto redo; if (errno != EINPROGRESS) goto fail; /* wait until we are connected or until abort */ for(;;) { if (url_interrupt_cb()) { ret = -EINTR; goto fail1; } fd_max = fd; FD_ZERO(&wfds); FD_SET(fd, &wfds); tv.tv_sec = 0; tv.tv_usec = 100 * 1000; ret = select(fd_max + 1, NULL, &wfds, NULL, &tv); if (ret > 0 && FD_ISSET(fd, &wfds)) break; } /* test error */ optlen = sizeof(ret); getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen); if (ret != 0) goto fail; } s->fd = fd; return 0; fail: ret = AVERROR_IO; fail1: if (fd >= 0) close(fd); av_free(s); return ret; }