more work on capmt
This commit is contained in:
parent
58868079ac
commit
39b6846883
1 changed files with 107 additions and 154 deletions
255
src/capmt.c
255
src/capmt.c
|
@ -264,71 +264,115 @@ capmt_transport_destroy(th_descrambler_t *td)
|
||||||
free(ct);
|
free(ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
handle_ca0(capmt_t* capmt) {
|
||||||
|
capmt_transport_t *ct;
|
||||||
|
th_transport_t *t;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
uint8_t invalid[8], buffer[20];
|
||||||
|
memset(invalid, 0, 8);
|
||||||
|
|
||||||
|
tvhlog(LOG_INFO, "capmt", "running handle_ca0");
|
||||||
|
|
||||||
|
while (capmt->capmt_running) {
|
||||||
|
|
||||||
|
ret = recv(capmt->capmt_sock_ca0, buffer, 18, MSG_WAITALL);
|
||||||
|
|
||||||
|
ct = capmt->ct;
|
||||||
|
|
||||||
|
if (ct == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
t = ct->ct_transport;
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
tvhlog(LOG_ERR, "capmt", "error receiving over socket");
|
||||||
|
// TODO reaction
|
||||||
|
} else if (ret == 0) {
|
||||||
|
// normal socket shutdown
|
||||||
|
tvhlog(LOG_INFO, "capmt", "normal socket shutdown");
|
||||||
|
break;
|
||||||
|
} else if(ret < 18) {
|
||||||
|
if(ct->ct_keystate != CT_FORBIDDEN) {
|
||||||
|
tvhlog(LOG_ERR, "capmt", "Can not descramble service \"%s\", access denied", t->tht_svcname);
|
||||||
|
|
||||||
|
ct->ct_keystate = CT_FORBIDDEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get control words */
|
||||||
|
uint8_t *even = &buffer[2], *odd = &buffer[10];
|
||||||
|
|
||||||
|
if (memcmp(even, invalid, 8))
|
||||||
|
set_even_control_word(ct->ct_keys, even);
|
||||||
|
if (memcmp(odd, invalid, 8))
|
||||||
|
set_odd_control_word(ct->ct_keys, odd);
|
||||||
|
|
||||||
|
if(ct->ct_keystate != CT_RESOLVED)
|
||||||
|
tvhlog(LOG_INFO, "capmt", "Obtained key for service \"%s\"",t->tht_svcname);
|
||||||
|
|
||||||
|
ct->ct_keystate = CT_RESOLVED;
|
||||||
|
}
|
||||||
|
|
||||||
|
tvhlog(LOG_INFO, "capmt", "exiting handle_ca0");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
/*
|
|
||||||
static void *
|
static void *
|
||||||
capmt_thread(void *aux)
|
capmt_thread(void *aux)
|
||||||
{
|
{
|
||||||
capmt_transport_t *ct;
|
|
||||||
capmt_t *capmt = aux;
|
capmt_t *capmt = aux;
|
||||||
int fd, d;
|
|
||||||
char errbuf[100];
|
|
||||||
th_transport_t *t;
|
|
||||||
char hostname[256];
|
|
||||||
int port;
|
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
int attempts = 0;
|
int d;
|
||||||
|
|
||||||
pthread_mutex_lock(&global_lock);
|
while (capmt->capmt_running) {
|
||||||
|
capmt->capmt_sock = -1;
|
||||||
|
capmt->capmt_sock_ca0 = -1;
|
||||||
|
|
||||||
while(capmt->capmt_running) {
|
pthread_mutex_lock(&global_lock);
|
||||||
|
|
||||||
while(capmt->capmt_running && capmt->capmt_enabled == 0)
|
while(capmt->capmt_running && capmt->capmt_enabled == 0)
|
||||||
pthread_cond_wait(&capmt->capmt_cond, &global_lock);
|
pthread_cond_wait(&capmt->capmt_cond, &global_lock);
|
||||||
|
|
||||||
snprintf(hostname, sizeof(hostname), "%s", capmt->capmt_hostname);
|
|
||||||
port = capmt->capmt_port;
|
|
||||||
|
|
||||||
tvhlog(LOG_INFO, "capmt", "Attemping to connect to %s:%d", hostname, port);
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&global_lock);
|
pthread_mutex_unlock(&global_lock);
|
||||||
|
|
||||||
fd = tcp_connect(hostname, port, errbuf, sizeof(errbuf), 10);
|
/* open connection to camd.socket */
|
||||||
|
capmt->capmt_sock = socket(AF_LOCAL, SOCK_STREAM, 0);
|
||||||
|
|
||||||
pthread_mutex_lock(&global_lock);
|
struct sockaddr_un serv_addr_un;
|
||||||
|
memset(&serv_addr_un, 0, sizeof(serv_addr_un));
|
||||||
|
serv_addr_un.sun_family = AF_LOCAL;
|
||||||
|
snprintf(serv_addr_un.sun_path, sizeof(serv_addr_un.sun_path), "%s", capmt->capmt_sockfile);
|
||||||
|
|
||||||
if(fd == -1) {
|
if (connect(capmt->capmt_sock, (const struct sockaddr*)&serv_addr_un, sizeof(serv_addr_un)) == 0) {
|
||||||
attempts++;
|
/* open connection to emulated ca0 device */
|
||||||
tvhlog(LOG_INFO, "capmt",
|
capmt->capmt_sock_ca0 = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||||
"Connection attempt to %s:%d failed: %s",
|
|
||||||
hostname, port, errbuf);
|
|
||||||
} else {
|
|
||||||
|
|
||||||
if(capmt->capmt_running == 0) {
|
struct sockaddr_in serv_addr;
|
||||||
close(fd);
|
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
|
||||||
break;
|
serv_addr.sin_port = htons( (unsigned short int)capmt->capmt_port);
|
||||||
}
|
serv_addr.sin_family = AF_INET;
|
||||||
|
|
||||||
tvhlog(LOG_INFO, "capmt", "Connected to %s:%d", hostname, port);
|
if (bind(capmt->capmt_sock_ca0, (const struct sockaddr*)&serv_addr, sizeof(serv_addr)) != 0)
|
||||||
attempts = 0;
|
perror("[CapmtServer] ERROR binding to ca0");
|
||||||
|
else
|
||||||
|
handle_ca0(capmt);
|
||||||
|
} else
|
||||||
|
tvhlog(LOG_ERR, "capmt", "Error connecting to %s: %s", capmt->capmt_sockfile, strerror(errno));
|
||||||
|
|
||||||
capmt->capmt_fd = fd;
|
/* close opened sockets */
|
||||||
capmt->capmt_reconfigure = 0;
|
if (capmt->capmt_sock > 0)
|
||||||
|
close(capmt->capmt_sock);
|
||||||
//capmt_session(capmt);
|
if (capmt->capmt_sock_ca0 > 0)
|
||||||
|
close(capmt->capmt_sock_ca0);
|
||||||
capmt->capmt_fd = -1;
|
|
||||||
close(fd);
|
|
||||||
capmt->capmt_caid = 0;
|
|
||||||
|
|
||||||
tvhlog(LOG_INFO, "capmt", "Disconnected from %s", capmt->capmt_hostname);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* schedule reconnection */
|
||||||
if(subscriptions_active()) {
|
if(subscriptions_active()) {
|
||||||
if(attempts == 1)
|
|
||||||
continue; // Retry immediately
|
|
||||||
d = 3;
|
d = 3;
|
||||||
} else {
|
} else {
|
||||||
d = 60;
|
d = 60;
|
||||||
|
@ -337,32 +381,15 @@ capmt_thread(void *aux)
|
||||||
ts.tv_sec = time(NULL) + d;
|
ts.tv_sec = time(NULL) + d;
|
||||||
ts.tv_nsec = 0;
|
ts.tv_nsec = 0;
|
||||||
|
|
||||||
tvhlog(LOG_INFO, "capmt",
|
tvhlog(LOG_INFO, "capmt", "Automatic reconnection attempt in in %d seconds", d);
|
||||||
"%s: Automatic connection attempt in in %d seconds",
|
|
||||||
capmt->capmt_hostname, d);
|
|
||||||
|
|
||||||
|
pthread_mutex_lock(&global_lock);
|
||||||
pthread_cond_timedwait(&capmt_config_changed, &global_lock, &ts);
|
pthread_cond_timedwait(&capmt_config_changed, &global_lock, &ts);
|
||||||
|
pthread_mutex_unlock(&global_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
tvhlog(LOG_INFO, "capmt", "%s destroyed", capmt->capmt_hostname);
|
|
||||||
|
|
||||||
while((ct = LIST_FIRST(&capmt->capmt_transports)) != NULL) {
|
|
||||||
t = ct->ct_transport;
|
|
||||||
pthread_mutex_lock(&t->tht_stream_mutex);
|
|
||||||
capmt_transport_destroy(&ct->ct_head);
|
|
||||||
pthread_mutex_unlock(&t->tht_stream_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
free((void *)capmt->capmt_password);
|
|
||||||
free((void *)capmt->capmt_password_salted);
|
|
||||||
free((void *)capmt->capmt_username);
|
|
||||||
free((void *)capmt->capmt_hostname);
|
|
||||||
free(capmt);
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&global_lock);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -604,67 +631,14 @@ capmt_destroy(capmt_t *capmt)
|
||||||
pthread_cond_signal(&capmt->capmt_cond);
|
pthread_cond_signal(&capmt->capmt_cond);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void* ca0Thread(void* pArg) {
|
|
||||||
capmt_t *capmt = (capmt_t*)pArg;
|
|
||||||
capmt_transport_t *ct;
|
|
||||||
th_transport_t *t;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
uint8_t invalid[8], buffer[20];
|
|
||||||
memset(invalid, 0, 8);
|
|
||||||
|
|
||||||
while (capmt->capmt_running) {
|
|
||||||
ret = recv(capmt->capmt_sock_ca0, buffer, 18, MSG_WAITALL);
|
|
||||||
|
|
||||||
ct = capmt->ct;
|
|
||||||
|
|
||||||
if (ct == NULL)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
t = ct->ct_transport;
|
|
||||||
|
|
||||||
if (ret < 0) {
|
|
||||||
tvhlog(LOG_ERR, "capmt", "error receiving over socket");
|
|
||||||
// TODO reaction
|
|
||||||
} else if (ret == 0) {
|
|
||||||
// normal socket shutdown
|
|
||||||
tvhlog(LOG_INFO, "capmt", "normal socket shutdown");
|
|
||||||
break;
|
|
||||||
} else if(ret < 18) {
|
|
||||||
if(ct->ct_keystate != CT_FORBIDDEN) {
|
|
||||||
tvhlog(LOG_ERR, "capmt",
|
|
||||||
"Can not descramble service \"%s\", access denied", t->tht_svcname);
|
|
||||||
|
|
||||||
ct->ct_keystate = CT_FORBIDDEN;
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* get control words */
|
|
||||||
uint8_t *even = &buffer[2], *odd = &buffer[10];
|
|
||||||
|
|
||||||
if (memcmp(even, invalid, 8))
|
|
||||||
set_even_control_word(ct->ct_keys, even);
|
|
||||||
if (memcmp(odd, invalid, 8))
|
|
||||||
set_odd_control_word(ct->ct_keys, odd);
|
|
||||||
|
|
||||||
if(ct->ct_keystate != CT_RESOLVED)
|
|
||||||
tvhlog(LOG_INFO, "capmt",
|
|
||||||
"Obtained key for service \"%s\"",t->tht_svcname);
|
|
||||||
|
|
||||||
ct->ct_keystate = CT_RESOLVED;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static capmt_t *
|
static capmt_t *
|
||||||
capmt_entry_find(const char *id, int create)
|
capmt_entry_find(const char *id, int create)
|
||||||
{
|
{
|
||||||
|
pthread_attr_t attr;
|
||||||
|
pthread_t ptid;
|
||||||
char buf[20];
|
char buf[20];
|
||||||
capmt_t *capmt;
|
capmt_t *capmt;
|
||||||
static int tally;
|
static int tally;
|
||||||
|
@ -691,33 +665,13 @@ capmt_entry_find(const char *id, int create)
|
||||||
capmt->capmt_id = strdup(id);
|
capmt->capmt_id = strdup(id);
|
||||||
capmt->capmt_running = 1;
|
capmt->capmt_running = 1;
|
||||||
|
|
||||||
/* open connection to camd.socket */
|
|
||||||
capmt->capmt_sock = socket(AF_LOCAL, SOCK_STREAM, 0);
|
|
||||||
|
|
||||||
struct sockaddr_un serv_addr_un;
|
|
||||||
memset(&serv_addr_un, 0, sizeof(serv_addr_un));
|
|
||||||
serv_addr_un.sun_family = AF_LOCAL;
|
|
||||||
snprintf(serv_addr_un.sun_path, sizeof(serv_addr_un.sun_path), "/tmp/camd.socket");
|
|
||||||
|
|
||||||
if (connect(capmt->capmt_sock, (const struct sockaddr*)&serv_addr_un, sizeof(serv_addr_un)) != 0)
|
|
||||||
perror("[CWCServer] ERROR connecting to camd.socket");
|
|
||||||
|
|
||||||
/* open connection to emulated ca0 device */
|
|
||||||
capmt->capmt_sock_ca0 = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
|
||||||
|
|
||||||
struct sockaddr_in serv_addr;
|
|
||||||
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
|
|
||||||
serv_addr.sin_port = htons( (unsigned short int)9000);
|
|
||||||
serv_addr.sin_family = AF_INET;
|
|
||||||
|
|
||||||
if (bind(capmt->capmt_sock_ca0, (const struct sockaddr*)&serv_addr, sizeof(serv_addr)) != 0)
|
|
||||||
perror("[CWCServer] ERROR binding to ca0");
|
|
||||||
|
|
||||||
pthread_t tCa0;
|
|
||||||
pthread_create(&tCa0, NULL, ca0Thread, (void*)capmt);
|
|
||||||
|
|
||||||
TAILQ_INSERT_TAIL(&capmts, capmt, capmt_link);
|
TAILQ_INSERT_TAIL(&capmts, capmt, capmt_link);
|
||||||
|
|
||||||
|
pthread_attr_init(&attr);
|
||||||
|
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||||
|
pthread_create(&ptid, &attr, capmt_thread, capmt);
|
||||||
|
pthread_attr_destroy(&attr);
|
||||||
|
|
||||||
return capmt;
|
return capmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -747,7 +701,6 @@ capmt_record_build(capmt_t *capmt)
|
||||||
static htsmsg_t *
|
static htsmsg_t *
|
||||||
capmt_entry_update(void *opaque, const char *id, htsmsg_t *values, int maycreate)
|
capmt_entry_update(void *opaque, const char *id, htsmsg_t *values, int maycreate)
|
||||||
{
|
{
|
||||||
printf("capmt entry update\n");
|
|
||||||
capmt_t *capmt;
|
capmt_t *capmt;
|
||||||
const char *s;
|
const char *s;
|
||||||
uint32_t u32;
|
uint32_t u32;
|
||||||
|
@ -760,28 +713,28 @@ capmt_entry_update(void *opaque, const char *id, htsmsg_t *values, int maycreate
|
||||||
if((s = htsmsg_get_str(values, "camdfilename")) != NULL) {
|
if((s = htsmsg_get_str(values, "camdfilename")) != NULL) {
|
||||||
free(capmt->capmt_sockfile);
|
free(capmt->capmt_sockfile);
|
||||||
capmt->capmt_sockfile = strdup(s);
|
capmt->capmt_sockfile = strdup(s);
|
||||||
printf("capmt sockfile %s\n", s);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!htsmsg_get_u32(values, "port", &u32)) {
|
if(!htsmsg_get_u32(values, "port", &u32))
|
||||||
capmt->capmt_port = u32;
|
capmt->capmt_port = u32;
|
||||||
printf("capmt listen port %d\n", u32);
|
|
||||||
}
|
|
||||||
|
|
||||||
if((s = htsmsg_get_str(values, "comment")) != NULL) {
|
if((s = htsmsg_get_str(values, "comment")) != NULL) {
|
||||||
free(capmt->capmt_comment);
|
free(capmt->capmt_comment);
|
||||||
capmt->capmt_comment = strdup(s);
|
capmt->capmt_comment = strdup(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
if(!htsmsg_get_u32(values, "enabled", &u32))
|
||||||
|
capmt->capmt_enabled = u32;
|
||||||
|
|
||||||
|
|
||||||
capmt->capmt_reconfigure = 1;
|
capmt->capmt_reconfigure = 1;
|
||||||
|
|
||||||
if(capmt->capmt_fd != -1)
|
/* if(capmt->capmt_fd != -1)
|
||||||
shutdown(capmt->capmt_fd, SHUT_RDWR);
|
shutdown(capmt->capmt_fd, SHUT_RDWR);*/
|
||||||
|
|
||||||
pthread_cond_signal(&capmt->capmt_cond);
|
pthread_cond_signal(&capmt->capmt_cond);
|
||||||
|
|
||||||
pthread_cond_broadcast(&capmt_config_changed);*/
|
pthread_cond_broadcast(&capmt_config_changed);
|
||||||
|
|
||||||
return capmt_record_build(capmt);
|
return capmt_record_build(capmt);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue