diff --git a/src/crc32.c b/src/crc32.c index 442e51d5..71a7f8b5 100644 --- a/src/crc32.c +++ b/src/crc32.c @@ -27,7 +27,10 @@ * it contains the precomputed table */ +#include "crc32.h" + #include +#include "ts.h" /**CRC table for PAT rebuilding, cam support and autoconfiguration*/ uint32_t crc32_table[256] = @@ -98,3 +101,34 @@ uint32_t crc32_table[256] = 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 }; +/** + * @brief CRC32 calculation inspired by the xine project + * @param data to be hashed + * @param len of data + * @return CRC32 value of data + */ +unsigned long calculateCRC32(const unsigned char *data, int len) +{ + // Now we must adjust the CRC32 + unsigned long crc32 = 0xffffffff; + for (int i = 0; i < len; ++i) { + crc32 = (crc32 << 8) ^ crc32_table[((crc32 >> 24) ^ data[i]) & 0xff]; + } + return crc32; +} + +/** + * @brief Calculates and sets CRC32 for PAT, EIT, SDT, PMT, NIT + * @param data pointer to table + */ +void setCRC32(unsigned char *data) +{ + tbl_h_t *table = (tbl_h_t *)data; + int len = 3 + HILO(table->section_length) - 4; // CRC for complete section but CRC (4 Bytes) + unsigned long crc32 = calculateCRC32(data, len); + // We write the CRC32 to the buffer + data[len] = (crc32 >> 24) & 0xff; + data[len + 1] = (crc32 >> 16) & 0xff; + data[len + 2] = (crc32 >> 8) & 0xff; + data[len + 3] = crc32 & 0xff; +} diff --git a/src/crc32.h b/src/crc32.h new file mode 100644 index 00000000..396b25c9 --- /dev/null +++ b/src/crc32.h @@ -0,0 +1,12 @@ +#ifndef _CRC32_H +#define _CRC32_H + +#include + +extern uint32_t crc32_table[256]; + +unsigned long calculateCRC32(const unsigned char *data, int len); + +void setCRC32(unsigned char *data); + +#endif //_CRC32_H diff --git a/src/mumudvb.c b/src/mumudvb.c index 6f0f8c7b..e5e616c8 100644 --- a/src/mumudvb.c +++ b/src/mumudvb.c @@ -348,7 +348,8 @@ int main (int argc, char **argv) exit(666); //Right code for a bad daemon no ? } - //If the user didn't defined a preferred logging way, and we daemonize, we set to syslog (except windows, where we don't, and log to console) + //If the user didn't define a preferred logging way, and we daemonize, + //we set to syslog (except windows, where we don't, and log to console) if (!no_daemon) { if(log_params.log_type==LOGGING_UNDEFINED) diff --git a/src/rewrite.c b/src/rewrite.c index 2cdbf4dd..b46af07b 100644 --- a/src/rewrite.c +++ b/src/rewrite.c @@ -231,3 +231,38 @@ void set_continuity_counter(unsigned char *buf,int continuity_counter) ts_header->continuity_counter=continuity_counter; } +/** @brief Determines if the table has a newer version than the currently recorded one + * + * In the table there is a field to say if the table was updated + * This function checks if it has changed (in order to rewrite the table only once) + * @note Note in case it change during streaming, it can be a problem, + * and we would have to deal with re-autoconfiguration + * @note Note this function can give false positive since it doesn't check the CRC32 + * + * @param mod_log_module The log module of the calling function + * @param stored_version The current version to be checked against + * @param buf the received packet that is to be checked + * @param table_condition pass either NULL or a function that checks the table for preconditions + * @returns true if the packet is the beginning of an applicable table and contains a new version, otherwise false + */ +bool table_needs_update(char *mod_log_module, const int stored_version, unsigned char *buf, + bool (*table_condition)(tbl_h_t *table)) { + tbl_h_t *table=(tbl_h_t *)(get_ts_begin(buf)); + + // Check if it's the beginning of a new table + if (!table) return false; + /* current_next_indicator – A 1-bit indicator, which when set to '1' indicates that the table + sent is currently applicable. When the bit is set to '0', it indicates that the table sent is not yet applicable + and shall be the next table to become valid. */ + if (table->current_next_indicator == 0) { + return false; + } + if (table_condition != NULL && table_condition(table) == false) { + return false; + } + if (table->version_number!=stored_version) { + log_message(mod_log_module, MSG_DEBUG,"Need update. stored version : %d, new: %d\n",stored_version,table->version_number); + return true; + } + return false; +} diff --git a/src/rewrite.h b/src/rewrite.h index b657dcc7..b1c829c4 100644 --- a/src/rewrite.h +++ b/src/rewrite.h @@ -151,4 +151,6 @@ void eit_rewrite_new_global_packet(unsigned char *ts_packet, rewrite_parameters_ void eit_rewrite_new_channel_packet(unsigned char *ts_packet, rewrite_parameters_t *rewrite_vars, mumudvb_channel_t *channel, unicast_parameters_t *unicast_vars, void *scam_vars_v); +bool table_needs_update(char *mod_log_module, int stored_version, unsigned char *buf, + bool (*table_condition)(tbl_h_t *table)); #endif diff --git a/src/rewrite_pat.c b/src/rewrite_pat.c index 44fbe849..2d26acd7 100644 --- a/src/rewrite_pat.c +++ b/src/rewrite_pat.c @@ -33,48 +33,15 @@ #include #include +#include "crc32.h" #include "mumudvb.h" #include "ts.h" #include "rewrite.h" #include "log.h" #include -extern uint32_t crc32_table[256]; static char *log_module="PAT Rewrite: "; -/** @brief, tell if the pat have a newer version than the one recorded actually - * In the PAT pid there is a field to say if the PAT was updated - * This function check if it has changed (in order to rewrite the pat only once) - * General Note : in case it change during streaming it can be a problem ane we would have to deal with re-autoconfiguration - * Note this function can give flase positive since it doesn't check the CRC32 - * - *@param rewrite_vars the parameters for pat rewriting - *@param buf : the received buffer - */ -int pat_need_update(rewrite_parameters_t *rewrite_vars, unsigned char *buf) -{ - pat_t *pat=(pat_t*)(get_ts_begin(buf)); - - - if(pat) //It's the beginning of a new packet - { - /*current_next_indicator – A 1-bit indicator, which when set to '1' indicates that the Program Association Table - sent is currently applicable. When the bit is set to '0', it indicates that the table sent is not yet applicable - and shall be the next table to become valid.*/ - if(pat->current_next_indicator == 0) - { - return 0; - } - if(pat->version_number!=rewrite_vars->pat_version) - { - log_message( log_module, MSG_DEBUG,"Need update. stored version : %d, new: %d\n",rewrite_vars->pat_version,pat->version_number); - return 1; - } - } - return 0; - -} - /** @brief update the version using the dowloaded pat*/ void update_pat_version(rewrite_parameters_t *rewrite_vars) { @@ -187,26 +154,8 @@ int pat_channel_rewrite(rewrite_parameters_t *rewrite_vars, mumudvb_channel_t *c buf_dest[1+TS_HEADER_LEN]=(((new_section_length)&0x0f00)>>8) | (0xf0 & buf_dest[1+TS_HEADER_LEN]); buf_dest[2+TS_HEADER_LEN]=new_section_length & 0xff; - - //CRC32 calculation inspired by the xine project - //Now we must adjust the CRC32 - //we compute the CRC32 - crc32=0xffffffff; - for(i = 0; i < new_section_length-1; i++) { - crc32 = (crc32 << 8) ^ crc32_table[((crc32 >> 24) ^ buf_dest[i+TS_HEADER_LEN])&0xff]; - } - - - //We write the CRC32 to the buffer - buf_dest[buf_dest_pos]=(crc32>>24) & 0xff; - buf_dest_pos+=1; - buf_dest[buf_dest_pos]=(crc32>>16) & 0xff; - buf_dest_pos+=1; - buf_dest[buf_dest_pos]=(crc32>>8) & 0xff; - buf_dest_pos+=1; - buf_dest[buf_dest_pos]=crc32 & 0xff; - buf_dest_pos+=1; - + setCRC32(buf_dest + TS_HEADER_LEN); + buf_dest_pos += 4; //Padding with 0xFF memset(buf_dest+buf_dest_pos,0xFF,TS_PACKET_SIZE-buf_dest_pos); @@ -226,7 +175,7 @@ void pat_rewrite_new_global_packet(unsigned char *ts_packet, rewrite_parameters_ /*Check the version before getting the full packet*/ if(!rewrite_vars->pat_needs_update) { - rewrite_vars->pat_needs_update=pat_need_update(rewrite_vars,ts_packet); + rewrite_vars->pat_needs_update=table_needs_update(log_module, rewrite_vars->pat_version, ts_packet, NULL); } /*We need to update the full packet, we download it*/ if(rewrite_vars->pat_needs_update) diff --git a/src/rewrite_pmt.c b/src/rewrite_pmt.c index a69d6859..79b7bd3d 100644 --- a/src/rewrite_pmt.c +++ b/src/rewrite_pmt.c @@ -39,6 +39,7 @@ #include #include +#include "crc32.h" #include "mumudvb.h" #include "ts.h" #include "rewrite.h" @@ -179,23 +180,8 @@ int pmt_channel_rewrite(mumudvb_channel_t *channel) { buf_dest[1 + TS_HEADER_LEN] = (((new_section_length) & 0x0f00) >> 8) | (0xf0 & buf_dest[1 + TS_HEADER_LEN]); buf_dest[2 + TS_HEADER_LEN] = new_section_length & 0xff; - //CRC32 calculation inspired by the xine project - //Now we must adjust the CRC32 - //we compute the CRC32 - crc32 = 0xffffffff; - for (i = 0; i < new_section_length - 1; i++) { - crc32 = (crc32 << 8) ^ crc32_table[((crc32 >> 24) ^ buf_dest[i + TS_HEADER_LEN]) & 0xff]; - } - - //We write the CRC32 to the buffer - buf_dest[buf_dest_pos] = (crc32 >> 24) & 0xff; - buf_dest_pos += 1; - buf_dest[buf_dest_pos] = (crc32 >> 16) & 0xff; - buf_dest_pos += 1; - buf_dest[buf_dest_pos] = (crc32 >> 8) & 0xff; - buf_dest_pos += 1; - buf_dest[buf_dest_pos] = crc32 & 0xff; - buf_dest_pos += 1; + setCRC32(buf_dest); + buf_dest_pos += 4; //Padding with 0xFF memset(buf_dest + buf_dest_pos, 0xFF, TS_PACKET_SIZE - buf_dest_pos); diff --git a/src/rewrite_sdt.c b/src/rewrite_sdt.c index 4bcf04d4..460b0f39 100644 --- a/src/rewrite_sdt.c +++ b/src/rewrite_sdt.c @@ -33,6 +33,7 @@ #include #include +#include "crc32.h" #include "mumudvb.h" #include "ts.h" #include "rewrite.h" @@ -57,40 +58,16 @@ int sdt_rewrite_all_sections_seen(rewrite_parameters_t *rewrite_vars) return all_seen; } - - -/** @brief, tell if the sdt have a newer version than the one recorded actually - * In the SDT pid there is a field to say if the SDT was updated - * This function check if it has changed (in order to rewrite the sdt only once) - * General Note : in case it change during streaming it can be a problem ane we would have to deal with re-autoconfiguration - * Note this function can give flase positive since it doesn't check the CRC32 - * - *@param rewrite_vars the parameters for sdt rewriting - *@param buf : the received buffer +/** + * @brief Check if sdt section describes actual transport stream */ -int sdt_need_update(rewrite_parameters_t *rewrite_vars, unsigned char *buf) +bool actual_subtable_id(tbl_h_t *section) { - sdt_t *sdt=(sdt_t*)(get_ts_begin(buf)); - if(sdt) //It's the beginning of a new packet - if((sdt->version_number!=rewrite_vars->sdt_version) && (sdt->table_id==0x42)) - { - /*current_next_indicator – A 1-bit indicator, which when set to '1' indicates that the Program Association Table - sent is currently applicable. When the bit is set to '0', it indicates that the table sent is not yet applicable - and shall be the next table to become valid.*/ - if(sdt->current_next_indicator == 0) - { - return 0; - } - log_message( log_module, MSG_DEBUG,"Need update. stored version : %d, new: %d\n",rewrite_vars->sdt_version,sdt->version_number); - if(rewrite_vars->sdt_version!=-1) - log_message( log_module, MSG_INFO,"The SDT version changed, so the channels names changed probably.\n"); - return 1; - } - return 0; - + const sdt_t *sdt_section = (sdt_t*)section; + return sdt_section->table_id == SDT_ACTUAL_TS; } -/** @brief update the version using the dowloaded SDT*/ +/** @brief update the version using the downloaded SDT*/ void update_sdt_version(rewrite_parameters_t *rewrite_vars) { sdt_t *sdt=(sdt_t*)(rewrite_vars->full_sdt->data_full); @@ -154,7 +131,8 @@ int sdt_channel_rewrite(rewrite_parameters_t *rewrite_vars, mumudvb_channel_t *c if(!channel->service_id) { - log_message( log_module, MSG_WARN,"Cannot rewrite a program without the service_id set. We deactivate SDT rewrititng for this channel %d : \"%s\"\n", curr_channel, channel->name); + log_message( log_module, MSG_WARN,"Cannot rewrite a program without the service_id set. " + "We deactivate SDT rewrititng for this channel %d : \"%s\"\n", curr_channel, channel->name); channel->sdt_rewrite_skip=1; return 0; } @@ -234,7 +212,7 @@ int sdt_channel_rewrite(rewrite_parameters_t *rewrite_vars, mumudvb_channel_t *c else { log_message( log_module, MSG_DETAIL,"NEW program for channel %d : \"%s\". service_id : %d\n", curr_channel, channel->name,channel->service_id); - //we found a announce for a program in our stream, we keep it + //we found an announcement for a program in our stream, we keep it //We fill the descriptor loop length t_buffer_ptr->descriptors_loop_length_lo = (loop_length & 0x00FF); t_buffer_ptr->descriptors_loop_length_hi = (loop_length & 0xFF00)>>8; @@ -274,27 +252,8 @@ int sdt_channel_rewrite(rewrite_parameters_t *rewrite_vars, mumudvb_channel_t *c buf_dest[1+TS_HEADER_LEN]=(((new_section_length)&0x0f00)>>8) | (0xf0 & buf_dest[1+TS_HEADER_LEN]); buf_dest[2+TS_HEADER_LEN]=new_section_length & 0xff; - - //CRC32 calculation inspired by the xine project - //Now we must adjust the CRC32 - //we compute the CRC32 - crc32=0xffffffff; - int i; - for(i = 0; i < new_section_length-1; i++) { - crc32 = (crc32 << 8) ^ crc32_table[((crc32 >> 24) ^ buf_dest[i+TS_HEADER_LEN])&0xff]; - } - - - //We write the CRC32 to the buffer - buf_dest[buf_dest_pos]=(crc32>>24) & 0xff; - buf_dest_pos+=1; - buf_dest[buf_dest_pos]=(crc32>>16) & 0xff; - buf_dest_pos+=1; - buf_dest[buf_dest_pos]=(crc32>>8) & 0xff; - buf_dest_pos+=1; - buf_dest[buf_dest_pos]=crc32 & 0xff; - buf_dest_pos+=1; - + setCRC32(buf_dest + TS_HEADER_LEN); + buf_dest_pos += 4; //Padding with 0xFF memset(buf_dest+buf_dest_pos,0xFF,TS_PACKET_SIZE-buf_dest_pos); @@ -337,9 +296,12 @@ int sdt_rewrite_new_global_packet(unsigned char *ts_packet, rewrite_parameters_t /*Check the version before getting the full packet*/ if(!rewrite_vars->sdt_needs_update) { - rewrite_vars->sdt_needs_update=sdt_need_update(rewrite_vars,ts_packet); - if(rewrite_vars->sdt_needs_update) //It needs update we mark the packet as empty and we clear the sections seen + rewrite_vars->sdt_needs_update = table_needs_update(log_module, rewrite_vars->sdt_version, + ts_packet, actual_subtable_id); + if(rewrite_vars->sdt_needs_update) //It needs update we mark the packet as empty, and we clear the sections seen { + if(rewrite_vars->sdt_version != -1) + log_message( log_module, MSG_INFO,"The SDT version changed, so the channels names changed probably."); //We clear the section numbers seen memset(&rewrite_vars->sdt_section_numbers_seen,0,sizeof(rewrite_vars->sdt_section_numbers_seen)); } @@ -393,8 +355,9 @@ int sdt_rewrite_new_global_packet(unsigned char *ts_packet, rewrite_parameters_t } -/** @brief This function is called when a new SDT packet for a channel is there and we asked for rewrite - * This function copy the rewritten SDT to the buffer. And checks if the SDT was changed so the rewritten version have to be updated +/** @brief This function is called when a new SDT packet for a channel is there, and we asked for rewrite + * This function copies the rewritten SDT to the buffer and checks if the SDT was changed + * so the rewritten version has to be updated */ int sdt_rewrite_new_channel_packet(unsigned char *ts_packet, rewrite_parameters_t *rewrite_vars, mumudvb_channel_t *channel, int curr_channel) { diff --git a/src/ts.c b/src/ts.c index ce184741..e76ce7cf 100644 --- a/src/ts.c +++ b/src/ts.c @@ -55,12 +55,12 @@ void add_ts_packet_data(unsigned char *buf, mumudvb_ts_packet_t *pkt, int data_l * * the continuity counter which is incremented for each packet * * The payload_unit_start_indicator which says if it's the first packet * - * When a packet is splitted in 188 bytes packets, there must be no other PID between two sub packets + * When a packet is split in 188 bytes packets, there must be no other PID between two sub packets * * Return 1 when there is one packet full and OK * * @param buf : the received buffer from the card - * @param ts_packet : the packet to be completed + * @param pkt : the packet to be completed */ int get_ts_packet(unsigned char *buf, mumudvb_ts_packet_t *pkt) { diff --git a/src/ts.h b/src/ts.h index 83af76f3..17b42078 100644 --- a/src/ts.h +++ b/src/ts.h @@ -334,6 +334,10 @@ typedef struct { * names of services, the service provider, etc. * */ + +#define SDT_ACTUAL_TS 0x42 +#define SDT_OTHER_TS 0x46 + typedef struct { uint8_t table_id :8; #ifdef __BIG_ENDIAN__ @@ -511,7 +515,7 @@ typedef struct { /* descriptors */ }nit_t; -#define SIZE_NIT_MID 2 +#define SIZE_NIT_MID 2 // transport stream loop length typedef struct { // after descriptors #ifdef __BIG_ENDIAN__ @@ -824,10 +828,9 @@ typedef enum packet_status { #define FULL_BUFFER_SIZE 2*MAX_TS_SIZE -/**@brief structure for the build of a ts packet - Since a packet can be finished and another one starts in the same - elementary TS packet, there is two packets in this structure - +/** @brief structure for the build of a ts packet + * Since a packet can be finished and another one starts in the same + * elementary TS packet, there is two packets in this structure */ typedef struct { /** the buffer for the packet full (empty or contains a valid full packet)*/ @@ -835,7 +838,7 @@ typedef struct { /** the length of the data contained in data_full */ int len_full; - //starting from here, these variables MUSN'T be accessed outside ts.c + //starting from here, these variables MUSTN'T be accessed outside ts.c /** The number of full packets */ int full_number; /** The lengths of the full packets */