htsbuf_append(&q, MSG, sizeof(MSG)-1);
htsbuf_qprintf(&q, "USER-AGENT: unix/1.0 UPnP/1.1 tvheadend/%s\r\n", tvheadend_version);
htsbuf_append(&q, "\r\n", 2);
- upnp_send(&q, NULL, 0, 0);
+ upnp_send(&q, NULL, 0, 0, 0);
htsbuf_queue_flush(&q);
mtimer_arm_rel(&satip_discovery_msearch_timer, satip_discovery_send_msearch,
reg = 1;
}
s = rtsp_ip;
- rtsp_ip = strdup(bindaddr);
+ if(bindaddr != NULL)
+ rtsp_ip = strdup(bindaddr);
free(s);
rtsp_port = port;
rtsp_descramble = descramble;
char buf[sizeof(MSG) + 1024], buf2[64], purl[128];
const char *cs;
+ char addrbuf[50];
char *devicelist = NULL;
htsbuf_queue_t q;
mpegts_network_t *mn;
{}
};
- if (http_server_ip == NULL)
+ if (http_server_port == 0)
return HTTP_STATUS_NOT_FOUND;
htsbuf_queue_init(&q, 0);
tvheadend_webroot ?: "", cs);
}
+ char* own_server_ip = http_server_ip;
+
+ if(own_server_ip == NULL) {
+ tcp_get_str_from_ip(hc->hc_self, addrbuf, sizeof(addrbuf));
+ own_server_ip = addrbuf;
+ }
+
snprintf(buf, sizeof(buf), MSG,
config_get_server_name(),
buf2, tvheadend_version,
satip_server_conf.satip_uuid,
- http_server_ip, http_server_port,
- http_server_ip, http_server_port,
- http_server_ip, http_server_port,
- http_server_ip, http_server_port,
- http_server_ip, http_server_port,
+ own_server_ip, http_server_port,
+ own_server_ip, http_server_port,
+ own_server_ip, http_server_port,
+ own_server_ip, http_server_port,
+ own_server_ip, http_server_port,
devicelist ?: "", purl);
free(devicelist);
htsbuf_queue_init(&q, 0);
htsbuf_append_str(&q, buf);
- upnp_send(&q, NULL, attempt * 11, 1);
+ upnp_send(&q, NULL, attempt * 11, 1, 0);
htsbuf_queue_flush(&q);
}
#undef MSG
abort();
}
+ char* own_server_ip = http_server_ip;
+
snprintf(buf, sizeof(buf), MSG, UPNP_MAX_AGE,
- http_server_ip, http_server_port, tvheadend_webroot ?: "",
+ own_server_ip ?: "%s", http_server_port, tvheadend_webroot ?: "",
nt, tvheadend_version,
satip_server_conf.satip_uuid, usn2, (long)satip_server_bootid,
satip_server_deviceid);
htsbuf_queue_init(&q, 0);
htsbuf_append_str(&q, buf);
- upnp_send(&q, NULL, attempt * 11, 1);
+ upnp_send(&q, NULL, attempt * 11, 1, own_server_ip == NULL);
htsbuf_queue_flush(&q);
}
#undef MSG
buf, ntohs(IP_PORT(*dst)), deviceid ? " device: " : "", deviceid ?: "");
}
+ char* own_server_ip = http_server_ip;
+
snprintf(buf, sizeof(buf), MSG, UPNP_MAX_AGE,
- http_server_ip, http_server_port, tvheadend_webroot ?: "",
+ own_server_ip ?: "%s", http_server_port, tvheadend_webroot ?: "",
tvheadend_version,
satip_server_conf.satip_uuid, (long)satip_server_bootid);
htsbuf_qprintf(&q, "DEVICEID.SES.COM: %s", deviceid);
htsbuf_append(&q, "\r\n", 2);
storage = *dst;
- upnp_send(&q, &storage, 0, from_multicast);
+ upnp_send(&q, &storage, 0, from_multicast, own_server_ip == NULL);
htsbuf_queue_flush(&q);
#undef MSG
}
return;
if (conn->multicast && strcmp(argv[0], "239.255.255.250"))
return;
- if (!conn->multicast && strcmp(argv[0], http_server_ip))
+ if (!conn->multicast && http_server_ip != NULL && strcmp(argv[0], http_server_ip))
return;
if (tvhtrace_enabled()) {
}
tvhinfo(LS_SATIPS, "SAT>IP Server %sinitialized", prefix);
tvhinfo(LS_SATIPS, " HTTP %s:%d, RTSP %s:%d",
- http_server_ip, http_server_port,
- http_server_ip, satip_server_rtsp_port);
+ http_server_ip ?: "0.0.0.0", http_server_port,
+ http_server_ip ?: "0.0.0.0", satip_server_rtsp_port);
tvhinfo(LS_SATIPS, " descramble %d, muxcnf %d",
descramble, muxcnf);
for (fe = 1; fe <= 128; fe++) {
*/
static void satip_server_init_common(const char *prefix, int announce)
{
- struct sockaddr_storage http;
- char http_ip[128];
int descramble, rewrite_pmt, muxcnf;
char *nat_ip, *rtp_src_ip;
int nat_port;
if (satip_server_rtsp_port <= 0)
return;
- if (http_server_ip == NULL) {
- if (tcp_server_onall(http_server) && satip_server_bindaddr == NULL) {
- tvherror(LS_SATIPS, "use --satip_bindaddr parameter to select the local IP for SAT>IP");
- tvherror(LS_SATIPS, "using Google lookup (might block the task until timeout)");
- }
- if (tcp_server_bound(http_server, &http, PF_INET) < 0) {
- tvherror(LS_SATIPS, "Unable to determine the HTTP/RTSP address");
- return;
- }
- tcp_get_str_from_ip(&http, http_ip, sizeof(http_ip));
- http_server_ip = strdup(satip_server_bindaddr ?: http_ip);
- http_server_port = ntohs(IP_PORT(http));
+ if (http_server_port == 0) {
+ http_server_ip = satip_server_bindaddr ? strdup(satip_server_bindaddr) : NULL;
+ tcp_server_t* srv = http_server;
+ http_server_port = ntohs(IP_PORT(srv->bound));
}
descramble = satip_server_conf.satip_descramble;
tvh_uuid_t u;
int save = 0;
- if (http_server_ip == NULL)
+ if (http_server_port == 0)
return;
if (satip_server_conf.satip_rtsp != satip_server_rtsp_port) {
satip_server_rtsp_port = 0;
free(http_server_ip);
http_server_ip = NULL;
+ http_server_port = 0;
free(satip_server_conf.satip_uuid);
satip_server_conf.satip_uuid = NULL;
free(satip_server_bindaddr);
static tvhpoll_t *tcp_server_poll;
static uint32_t tcp_server_launch_id;
-typedef struct tcp_server {
- int serverfd;
- struct sockaddr_storage bound;
- tcp_server_ops_t ops;
- void *opaque;
- LIST_ENTRY(tcp_server) link;
-} tcp_server_t;
-
-typedef struct tcp_server_launch {
- pthread_t tid;
- uint32_t id;
- int fd;
- int streaming;
- tcp_server_ops_t ops;
- void *opaque;
- char *representative;
- void (*status) (void *opaque, htsmsg_t *m);
- struct sockaddr_storage peer;
- struct sockaddr_storage self;
- time_t started;
- LIST_ENTRY(tcp_server_launch) link;
- LIST_ENTRY(tcp_server_launch) alink;
- LIST_ENTRY(tcp_server_launch) jlink;
-} tcp_server_launch_t;
-
static LIST_HEAD(, tcp_server) tcp_server_delete_list = { 0 };
static LIST_HEAD(, tcp_server_launch) tcp_server_launches = { 0 };
static LIST_HEAD(, tcp_server_launch) tcp_server_active = { 0 };
void (*cancel) (void *opaque);
} tcp_server_ops_t;
+typedef struct tcp_server {
+ int serverfd;
+ struct sockaddr_storage bound;
+ tcp_server_ops_t ops;
+ void *opaque;
+ LIST_ENTRY(tcp_server) link;
+} tcp_server_t;
+
+typedef struct tcp_server_launch {
+ pthread_t tid;
+ uint32_t id;
+ int fd;
+ int streaming;
+ tcp_server_ops_t ops;
+ void *opaque;
+ char *representative;
+ void (*status) (void *opaque, htsmsg_t *m);
+ struct sockaddr_storage peer;
+ struct sockaddr_storage self;
+ time_t started;
+ LIST_ENTRY(tcp_server_launch) link;
+ LIST_ENTRY(tcp_server_launch) alink;
+ LIST_ENTRY(tcp_server_launch) jlink;
+} tcp_server_launch_t;
+
extern int tcp_preferred_address_family;
void tcp_server_preinit(int opt_ipv6);
free(uc);
}
+int
+udp_write_fill_source( udp_connection_t *uc, const void *buf, size_t len,
+ struct sockaddr_storage *storage)
+{
+ int r;
+ struct sockaddr_in local_addr;
+ socklen_t local_addr_len = sizeof(local_addr);
+ struct sockaddr_in parent_addr;
+ socklen_t parent_addrlen = sizeof(parent_addr);
+ int reuse = 1;
+
+
+ if (storage == NULL)
+ storage = &uc->ip;
+
+ tvhdebug(uc->subsystem, "Got dst IP address: %s", inet_ntoa(((struct sockaddr_in*)storage)->sin_addr));
+
+ // Get the current socket configuration
+ if (getsockname(uc->fd, (struct sockaddr *)&parent_addr, &parent_addrlen) < 0) {
+ perror("getsockname");
+ return -1;
+ }
+ tvhdebug(uc->subsystem, "Got parent IP address: %s", inet_ntoa(parent_addr.sin_addr));
+
+ // Create a new socket
+ int cloned_sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (cloned_sockfd < 0) {
+ perror("socket");
+ return -1;
+ }
+
+
+ /* Mark reuse address */
+ if (setsockopt(cloned_sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse))) {
+ tvherror(uc->subsystem, "failed to reuse address for socket [%s]", strerror(errno));
+ close(cloned_sockfd);
+ return -1;
+ }
+
+ // Set the address to INADDR_ANY to let the routing table choose the source IP
+ parent_addr.sin_addr.s_addr = INADDR_ANY;
+
+ // Bind the new socket to the same port
+ if (bind(cloned_sockfd, (struct sockaddr *)&parent_addr, parent_addrlen) < 0) {
+ tvherror(uc->subsystem, "failed to bind address for socket [%s]", strerror(errno));
+ close(cloned_sockfd);
+ return -1;
+ }
+
+ // Connect the socket to the destination address
+ if (connect(cloned_sockfd, (struct sockaddr *)storage, sizeof(*storage)) < 0) {
+ tvherror(uc->subsystem, "connect() failed: %s", strerror(errno));
+ return -1;
+ }
+
+ // Get the local endpoint information (source IP address)
+ if (getsockname(cloned_sockfd, (struct sockaddr *)&local_addr, &local_addr_len) == -1) {
+ tvherror(uc->subsystem, "getsockname() failed: %s", strerror(errno));
+ return -1;
+ }
+
+ tvhdebug(uc->subsystem, "Got source IP address: %s", inet_ntoa(local_addr.sin_addr));
+
+ len += strlen(inet_ntoa(local_addr.sin_addr)) - 2;
+ char* data = malloc(len + 1);
+
+ len = snprintf(data, len + 1, buf, inet_ntoa(local_addr.sin_addr));
+
+ tvhdebug(uc->subsystem, "Assembled msg [len: %ld]", len);
+ tvhlog_hexdump(uc->subsystem, data, len);
+
+ // Send data over the established connection
+ char* sdata = data;
+ while (len) {
+ r = write(cloned_sockfd, sdata, len);
+ if (r < 0) {
+ if (ERRNO_AGAIN(errno)) {
+ tvh_safe_usleep(100);
+ continue;
+ }
+ break;
+ }
+ len -= r;
+ sdata += r;
+ }
+
+ free(data);
+ close(cloned_sockfd);
+
+ return len;
+}
+
int
udp_write( udp_connection_t *uc, const void *buf, size_t len,
struct sockaddr_storage *storage )
int
udp_write_queue( udp_connection_t *uc, htsbuf_queue_t *q,
- struct sockaddr_storage *storage )
+ struct sockaddr_storage *storage)
+{
+ return udp_write_queue_fill_source(uc, q, storage, 0);
+}
+
+int
+udp_write_queue_fill_source( udp_connection_t *uc, htsbuf_queue_t *q,
+ struct sockaddr_storage *storage, int fill_source)
{
htsbuf_data_t *hd;
int l, r = 0;
if (!r) {
l = hd->hd_data_len - hd->hd_data_off;
p = hd->hd_data + hd->hd_data_off;
- r = udp_write(uc, p, l, storage);
+ if(fill_source)
+ r = udp_write_fill_source(uc, p, l, storage);
+ else
+ r = udp_write(uc, p, l, storage);
}
htsbuf_data_free(q, hd);
}
int
udp_write_queue( udp_connection_t *uc, htsbuf_queue_t *q,
struct sockaddr_storage *storage );
+int
+udp_write_queue_fill_source( udp_connection_t *uc, htsbuf_queue_t *q,
+ struct sockaddr_storage *storage, int fill_source );
+
+int
+udp_write_fill_source( udp_connection_t *uc, const void *buf, size_t len,
+ struct sockaddr_storage *storage);
typedef struct udp_multirecv {
int um_psize;
htsbuf_queue_t queue;
int delay_ms;
int from_multicast;
+ int fill_source;
} upnp_data_t;
TAILQ_HEAD(upnp_data_queue_write, upnp_data);
*/
void
upnp_send( htsbuf_queue_t *q, struct sockaddr_storage *storage,
- int delay_ms, int from_multicast )
+ int delay_ms, int from_multicast, int fill_source )
{
upnp_data_t *data;
data->storage = *storage;
data->delay_ms = delay_ms;
data->from_multicast = from_multicast;
+ data->fill_source = fill_source;
tvh_mutex_lock(&upnp_lock);
TAILQ_INSERT_TAIL(&upnp_data_write, data, data_link);
tvh_mutex_unlock(&upnp_lock);
if (data == NULL)
break;
upnp_dump_data(data);
- udp_write_queue(data->from_multicast ? multicast : unicast,
- &data->queue, &data->storage);
+ udp_write_queue_fill_source(data->from_multicast ? multicast : unicast,
+ &data->queue, &data->storage, data->fill_source);
htsbuf_queue_flush(&data->queue);
free(data);
delay_ms = 0;
break;
tvh_safe_usleep((long)data->delay_ms * 1000);
upnp_dump_data(data);
- udp_write_queue(unicast, &data->queue, &data->storage);
+ udp_write_queue_fill_source(unicast, &data->queue, &data->storage, data->fill_source);
htsbuf_queue_flush(&data->queue);
free(data);
}
void upnp_service_destroy(upnp_service_t *service);
void upnp_send(htsbuf_queue_t *q, struct sockaddr_storage *storage,
- int delay_ms, int from_multicast);
+ int delay_ms, int from_multicast, int fill_source);
void upnp_server_init(const char *bindaddr);
void upnp_server_done(void);