.number = 6,
},
{
- .name = N_("Miscellaneous Settings"),
+ .name = N_("Ports settings"),
.number = 7,
},
+ {
+ .name = N_("Miscellaneous Settings"),
+ .number = 8,
+ },
{}
},
.ic_properties = (const property_t[]){
,
.group = 6
},
+ {
+ .type = PT_INT,
+ .id = "rtsp_udp_min_port",
+ .name = N_("RTSP UDP minimum port"),
+ .desc = N_("When using RTSP IPTV, this correspond to the "
+ "minimum port bind on the client (this server), "
+ "sent to the server. This is especially useful "
+ "when using firewalls and NAT or containers."),
+ .off = offsetof(config_t, rtsp_udp_min_port),
+ .opts = PO_EXPERT,
+ .group = 7,
+ },
+ {
+ .type = PT_INT,
+ .id = "rtsp_udp_max_port",
+ .name = N_("RTSP UDP maximum port"),
+ .desc = N_("Same as above, but for the maximum allowed "
+ "port. Note that each stream requires two ports."),
+ .off = offsetof(config_t, rtsp_udp_max_port),
+ .opts = PO_EXPERT,
+ .group = 7,
+ },
{
.type = PT_STR,
.id = "http_user_agent",
.desc = N_("The user agent string for the build-in HTTP client."),
.off = offsetof(config_t, http_user_agent),
.opts = PO_HIDDEN | PO_EXPERT,
- .group = 7,
+ .group = 8,
},
{
.type = PT_INT,
.desc = N_("Set the number of threads for IPTV to split load "
"across more CPUs."),
.off = offsetof(config_t, iptv_tpool_count),
- .group = 7,
+ .group = 8,
},
{
.type = PT_INT,
.off = offsetof(config_t, dscp),
.list = config_class_dscp_list,
.opts = PO_EXPERT | PO_DOC_NLIST,
- .group = 7,
+ .group = 8,
},
{
.type = PT_U32,
"there is a delay receiving CA keys. "),
.off = offsetof(config_t, descrambler_buffer),
.opts = PO_EXPERT,
- .group = 7,
+ .group = 8,
},
{
.type = PT_BOOL,
"It may cause issues with some clients / players."),
.off = offsetof(config_t, parser_backlog),
.opts = PO_EXPERT,
- .group = 7,
+ .group = 8,
},
{
.type = PT_STR,
.off = offsetof(config_t, muxconf_path),
.notify = config_muxconfpath_notify,
.opts = PO_ADVANCED,
- .group = 7,
+ .group = 8,
},
{
.type = PT_BOOL,
.name = N_("Parse HbbTV info"),
.desc = N_("Parse HbbTV information from services."),
.off = offsetof(config_t, hbbtv),
- .group = 7,
+ .group = 8,
.def.i = 1,
},
{
"the system clock (normally only root)."),
.off = offsetof(config_t, tvhtime_update_enabled),
.opts = PO_EXPERT,
- .group = 7,
+ .group = 8,
},
{
.type = PT_BOOL,
"performance is not that great."),
.off = offsetof(config_t, tvhtime_ntp_enabled),
.opts = PO_EXPERT,
- .group = 7,
+ .group = 8,
},
{
.type = PT_U32,
"excessive oscillations on the system clock."),
.off = offsetof(config_t, tvhtime_tolerance),
.opts = PO_EXPERT,
- .group = 7,
+ .group = 8,
},
#if ENABLE_VAAPI
{
char *hdhomerun_ip;
char *local_ip;
int local_port;
+ int rtsp_udp_min_port;
+ int rtsp_udp_max_port;
uint32_t hdhomerun_server_tuner_count;
char *hdhomerun_server_model_name;
int hdhomerun_server_enable;
if (info->connection == NULL) {
rtcp_conn = udp_bind(LS_IPTV, nicename, NULL, 0, NULL, interface,
- IPTV_BUF_SIZE, 1024);
+ IPTV_BUF_SIZE, 1024, 0);
if (rtcp_conn == NULL || rtcp_conn == UDP_FATAL_ERROR) {
tvhwarn(LS_IPTV, "%s - Unable to bind, RTCP won't be available",
nicename);
*/
#include "tvheadend.h"
+#include "config.h"
#include "iptv_private.h"
#include "iptv_rtcp.h"
#include "http.h"
http_client_t *hc;
udp_connection_t *rtp, *rtcp;
int r;
+ int rtp_port;
+ int max_rtp_port;
if (!(hc = http_client_connect(im, RTSP_VERSION_1_0, u->scheme,
u->host, u->port, NULL)))
hc->hc_rtsp_user = strdup(u->user);
if (u->pass)
hc->hc_rtsp_pass = strdup(u->pass);
+
+ rtp_port = config.rtsp_udp_min_port;
+ max_rtp_port = config.rtsp_udp_max_port;
- if (udp_bind_double(&rtp, &rtcp,
- LS_IPTV, "rtp", "rtcp",
- NULL, 0, NULL,
- 128*1024, 16384, 4*1024, 4*1024) < 0) {
+ if (!max_rtp_port) {
+ rtp_port = 0;
+ }
+
+ if (rtp_port > max_rtp_port)
+ {
+ tvherror(LS_IPTV, "UDP minimum port is set higher than the UDP maximum port");
http_client_close(hc);
return SM_CODE_TUNING_FAILED;
}
+ while (udp_bind_double(&rtp, &rtcp,
+ LS_IPTV, "rtp", "rtcp",
+ NULL, rtp_port, NULL,
+ 128 * 1024, 16384, 4 * 1024, 4 * 1024, 1) < 0)
+ {
+ if (!rtp_port) {
+ tvherror(LS_IPTV, "could not bind a random UDP port for RTP");
+ http_client_close(hc);
+ return SM_CODE_TUNING_FAILED;
+ } else if (max_rtp_port && rtp_port >= max_rtp_port - 2) {
+ tvherror(LS_IPTV, "all the UDP ports allocated are used, please reduce the number of simultaneous IPTV streams or increase the number of ports in the global settings");
+ http_client_close(hc);
+ return SM_CODE_TUNING_FAILED;
+ }
+ rtp_port += 2;
+ }
+
hc->hc_hdr_received = iptv_rtsp_header;
hc->hc_data_received = iptv_rtsp_data;
hc->hc_handle_location = 1; /* allow redirects */
/* Note: url->user is used for specifying multicast source address (SSM)
here. The URL format is rtp://<srcaddr>@<grpaddr>:<port> */
conn = udp_bind(LS_IPTV, im->mm_nicename, url->host, url->port, url->user,
- im->mm_iptv_interface, IPTV_BUF_SIZE, 4*1024);
+ im->mm_iptv_interface, IPTV_BUF_SIZE, 4*1024, 0);
if (conn == UDP_FATAL_ERROR)
return SM_CODE_TUNING_FAILED;
if (conn == NULL)
if (udp_bind_double(&rtp, &rtcp,
LS_SATIP, "rtp", "rtcp",
satip_frontend_bindaddr(lfe), lfe->sf_udp_rtp_port,
- NULL, SATIP_BUF_SIZE, 16384, 4*1024, 4*1024) < 0) {
+ NULL, SATIP_BUF_SIZE, 16384, 4*1024, 4*1024, 0) < 0) {
satip_frontend_tuning_error(lfe, tr);
goto done;
}
LS_SATIPS, "rtsp", "rtcp",
(rtp_src_ip != NULL && rtp_src_ip[0] != '\0') ? rtp_src_ip : rtsp_ip, 0, NULL,
4*1024, 4*1024,
- RTP_BUFSIZE, RTCP_BUFSIZE)) {
+ RTP_BUFSIZE, RTCP_BUFSIZE, 0)) {
errcode = HTTP_STATUS_INTERNAL;
goto error;
}
udp_connection_t *
udp_bind ( int subsystem, const char *name,
const char *bindaddr, int port, const char *multicast_src,
- const char *ifname, int rxsize, int txsize )
+ const char *ifname, int rxsize, int txsize, int bind_fail_allowed )
{
int fd, ifindex, reuse = 1;
udp_connection_t *uc;
uc->fd = fd;
- /* Mark reuse address */
- if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse))) {
+ /* Mark reuse address, only wanted and required for Multicast in UDP (and TCP, but not here, then) */
+ if (uc->multicast && setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse))) {
tvherror(subsystem, "%s - failed to reuse address for socket [%s]",
name, strerror(errno));
udp_close(uc);
/* Bind useful for receiver subsystem (not for udp streamer) */
if (subsystem != LS_UDP) {
if (bind(fd, (struct sockaddr *)&uc->ip, sizeof(struct sockaddr_in))) {
- inet_ntop(AF_INET, &IP_AS_V4(&uc->ip, addr), buf, sizeof(buf));
- tvherror(subsystem, "%s - cannot bind %s:%hu [e=%s]",
- name, buf, ntohs(IP_AS_V4(&uc->ip, port)), strerror(errno));
+ if (!bind_fail_allowed) {
+ inet_ntop(AF_INET, &IP_AS_V4(&uc->ip, addr), buf, sizeof(buf));
+ tvherror(subsystem, "%s - cannot bind %s:%hu [e=%s]",
+ name, buf, ntohs(IP_AS_V4(&uc->ip, port)), strerror(errno));
+ }
goto error;
}
}
/* Bind */
if (bind(fd, (struct sockaddr *)&uc->ip, sizeof(struct sockaddr_in6))) {
- inet_ntop(AF_INET6, &IP_AS_V6(&uc->ip, addr), buf, sizeof(buf));
- tvherror(subsystem, "%s - cannot bind %s:%hu [e=%s]",
- name, buf, ntohs(IP_AS_V6(&uc->ip, port)), strerror(errno));
+ if (!bind_fail_allowed) {
+ inet_ntop(AF_INET6, &IP_AS_V6(&uc->ip, addr), buf, sizeof(buf));
+ tvherror(subsystem, "%s - cannot bind %s:%hu [e=%s]",
+ name, buf, ntohs(IP_AS_V6(&uc->ip, port)), strerror(errno));
+ }
goto error;
}
int subsystem, const char *name1,
const char *name2, const char *host, int port,
const char *ifname, int rxsize1, int rxsize2,
- int txsize1, int txsize2 )
+ int txsize1, int txsize2, int bind_fail_allowed )
{
udp_connection_t *u1 = NULL, *u2 = NULL;
udp_connection_t *ucs[10];
memset(&ucs, 0, sizeof(ucs));
while (1) {
- u1 = udp_bind(subsystem, name1, host, port, NULL, ifname, rxsize1, txsize1);
+ u1 = udp_bind(subsystem, name1, host, port, NULL, ifname, rxsize1, txsize1, bind_fail_allowed);
if (u1 == NULL || u1 == UDP_FATAL_ERROR)
goto fail;
port2 = ntohs(IP_PORT(u1->ip));
/* RTP port should be even, RTCP port should be odd */
if ((port2 % 2) == 0) {
- u2 = udp_bind(subsystem, name2, host, port2 + 1, NULL, ifname, rxsize2, txsize2);
+ u2 = udp_bind(subsystem, name2, host, port2 + 1, NULL, ifname, rxsize2, txsize2, bind_fail_allowed);
if (u2 != NULL && u2 != UDP_FATAL_ERROR)
break;
}
udp_connection_t *
udp_bind ( int subsystem, const char *name,
const char *bindaddr, int port, const char *multicast_src,
- const char *ifname, int rxsize, int txsize );
+ const char *ifname, int rxsize, int txsize, int bind_fail_allowed );
int
udp_bind_double ( udp_connection_t **_u1, udp_connection_t **_u2,
int subsystem, const char *name1,
const char *name2, const char *host, int port,
const char *ifname, int rxsize1, int rxsize2,
- int txsize1, int txsize2 );
+ int txsize1, int txsize2, int bind_fail_allowed );
udp_connection_t *
udp_sendinit ( int subsystem, const char *name,
const char *ifname, int txsize );
multicast = udp_bind(LS_UPNP, "upnp_thread_multicast",
"239.255.255.250", 1900, NULL,
- NULL, 32*1024, 32*1024);
+ NULL, 32*1024, 32*1024, 0);
if (multicast == NULL || multicast == UDP_FATAL_ERROR)
goto error;
unicast = udp_bind(LS_UPNP, "upnp_thread_unicast", bindaddr, 0, NULL,
- NULL, 32*1024, 32*1024);
+ NULL, 32*1024, 32*1024, 0);
if (unicast == NULL || unicast == UDP_FATAL_ERROR)
goto error;
if (!(uc = udp_bind(LS_UDP, "udp_streamer",
address, port, NULL,
- NULL, 1024, 188*7))) {
+ NULL, 1024, 188*7, 0))) {
tvhwarn(LS_WEBUI, "Could not create and bind udp socket");
return res;
}
if (!(uc = udp_bind(LS_UDP, "udp_streamer",
address, port, NULL,
- NULL, 1024, 188*7))) {
+ NULL, 1024, 188*7, 0))) {
tvhwarn(LS_WEBUI, "Could not create and bind udp socket");
return res;
}