Initial work to fix code word client

This commit is contained in:
Andreas Öman 2008-09-01 18:33:46 +00:00
parent 3c92fe070c
commit 85b71cb763
2 changed files with 196 additions and 155 deletions

317
cwc.c
View file

@ -110,21 +110,6 @@ typedef struct cwc_transport {
} cwc_transport_t;
/**
*
*/
static void
cwc_set_state(cwc_t *cwc, int newstate, const char *errtxt)
{
cwc->cwc_state = newstate;
if(newstate == CWC_STATE_IDLE)
cwc->cwc_errtxt = errtxt;
//notify_cwc_status_change(cwc);
}
/**
*
@ -276,26 +261,12 @@ des_make_session_key(cwc_t *cwc)
memcpy(cwc->cwc_key, des_key_spread(des14), 16);
}
/**
*
*/
static void
cwc_timeout(void *aux, int64_t now)
{
cwc_t *cwc = aux;
tcp_disconnect(&cwc->cwc_tcp_session, ETIMEDOUT);
}
/**
*
*/
static int
cwc_send_msg(cwc_t *cwc, const uint8_t *msg, size_t len, int sid)
{
tcp_session_t *ses = &cwc->cwc_tcp_session;
uint8_t *buf = malloc(CWS_NETMSGSIZE);
memset(buf, 0, 12);
@ -318,10 +289,8 @@ cwc_send_msg(cwc_t *cwc, const uint8_t *msg, size_t len, int sid)
buf[0] = (len - 2) >> 8;
buf[1] = len - 2;
tcp_send_msg(ses, 0, buf, len);
/* Expect a response within 4 seconds */
dtimer_arm(&cwc->cwc_idle_timer, cwc_timeout, cwc, 4);
write(cwc->cwc_fd, buf, len);
free(buf);
return cwc->cwc_seq;
}
@ -330,13 +299,12 @@ cwc_send_msg(cwc_t *cwc, const uint8_t *msg, size_t len, int sid)
/**
* Card data command
*/
static void
cwc_send_data_req(cwc_t *cwc)
{
uint8_t buf[CWS_NETMSGSIZE];
cwc_set_state(cwc, CWC_STATE_WAIT_CARD_DATA, NULL);
buf[0] = MSG_CARD_DATA_REQ;
buf[1] = 0;
buf[2] = 0;
@ -348,6 +316,7 @@ cwc_send_data_req(cwc_t *cwc)
/**
* Send keep alive
*/
#if 0
static void
cwc_send_ka(void *aux, int64_t now)
{
@ -359,49 +328,44 @@ cwc_send_ka(void *aux, int64_t now)
buf[2] = 0;
cwc_send_msg(cwc, buf, 3, 0);
dtimer_arm(&cwc->cwc_send_ka_timer, cwc_send_ka, cwc,
CWC_KEEPALIVE_INTERVAL);
}
#endif
/**
* Handle reply to card data request
*/
static int
cwc_dispatch_card_data_reply(cwc_t *cwc, uint8_t msgtype,
uint8_t *msg, int len)
cwc_decode_card_data_reply(cwc_t *cwc, uint8_t *msg, int len)
{
int plen;
const char *n;
if(msgtype != MSG_CARD_DATA)
return EBADMSG;
msg += 12;
len -= 12;
if(len < 3) {
tvhlog(LOG_INFO, "cwc", "Invalid card data reply");
return -1;
}
plen = (msg[1] & 0xf) << 8 | msg[2];
if(plen < 14)
return EBADMSG;
if(plen < 14) {
tvhlog(LOG_INFO, "cwc", "Invalid card data reply");
return -1;
}
cwc->cwc_caid = (msg[4] << 8) | msg[5];
n = psi_caid2name(cwc->cwc_caid) ?: "Unknown";
tvhlog(LOG_INFO, "cwc", "%s: Connected as user 0x%02x "
"to a %s-card [0x%04x : %02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x] "
"with %d providers",
cwc->cwc_tcp_session.tcp_hostname,
cwc->cwc_hostname,
msg[3], n, cwc->cwc_caid,
msg[6], msg[7], msg[8], msg[9], msg[10], msg[11], msg[12], msg[13],
msg[14]);
cwc_set_state(cwc, CWC_STATE_RUNNING, NULL);
/* Send KA every CWC_KEEPALIVE_INTERVAL seconds */
dtimer_arm(&cwc->cwc_send_ka_timer, cwc_send_ka, cwc,
CWC_KEEPALIVE_INTERVAL);
return 0;
}
@ -416,8 +380,6 @@ cwc_send_login(cwc_t *cwc)
int ul = strlen(cwc->cwc_username) + 1;
int pl = strlen(cwc->cwc_password_salted) + 1;
cwc_set_state(cwc, CWC_STATE_WAIT_LOGIN_ACK, NULL);
buf[0] = MSG_CLIENT_2_SERVER_LOGIN;
buf[1] = 0;
buf[2] = ul + pl;
@ -427,7 +389,7 @@ cwc_send_login(cwc_t *cwc)
cwc_send_msg(cwc, buf, ul + pl + 3, 0);
}
#if 0
/**
* Handle reply to login
*/
@ -591,37 +553,155 @@ cwc_data_input(cwc_t *cwc)
}
}
}
#endif
/**
*
*/
static int
cwc_read_message(cwc_t *cwc, const char *state)
{
char buf[2];
int msglen, r;
if((r = tcp_read(cwc->cwc_fd, buf, 2))) {
tvhlog(LOG_INFO, "cwc", "%s: %s: Read error (header): %s",
cwc->cwc_hostname, state, strerror(r));
return -1;
}
msglen = (buf[0] << 8) | buf[1];
if(msglen >= CWS_NETMSGSIZE) {
tvhlog(LOG_INFO, "cwc", "%s: %s: Invalid message size: %d",
cwc->cwc_hostname, state, msglen);
return -1;
}
if((r = tcp_read(cwc->cwc_fd, cwc->cwc_buf + 2, msglen))) {
tvhlog(LOG_INFO, "cwc", "%s: %s: Read error: %s",
cwc->cwc_hostname, state, strerror(r));
return -1;
}
if((msglen = des_decrypt(cwc->cwc_buf, msglen + 2, cwc->cwc_key)) < 15) {
tvhlog(LOG_INFO, "cwc", "%s: %s: Decrypt failed", state, cwc->cwc_hostname);
return -1;
}
return msglen;
}
/**
*
*/
static void
cwc_tcp_callback(tcpevent_t event, void *tcpsession)
cwc_session(cwc_t *cwc)
{
cwc_t *cwc = tcpsession;
dtimer_disarm(&cwc->cwc_idle_timer);
switch(event) {
case TCP_CONNECT:
cwc->cwc_seq = 0;
cwc->cwc_bufptr = 0;
cwc_set_state(cwc, CWC_STATE_WAIT_LOGIN_KEY, NULL);
/* We want somthing within 20 seconds */
dtimer_arm(&cwc->cwc_idle_timer, cwc_timeout, cwc, 20);
break;
case TCP_DISCONNECT:
cwc_set_state(cwc, CWC_STATE_IDLE, "Disconnected");
dtimer_disarm(&cwc->cwc_send_ka_timer);
break;
case TCP_INPUT:
cwc_data_input(cwc);
break;
int r;
/**
* Get login key
*/
if((r = tcp_read(cwc->cwc_fd, cwc->cwc_buf, 14))) {
tvhlog(LOG_INFO, "cwc", "%s: No login key received: %s",
cwc->cwc_hostname, strerror(r));
return;
}
des_make_login_key(cwc, cwc->cwc_buf);
/**
* Login
*/
cwc_send_login(cwc);
if(cwc_read_message(cwc, "Wait login response") < 0)
return;
if(!cwc->cwc_running || !cwc->cwc_enabled)
return;
if(cwc->cwc_buf[12] != MSG_CLIENT_2_SERVER_LOGIN_ACK) {
tvhlog(LOG_INFO, "cwc", "%s: Login failed", cwc->cwc_hostname);
return;
}
des_make_session_key(cwc);
/**
* Request card data
*/
cwc_send_data_req(cwc);
if((r = cwc_read_message(cwc, "Request card data")) < 0)
return;
if(cwc->cwc_buf[12] != MSG_CARD_DATA) {
tvhlog(LOG_INFO, "cwc", "%s: Card data request failed", cwc->cwc_hostname);
return;
}
if(!cwc->cwc_running || !cwc->cwc_enabled)
return;
cwc_decode_card_data_reply(cwc, cwc->cwc_buf, r);
sleep(4);
}
/**
*
*/
static void *
cwc_thread(void *aux)
{
cwc_t *cwc = aux;
int fd;
char errbuf[100];
pthread_mutex_lock(&cwc->cwc_mutex);
while(cwc->cwc_running) {
while(cwc->cwc_running && cwc->cwc_enabled == 0)
pthread_cond_wait(&cwc->cwc_cond, &cwc->cwc_mutex);
tvhlog(LOG_INFO, "cwc", "Attemping to connect to %s:%d",
cwc->cwc_hostname, cwc->cwc_port);
fd = tcp_connect(cwc->cwc_hostname, cwc->cwc_port, errbuf,
sizeof(errbuf), 10);
if(fd == -1) {
tvhlog(LOG_INFO, "cwc", "Connection attempt to %s:%d failed: %s",
cwc->cwc_hostname, cwc->cwc_port, errbuf);
continue;
}
if(cwc->cwc_running == 0)
break;
tvhlog(LOG_INFO, "cwc", "Connected to %s:%d",
cwc->cwc_hostname, cwc->cwc_port);
cwc->cwc_fd = fd;
pthread_mutex_unlock(&cwc->cwc_mutex);
cwc_session(cwc);
pthread_mutex_lock(&cwc->cwc_mutex);
cwc->cwc_fd = -1;
close(fd);
tvhlog(LOG_INFO, "cwc", "Disconnected from %s", cwc->cwc_hostname);
sleep(1);
}
pthread_mutex_unlock(&cwc->cwc_mutex);
return NULL;
}
@ -653,11 +733,14 @@ cwc_table_input(struct th_descrambler *td, struct th_transport *t,
if(ct->ct_ecmsize == len && !memcmp(ct->ct_ecm, data, len))
return; /* key already sent */
abort();
/*
if(cwc->cwc_state != CWC_STATE_RUNNING) {
/* New key, but we are not connected (anymore), can not descramble */
// New key, but we are not connected (anymore), can not descramble
ct->ct_keystate = CT_UNKNOWN;
break;
}
*/
memcpy(ct->ct_ecm, data, len);
ct->ct_ecmsize = len;
@ -757,6 +840,8 @@ cwc_transport_start(th_transport_t *t)
th_descrambler_t *td;
th_stream_t *st;
lock_assert(&global_lock);
TAILQ_FOREACH(cwc, &cwcs, cwc_link) {
if(cwc->cwc_caid == 0)
continue;
@ -794,6 +879,13 @@ cwc_destroy(cwc_t *cwc)
{
cwc_transport_t *ct;
pthread_mutex_lock(&cwc->cwc_mutex);
cwc->cwc_running = 0;
pthread_cond_signal(&cwc->cwc_cond);
pthread_mutex_unlock(&cwc->cwc_mutex);
pthread_join(cwc->cwc_thread_id, NULL);
while((ct = LIST_FIRST(&cwc->cwc_transports)) != NULL)
cwc_transport_destroy(ct);
@ -801,8 +893,8 @@ cwc_destroy(cwc_t *cwc)
free((void *)cwc->cwc_password);
free((void *)cwc->cwc_password_salted);
free((void *)cwc->cwc_username);
tcp_destroy_client(&cwc->cwc_tcp_session);
free((void *)cwc->cwc_hostname);
free(cwc);
}
@ -831,14 +923,12 @@ cwc_entry_find(const char *id, int create)
cwc_tally = atoi(id);
}
cwc = tcp_create_client(NULL, 11000, sizeof(cwc_t),
"cwc", cwc_tcp_callback, 0);
cwc = calloc(1, sizeof(cwc_t));
cwc->cwc_id = strdup(id);
cwc->cwc_username = NULL;
cwc->cwc_password = NULL;
cwc->cwc_running = 1;
TAILQ_INSERT_TAIL(&cwcs, cwc, cwc_link);
pthread_create(&cwc->cwc_thread_id, NULL, cwc_thread, cwc);
return cwc;
}
@ -855,8 +945,8 @@ cwc_record_build(cwc_t *cwc)
htsmsg_add_str(e, "id", cwc->cwc_id);
htsmsg_add_u32(e, "enabled", !!cwc->cwc_enabled);
htsmsg_add_str(e, "hostname", cwc->cwc_tcp_session.tcp_hostname ?: "");
htsmsg_add_u32(e, "port", cwc->cwc_tcp_session.tcp_port);
htsmsg_add_str(e, "hostname", cwc->cwc_hostname ?: "");
htsmsg_add_u32(e, "port", cwc->cwc_port);
htsmsg_add_str(e, "username", cwc->cwc_username ?: "");
htsmsg_add_str(e, "password", cwc->cwc_password ?: "");
@ -920,8 +1010,7 @@ cwc_entry_update(void *opaque, const char *id, htsmsg_t *values, int maycreate)
if((cwc = cwc_entry_find(id, maycreate)) == NULL)
return NULL;
/* Disable while changing */
tcp_enable_disable(&cwc->cwc_tcp_session, 0);
pthread_mutex_lock(&cwc->cwc_mutex);
if((s = htsmsg_get_str(values, "username")) != NULL) {
free(cwc->cwc_username);
@ -941,14 +1030,15 @@ cwc_entry_update(void *opaque, const char *id, htsmsg_t *values, int maycreate)
}
if((s = htsmsg_get_str(values, "hostname")) != NULL) {
tcp_set_hostname(&cwc->cwc_tcp_session, s);
free(cwc->cwc_hostname);
cwc->cwc_hostname = strdup(s);
}
if(!htsmsg_get_u32(values, "enabled", &u32))
cwc->cwc_enabled = u32;
if(!htsmsg_get_u32(values, "port", &u32))
cwc->cwc_tcp_session.tcp_port = u32;
cwc->cwc_port = u32;
if((s = htsmsg_get_str(values, "deskey")) != NULL) {
for(i = 0; i < 14; i++) {
@ -965,8 +1055,8 @@ cwc_entry_update(void *opaque, const char *id, htsmsg_t *values, int maycreate)
memcpy(cwc->cwc_confedkey, key, 14);
}
if(cwc->cwc_enabled)
tcp_enable_disable(&cwc->cwc_tcp_session, 1);
pthread_cond_signal(&cwc->cwc_cond);
pthread_mutex_unlock(&cwc->cwc_mutex);
return cwc_record_build(cwc);
}
@ -1058,38 +1148,3 @@ cwc_init(void)
dt = dtable_create(&cwc_dtc, "cwc", NULL);
dtable_load(dt);
}
/**
*
*/
static struct strtab cwcstatustab[] = {
{ "Waiting for login key", CWC_STATE_WAIT_LOGIN_KEY },
{ "Waiting for login ACK", CWC_STATE_WAIT_LOGIN_ACK },
{ "Waiting for card data", CWC_STATE_WAIT_CARD_DATA },
{ "Running", CWC_STATE_RUNNING },
};
const char *
cwc_status_to_text(struct cwc *cwc)
{
static char buf[100];
char buf2[30];
const char *n;
if(cwc->cwc_state == CWC_STATE_IDLE)
return cwc->cwc_errtxt ?: "Not connected";
if(cwc->cwc_state == CWC_STATE_RUNNING) {
n = psi_caid2name(cwc->cwc_caid);
if(n == NULL) {
snprintf(buf2, sizeof(buf2), "0x%x", cwc->cwc_caid);
n = buf2;
}
snprintf(buf, sizeof(buf), "Connected to a %s card", n);
return buf;
}
return val2str(cwc->cwc_state, cwcstatustab) ?: "Invalid status";
}

34
cwc.h
View file

@ -26,22 +26,16 @@ TAILQ_HEAD(cwc_queue, cwc);
extern struct cwc_queue cwcs;
typedef struct cwc {
// tcp_session_t cwc_tcp_session; /* Must be first */
int cwc_fd;
TAILQ_ENTRY(cwc) cwc_link;
pthread_mutex_t cwc_mutex;
pthread_cond_t cwc_cond;
pthread_t cwc_thread_id;
TAILQ_ENTRY(cwc) cwc_link; /* Linkage protected via global_lock */
LIST_HEAD(, cwc_transport) cwc_transports;
enum {
CWC_STATE_IDLE,
CWC_STATE_WAIT_LOGIN_KEY,
CWC_STATE_WAIT_LOGIN_ACK,
CWC_STATE_WAIT_CARD_DATA,
CWC_STATE_RUNNING,
CWC_STATE_HOST_ERROR,
CWC_STATE_ACCESS_ERROR,
} cwc_state;
uint16_t cwc_caid;
uint16_t cwc_seq;
@ -58,17 +52,14 @@ typedef struct cwc {
char *cwc_password;
char *cwc_password_salted; /* salted version */
char *cwc_comment;
// dtimer_t cwc_idle_timer;
// dtimer_t cwc_send_ka_timer;
char *cwc_hostname;
int cwc_port;
char *cwc_id;
const char *cwc_errtxt;
int cwc_enabled;
int cwc_running;
} cwc_t;
@ -76,14 +67,9 @@ void cwc_init(void);
void cwc_transport_start(th_transport_t *t);
const char *cwc_add(const char *hostname, const char *porttxt,
const char *username, const char *password,
const char *deskey, const char *enabled,
int save, int salt);
const char *cwc_status_to_text(struct cwc *cwc);
cwc_t *cwc_find(int id);
//cwc_t *cwc_find(int id);
void cwc_delete(cwc_t *cwc);