Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
tsdebug: add possibility to save the whole input mux with decrambler …
…keys
  • Loading branch information
perexg committed Dec 7, 2014
1 parent b87eb89 commit 2b2cb32
Show file tree
Hide file tree
Showing 15 changed files with 401 additions and 5 deletions.
4 changes: 4 additions & 0 deletions Makefile
Expand Up @@ -329,6 +329,10 @@ SRCS-${CONFIG_CAPMT} += \
SRCS-${CONFIG_CONSTCW} += \
src/descrambler/constcw.c

# TSDEBUGCW
SRCS-${CONFIG_TSDEBUG} += \
src/descrambler/tsdebugcw.c

# FFdecsa
ifneq ($(CONFIG_DVBCSA),yes)
FFDECSA-$(CONFIG_CAPMT) = yes
Expand Down
8 changes: 8 additions & 0 deletions configure
Expand Up @@ -44,6 +44,7 @@ OPTIONS=(
"kqueue:no"
"dbus_1:auto"
"android:no"
"tsdebug:no"
)

#
Expand Down Expand Up @@ -472,6 +473,13 @@ if enabled_or_auto dbus_1; then
fi
fi

#
# TSDebug
#
if enabled_or_auto tsdebug; then
enable mpegts_dvb
fi


# ###########################################################################
# Write config
Expand Down
6 changes: 6 additions & 0 deletions src/descrambler/caclient.c
Expand Up @@ -296,6 +296,9 @@ caclient_start ( struct service *t )
if (cac->cac_enabled)
cac->cac_start(cac, t);
pthread_mutex_unlock(&caclients_mutex);
#if ENABLE_TSDEBUG
tsdebugcw_service_start(t);
#endif
}

void
Expand Down Expand Up @@ -344,6 +347,9 @@ caclient_init(void)

pthread_mutex_init(&caclients_mutex, NULL);
TAILQ_INIT(&caclients);
#if ENABLE_TSDEBUG
tsdebugcw_init();
#endif

if (!(c = hts_settings_load("caclient")))
return;
Expand Down
6 changes: 6 additions & 0 deletions src/descrambler/caclient.h
Expand Up @@ -75,8 +75,14 @@ const char *caclient_get_status(caclient_t *cac);
void caclient_init(void);
void caclient_done(void);

void tsdebugcw_service_start(struct service *t);
void tsdebugcw_new_keys(struct service *t, int type, uint8_t *odd, uint8_t *even);
void tsdebugcw_go(void);
void tsdebugcw_init(void);

caclient_t *cwc_create(void);
caclient_t *capmt_create(void);
caclient_t *constcw_create(void);
caclient_t *tsdebugcw_create(void);

#endif /* __TVH_CACLIENT_H__ */
34 changes: 34 additions & 0 deletions src/descrambler/descrambler.c
Expand Up @@ -252,6 +252,40 @@ descrambler_keys ( th_descrambler_t *td, int type,

fin:
pthread_mutex_unlock(&t->s_stream_mutex);
#if ENABLE_TSDEBUG
if (j) {
tsdebug_packet_t *tp = malloc(sizeof(*tp));
uint16_t keylen = dr->dr_csa.csa_keylen;
uint16_t sid = ((mpegts_service_t *)td->td_service)->s_dvb_service_id;
uint32_t pos = 0, crc;
mpegts_mux_t *mm = ((mpegts_service_t *)td->td_service)->s_dvb_mux;
if (!mm->mm_active)
return;
pthread_mutex_lock(&mm->mm_active->mmi_input->mi_output_lock);
tp->pos = mm->mm_tsdebug_pos;
memset(tp->pkt, 0xff, sizeof(tp->pkt));
tp->pkt[pos++] = 0x47; /* sync byte */
tp->pkt[pos++] = 0x1f; /* PID MSB */
tp->pkt[pos++] = 0xff; /* PID LSB */
tp->pkt[pos++] = 0x00; /* CC */
memcpy(tp->pkt + pos, "TVHeadendDescramblerKeys", 24);
pos += 24;
tp->pkt[pos++] = type & 0xff;
tp->pkt[pos++] = keylen & 0xff;
tp->pkt[pos++] = (sid >> 8) & 0xff;
tp->pkt[pos++] = sid & 0xff;
memcpy(tp->pkt + pos, even, keylen);
memcpy(tp->pkt + pos + keylen, odd, keylen);
pos += 2 * keylen;
crc = tvh_crc32(tp->pkt, pos, 0x859aa5ba);
tp->pkt[pos++] = (crc >> 24) & 0xff;
tp->pkt[pos++] = (crc >> 16) & 0xff;
tp->pkt[pos++] = (crc >> 8) & 0xff;
tp->pkt[pos++] = crc & 0xff;
TAILQ_INSERT_HEAD(&mm->mm_tsdebug_packets, tp, link);
pthread_mutex_unlock(&mm->mm_active->mmi_input->mi_output_lock);
}
#endif
}

static void
Expand Down
169 changes: 169 additions & 0 deletions src/descrambler/tsdebugcw.c
@@ -0,0 +1,169 @@
/*
* tvheadend, tsdebug code word interface
* Copyright (C) 2014 Jaroslav Kysela
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include <ctype.h>
#include "tvheadend.h"
#include "caclient.h"
#include "service.h"
#include "input.h"

/**
*
*/
typedef struct tsdebugcw_service {
th_descrambler_t;

int tdcw_type;
uint8_t tdcw_key_even[16]; /* DES or AES key */
uint8_t tdcw_key_odd [16]; /* DES or AES key */

} tsdebugcw_service_t;

typedef struct tsdebugcw_request {
TAILQ_ENTRY(tsdebugcw_request) link;
tsdebugcw_service_t *ct;
} tsdebugcw_request_t;

pthread_mutex_t tsdebugcw_mutex;
TAILQ_HEAD(,tsdebugcw_request) tsdebugcw_requests;

/*
*
*/
static int
tsdebugcw_ecm_reset(th_descrambler_t *th)
{
return 1;
}

/**
* s_stream_mutex is held
*/
static void
tsdebugcw_service_destroy(th_descrambler_t *td)
{
tsdebugcw_service_t *ct = (tsdebugcw_service_t *)td;
tsdebugcw_request_t *ctr, *ctrnext;

pthread_mutex_lock(&tsdebugcw_mutex);
for (ctr = TAILQ_FIRST(&tsdebugcw_requests); ctr; ctr = ctrnext) {
ctrnext = TAILQ_NEXT(ctr, link);
if (ctr->ct == ct) {
TAILQ_REMOVE(&tsdebugcw_requests, ctr, link);
free(ctr);
}
}
pthread_mutex_unlock(&tsdebugcw_mutex);

LIST_REMOVE(td, td_service_link);
free(ct->td_nicename);
free(ct);
}

/**
* global_lock is held. Not that we care about that, but either way, it is.
*/
void
tsdebugcw_service_start(service_t *t)
{
tsdebugcw_service_t *ct;
th_descrambler_t *td;
char buf[128];

extern const idclass_t mpegts_service_class;
if (!idnode_is_instance(&t->s_id, &mpegts_service_class))
return;

LIST_FOREACH(td, &t->s_descramblers, td_service_link)
if (td->td_stop == tsdebugcw_service_destroy)
break;
if (td)
return;

ct = calloc(1, sizeof(tsdebugcw_service_t));
td = (th_descrambler_t *)ct;
snprintf(buf, sizeof(buf), "tsdebugcw");
td->td_nicename = strdup(buf);
td->td_service = t;
td->td_stop = tsdebugcw_service_destroy;
td->td_ecm_reset = tsdebugcw_ecm_reset;
LIST_INSERT_HEAD(&t->s_descramblers, td, td_service_link);
}

/*
*
*/
void
tsdebugcw_new_keys(service_t *t, int type, uint8_t *odd, uint8_t *even)
{
static char empty[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
th_descrambler_t *td;
tsdebugcw_service_t *ct;
tsdebugcw_request_t *ctr;
int keylen = type == DESCRAMBLER_AES ? 16 : 8;

LIST_FOREACH(td, &t->s_descramblers, td_service_link)
if (td->td_stop == tsdebugcw_service_destroy)
break;
if (!td)
return;
ct = (tsdebugcw_service_t *)td;
ct->tdcw_type = type;
if (memcmp(empty, odd, keylen))
memcpy(ct->tdcw_key_odd, odd, keylen);
if (memcmp(empty, even, keylen))
memcpy(ct->tdcw_key_even, even, keylen);
ctr = malloc(sizeof(*ctr));
ctr->ct = ct;
pthread_mutex_lock(&tsdebugcw_mutex);
TAILQ_INSERT_TAIL(&tsdebugcw_requests, ctr, link);
pthread_mutex_unlock(&tsdebugcw_mutex);
}

/*
*
*/
void
tsdebugcw_go(void)
{
tsdebugcw_request_t *ctr;
tsdebugcw_service_t *ct;

while (1) {
pthread_mutex_lock(&tsdebugcw_mutex);
ctr = TAILQ_FIRST(&tsdebugcw_requests);
if (ctr)
TAILQ_REMOVE(&tsdebugcw_requests, ctr, link);
pthread_mutex_unlock(&tsdebugcw_mutex);
if (!ctr) break;
ct = ctr->ct;
descrambler_keys((th_descrambler_t *)ct, ct->tdcw_type,
ct->tdcw_key_odd, ct->tdcw_key_even);
free(ctr);
}
}

/*
*
*/
void
tsdebugcw_init(void)
{
pthread_mutex_init(&tsdebugcw_mutex, NULL);
TAILQ_INIT(&tsdebugcw_requests);
}
38 changes: 38 additions & 0 deletions src/input/mpegts.h
Expand Up @@ -329,6 +329,12 @@ enum mpegts_mux_epg_flag
};
#define MM_EPG_LAST MM_EPG_ONLY_OPENTV_SKY_AUSAT

typedef struct tsdebug_packet {
TAILQ_ENTRY(tsdebug_packet) link;
uint8_t pkt[188];
off_t pos;
} tsdebug_packet_t;

/* Multiplex */
struct mpegts_mux
{
Expand Down Expand Up @@ -421,6 +427,16 @@ struct mpegts_mux
int mm_epg;
char *mm_charset;
int mm_pmt_06_ac3;

/*
* TSDEBUG
*/
#if ENABLE_TSDEBUG
int mm_tsdebug_fd;
int mm_tsdebug_fd2;
off_t mm_tsdebug_pos;
TAILQ_HEAD(, tsdebug_packet) mm_tsdebug_packets;
#endif
};

/* Service */
Expand Down Expand Up @@ -803,6 +819,28 @@ mpegts_pid_t * mpegts_input_open_pid
void mpegts_input_close_pid
( mpegts_input_t *mi, mpegts_mux_t *mm, int pid, int type, void *owner );

static inline void
tsdebug_write(mpegts_mux_t *mm, uint8_t *buf, size_t len)
{
#if ENABLE_TSDEBUG
ssize_t r = write(mm->mm_tsdebug_fd2, buf, len);
if (r != len && mm->mm_tsdebug_fd2 >= 0)
tvherror("tsdebug", "unable to write input data (%i)", errno);
#endif
}

static inline ssize_t
sbuf_tsdebug_read(mpegts_mux_t *mm, sbuf_t *sb, int fd)
{
#if ENABLE_TSDEBUG
ssize_t r = sbuf_read(sb, fd);
tsdebug_write(mm, sb->sb_data + sb->sb_ptr - r, r);
return r;
#else
return sbuf_read(sb, fd);
#endif
}

void mpegts_table_dispatch
(const uint8_t *sec, size_t r, void *mt);
static inline void mpegts_table_grab
Expand Down
1 change: 1 addition & 0 deletions src/input/mpegts/iptv/iptv_http.c
Expand Up @@ -47,6 +47,7 @@ iptv_http_data

pthread_mutex_lock(&iptv_lock);

tsdebug_write((mpegts_mux_t *)im, buf, len);
sbuf_append(&im->mm_iptv_buffer, buf, len);

if (len > 0)
Expand Down
1 change: 1 addition & 0 deletions src/input/mpegts/iptv/iptv_udp.c
Expand Up @@ -137,6 +137,7 @@ iptv_rtp_read ( iptv_mux_t *im )

/* Move data */
len -= hlen;
tsdebug_write((mpegts_mux_t *)im, rtp + hlen, len);
sbuf_append(&im->mm_iptv_buffer, rtp + hlen, len);
res += len;
}
Expand Down
2 changes: 1 addition & 1 deletion src/input/mpegts/linuxdvb/linuxdvb_frontend.c
Expand Up @@ -856,7 +856,7 @@ linuxdvb_frontend_input_thread ( void *aux )
if (ev[0].data.fd != dvr) break;

/* Read */
if ((n = sbuf_read(&sb, dvr)) < 0) {
if ((n = sbuf_tsdebug_read(mmi->mmi_mux, &sb, dvr)) < 0) {
if (ERRNO_AGAIN(errno))
continue;
if (errno == EOVERFLOW) {
Expand Down

0 comments on commit 2b2cb32

Please sign in to comment.