aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Storsjö <martin@martin.st>2013-08-13 13:20:42 +0300
committerMartin Storsjö <martin@martin.st>2013-08-14 11:21:32 +0300
commit6b58e11a8331690ec32e9869db89ae10c54614e9 (patch)
treecaff2e9ae6d1d6738e5d4742c8c3dea8ba77c88c
parent2427ac6ccd868811d1fe9df7c64c50ca58abe6f6 (diff)
downloadffmpeg-6b58e11a8331690ec32e9869db89ae10c54614e9.tar.gz
rtpproto: Add an option for writing return packets to the address of the last received packets
If we've received packets on the same socket before, the return packets are sent to that address. If we've only received packets on the other socket, try to guess the source port for the other one assuming the basic +1/-1 logic. Signed-off-by: Martin Storsjö <martin@martin.st>
-rw-r--r--libavformat/rtpproto.c89
1 files changed, 84 insertions, 5 deletions
diff --git a/libavformat/rtpproto.c b/libavformat/rtpproto.c
index 27ea37099a..6fa3182c96 100644
--- a/libavformat/rtpproto.c
+++ b/libavformat/rtpproto.c
@@ -45,6 +45,9 @@ typedef struct RTPContext {
URLContext *rtp_hd, *rtcp_hd;
int rtp_fd, rtcp_fd, nb_ssm_include_addrs, nb_ssm_exclude_addrs;
struct sockaddr_storage **ssm_include_addrs, **ssm_exclude_addrs;
+ int write_to_source;
+ struct sockaddr_storage last_rtp_source, last_rtcp_source;
+ socklen_t last_rtp_source_len, last_rtcp_source_len;
} RTPContext;
/**
@@ -125,6 +128,27 @@ static int compare_addr(const struct sockaddr_storage *a,
return 1;
}
+static int get_port(const struct sockaddr_storage *ss)
+{
+ if (ss->ss_family == AF_INET)
+ return ntohs(((const struct sockaddr_in *)ss)->sin_port);
+#ifdef AF_INET6
+ if (ss->ss_family == AF_INET6)
+ return ntohs(((const struct sockaddr_in6 *)ss)->sin6_port);
+#endif
+ return 0;
+}
+
+static void set_port(struct sockaddr_storage *ss, int port)
+{
+ if (ss->ss_family == AF_INET)
+ ((struct sockaddr_in *)ss)->sin_port = htons(port);
+#ifdef AF_INET6
+ else if (ss->ss_family == AF_INET6)
+ ((struct sockaddr_in6 *)ss)->sin6_port = htons(port);
+#endif
+}
+
static int rtp_check_source_lists(RTPContext *s, struct sockaddr_storage *source_addr_ptr)
{
int i;
@@ -236,6 +260,7 @@ static void rtp_parse_addr_list(URLContext *h, char *buf,
* 'connect=0/1' : do a connect() on the UDP socket
* 'sources=ip[,ip]' : list allowed source IP addresses
* 'block=ip[,ip]' : list disallowed source IP addresses
+ * 'write_to_source=0/1' : send packets to the source address of the latest received packet
* deprecated option:
* 'localport=n' : set the local port to n
*
@@ -289,6 +314,9 @@ static int rtp_open(URLContext *h, const char *uri, int flags)
if (av_find_info_tag(buf, sizeof(buf), "connect", p)) {
connect = strtol(buf, NULL, 10);
}
+ if (av_find_info_tag(buf, sizeof(buf), "write_to_source", p)) {
+ s->write_to_source = strtol(buf, NULL, 10);
+ }
if (av_find_info_tag(buf, sizeof(buf), "sources", p)) {
av_strlcpy(include_sources, buf, sizeof(include_sources));
rtp_parse_addr_list(h, buf, &s->ssm_include_addrs, &s->nb_ssm_include_addrs);
@@ -333,11 +361,11 @@ static int rtp_open(URLContext *h, const char *uri, int flags)
static int rtp_read(URLContext *h, uint8_t *buf, int size)
{
RTPContext *s = h->priv_data;
- struct sockaddr_storage from;
- socklen_t from_len;
int len, n, i;
struct pollfd p[2] = {{s->rtp_fd, POLLIN, 0}, {s->rtcp_fd, POLLIN, 0}};
int poll_delay = h->flags & AVIO_FLAG_NONBLOCK ? 0 : 100;
+ struct sockaddr_storage *addrs[2] = { &s->last_rtp_source, &s->last_rtcp_source };
+ socklen_t *addr_lens[2] = { &s->last_rtp_source_len, &s->last_rtcp_source_len };
for(;;) {
if (ff_check_interrupt(&h->interrupt_callback))
@@ -348,16 +376,16 @@ static int rtp_read(URLContext *h, uint8_t *buf, int size)
for (i = 1; i >= 0; i--) {
if (!(p[i].revents & POLLIN))
continue;
- from_len = sizeof(from);
+ *addr_lens[i] = sizeof(*addrs[i]);
len = recvfrom(p[i].fd, buf, size, 0,
- (struct sockaddr *)&from, &from_len);
+ (struct sockaddr *)addrs[i], addr_lens[i]);
if (len < 0) {
if (ff_neterrno() == AVERROR(EAGAIN) ||
ff_neterrno() == AVERROR(EINTR))
continue;
return AVERROR(EIO);
}
- if (rtp_check_source_lists(s, &from))
+ if (rtp_check_source_lists(s, addrs[i]))
continue;
return len;
}
@@ -381,6 +409,57 @@ static int rtp_write(URLContext *h, const uint8_t *buf, int size)
if (size < 2)
return AVERROR(EINVAL);
+ if (s->write_to_source) {
+ int fd;
+ struct sockaddr_storage *source, temp_source;
+ socklen_t *source_len, temp_len;
+ if (!s->last_rtp_source.ss_family && !s->last_rtcp_source.ss_family) {
+ av_log(h, AV_LOG_ERROR,
+ "Unable to send packet to source, no packets received yet\n");
+ // Intentionally not returning an error here
+ return size;
+ }
+
+ if (RTP_PT_IS_RTCP(buf[1])) {
+ fd = s->rtcp_fd;
+ source = &s->last_rtcp_source;
+ source_len = &s->last_rtcp_source_len;
+ } else {
+ fd = s->rtp_fd;
+ source = &s->last_rtp_source;
+ source_len = &s->last_rtp_source_len;
+ }
+ if (!source->ss_family) {
+ source = &temp_source;
+ source_len = &temp_len;
+ if (RTP_PT_IS_RTCP(buf[1])) {
+ temp_source = s->last_rtp_source;
+ temp_len = s->last_rtp_source_len;
+ set_port(source, get_port(source) + 1);
+ av_log(h, AV_LOG_INFO,
+ "Not received any RTCP packets yet, inferring peer port "
+ "from the RTP port\n");
+ } else {
+ temp_source = s->last_rtcp_source;
+ temp_len = s->last_rtcp_source_len;
+ set_port(source, get_port(source) - 1);
+ av_log(h, AV_LOG_INFO,
+ "Not received any RTP packets yet, inferring peer port "
+ "from the RTCP port\n");
+ }
+ }
+
+ if (!(h->flags & AVIO_FLAG_NONBLOCK)) {
+ ret = ff_network_wait_fd(fd, 1);
+ if (ret < 0)
+ return ret;
+ }
+ ret = sendto(fd, buf, size, 0, (struct sockaddr *) source,
+ *source_len);
+
+ return ret < 0 ? ff_neterrno() : ret;
+ }
+
if (RTP_PT_IS_RTCP(buf[1])) {
/* RTCP payload type */
hd = s->rtcp_hd;