Merge remote-tracking branch 'origin/pr/226'
This commit is contained in:
commit
44932dd601
13 changed files with 342 additions and 81 deletions
218
src/access.c
218
src/access.c
|
@ -149,6 +149,74 @@ access_ticket_verify(const char *id, const char *resource)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int
|
||||
netmask_verify(access_entry_t *ae, struct sockaddr *src)
|
||||
{
|
||||
access_ipmask_t *ai;
|
||||
int isv4v6 = 0;
|
||||
uint32_t v4v6 = 0;
|
||||
|
||||
if(src->sa_family == AF_INET6)
|
||||
{
|
||||
struct in6_addr *in6 = &(((struct sockaddr_in6 *)src)->sin6_addr);
|
||||
uint32_t *a32 = (uint32_t*)in6->s6_addr;
|
||||
if(a32[0] == 0 && a32[1] == 0 && ntohl(a32[2]) == 0x0000FFFFu)
|
||||
{
|
||||
isv4v6 = 1;
|
||||
v4v6 = ntohl(a32[3]);
|
||||
}
|
||||
}
|
||||
|
||||
LIST_FOREACH(ai, &ae->ae_ipmasks, ai_link)
|
||||
{
|
||||
if(ai->ai_ipv6 == 0 && src->sa_family == AF_INET)
|
||||
{
|
||||
struct sockaddr_in *in4 = (struct sockaddr_in *)src;
|
||||
uint32_t b = ntohl(in4->sin_addr.s_addr);
|
||||
if((b & ai->ai_netmask) == ai->ai_network)
|
||||
return 1;
|
||||
}
|
||||
else if(ai->ai_ipv6 == 0 && isv4v6)
|
||||
{
|
||||
if((v4v6 & ai->ai_netmask) == ai->ai_network)
|
||||
return 1;
|
||||
}
|
||||
else if(ai->ai_ipv6 && isv4v6)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if(ai->ai_ipv6 && src->sa_family == AF_INET6)
|
||||
{
|
||||
struct in6_addr *in6 = &(((struct sockaddr_in6 *)src)->sin6_addr);
|
||||
uint8_t *a8 = (uint8_t*)in6->s6_addr;
|
||||
uint8_t *m8 = (uint8_t*)ai->ai_ip6.s6_addr;
|
||||
int slen = ai->ai_prefixlen;
|
||||
uint32_t apos = 0;
|
||||
uint8_t lastMask = (0xFFu << (8 - (slen % 8)));
|
||||
|
||||
if(slen < 0 || slen > 128)
|
||||
continue;
|
||||
|
||||
while(slen >= 8)
|
||||
{
|
||||
if(a8[apos] != m8[apos])
|
||||
continue;
|
||||
|
||||
apos += 1;
|
||||
slen -= 8;
|
||||
}
|
||||
|
||||
if(slen == 0 || (a8[apos] & lastMask) == (m8[apos] & lastMask))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -157,8 +225,6 @@ access_verify(const char *username, const char *password,
|
|||
struct sockaddr *src, uint32_t mask)
|
||||
{
|
||||
uint32_t bits = 0;
|
||||
struct sockaddr_in *si = (struct sockaddr_in *)src;
|
||||
uint32_t b = ntohl(si->sin_addr.s_addr);
|
||||
access_entry_t *ae;
|
||||
|
||||
if(username != NULL && superuser_username != NULL &&
|
||||
|
@ -182,7 +248,7 @@ access_verify(const char *username, const char *password,
|
|||
continue; /* username/password mismatch */
|
||||
}
|
||||
|
||||
if((b & ae->ae_netmask) != ae->ae_network)
|
||||
if(!netmask_verify(ae, src))
|
||||
continue; /* IP based access mismatches */
|
||||
|
||||
bits |= ae->ae_rights;
|
||||
|
@ -200,8 +266,6 @@ access_get_hashed(const char *username, const uint8_t digest[20],
|
|||
const uint8_t *challenge, struct sockaddr *src,
|
||||
int *entrymatch)
|
||||
{
|
||||
struct sockaddr_in *si = (struct sockaddr_in *)src;
|
||||
uint32_t b = ntohl(si->sin_addr.s_addr);
|
||||
access_entry_t *ae;
|
||||
SHA_CTX shactx;
|
||||
uint8_t d[20];
|
||||
|
@ -226,7 +290,7 @@ access_get_hashed(const char *username, const uint8_t digest[20],
|
|||
if(!ae->ae_enabled)
|
||||
continue;
|
||||
|
||||
if((b & ae->ae_netmask) != ae->ae_network)
|
||||
if(!netmask_verify(ae, src))
|
||||
continue; /* IP based access mismatches */
|
||||
|
||||
SHA1_Init(&shactx);
|
||||
|
@ -253,8 +317,6 @@ access_get_hashed(const char *username, const uint8_t digest[20],
|
|||
uint32_t
|
||||
access_get_by_addr(struct sockaddr *src)
|
||||
{
|
||||
struct sockaddr_in *si = (struct sockaddr_in *)src;
|
||||
uint32_t b = ntohl(si->sin_addr.s_addr);
|
||||
access_entry_t *ae;
|
||||
uint32_t r = 0;
|
||||
|
||||
|
@ -263,7 +325,7 @@ access_get_by_addr(struct sockaddr *src)
|
|||
if(ae->ae_username[0] != '*')
|
||||
continue;
|
||||
|
||||
if((b & ae->ae_netmask) != ae->ae_network)
|
||||
if(!netmask_verify(ae, src))
|
||||
continue; /* IP based access mismatches */
|
||||
|
||||
r |= ae->ae_rights;
|
||||
|
@ -293,28 +355,90 @@ static void
|
|||
access_set_prefix(access_entry_t *ae, const char *prefix)
|
||||
{
|
||||
char buf[100];
|
||||
char tokbuf[4096];
|
||||
int prefixlen;
|
||||
char *p;
|
||||
char *p, *tok, *saveptr;
|
||||
access_ipmask_t *ai;
|
||||
|
||||
if(strlen(prefix) > 90)
|
||||
return;
|
||||
|
||||
strcpy(buf, prefix);
|
||||
p = strchr(buf, '/');
|
||||
if(p) {
|
||||
*p++ = 0;
|
||||
prefixlen = atoi(p);
|
||||
if(prefixlen > 32)
|
||||
return;
|
||||
} else {
|
||||
prefixlen = 32;
|
||||
while((ai = LIST_FIRST(&ae->ae_ipmasks)) != NULL)
|
||||
{
|
||||
LIST_REMOVE(ai, ai_link);
|
||||
free(ai);
|
||||
}
|
||||
|
||||
ae->ae_ip.s_addr = inet_addr(buf);
|
||||
ae->ae_prefixlen = prefixlen;
|
||||
strncpy(tokbuf, prefix, 4095);
|
||||
tokbuf[4095] = 0;
|
||||
tok = strtok_r(tokbuf, ",;| ", &saveptr);
|
||||
|
||||
ae->ae_netmask = prefixlen ? 0xffffffff << (32 - prefixlen) : 0;
|
||||
ae->ae_network = ntohl(ae->ae_ip.s_addr) & ae->ae_netmask;
|
||||
while(tok != NULL)
|
||||
{
|
||||
ai = calloc(1, sizeof(access_ipmask_t));
|
||||
|
||||
if(strlen(tok) > 90 || strlen(tok) == 0)
|
||||
{
|
||||
free(ai);
|
||||
tok = strtok_r(NULL, ",;| ", &saveptr);
|
||||
continue;
|
||||
}
|
||||
|
||||
strcpy(buf, tok);
|
||||
|
||||
if(strchr(buf, ':') != NULL)
|
||||
ai->ai_ipv6 = 1;
|
||||
else
|
||||
ai->ai_ipv6 = 0;
|
||||
|
||||
if(ai->ai_ipv6)
|
||||
{
|
||||
p = strchr(buf, '/');
|
||||
if(p)
|
||||
{
|
||||
*p++ = 0;
|
||||
prefixlen = atoi(p);
|
||||
if(prefixlen > 128)
|
||||
{
|
||||
free(ai);
|
||||
tok = strtok_r(NULL, ",;| ", &saveptr);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
prefixlen = 128;
|
||||
}
|
||||
|
||||
ai->ai_prefixlen = prefixlen;
|
||||
inet_pton(AF_INET6, buf, &ai->ai_ip6);
|
||||
|
||||
ai->ai_netmask = 0xffffffff;
|
||||
ai->ai_network = 0x00000000;
|
||||
}
|
||||
else
|
||||
{
|
||||
p = strchr(buf, '/');
|
||||
if(p)
|
||||
{
|
||||
*p++ = 0;
|
||||
prefixlen = atoi(p);
|
||||
if(prefixlen > 32)
|
||||
{
|
||||
free(ai);
|
||||
tok = strtok_r(NULL, ",;| ", &saveptr);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
prefixlen = 32;
|
||||
}
|
||||
|
||||
ai->ai_ip.s_addr = inet_addr(buf);
|
||||
ai->ai_prefixlen = prefixlen;
|
||||
|
||||
ai->ai_netmask = prefixlen ? 0xffffffff << (32 - prefixlen) : 0;
|
||||
ai->ai_network = ntohl(ai->ai_ip.s_addr) & ai->ai_netmask;
|
||||
}
|
||||
|
||||
LIST_INSERT_HEAD(&ae->ae_ipmasks, ai, ai_link);
|
||||
|
||||
tok = strtok_r(NULL, ",;| ", &saveptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -363,6 +487,14 @@ access_entry_find(const char *id, int create)
|
|||
static void
|
||||
access_entry_destroy(access_entry_t *ae)
|
||||
{
|
||||
access_ipmask_t *ai;
|
||||
|
||||
while((ai = LIST_FIRST(&ae->ae_ipmasks)) != NULL)
|
||||
{
|
||||
LIST_REMOVE(ai, ai_link);
|
||||
free(ai);
|
||||
}
|
||||
|
||||
free(ae->ae_id);
|
||||
free(ae->ae_username);
|
||||
free(ae->ae_password);
|
||||
|
@ -378,7 +510,12 @@ static htsmsg_t *
|
|||
access_record_build(access_entry_t *ae)
|
||||
{
|
||||
htsmsg_t *e = htsmsg_create_map();
|
||||
char buf[100];
|
||||
access_ipmask_t *ai;
|
||||
char addrbuf[50];
|
||||
char buf[4096];
|
||||
int pos = 0;
|
||||
|
||||
memset(buf, 0, 4096);
|
||||
|
||||
htsmsg_add_u32(e, "enabled", !!ae->ae_enabled);
|
||||
|
||||
|
@ -386,8 +523,22 @@ access_record_build(access_entry_t *ae)
|
|||
htsmsg_add_str(e, "password", ae->ae_password);
|
||||
htsmsg_add_str(e, "comment", ae->ae_comment);
|
||||
|
||||
snprintf(buf, sizeof(buf), "%s/%d", inet_ntoa(ae->ae_ip), ae->ae_prefixlen);
|
||||
htsmsg_add_str(e, "prefix", buf);
|
||||
LIST_FOREACH(ai, &ae->ae_ipmasks, ai_link)
|
||||
{
|
||||
if(sizeof(buf)-pos <= 0)
|
||||
break;
|
||||
|
||||
if(ai->ai_ipv6)
|
||||
{
|
||||
inet_ntop(AF_INET6, &ai->ai_ip6, addrbuf, 50);
|
||||
pos += snprintf(buf+pos, sizeof(buf)-pos, ",%s/%d", addrbuf, ai->ai_prefixlen);
|
||||
}
|
||||
else
|
||||
{
|
||||
pos += snprintf(buf+pos, sizeof(buf)-pos, ",%s/%d", inet_ntoa(ai->ai_ip), ai->ai_prefixlen);
|
||||
}
|
||||
}
|
||||
htsmsg_add_str(e, "prefix", buf + 1);
|
||||
|
||||
htsmsg_add_u32(e, "streaming", ae->ae_rights & ACCESS_STREAMING ? 1 : 0);
|
||||
htsmsg_add_u32(e, "dvr" , ae->ae_rights & ACCESS_RECORDER ? 1 : 0);
|
||||
|
@ -537,6 +688,7 @@ access_init(int createdefault)
|
|||
dtable_t *dt;
|
||||
htsmsg_t *r, *m;
|
||||
access_entry_t *ae;
|
||||
access_ipmask_t *ai;
|
||||
const char *s;
|
||||
|
||||
static struct {
|
||||
|
@ -563,6 +715,14 @@ access_init(int createdefault)
|
|||
ae->ae_enabled = 1;
|
||||
ae->ae_rights = 0xffffffff;
|
||||
|
||||
ai = calloc(1, sizeof(access_ipmask_t));
|
||||
ai->ai_ipv6 = 0;
|
||||
LIST_INSERT_HEAD(&ae->ae_ipmasks, ai, ai_link);
|
||||
|
||||
ai = calloc(1, sizeof(access_ipmask_t));
|
||||
ai->ai_ipv6 = 1;
|
||||
LIST_INSERT_HEAD(&ae->ae_ipmasks, ai, ai_link);
|
||||
|
||||
r = access_record_build(ae);
|
||||
dtable_record_store(dt, ae->ae_id, r);
|
||||
htsmsg_destroy(r);
|
||||
|
|
19
src/access.h
19
src/access.h
|
@ -20,6 +20,20 @@
|
|||
#define ACCESS_H_
|
||||
|
||||
|
||||
typedef struct access_ipmask {
|
||||
LIST_ENTRY(access_ipmask) ai_link;
|
||||
|
||||
int ai_ipv6;
|
||||
|
||||
struct in_addr ai_ip;
|
||||
struct in6_addr ai_ip6;
|
||||
|
||||
int ai_prefixlen;
|
||||
|
||||
uint32_t ai_network;
|
||||
uint32_t ai_netmask;
|
||||
} access_ipmask_t;
|
||||
|
||||
TAILQ_HEAD(access_entry_queue, access_entry);
|
||||
|
||||
extern struct access_entry_queue access_entries;
|
||||
|
@ -31,15 +45,12 @@ typedef struct access_entry {
|
|||
char *ae_username;
|
||||
char *ae_password;
|
||||
char *ae_comment;
|
||||
struct in_addr ae_ip;
|
||||
int ae_prefixlen;
|
||||
int ae_enabled;
|
||||
|
||||
|
||||
uint32_t ae_rights;
|
||||
|
||||
uint32_t ae_network; /* derived from ae_ip */
|
||||
uint32_t ae_netmask; /* derived from ae_prefixlen */
|
||||
LIST_HEAD(, access_ipmask) ae_ipmasks;
|
||||
} access_entry_t;
|
||||
|
||||
TAILQ_HEAD(access_ticket_queue, access_ticket);
|
||||
|
|
0
src/capmt.c
Executable file → Normal file
0
src/capmt.c
Executable file → Normal file
0
src/dvr/dvr_rec.c
Executable file → Normal file
0
src/dvr/dvr_rec.c
Executable file → Normal file
|
@ -115,7 +115,7 @@ typedef struct htsp_connection {
|
|||
LIST_ENTRY(htsp_connection) htsp_link;
|
||||
|
||||
int htsp_fd;
|
||||
struct sockaddr_in *htsp_peer;
|
||||
struct sockaddr_storage *htsp_peer;
|
||||
|
||||
uint32_t htsp_version;
|
||||
|
||||
|
@ -464,19 +464,22 @@ htsp_build_channel(channel_t *ch, const char *method, htsp_connection_t *htsp)
|
|||
htsmsg_add_str(out, "channelName", ch->ch_name);
|
||||
if(ch->ch_icon != NULL) {
|
||||
uint32_t id;
|
||||
struct sockaddr_in addr;
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addrlen;
|
||||
if ((id = imagecache_get_id(ch->ch_icon))) {
|
||||
size_t p = 0;
|
||||
char url[256];
|
||||
char buf[50];
|
||||
if (htsp->htsp_version < 8) {
|
||||
addrlen = sizeof(addr);
|
||||
getsockname(htsp->htsp_fd, (struct sockaddr*)&addr, &addrlen);
|
||||
tcp_get_ip_str((struct sockaddr*)&addr, buf, 50);
|
||||
strcpy(url, "http://");
|
||||
p = strlen(url);
|
||||
inet_ntop(AF_INET, &addr.sin_addr, url+p, sizeof(url)-p);
|
||||
p = strlen(url);
|
||||
p += snprintf(url+p, sizeof(url)-p, ":%hd%s",
|
||||
p += snprintf(url+p, sizeof(url)-p, "%s%s%s:%hd%s",
|
||||
(addr.ss_family == AF_INET6)?"[":"",
|
||||
buf,
|
||||
(addr.ss_family == AF_INET6)?"]":"",
|
||||
tvheadend_webui_port,
|
||||
tvheadend_webroot ?: "");
|
||||
}
|
||||
|
@ -1871,14 +1874,14 @@ htsp_write_scheduler(void *aux)
|
|||
*
|
||||
*/
|
||||
static void
|
||||
htsp_serve(int fd, void *opaque, struct sockaddr_in *source,
|
||||
struct sockaddr_in *self)
|
||||
htsp_serve(int fd, void *opaque, struct sockaddr_storage *source,
|
||||
struct sockaddr_storage *self)
|
||||
{
|
||||
htsp_connection_t htsp;
|
||||
char buf[30];
|
||||
char buf[50];
|
||||
htsp_subscription_t *s;
|
||||
|
||||
snprintf(buf, sizeof(buf), "%s", inet_ntoa(source->sin_addr));
|
||||
tcp_get_ip_str((struct sockaddr*)source, buf, 50);
|
||||
|
||||
memset(&htsp, 0, sizeof(htsp_connection_t));
|
||||
|
||||
|
|
24
src/http.c
24
src/http.c
|
@ -247,9 +247,12 @@ void
|
|||
http_error(http_connection_t *hc, int error)
|
||||
{
|
||||
const char *errtxt = http_rc2str(error);
|
||||
char *addrstr = (char*)malloc(50);
|
||||
tcp_get_ip_str((struct sockaddr*)hc->hc_peer, addrstr, 50);
|
||||
|
||||
tvhlog(LOG_ERR, "HTTP", "%s: %s -- %d",
|
||||
inet_ntoa(hc->hc_peer->sin_addr), hc->hc_url, error);
|
||||
addrstr, hc->hc_url, error);
|
||||
free(addrstr);
|
||||
|
||||
htsbuf_queue_flush(&hc->hc_reply);
|
||||
|
||||
|
@ -315,10 +318,13 @@ http_access_verify(http_connection_t *hc, int mask)
|
|||
{
|
||||
const char *ticket_id = http_arg_get(&hc->hc_req_args, "ticket");
|
||||
|
||||
if(!access_ticket_verify(ticket_id, hc->hc_url)) {
|
||||
if(!access_ticket_verify(ticket_id, hc->hc_url))
|
||||
{
|
||||
char *addrstr = (char*)malloc(50);
|
||||
tcp_get_ip_str((struct sockaddr*)hc->hc_peer, addrstr, 50);
|
||||
tvhlog(LOG_INFO, "HTTP", "%s: using ticket %s for %s",
|
||||
inet_ntoa(hc->hc_peer->sin_addr), ticket_id,
|
||||
hc->hc_url);
|
||||
addrstr, ticket_id, hc->hc_url);
|
||||
free(addrstr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -504,11 +510,9 @@ process_request(http_connection_t *hc, htsbuf_queue_t *spill)
|
|||
if(hc->hc_username != NULL) {
|
||||
hc->hc_representative = strdup(hc->hc_username);
|
||||
} else {
|
||||
hc->hc_representative = malloc(30);
|
||||
hc->hc_representative = malloc(50);
|
||||
/* Not threadsafe ? */
|
||||
snprintf(hc->hc_representative, 30,
|
||||
"%s", inet_ntoa(hc->hc_peer->sin_addr));
|
||||
|
||||
tcp_get_ip_str((struct sockaddr*)hc->hc_peer, hc->hc_representative, 50);
|
||||
}
|
||||
|
||||
switch(hc->hc_version) {
|
||||
|
@ -777,8 +781,8 @@ http_serve_requests(http_connection_t *hc, htsbuf_queue_t *spill)
|
|||
*
|
||||
*/
|
||||
static void
|
||||
http_serve(int fd, void *opaque, struct sockaddr_in *peer,
|
||||
struct sockaddr_in *self)
|
||||
http_serve(int fd, void *opaque, struct sockaddr_storage *peer,
|
||||
struct sockaddr_storage *self)
|
||||
{
|
||||
htsbuf_queue_t spill;
|
||||
http_connection_t hc;
|
||||
|
|
|
@ -39,8 +39,8 @@ typedef struct http_arg {
|
|||
|
||||
typedef struct http_connection {
|
||||
int hc_fd;
|
||||
struct sockaddr_in *hc_peer;
|
||||
struct sockaddr_in *hc_self;
|
||||
struct sockaddr_storage *hc_peer;
|
||||
struct sockaddr_storage *hc_self;
|
||||
char *hc_representative;
|
||||
|
||||
char *hc_url;
|
||||
|
|
|
@ -359,7 +359,8 @@ main(int argc, char **argv)
|
|||
opt_debug = 0,
|
||||
opt_syslog = 0,
|
||||
opt_uidebug = 0,
|
||||
opt_abort = 0;
|
||||
opt_abort = 0,
|
||||
opt_ipv6 = 0;
|
||||
const char *opt_config = NULL,
|
||||
*opt_user = NULL,
|
||||
*opt_group = NULL,
|
||||
|
@ -391,8 +392,8 @@ main(int argc, char **argv)
|
|||
{ 'a', "adapters", "Use only specified DVB adapters",
|
||||
OPT_STR, &opt_dvb_adapters },
|
||||
#endif
|
||||
|
||||
{ 0, NULL, "Server Connectivity", OPT_BOOL, NULL },
|
||||
{ '6', "ipv6", "Listen on IPv6", OPT_BOOL, &opt_ipv6 },
|
||||
{ 0, "http_port", "Specify alternative http port",
|
||||
OPT_INT, &tvheadend_webui_port },
|
||||
{ 0, "http_root", "Specify alternative http webroot",
|
||||
|
@ -606,7 +607,7 @@ main(int argc, char **argv)
|
|||
timeshift_init();
|
||||
#endif
|
||||
|
||||
tcp_server_init();
|
||||
tcp_server_init(opt_ipv6);
|
||||
http_server_init();
|
||||
webui_init();
|
||||
|
||||
|
|
0
src/streaming.c
Executable file → Normal file
0
src/streaming.c
Executable file → Normal file
92
src/tcp.c
92
src/tcp.c
|
@ -35,6 +35,7 @@
|
|||
#include "tcp.h"
|
||||
#include "tvheadend.h"
|
||||
|
||||
int tcp_preferred_address_family = AF_INET;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -344,6 +345,31 @@ tcp_read_timeout(int fd, void *buf, size_t len, int timeout)
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
char *
|
||||
tcp_get_ip_str(const struct sockaddr *sa, char *s, size_t maxlen)
|
||||
{
|
||||
if(sa == NULL || s == NULL)
|
||||
return NULL;
|
||||
|
||||
switch(sa->sa_family)
|
||||
{
|
||||
case AF_INET:
|
||||
inet_ntop(AF_INET, &(((struct sockaddr_in*)sa)->sin_addr), s, maxlen);
|
||||
break;
|
||||
case AF_INET6:
|
||||
inet_ntop(AF_INET6, &(((struct sockaddr_in6*)sa)->sin6_addr), s, maxlen);
|
||||
break;
|
||||
default:
|
||||
strncpy(s, "Unknown AF", maxlen);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -359,8 +385,8 @@ typedef struct tcp_server_launch_t {
|
|||
tcp_server_callback_t *start;
|
||||
void *opaque;
|
||||
int fd;
|
||||
struct sockaddr_in peer;
|
||||
struct sockaddr_in self;
|
||||
struct sockaddr_storage peer;
|
||||
struct sockaddr_storage self;
|
||||
} tcp_server_launch_t;
|
||||
|
||||
|
||||
|
@ -443,7 +469,7 @@ tcp_server_loop(void *aux)
|
|||
tsl = malloc(sizeof(tcp_server_launch_t));
|
||||
tsl->start = ts->start;
|
||||
tsl->opaque = ts->opaque;
|
||||
slen = sizeof(struct sockaddr_in);
|
||||
slen = sizeof(struct sockaddr_storage);
|
||||
|
||||
tsl->fd = accept(ts->serverfd,
|
||||
(struct sockaddr *)&tsl->peer, &slen);
|
||||
|
@ -455,7 +481,7 @@ tcp_server_loop(void *aux)
|
|||
}
|
||||
|
||||
|
||||
slen = sizeof(struct sockaddr_in);
|
||||
slen = sizeof(struct sockaddr_storage);
|
||||
if(getsockname(tsl->fd, (struct sockaddr *)&tsl->self, &slen)) {
|
||||
close(tsl->fd);
|
||||
free(tsl);
|
||||
|
@ -478,21 +504,55 @@ tcp_server_create(int port, tcp_server_callback_t *start, void *opaque)
|
|||
int fd, x;
|
||||
struct epoll_event e;
|
||||
tcp_server_t *ts;
|
||||
struct sockaddr_in s;
|
||||
struct addrinfo hints, *res, *ressave, *use = NULL;
|
||||
char *portBuf = (char*)malloc(6);
|
||||
int one = 1;
|
||||
int zero = 0;
|
||||
|
||||
memset(&e, 0, sizeof(e));
|
||||
fd = tvh_socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
snprintf(portBuf, 6, "%d", port);
|
||||
|
||||
memset(&hints, 0, sizeof(struct addrinfo));
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
x = getaddrinfo(NULL, portBuf, &hints, &res);
|
||||
free(portBuf);
|
||||
|
||||
if(x != 0)
|
||||
return NULL;
|
||||
|
||||
ressave = res;
|
||||
while(res)
|
||||
{
|
||||
if(res->ai_family == tcp_preferred_address_family)
|
||||
{
|
||||
use = res;
|
||||
break;
|
||||
}
|
||||
else if(use == NULL)
|
||||
{
|
||||
use = res;
|
||||
}
|
||||
res = res->ai_next;
|
||||
}
|
||||
|
||||
fd = tvh_socket(use->ai_family, use->ai_socktype, use->ai_protocol);
|
||||
if(fd == -1)
|
||||
return NULL;
|
||||
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int));
|
||||
if(use->ai_family == AF_INET6)
|
||||
setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(int));
|
||||
|
||||
memset(&s, 0, sizeof(s));
|
||||
s.sin_family = AF_INET;
|
||||
s.sin_port = htons(port);
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int));
|
||||
|
||||
x = bind(fd, (struct sockaddr *)&s, sizeof(s));
|
||||
if(x < 0) {
|
||||
x = bind(fd, use->ai_addr, use->ai_addrlen);
|
||||
freeaddrinfo(ressave);
|
||||
|
||||
if(x != 0)
|
||||
{
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -504,11 +564,10 @@ tcp_server_create(int port, tcp_server_callback_t *start, void *opaque)
|
|||
ts->start = start;
|
||||
ts->opaque = opaque;
|
||||
|
||||
|
||||
e.events = EPOLLIN;
|
||||
e.data.ptr = ts;
|
||||
|
||||
epoll_ctl(tcp_server_epoll_fd, EPOLL_CTL_ADD, fd, &e);
|
||||
|
||||
return ts;
|
||||
}
|
||||
|
||||
|
@ -516,10 +575,13 @@ tcp_server_create(int port, tcp_server_callback_t *start, void *opaque)
|
|||
*
|
||||
*/
|
||||
void
|
||||
tcp_server_init(void)
|
||||
tcp_server_init(int opt_ipv6)
|
||||
{
|
||||
pthread_t tid;
|
||||
|
||||
if(opt_ipv6)
|
||||
tcp_preferred_address_family = AF_INET6;
|
||||
|
||||
tcp_server_epoll_fd = epoll_create(10);
|
||||
pthread_create(&tid, NULL, tcp_server_loop, NULL);
|
||||
}
|
||||
|
|
10
src/tcp.h
10
src/tcp.h
|
@ -21,14 +21,16 @@
|
|||
|
||||
#include "htsbuf.h"
|
||||
|
||||
void tcp_server_init(void);
|
||||
extern int tcp_preferred_address_family;
|
||||
|
||||
void tcp_server_init(int opt_ipv6);
|
||||
|
||||
int tcp_connect(const char *hostname, int port, char *errbuf,
|
||||
size_t errbufsize, int timeout);
|
||||
|
||||
typedef void (tcp_server_callback_t)(int fd, void *opaque,
|
||||
struct sockaddr_in *peer,
|
||||
struct sockaddr_in *self);
|
||||
struct sockaddr_storage *peer,
|
||||
struct sockaddr_storage *self);
|
||||
|
||||
void *tcp_server_create(int port, tcp_server_callback_t *start, void *opaque);
|
||||
|
||||
|
@ -44,4 +46,6 @@ int tcp_write_queue(int fd, htsbuf_queue_t *q);
|
|||
|
||||
int tcp_read_timeout(int fd, void *buf, size_t len, int timeout);
|
||||
|
||||
char *tcp_get_ip_str(const struct sockaddr *sa, char *s, size_t maxlen);
|
||||
|
||||
#endif /* TCP_H_ */
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "http.h"
|
||||
#include "webui/webui.h"
|
||||
#include "access.h"
|
||||
#include "tcp.h"
|
||||
|
||||
static pthread_mutex_t comet_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_cond_t comet_cond = PTHREAD_COND_INITIALIZER;
|
||||
|
@ -153,16 +154,24 @@ comet_access_update(http_connection_t *hc, comet_mailbox_t *cmb)
|
|||
static void
|
||||
comet_serverIpPort(http_connection_t *hc, comet_mailbox_t *cmb)
|
||||
{
|
||||
char buf[INET_ADDRSTRLEN + 1];
|
||||
char buf[50];
|
||||
uint32_t port;
|
||||
|
||||
inet_ntop(AF_INET, &hc->hc_self->sin_addr, buf, sizeof(buf));
|
||||
tcp_get_ip_str((struct sockaddr*)hc->hc_self, buf, 50);
|
||||
|
||||
if(hc->hc_self->ss_family == AF_INET)
|
||||
port = ((struct sockaddr_in*)hc->hc_self)->sin_port;
|
||||
else if(hc->hc_self->ss_family == AF_INET6)
|
||||
port = ((struct sockaddr_in6*)hc->hc_self)->sin6_port;
|
||||
else
|
||||
port = 0;
|
||||
|
||||
htsmsg_t *m = htsmsg_create_map();
|
||||
|
||||
htsmsg_add_str(m, "notificationClass", "setServerIpPort");
|
||||
|
||||
htsmsg_add_str(m, "ip", buf);
|
||||
htsmsg_add_u32(m, "port", ntohs(hc->hc_self->sin_port));
|
||||
htsmsg_add_u32(m, "port", ntohs(port));
|
||||
|
||||
if(cmb->cmb_messages == NULL)
|
||||
cmb->cmb_messages = htsmsg_create_list();
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include "dvb/dvb.h"
|
||||
#include "dvb/dvb_support.h"
|
||||
#include "imagecache.h"
|
||||
#include "tcp.h"
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -564,6 +565,7 @@ http_stream_service(http_connection_t *hc, service_t *service)
|
|||
const char *str;
|
||||
size_t qsize;
|
||||
const char *name;
|
||||
char addrbuf[50];
|
||||
|
||||
mc = muxer_container_txt2type(http_arg_get(&hc->hc_req_args, "mux"));
|
||||
if(mc == MC_UNKNOWN) {
|
||||
|
@ -590,8 +592,9 @@ http_stream_service(http_connection_t *hc, service_t *service)
|
|||
flags = 0;
|
||||
}
|
||||
|
||||
tcp_get_ip_str((struct sockaddr*)hc->hc_peer, addrbuf, 50);
|
||||
s = subscription_create_from_service(service, "HTTP", st, flags,
|
||||
inet_ntoa(hc->hc_peer->sin_addr),
|
||||
addrbuf,
|
||||
hc->hc_username,
|
||||
http_arg_get(&hc->hc_args, "User-Agent"));
|
||||
if(s) {
|
||||
|
@ -625,10 +628,12 @@ http_stream_tdmi(http_connection_t *hc, th_dvb_mux_instance_t *tdmi)
|
|||
th_subscription_t *s;
|
||||
streaming_queue_t sq;
|
||||
const char *name;
|
||||
char addrbuf[50];
|
||||
streaming_queue_init(&sq, SMT_PACKET);
|
||||
|
||||
tcp_get_ip_str((struct sockaddr*)hc->hc_peer, addrbuf, 50);
|
||||
s = dvb_subscription_create_from_tdmi(tdmi, "HTTP", &sq.sq_st,
|
||||
inet_ntoa(hc->hc_peer->sin_addr),
|
||||
addrbuf,
|
||||
hc->hc_username,
|
||||
http_arg_get(&hc->hc_args, "User-Agent"));
|
||||
name = strdupa(tdmi->tdmi_identifier);
|
||||
|
@ -662,6 +667,7 @@ http_stream_channel(http_connection_t *hc, channel_t *ch)
|
|||
char *str;
|
||||
size_t qsize;
|
||||
const char *name;
|
||||
char addrbuf[50];
|
||||
|
||||
mc = muxer_container_txt2type(http_arg_get(&hc->hc_req_args, "mux"));
|
||||
if(mc == MC_UNKNOWN) {
|
||||
|
@ -688,8 +694,9 @@ http_stream_channel(http_connection_t *hc, channel_t *ch)
|
|||
flags = 0;
|
||||
}
|
||||
|
||||
tcp_get_ip_str((struct sockaddr*)hc->hc_peer, addrbuf, 50);
|
||||
s = subscription_create_from_channel(ch, priority, "HTTP", st, flags,
|
||||
inet_ntoa(hc->hc_peer->sin_addr),
|
||||
addrbuf,
|
||||
hc->hc_username,
|
||||
http_arg_get(&hc->hc_args, "User-Agent"));
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue