follow enigma2 pvr channel allocation api change
[enigma2-plugins.git] / bitrateviewer / src / bitratecalc / bitratecalc.cpp
1 /*
2 #  BitrateCalculator E2
3 #
4 #  $Id$
5 #
6 #  Coded by Dr.Best (c) 2010
7 #  Support: www.dreambox-tools.info
8 #
9 #  This plugin is licensed under the Creative Commons 
10 #  Attribution-NonCommercial-ShareAlike 3.0 Unported 
11 #  License. To view a copy of this license, visit
12 #  http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to Creative
13 #  Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
14 #
15 #  Alternatively, this plugin may be distributed and executed on hardware which
16 #  is licensed by Dream Multimedia GmbH.
17
18 #  This plugin is NOT free software. It is open source, you are allowed to
19 #  modify it (if you keep the license), but it may not be commercially 
20 #  distributed other than under the conditions noted above.
21 */
22
23 #include "bitratecalc.h"
24 #include <fcntl.h>
25 #include <lib/base/etpm.h>
26 #include <openssl/bn.h>
27 #include <openssl/sha.h>
28
29 eBitrateCalc::eBitrateCalc(const eServiceReference &ref, int pid, int refreshintervall, int buffer_size): m_size(0), m_refresh_intervall(refreshintervall)
30 {
31         m_send_data_timer = eTimer::create(eApp);
32         CONNECT(m_send_data_timer->timeout, eBitrateCalc::sendDataTimerTimeoutCB);
33         eDVBChannelID chid;
34         if (ref.type == eServiceReference::idDVB)
35         {
36                 int success = 0;
37                 eUsePtr<iDVBChannel> channel;
38                 eUsePtr<iDVBPVRChannel> pvr_channel;
39                 ePtr<iDVBDemux> demux;
40                 ePtr<eDVBResourceManager> res_mgr;
41                 eDVBResourceManager::getInstance(res_mgr);
42                 const eServiceReferenceDVB &dvb_ref = (eServiceReferenceDVB&)ref;
43                 eDVBChannelID chid;
44                 dvb_ref.getChannelID(chid);
45                 bool is_pvr = !chid.pvr_source.empty();
46                 m_reader = NULL;
47                 if ((is_pvr && !res_mgr->allocateChannel(chid, pvr_channel)) ||
48                     (!is_pvr && !res_mgr->allocateChannel(chid, channel)))
49                 {
50                         if (is_pvr)
51                                 channel = pvr_channel;
52                         if (!channel->getDemux(demux))
53                         {
54                                 if (!demux->createPESReader(eApp, m_reader))
55                                 {
56                                         if (!m_reader->connectRead(slot(*this, &eBitrateCalc::dataReady), m_pes_connection))
57                                         {
58                                                 channel->connectStateChange(slot(*this, &eBitrateCalc::stateChange), m_channel_connection);
59                                                 success = 1;
60                                         }
61                                         else
62                                                 eDebug("[eBitrateCalc] connect pes reader failed...");
63                                 }
64                                 else
65                                         eDebug("[eBitrateCalc] create PES reader failed...");
66                         }
67                         else
68                                 eDebug("[eBitrateCalc] getDemux failed...");
69                 }
70                 if (m_reader && success)
71                 {
72                         clock_gettime(CLOCK_MONOTONIC, &m_start);
73                         m_reader->setBufferSize(buffer_size);
74                         m_reader->start(pid);
75                         m_send_data_timer->start(m_refresh_intervall, true);
76                 }
77                 else
78                         sendData(-1,0);
79         }
80 }
81
82 void eBitrateCalc::dataReady(const __u8*,  int size)
83 {
84         m_size += size;
85 }
86
87 void eBitrateCalc::sendDataTimerTimeoutCB()
88 {
89         struct timespec now;
90         clock_gettime(CLOCK_MONOTONIC, &now);
91         timespec delta = now - m_start;
92         unsigned int delta_ms = delta.tv_nsec / 1000000 + delta.tv_sec * 1000;
93         if (delta_ms)
94         {
95                 int bitrate =  int(m_size / delta_ms)*8;
96                 sendData(bitrate,1);
97         }               
98         m_send_data_timer->start(m_refresh_intervall, true);
99 }
100
101 void eBitrateCalc::stateChange(iDVBChannel *ch)
102 {
103         int state;
104         if (ch->getState(state))
105                 return;
106         if (state == iDVBChannel::state_release)
107         {
108                 m_send_data_timer = NULL;
109                 m_reader = NULL;
110                 m_pes_connection = NULL;
111                 m_channel_connection = NULL;
112                 sendData(-1,0);
113         }
114 }
115
116 static void rsa_pub1024(unsigned char dest[128],
117                         const unsigned char src[128],
118                         const unsigned char mod[128])
119 {
120         BIGNUM bbuf, bexp, bmod;
121         BN_CTX *ctx;
122
123         ctx = BN_CTX_new();
124         BN_init(&bbuf);
125         BN_init(&bexp);
126         BN_init(&bmod);
127
128         BN_bin2bn(src, 128, &bbuf);
129         BN_bin2bn(mod, 128, &bmod);
130         BN_bin2bn((const unsigned char *)"\x01\x00\x01", 3, &bexp);
131
132         BN_mod_exp(&bbuf, &bbuf, &bexp, &bmod, ctx);
133
134         BN_bn2bin(&bbuf, dest);
135
136         BN_clear_free(&bexp);
137         BN_clear_free(&bmod);
138         BN_clear_free(&bbuf);
139         BN_CTX_free(ctx);
140 }
141
142 static bool decrypt_block(unsigned char dest[128],
143                           const unsigned char *src,
144                           unsigned int len,
145                           const unsigned char mod[128])
146 {
147         unsigned char hash[20];
148         SHA_CTX ctx;
149
150         if ((len != 128) &&
151             (len != 202))
152                 return false;
153
154         rsa_pub1024(dest, src, mod);
155
156         SHA1_Init(&ctx);
157         SHA1_Update(&ctx, &dest[1], 106);
158         if (len == 202)
159                 SHA1_Update(&ctx, &src[131], 61);
160         SHA1_Final(hash, &ctx);
161
162         return (memcmp(hash, &dest[107], 20) == 0);
163 }
164
165 static bool read_random(unsigned char *buf, size_t len)
166 {
167         ssize_t ret;
168         int fd;
169
170         fd = open("/dev/urandom", O_RDONLY);
171         if (fd < 0) {
172                 perror("/dev/urandom");
173                 return false;
174         }
175
176         ret = read(fd, buf, len);
177
178         close(fd);
179
180         if (ret != (ssize_t)len) {
181                 fprintf(stderr, "could not read random data\n");
182                 return false;
183         }
184
185         return true;
186 }
187
188 static bool validate_cert(unsigned char dest[128],
189                           const unsigned char *src,
190                           const unsigned char mod[128])
191 {
192         unsigned char buf[128];
193
194         if (!decrypt_block(buf, &src[8], 210 - 8, mod))
195                 return false;
196
197         memcpy(&dest[0], &buf[36], 71);
198         memcpy(&dest[71], &src[131 + 8], 57);
199         return true;
200 }
201
202 static const unsigned char tpm_root_mod[128] = {
203         0x9F,0x7C,0xE4,0x47,0xC9,0xB4,0xF4,0x23,0x26,0xCE,0xB3,0xFE,0xDA,0xC9,0x55,0x60,
204         0xD8,0x8C,0x73,0x6F,0x90,0x9B,0x5C,0x62,0xC0,0x89,0xD1,0x8C,0x9E,0x4A,0x54,0xC5,
205         0x58,0xA1,0xB8,0x13,0x35,0x45,0x02,0xC9,0xB2,0xE6,0x74,0x89,0xDE,0xCD,0x9D,0x11,
206         0xDD,0xC7,0xF4,0xE4,0xE4,0xBC,0xDB,0x9C,0xEA,0x7D,0xAD,0xDA,0x74,0x72,0x9B,0xDC,
207         0xBC,0x18,0x33,0xE7,0xAF,0x7C,0xAE,0x0C,0xE3,0xB5,0x84,0x8D,0x0D,0x8D,0x9D,0x32,
208         0xD0,0xCE,0xD5,0x71,0x09,0x84,0x63,0xA8,0x29,0x99,0xDC,0x3C,0x22,0x78,0xE8,0x87,
209         0x8F,0x02,0x3B,0x53,0x6D,0xD5,0xF0,0xA3,0x5F,0xB7,0x54,0x09,0xDE,0xA7,0xF1,0xC9,
210         0xAE,0x8A,0xD7,0xD2,0xCF,0xB2,0x2E,0x13,0xFB,0xAC,0x6A,0xDF,0xB1,0x1D,0x3A,0x3F,
211 };
212
213 #define CLEN 8
214
215 static bool signature()
216 {
217         int chk = 1;
218         FILE *fp; 
219         fp = fopen ("/proc/stb/info/model", "r");
220         if (fp)
221         {
222                 char line[256];
223                 int n;
224                 fgets(line, sizeof(line), fp);
225                 if ((n = strlen(line)) && line[n - 1] == '\n')
226                          line[n - 1] = '\0';
227                 fclose(fp);
228                 if (strstr(line,"dm7025"))
229                         chk = 0;
230         }
231         if (chk)
232         {
233                 eTPM tpm;
234                 unsigned char rnd[CLEN];
235                 /* read random bytes */
236                 if (!read_random(rnd, CLEN))
237                         return 1;
238                 unsigned char level2_mod[128];
239                 unsigned char level3_mod[128];
240                 unsigned char buf[128];
241                 std::string challenge((char*)rnd, CLEN);
242                 std::string response = tpm.challenge(challenge);
243                 unsigned int len = response.size();
244                 unsigned char val[len];
245                 if ( len != 128 )
246                         return false;
247                 memcpy(val, response.c_str(), len);
248                 std::string cert = tpm.getCert(eTPM::TPMD_DT_LEVEL2_CERT);
249                 if ( cert.size() != 210 || !validate_cert(level2_mod, (const unsigned char*) cert.c_str(), tpm_root_mod))
250                         return false;
251                 cert = tpm.getCert(eTPM::TPMD_DT_LEVEL3_CERT);
252                 if ( cert.size() != 210 || !validate_cert(level3_mod, (const unsigned char*) cert.c_str(), level2_mod))
253                         return false;
254                 if (!decrypt_block(buf, val, 128, level3_mod))
255                         return false;
256                 if (memcmp(&buf[80], rnd, CLEN))
257                         return false;
258                 return true;
259         }
260         else
261                 return true;
262 }
263
264 // eBitrateCalculator replacement
265 extern "C" {
266
267 struct eBitrateCalculatorPy
268 {
269         PyObject_HEAD
270         eBitrateCalc *bc;
271 };
272
273 static int
274 eBitrateCalculatorPy_traverse(eBitrateCalculatorPy *self, visitproc visit, void *arg)
275 {
276         PyObject *obj = self->bc->dataSent.getSteal();
277         if (obj)
278                 Py_VISIT(obj);
279         return 0;
280 }
281
282 static int
283 eBitrateCalculatorPy_clear(eBitrateCalculatorPy *self)
284 {
285         PyObject *obj = self->bc->dataSent.getSteal(true);
286         if (obj)
287                 Py_CLEAR(obj);
288         delete self->bc;
289         return 0;
290 }
291
292 static void
293 eBitrateCalculatorPy_dealloc(eBitrateCalculatorPy* self)
294 {
295         eBitrateCalculatorPy_clear(self);
296         self->ob_type->tp_free((PyObject*)self);
297 }
298
299 static PyObject *
300 eBitrateCalculatorPy_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
301 {
302         eBitrateCalculatorPy *self = (eBitrateCalculatorPy *)type->tp_alloc(type, 0);
303         int size = PyTuple_Size(args);
304         char *refstr=NULL;
305         int refreshinterval, buffer_size, pid;
306         if (size < 4 || !PyArg_ParseTuple(args, "isii", &pid, &refstr, &refreshinterval, &buffer_size))
307                 return NULL;
308         self->bc = new eBitrateCalc(eServiceReference(refstr), pid, refreshinterval, buffer_size);
309         return (PyObject *)self;
310 }
311
312 static PyObject *
313 eBitrateCalculatorPy_get_cb_list(eBitrateCalculatorPy *self, void *closure)
314 {
315         return self->bc->dataSent.get();
316 }
317
318 static PyGetSetDef eBitrateCalculatorPy_getseters[] = {
319         {"callback",
320          (getter)eBitrateCalculatorPy_get_cb_list, (setter)0,
321          "returns the callback python list",
322          NULL},
323         {NULL} /* Sentinel */
324 };
325
326 static PyTypeObject eBitrateCalculatorPyType = {
327         PyObject_HEAD_INIT(NULL)
328         0, /*ob_size*/
329         "eBitrateImpl.eBitrateCalculator", /*tp_name*/
330         sizeof(eBitrateCalculatorPy), /*tp_basicsize*/
331         0, /*tp_itemsize*/
332         (destructor)eBitrateCalculatorPy_dealloc, /*tp_dealloc*/
333         0, /*tp_print*/
334         0, /*tp_getattr*/
335         0, /*tp_setattr*/
336         0, /*tp_compare*/
337         0, /*tp_repr*/
338         0, /*tp_as_number*/
339         0, /*tp_as_sequence*/
340         0, /*tp_as_mapping*/
341         0, /*tp_hash */
342         0, /*tp_call*/
343         0, /*tp_str*/
344         0, /*tp_getattro*/
345         0, /*tp_setattro*/
346         0, /*tp_as_buffer*/
347         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
348         "eBitrateCalculator objects", /* tp_doc */
349         (traverseproc)eBitrateCalculatorPy_traverse, /* tp_traverse */
350         (inquiry)eBitrateCalculatorPy_clear, /* tp_clear */
351         0, /* tp_richcompare */
352         0, /* tp_weaklistoffset */
353         0, /* tp_iter */
354         0, /* tp_iternext */
355         0, /* tp_methods */
356         0, /* tp_members */
357         eBitrateCalculatorPy_getseters, /* tp_getset */
358         0, /* tp_base */
359         0, /* tp_dict */
360         0, /* tp_descr_get */
361         0, /* tp_descr_set */
362         0, /* tp_dictoffset */
363         0, /* tp_init */
364         0, /* tp_alloc */
365         eBitrateCalculatorPy_new, /* tp_new */
366 };
367
368 static PyMethodDef module_methods[] = {
369         {NULL}  /* Sentinel */
370 };
371
372 PyMODINIT_FUNC
373 initbitratecalc(void)
374 {
375         bool init = signature();
376         PyObject* m = Py_InitModule3("bitratecalc", module_methods,
377                 "Module that implements bitrate calculations.");
378         if (m == NULL)
379                 return;
380         if (!init)
381         {
382                 PyErr_SetString(PyExc_TypeError, "TPM challenge failed");
383                 return; 
384         }
385         if (!PyType_Ready(&eBitrateCalculatorPyType))
386         {
387                 Org_Py_INCREF((PyObject*)&eBitrateCalculatorPyType);
388                 PyModule_AddObject(m, "eBitrateCalculator", (PyObject*)&eBitrateCalculatorPyType);
389         }
390 }
391 };