You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

427 lines
12 KiB

  1. /*
  2. * sectionfilter.c: IPTV plugin for the Video Disk Recorder
  3. *
  4. * See the README file for copyright information and how to reach the author.
  5. *
  6. */
  7. #include "config.h"
  8. #include "log.h"
  9. #include "sectionfilter.h"
  10. cIptvSectionFilter::cIptvSectionFilter(int deviceIndexP, uint16_t pidP, uint8_t tidP, uint8_t maskP)
  11. : pusiSeenM(0),
  12. feedCcM(0),
  13. doneqM(0),
  14. secBufM(NULL),
  15. secBufpM(0),
  16. secLenM(0),
  17. tsFeedpM(0),
  18. pidM(pidP),
  19. ringBufferM(new cRingBufferFrame(eDmxMaxSectionCount * eDmxMaxSectionSize)),
  20. deviceIndexM(deviceIndexP)
  21. {
  22. debug16("%s (%d, %d)", __PRETTY_FUNCTION__, deviceIndexM, pidM);
  23. int i;
  24. memset(secBufBaseM, 0, sizeof(secBufBaseM));
  25. memset(filterValueM, 0, sizeof(filterValueM));
  26. memset(filterMaskM, 0, sizeof(filterMaskM));
  27. memset(filterModeM, 0, sizeof(filterModeM));
  28. memset(maskAndModeM, 0, sizeof(maskAndModeM));
  29. memset(maskAndNotModeM, 0, sizeof(maskAndNotModeM));
  30. filterValueM[0] = tidP;
  31. filterMaskM[0] = maskP;
  32. // Invert the filter
  33. for (i = 0; i < eDmxMaxFilterSize; ++i)
  34. filterValueM[i] ^= 0xFF;
  35. uint8_t mask, mode, doneq = 0;
  36. for (i = 0; i < eDmxMaxFilterSize; ++i) {
  37. mode = filterModeM[i];
  38. mask = filterMaskM[i];
  39. maskAndModeM[i] = (uint8_t)(mask & mode);
  40. maskAndNotModeM[i] = (uint8_t)(mask & ~mode);
  41. doneq |= maskAndNotModeM[i];
  42. }
  43. doneqM = doneq ? 1 : 0;
  44. // Create sockets
  45. socketM[0] = socketM[1] = -1;
  46. if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, socketM) != 0) {
  47. char tmp[64];
  48. error("Opening section filter sockets failed (device=%d pid=%d): %s", deviceIndexM, pidM, strerror_r(errno, tmp, sizeof(tmp)));
  49. }
  50. else if ((fcntl(socketM[0], F_SETFL, O_NONBLOCK) != 0) || (fcntl(socketM[1], F_SETFL, O_NONBLOCK) != 0)) {
  51. char tmp[64];
  52. error("Setting section filter socket to non-blocking mode failed (device=%d pid=%d): %s", deviceIndexM, pidM, strerror_r(errno, tmp, sizeof(tmp)));
  53. }
  54. }
  55. cIptvSectionFilter::~cIptvSectionFilter()
  56. {
  57. debug16("%s (%d, %d)", __PRETTY_FUNCTION__, deviceIndexM, pidM);
  58. int tmp = socketM[1];
  59. socketM[1] = -1;
  60. if (tmp >= 0)
  61. close(tmp);
  62. tmp = socketM[0];
  63. socketM[0] = -1;
  64. if (tmp >= 0)
  65. close(tmp);
  66. secBufM = NULL;
  67. DELETENULL(ringBufferM);
  68. }
  69. inline uint16_t cIptvSectionFilter::GetLength(const uint8_t *dataP)
  70. {
  71. return (uint16_t)(3 + ((dataP[1] & 0x0f) << 8) + dataP[2]);
  72. }
  73. void cIptvSectionFilter::New(void)
  74. {
  75. tsFeedpM = secBufpM = secLenM = 0;
  76. secBufM = secBufBaseM;
  77. }
  78. int cIptvSectionFilter::Filter(void)
  79. {
  80. if (secBufM) {
  81. int i;
  82. uint8_t neq = 0;
  83. for (i = 0; i < eDmxMaxFilterSize; ++i) {
  84. uint8_t calcxor = (uint8_t)(filterValueM[i] ^ secBufM[i]);
  85. if (maskAndModeM[i] & calcxor)
  86. return 0;
  87. neq |= (maskAndNotModeM[i] & calcxor);
  88. }
  89. if (doneqM && !neq)
  90. return 0;
  91. if (ringBufferM && (secLenM > 0))
  92. ringBufferM->Put(new cFrame(secBufM, secLenM));
  93. }
  94. return 0;
  95. }
  96. inline int cIptvSectionFilter::Feed(void)
  97. {
  98. if (Filter() < 0)
  99. return -1;
  100. secLenM = 0;
  101. return 0;
  102. }
  103. int cIptvSectionFilter::CopyDump(const uint8_t *bufP, uint8_t lenP)
  104. {
  105. uint16_t limit, seclen, n;
  106. if (tsFeedpM >= eDmxMaxSectionFeedSize)
  107. return 0;
  108. if (tsFeedpM + lenP > eDmxMaxSectionFeedSize)
  109. lenP = (uint8_t)(eDmxMaxSectionFeedSize - tsFeedpM);
  110. if (lenP <= 0)
  111. return 0;
  112. memcpy(secBufBaseM + tsFeedpM, bufP, lenP);
  113. tsFeedpM = uint16_t(tsFeedpM + lenP);
  114. limit = tsFeedpM;
  115. if (limit > eDmxMaxSectionFeedSize)
  116. return -1; // internal error should never happen
  117. // Always set secbuf
  118. secBufM = secBufBaseM + secBufpM;
  119. for (n = 0; secBufpM + 2 < limit; ++n) {
  120. seclen = GetLength(secBufM);
  121. if ((seclen <= 0) || (seclen > eDmxMaxSectionSize) || ((seclen + secBufpM) > limit))
  122. return 0;
  123. secLenM = seclen;
  124. if (pusiSeenM)
  125. Feed();
  126. secBufpM = uint16_t(secBufpM + seclen);
  127. secBufM += seclen;
  128. }
  129. return 0;
  130. }
  131. void cIptvSectionFilter::Process(const uint8_t* dataP)
  132. {
  133. if (dataP[0] != TS_SYNC_BYTE)
  134. return;
  135. // Stop if not the PID this filter is looking for
  136. if (ts_pid(dataP) != pidM)
  137. return;
  138. uint8_t count = payload(dataP);
  139. // Check if no payload or out of range
  140. if (count == 0)
  141. return;
  142. // Payload start
  143. uint8_t p = (uint8_t)(TS_SIZE - count);
  144. uint8_t cc = (uint8_t)(dataP[3] & 0x0f);
  145. int ccok = ((feedCcM + 1) & 0x0f) == cc;
  146. feedCcM = cc;
  147. int dc_i = 0;
  148. if (dataP[3] & 0x20) {
  149. // Adaption field present, check for discontinuity_indicator
  150. if ((dataP[4] > 0) && (dataP[5] & 0x80))
  151. dc_i = 1;
  152. }
  153. if (!ccok || dc_i) {
  154. // Discontinuity detected. Reset pusiSeenM = 0 to
  155. // stop feeding of suspicious data until next PUSI=1 arrives
  156. pusiSeenM = 0;
  157. New();
  158. }
  159. if (dataP[1] & 0x40) {
  160. // PUSI=1 (is set), section boundary is here
  161. if (count > 1 && dataP[p] < count) {
  162. const uint8_t *before = &dataP[p + 1];
  163. uint8_t before_len = dataP[p];
  164. const uint8_t *after = &before[before_len];
  165. uint8_t after_len = (uint8_t)(count - 1 - before_len);
  166. CopyDump(before, before_len);
  167. // Before start of new section, set pusiSeenM = 1
  168. pusiSeenM = 1;
  169. New();
  170. CopyDump(after, after_len);
  171. }
  172. }
  173. else {
  174. // PUSI=0 (is not set), no section boundary
  175. CopyDump(&dataP[p], count);
  176. }
  177. }
  178. bool cIptvSectionFilter::Send(void)
  179. {
  180. bool result = false;
  181. cFrame *section = ringBufferM->Get();
  182. if (section) {
  183. uchar *data = section->Data();
  184. int count = section->Count();
  185. if (data && (count > 0) && (socketM[1] >= 0) && (socketM[0] >= 0)) {
  186. ssize_t len = send(socketM[1], data, count, MSG_EOR);
  187. ERROR_IF(len < 0 && errno != EAGAIN, "send()");
  188. if (len > 0) {
  189. ringBufferM->Drop(section);
  190. result = !!ringBufferM->Available();
  191. // Update statistics
  192. AddSectionStatistic(len, 1);
  193. }
  194. }
  195. }
  196. return result;
  197. }
  198. cIptvSectionFilterHandler::cIptvSectionFilterHandler(int deviceIndexP, unsigned int bufferLenP)
  199. : cThread("IPTV section handler"),
  200. ringBufferM(new cRingBufferLinear(bufferLenP, TS_SIZE, false, *cString::sprintf("IPTV SECTION HANDLER %d", deviceIndexP))),
  201. mutexM(),
  202. deviceIndexM(deviceIndexP)
  203. {
  204. debug1("%s (%d, %d) [device %d]", __PRETTY_FUNCTION__, deviceIndexP, bufferLenP, deviceIndexM);
  205. // Initialize filter pointers
  206. memset(filtersM, 0, sizeof(filtersM));
  207. // Create input buffer
  208. if (ringBufferM) {
  209. ringBufferM->SetTimeouts(100, 100);
  210. ringBufferM->SetIoThrottle();
  211. }
  212. else
  213. error("Failed to allocate buffer for section filter handler (device=%d): ", deviceIndexM);
  214. Start();
  215. }
  216. cIptvSectionFilterHandler::~cIptvSectionFilterHandler()
  217. {
  218. debug1("%s [device %d]", __PRETTY_FUNCTION__, deviceIndexM);
  219. // Stop thread
  220. if (Running())
  221. Cancel(3);
  222. DELETE_POINTER(ringBufferM);
  223. // Destroy all filters
  224. cMutexLock MutexLock(&mutexM);
  225. for (int i = 0; i < eMaxSecFilterCount; ++i)
  226. Delete(i);
  227. }
  228. void cIptvSectionFilterHandler::Action(void)
  229. {
  230. debug1("%s Entering [device %d]", __PRETTY_FUNCTION__, deviceIndexM);
  231. bool processed = false;
  232. // Do the thread loop
  233. while (Running()) {
  234. // Send demuxed section packets through all filters
  235. bool retry = false;
  236. mutexM.Lock();
  237. for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) {
  238. if (filtersM[i] && filtersM[i]->Send())
  239. retry = true;
  240. }
  241. mutexM.Unlock();
  242. if (retry)
  243. continue;
  244. // Read one TS packet
  245. if (ringBufferM) {
  246. int len = 0;
  247. if (processed) {
  248. ringBufferM->Del(TS_SIZE);
  249. processed = false;
  250. }
  251. uchar *p = ringBufferM->Get(len);
  252. if (p && (len >= TS_SIZE)) {
  253. if (*p != TS_SYNC_BYTE) {
  254. for (int i = 1; i < len; ++i) {
  255. if (p[i] == TS_SYNC_BYTE) {
  256. len = i;
  257. break;
  258. }
  259. }
  260. ringBufferM->Del(len);
  261. debug1("%s Skipped %d bytes to sync on TS packet [device %d]]", __PRETTY_FUNCTION__, len, deviceIndexM);
  262. continue;
  263. }
  264. // Process TS packet through all filters
  265. mutexM.Lock();
  266. for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) {
  267. if (filtersM[i])
  268. filtersM[i]->Process(p);
  269. }
  270. mutexM.Unlock();
  271. processed = true;
  272. continue;
  273. }
  274. }
  275. cCondWait::SleepMs(10); // to avoid busy loop and reduce cpu load
  276. }
  277. debug1("%s Exiting [device %d]", __PRETTY_FUNCTION__, deviceIndexM);
  278. }
  279. cString cIptvSectionFilterHandler::GetInformation(void)
  280. {
  281. debug16("%s [device %d]", __PRETTY_FUNCTION__, deviceIndexM);
  282. // loop through active section filters
  283. cMutexLock MutexLock(&mutexM);
  284. cString s = "";
  285. unsigned int count = 0;
  286. for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) {
  287. if (filtersM[i]) {
  288. s = cString::sprintf("%sFilter %d: %s Pid=0x%02X (%s)\n", *s, i,
  289. *filtersM[i]->GetSectionStatistic(), filtersM[i]->GetPid(),
  290. id_pid(filtersM[i]->GetPid()));
  291. if (++count > IPTV_STATS_ACTIVE_FILTERS_COUNT)
  292. break;
  293. }
  294. }
  295. return s;
  296. }
  297. bool cIptvSectionFilterHandler::Delete(unsigned int indexP)
  298. {
  299. debug16("%s (%d) [device %d]", __PRETTY_FUNCTION__, indexP, deviceIndexM);
  300. if ((indexP < eMaxSecFilterCount) && filtersM[indexP]) {
  301. debug16("%s (%d) Found [device %d]", __PRETTY_FUNCTION__, indexP, deviceIndexM);
  302. cIptvSectionFilter *tmp = filtersM[indexP];
  303. filtersM[indexP] = NULL;
  304. delete tmp;
  305. return true;
  306. }
  307. return false;
  308. }
  309. bool cIptvSectionFilterHandler::IsBlackListed(u_short pidP, u_char tidP, u_char maskP) const
  310. {
  311. debug16("%s (%d, %02X, %02X) [device %d]", __PRETTY_FUNCTION__, pidP, tidP, maskP, deviceIndexM);
  312. // loop through section filter table
  313. for (int i = 0; i < SECTION_FILTER_TABLE_SIZE; ++i) {
  314. int index = IptvConfig.GetDisabledFilters(i);
  315. // Check if matches
  316. if ((index >= 0) && (index < SECTION_FILTER_TABLE_SIZE) &&
  317. (section_filter_table[index].pid == pidP) && (section_filter_table[index].tid == tidP) &&
  318. (section_filter_table[index].mask == maskP)) {
  319. debug16("%s (%d, %02X, %02X) Found %s [device %d]", __PRETTY_FUNCTION__, pidP, tidP, maskP, section_filter_table[index].description, deviceIndexM);
  320. return true;
  321. }
  322. }
  323. return false;
  324. }
  325. int cIptvSectionFilterHandler::Open(u_short pidP, u_char tidP, u_char maskP)
  326. {
  327. // Lock
  328. cMutexLock MutexLock(&mutexM);
  329. // Blacklist check, refuse certain filters
  330. if (IsBlackListed(pidP, tidP, maskP))
  331. return -1;
  332. // Search the next free filter slot
  333. for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) {
  334. if (!filtersM[i]) {
  335. filtersM[i] = new cIptvSectionFilter(deviceIndexM, pidP, tidP, maskP);
  336. debug16("%s (%d, %02X, %02X) handle=%d index=%u [device %d]", __PRETTY_FUNCTION__, pidP, tidP, maskP, filtersM[i]->GetFd(), i, deviceIndexM);
  337. return filtersM[i]->GetFd();
  338. }
  339. }
  340. // No free filter slot found
  341. return -1;
  342. }
  343. void cIptvSectionFilterHandler::Close(int handleP)
  344. {
  345. // Lock
  346. cMutexLock MutexLock(&mutexM);
  347. // Search the filter for deletion
  348. for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) {
  349. if (filtersM[i] && (handleP == filtersM[i]->GetFd())) {
  350. debug1("%s (%d) pid=%d handle=%d index=%d [device %d]", __PRETTY_FUNCTION__, handleP, filtersM[i]->GetPid(), filtersM[i]->GetFd(), i, deviceIndexM);
  351. Delete(i);
  352. break;
  353. }
  354. }
  355. }
  356. int cIptvSectionFilterHandler::GetPid(int handleP)
  357. {
  358. // Lock
  359. cMutexLock MutexLock(&mutexM);
  360. // Search the filter for data
  361. for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) {
  362. if (filtersM[i] && (handleP == filtersM[i]->GetFd())) {
  363. debug1("%s (%d) pid=%d handle=%d index=%d [device %d]", __PRETTY_FUNCTION__, handleP, filtersM[i]->GetPid(), filtersM[i]->GetFd(), i, deviceIndexM);
  364. return filtersM[i]->GetPid();
  365. }
  366. }
  367. return -1;
  368. }
  369. void cIptvSectionFilterHandler::Write(uchar *bufferP, int lengthP)
  370. {
  371. debug16("%s (, %d) [device %d]", __PRETTY_FUNCTION__, lengthP, deviceIndexM);
  372. // Fill up the buffer
  373. if (ringBufferM) {
  374. int len = ringBufferM->Put(bufferP, lengthP);
  375. if (len != lengthP)
  376. ringBufferM->ReportOverflow(lengthP - len);
  377. }
  378. }