diff --git a/openbsc/src/libtrau/rtp_proxy.c b/openbsc/src/libtrau/rtp_proxy.c index 3d34ac6..8e705e4 100644 --- a/openbsc/src/libtrau/rtp_proxy.c +++ b/openbsc/src/libtrau/rtp_proxy.c @@ -560,13 +560,17 @@ struct rtp_socket *rtp_socket_create(void) return rs; out_rtcp_bfd: - osmo_fd_unregister(&rs->rtcp.bfd); + if (rs->rtcp.bfd.fd > 0) { + osmo_fd_unregister(&rs->rtcp.bfd); out_rtcp_socket: - close(rs->rtcp.bfd.fd); + close(rs->rtcp.bfd.fd); + } out_rtp_bfd: - osmo_fd_unregister(&rs->rtp.bfd); + if (rs->rtp.bfd.fd > 0) { + osmo_fd_unregister(&rs->rtp.bfd); out_rtp_socket: - close(rs->rtp.bfd.fd); + close(rs->rtp.bfd.fd); + } out_free: talloc_free(rs); DEBUGPC(DLMUX, "failed\n"); @@ -595,29 +599,53 @@ static int rtp_sub_socket_bind(struct rtp_sub_socket *rss, uint32_t ip, &alen); } -#define RTP_PORT_BASE 30000 -static unsigned int next_udp_port = RTP_PORT_BASE; +#define RTP_PORT_BASE 30000 +#define RTP_PORT_MAX 39998 +static unsigned short next_udp_port = RTP_PORT_BASE; /* bind a RTP socket to a local address */ int rtp_socket_bind(struct rtp_socket *rs, uint32_t ip) { - int rc = -EIO; + int rc, rc2; struct in_addr ia; + unsigned short start_port; ia.s_addr = htonl(ip); DEBUGP(DLMUX, "rtp_socket_bind(rs=%p, IP=%s): ", rs, inet_ntoa(ia)); /* try to bind to a consecutive pair of ports */ - for (next_udp_port = next_udp_port % 0xffff; - next_udp_port < 0xffff; next_udp_port += 2) { + start_port = next_udp_port; + while (1) { rc = rtp_sub_socket_bind(&rs->rtp, ip, next_udp_port); if (rc != 0) - continue; + goto try_next_port; rc = rtp_sub_socket_bind(&rs->rtcp, ip, next_udp_port+1); - if (rc == 0) + if (rc == 0) { + next_udp_port = (next_udp_port + 2 > RTP_PORT_MAX) ? + RTP_PORT_BASE : next_udp_port + 2; + break; + } + /* reopen rtp socket and try again with next udp port */ + osmo_fd_unregister(&rs->rtp.bfd); + close(rs->rtp.bfd.fd); + rs->rtp.bfd.fd = 0; + rc2 = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (rc2 < 0) + return rc2; + init_rss(&rs->rtp, rs, rc2, RTP_PRIV_RTP); + rc2 = osmo_fd_register(&rs->rtp.bfd); + if (rc2 < 0) { + close(rs->rtp.bfd.fd); + return rc2; + } +try_next_port: + next_udp_port = (next_udp_port + 2 > RTP_PORT_MAX) ? + RTP_PORT_BASE : next_udp_port + 2; + if (next_udp_port == start_port) break; + /* we must use rc2, in order to preserve rc */ } if (rc < 0) { DEBUGPC(DLMUX, "failed\n");