MythTV  0.26-pre
dsmccbiop.cpp
Go to the documentation of this file.
00001 /*
00002  *  Copyright (C) David C.J. Matthews 2005, 2006
00003  *     Derived from libdsmcc by Richard Palmer
00004  */
00005 //#include <stdio.h>
00006 #include <stdlib.h>
00007 #include <string.h>
00008 
00009 #include "dsmccbiop.h"
00010 #include "dsmccreceiver.h"
00011 #include "dsmcccache.h"
00012 #include "dsmccobjcarousel.h"
00013 #include "dsmcc.h"
00014 
00015 #include "mythlogging.h"
00016 
00017 BiopNameComp::~BiopNameComp()
00018 {
00019     if (m_id)
00020         free(m_id);
00021     if (m_kind)
00022         free(m_kind);
00023 }
00024 
00025 int BiopNameComp::Process(const unsigned char *data)
00026 {
00027     int off = 0;
00028 
00029     m_id_len    = data[off++];
00030     m_id        = (char*) malloc(m_id_len);
00031     memcpy(m_id, data + off, m_id_len);
00032 
00033     off        += m_id_len;
00034     m_kind_len  = data[off++];
00035     m_kind      = (char*) malloc(m_kind_len);
00036     memcpy(m_kind, data + off, m_kind_len);
00037 
00038     off        += m_kind_len;
00039 
00040     return off;
00041 }
00042 
00043 BiopName::BiopName()
00044 {
00045     m_comp_count = 0;
00046     m_comps = NULL;
00047 }
00048 
00049 BiopName::~BiopName()
00050 {
00051     delete[] m_comps;
00052 }
00053 
00054 int BiopName::Process(const unsigned char *data)
00055 {
00056     int off = 0;
00057     m_comp_count = data[0];
00058 
00059     if (m_comp_count != 1)
00060         LOG(VB_DSMCC, LOG_WARNING, "[biop] Expected one name");
00061 
00062     off++;
00063     m_comps = new BiopNameComp[m_comp_count];
00064 
00065     for (int i = 0; i < m_comp_count; i++)
00066     {
00067         int ret = m_comps[i].Process(data + off);
00068         if (ret <= 0)
00069             return ret;
00070         off += ret;
00071     }
00072 
00073     return off;
00074 }
00075 
00076 int BiopBinding::Process(const unsigned char *data)
00077 {
00078     int off = 0, ret;
00079     ret = m_name.Process(data);
00080 
00081     if (ret > 0)
00082         off += ret;
00083     else
00084         return ret; // Error
00085 
00086     m_binding_type = data[off++];
00087     ret = m_ior.Process(data + off);
00088 
00089     if (ret > 0)
00090         off += ret;
00091     else
00092         return ret; // Error
00093 
00094     m_objinfo_len = (data[off] << 8) | data[off + 1];
00095     off += 2;
00096 
00097     if (m_objinfo_len > 0)
00098     {
00099         m_objinfo = (char*) malloc(m_objinfo_len);
00100         memcpy(m_objinfo, data + off, m_objinfo_len);
00101     }
00102     else
00103         m_objinfo = NULL;
00104 
00105     off += m_objinfo_len;
00106 
00107     return off;
00108 }
00109 
00110 BiopBinding::~BiopBinding()
00111 {
00112     free(m_objinfo);
00113 }
00114 
00115 bool BiopMessage::Process(DSMCCCacheModuleData *cachep, DSMCCCache *filecache,
00116                           unsigned char *data, unsigned long *curp)
00117 {
00118     // Parse header
00119     if (! ProcessMsgHdr(data, curp))
00120     {
00121         LOG(VB_DSMCC, LOG_ERR, 
00122             "[biop] Invalid biop header, dropping rest of module");
00123 
00124         /* not valid, skip rest of data */
00125         return false;
00126     }
00127 
00128     // Handle each message type
00129     if (strcmp(m_objkind, "fil") == 0)
00130     {
00131         LOG(VB_DSMCC, LOG_DEBUG, "[biop] Processing file");
00132         return ProcessFile(cachep, filecache, data, curp);
00133     }
00134     else if (strcmp(m_objkind, "dir") == 0)
00135     {
00136         LOG(VB_DSMCC, LOG_DEBUG, "[biop] Processing directory");
00137         return ProcessDir(false, cachep, filecache, data, curp);
00138     }
00139     else if (strcmp(m_objkind, "srg") == 0)
00140     {
00141         LOG(VB_DSMCC, LOG_DEBUG, "[biop] Processing gateway");
00142         return ProcessDir(true, cachep, filecache, data, curp);
00143     }
00144     else
00145     {
00146         /* Error */
00147         LOG(VB_DSMCC, LOG_WARNING, QString("Unknown or unsupported format %1%2%3%4")
00148                 .arg(m_objkind[0]).arg(m_objkind[1])
00149                 .arg(m_objkind[2]).arg(m_objkind[3]));
00150         return false;
00151     }
00152 }
00153 
00154 BiopMessage::~BiopMessage()
00155 {
00156     free(m_objinfo);
00157     free(m_objkind);
00158 }
00159 
00160 bool BiopMessage::ProcessMsgHdr(unsigned char *data, unsigned long *curp)
00161 {
00162     const unsigned char *buf = data + (*curp);
00163     int off = 0;
00164 
00165     if (buf[off] !='B' || buf[off +1] !='I' || buf[off +2] !='O' || buf[off +3] !='P')
00166     {
00167         LOG(VB_DSMCC, LOG_WARNING, "BiopMessage - invalid header");
00168         return false;
00169     }
00170     off += 4;
00171 
00172     m_version_major = buf[off++];
00173     m_version_minor = buf[off++];
00174     if (m_version_major != 1 || m_version_minor != 0)
00175     {
00176         LOG(VB_DSMCC, LOG_WARNING, "BiopMessage invalid version");
00177         return false;
00178     }
00179 
00180     if (buf[off++] != 0)
00181     {
00182         LOG(VB_DSMCC, LOG_WARNING, "BiopMessage invalid byte order");
00183         return false;
00184     }
00185     if (buf[off++] != 0)
00186     {
00187         LOG(VB_DSMCC, LOG_WARNING, "BiopMessage invalid message type");
00188         return false;
00189     }
00190 
00191     m_message_size  = ((buf[off + 0] << 24) | (buf[off+1] << 16) |
00192                        (buf[off + 2] << 8)  | (buf[off + 3]));
00193     off += 4;
00194 
00195     uint nObjLen = buf[off++];
00196     m_objkey = DSMCCCacheKey((const char*)buf + off, nObjLen);
00197     off += nObjLen;
00198 
00199     m_objkind_len = ((buf[off + 0] << 24) | (buf[off + 1] << 16) |
00200                      (buf[off + 2] << 8)  | (buf[off + 3]));
00201     off += 4;
00202     m_objkind = (char*) malloc(m_objkind_len);
00203     memcpy(m_objkind, buf + off, m_objkind_len);
00204     off += m_objkind_len;
00205 
00206     m_objinfo_len = buf[off] << 8 | buf[off + 1];
00207     off += 2;
00208     m_objinfo = (char*) malloc(m_objinfo_len);
00209     memcpy(m_objinfo, buf + off, m_objinfo_len);
00210     off += m_objinfo_len;
00211 
00212     (*curp) += off;
00213 
00214     return true;
00215 }
00216 
00217 
00226 bool BiopMessage::ProcessDir(
00227     bool isSrg, DSMCCCacheModuleData *cachep, DSMCCCache *filecache,
00228     unsigned char *data, unsigned long *curp)
00229 {
00230     int off = 0;
00231     const unsigned char * const buf = data + (*curp);
00232 
00233     if (m_objinfo_len)
00234         LOG(VB_DSMCC, LOG_WARNING, "[biop] ProcessDir non-zero objectInfo_length");
00235 
00236     const unsigned serviceContextList_count = buf[off++];
00237     if (serviceContextList_count)
00238     {
00239         // TODO Handle serviceContextList for service gateway
00240         LOG(VB_DSMCC, LOG_WARNING, QString("[biop] ProcessDir serviceContextList count %1")
00241             .arg(serviceContextList_count));
00242         return false; // Error
00243     }
00244 
00245     unsigned long msgbody_len = ((buf[off + 0] << 24) | (buf[off + 1] << 16) |
00246                                  (buf[off + 2] <<  8) | (buf[off + 3]));
00247     off += 4;
00248     int const start = off;
00249 
00250     unsigned int bindings_count = buf[off] << 8 | buf[off + 1];
00251     off += 2;
00252 
00253     DSMCCCacheReference ref(cachep->CarouselId(), cachep->ModuleId(),
00254                             cachep->StreamId(), m_objkey);
00255     DSMCCCacheDir *pDir = isSrg ? filecache->Srg(ref) : filecache->Directory(ref);
00256 
00257     for (uint i = 0; i < bindings_count; i++)
00258     {
00259         BiopBinding binding;
00260         int ret = binding.Process(buf + off);
00261         if (ret > 0)
00262             off += ret;
00263         else
00264             return false; // Error
00265 
00266         if (binding.m_name.m_comp_count != 1)
00267             LOG(VB_DSMCC, LOG_WARNING, "[biop] ProcessDir nameComponents != 1");
00268 
00269         if (binding.m_binding_type != 1 && binding.m_binding_type != 2)
00270             LOG(VB_DSMCC, LOG_WARNING, "[biop] ProcessDir invalid BindingType");
00271 
00272         // Process any taps in this binding.
00273         binding.m_ior.AddTap(filecache->m_Dsmcc);
00274 
00275         if (pDir && binding.m_name.m_comp_count >= 1)
00276         {
00277             if (strcmp("fil", binding.m_name.m_comps[0].m_kind) == 0)
00278                 filecache->AddFileInfo(pDir, &binding);
00279             else if (strcmp("dir", binding.m_name.m_comps[0].m_kind) == 0)
00280                 filecache->AddDirInfo(pDir, &binding);
00281             else
00282                 LOG(VB_DSMCC, LOG_WARNING, QString("[biop] ProcessDir unknown kind %1")
00283                     .arg(binding.m_name.m_comps[0].m_kind));
00284         }
00285     }
00286 
00287     if ((unsigned)(off - start) != msgbody_len)
00288         LOG(VB_DSMCC, LOG_WARNING, "[biop] ProcessDir incorrect msgbody_len");
00289 
00290     (*curp) += off;
00291 
00292     return true;
00293 }
00294 
00295 bool BiopMessage::ProcessFile(DSMCCCacheModuleData *cachep, DSMCCCache *filecache,
00296                               unsigned char *data, unsigned long *curp)
00297 {
00298     int off = 0;
00299     const unsigned char *buf = data + (*curp);
00300     unsigned long msgbody_len;
00301     unsigned long content_len;
00302 
00303     if (m_objinfo_len != 8)
00304         LOG(VB_DSMCC, LOG_WARNING, QString("[biop] ProcessFile objectInfo_length = %1")
00305             .arg(m_objinfo_len));
00306 
00307     const unsigned serviceContextList_count = buf[off++];
00308     if (serviceContextList_count)
00309     {
00310         LOG(VB_DSMCC, LOG_WARNING,
00311             QString("[biop] ProcessFile Unexpected serviceContextList_count %1")
00312             .arg(serviceContextList_count));
00313         return false; // Error
00314     }
00315 
00316     msgbody_len = ((buf[off    ] << 24) | (buf[off + 1] << 16) |
00317                    (buf[off + 2] <<  8) | (buf[off + 3]));
00318     off += 4;
00319     content_len = ((buf[off    ] << 24) | (buf[off + 1] << 16) |
00320                    (buf[off + 2] <<  8) | (buf[off + 3]));
00321     off += 4;
00322     if (content_len + 4 != msgbody_len)
00323         LOG(VB_DSMCC, LOG_WARNING, "[biop] ProcessFile incorrect msgbody_len");
00324 
00325     (*curp) += off;
00326 
00327     DSMCCCacheReference ref(cachep->CarouselId(), cachep->ModuleId(),
00328                             cachep->StreamId(), m_objkey);
00329 
00330     QByteArray filedata = QByteArray((const char *)data+(*curp), content_len);
00331     filecache->CacheFileData(ref, filedata);
00332 
00333     (*curp) += content_len;
00334     return true;
00335 }
00336 
00337 void ModuleDescriptorData::Process(const unsigned char *data, int length)
00338 {
00339     while (length > 0)
00340     {
00341         unsigned char tag = *data++;
00342         unsigned char len = *data++;
00343         length -= 2;
00344         switch (tag)
00345         {
00346             case 0x01: // Type
00347                 break;
00348             case 0x02: // Name
00349                 break;
00350             case 0x03: // Info
00351                 break;
00352             case 0x04: // Modlink
00353                 break;
00354             case 0x05: // CRC
00355                 break;
00356             case 0x06: // Location
00357                 break;
00358             case 0x07: // DLtime
00359                 break;
00360             case 0x08: // Grouplink
00361                 break;
00362             case 0x09: // Compressed.
00363                 // Skip the method.
00364                 isCompressed = true;
00365                 originalSize = ((data[1] << 24) | (data[2] << 16) |
00366                                 (data[3] <<  8) | (data[4]));
00367                 break;
00368             default:
00369                 break;
00370         }
00371         length -= len;
00372         data += len;
00373     }
00374 }
00375 
00376 int BiopModuleInfo::Process(const unsigned char *data)
00377 {
00378     int off, ret;
00379     mod_timeout   = ((data[0]  << 24) | (data[1] << 16) |
00380                      (data[2]  <<  8) | (data[3]));
00381     block_timeout = ((data[4]  << 24) | (data[5] << 16) |
00382                      (data[6]  <<  8) | (data[7]));
00383     min_blocktime = ((data[8]  << 24) | (data[9] << 16) |
00384                      (data[10] <<  8) | (data[11]));
00385 
00386     taps_count = data[12];
00387     off = 13;
00388 
00389     LOG(VB_DSMCC, LOG_DEBUG, QString("[Biop] "
00390         "ModuleTimeout %1 BlockTimeout %2 MinBlockTime %3 Taps %4")
00391         .arg(mod_timeout).arg(block_timeout).arg(min_blocktime)
00392         .arg(taps_count));
00393 
00394     if (taps_count > 0)
00395     {
00396         /* only 1 allowed TODO - may not be first though ? */
00397         ret = tap.Process(data + off);
00398         if (ret <= 0)
00399             return ret;
00400         off += ret;
00401     }
00402 
00403     unsigned userinfo_len = data[off++];
00404 
00405     if (userinfo_len > 0)
00406     {
00407         descriptorData.Process(data + off, userinfo_len);
00408         off += userinfo_len;
00409     }
00410     return off;
00411 
00412 }
00413 
00414 int BiopTap::Process(const unsigned char *data)
00415 {
00416     int off=0;
00417 
00418     id = (data[off] << 8) | data[off + 1]; // Ignored
00419     off += 2;
00420     use = (data[off] << 8) | data[off + 1];
00421     off += 2;
00422     assoc_tag = (data[off] << 8) | data[off + 1];
00423     off += 2;
00424     selector_len = data[off++];
00425     selector_data = (char*) malloc(selector_len);
00426     memcpy(selector_data, data + off, selector_len);
00427     if (use == 0x0016) // BIOP_DELIVERY_PARA_USE
00428     {
00429         unsigned selector_type = (data[off] << 8) | data[off + 1];
00430         if (selector_len >= 10 && selector_type == 0x0001)
00431         {
00432             off += 2;
00433             unsigned long transactionId = ((data[off] << 24) | (data[off + 1] << 16) |
00434                          (data[off + 2] << 8)  | (data[off + 3]));
00435             off += 4;
00436             unsigned long timeout = ((data[off] << 24) | (data[off + 1] << 16) |
00437                          (data[off + 2] << 8)  | (data[off + 3]));
00438             LOG(VB_DSMCC, LOG_DEBUG, QString("[biop] BIOP_DELIVERY_PARA_USE tag %1 id 0x%2 timeout %3uS")
00439                 .arg(assoc_tag).arg(transactionId,0,16).arg(timeout));
00440             off += 4;
00441             selector_len -= 10;
00442         }
00443     }
00444 
00445     off += selector_len;
00446     return off;
00447 }
00448 
00449 int BiopConnbinder::Process(const unsigned char *data)
00450 {
00451     int off = 0, ret;
00452 
00453     component_tag = ((data[0] << 24) | (data[1] << 16) |
00454                      (data[2] << 8)  | (data[3]));
00455     if (0x49534F40 != component_tag)
00456     {
00457         LOG(VB_DSMCC, LOG_WARNING, "[biop] Invalid Connbinder tag");
00458         return 0;
00459     }
00460     off += 4;
00461     component_data_len = data[off++];
00462     taps_count = data[off++];
00463     if (taps_count > 0)
00464     {
00465         /* UKProfile - only first tap read */
00466         ret = tap.Process(data + off);
00467 #if 0
00468         LOG(VB_GENERAL, LOG_DEBUG, QString("Binder - assoc_tag %1")
00469                                        .arg(tap.assoc_tag));
00470 #endif
00471         if (ret > 0)
00472             off += ret;
00473         /* else TODO error */
00474     }
00475 
00476     return off;
00477 }
00478 
00479 int BiopObjLocation::Process(const unsigned char *data)
00480 {
00481     int off = 0;
00482 
00483     component_tag = ((data[0] << 24) | (data[1] << 16) |
00484                      (data[2] <<  8) | (data[3]));
00485     if (0x49534F50 != component_tag)
00486     {
00487         LOG(VB_DSMCC, LOG_WARNING, "[biop] Invalid ObjectLocation tag");
00488         return 0;
00489     }
00490     off += 4;
00491 
00492     component_data_len = data[off++];
00493     m_Reference.m_nCarouselId =
00494         ((data[off    ] << 24) | (data[off + 1] << 16) |
00495          (data[off + 2] <<  8) | (data[off + 3]));
00496 
00497     off += 4;
00498 
00499     m_Reference.m_nModuleId = (data[off] << 8) | data[off + 1];
00500     off += 2;
00501 
00502     version_major = data[off++];
00503     version_minor = data[off++];
00504     if (1 != version_major || 0 != version_minor)
00505     {
00506         LOG(VB_DSMCC, LOG_WARNING, "[biop] Invalid ObjectLocation version");
00507         return 0;
00508     }
00509 
00510     uint objKeyLen = data[off++]; /* <= 4 */
00511     m_Reference.m_Key = DSMCCCacheKey((char*)data + off, objKeyLen);
00512     off += objKeyLen;
00513     return off;
00514 }
00515 
00516 // A Lite profile body is used to refer to an object referenced through
00517 // a different PMT, We don't support that, at least at the moment.
00518 int ProfileBodyLite::Process(const unsigned char * /*data*/)
00519 {
00520     LOG(VB_DSMCC, LOG_WARNING, "Found LiteProfileBody - Not Implemented Yet");
00521     return 0;
00522 }
00523 
00524 int ProfileBodyFull::Process(const unsigned char *data)
00525 {
00526     int off = 0, ret;
00527 
00528     data_len = ((data[off    ] << 24) | (data[off + 1] << 16) |
00529                 (data[off + 2] <<  8) | (data[off + 3]));
00530     off += 4;
00531 
00532     /* bit order */
00533     if (data[off++] != 0)
00534     {
00535         LOG(VB_DSMCC, LOG_WARNING, "[biop] ProfileBody invalid byte order");
00536         return 0;
00537     }
00538 
00539     lite_components_count = data[off++];
00540     if (lite_components_count < 2)
00541     {
00542         LOG(VB_DSMCC, LOG_WARNING, "[biop] ProfileBody invalid components_count");
00543         return 0;
00544     }
00545 
00546     ret = obj_loc.Process(data + off);
00547     if (ret <= 0)
00548         return ret;
00549     off += ret;
00550 
00551     ret = dsm_conn.Process(data + off);
00552     if (ret <= 0)
00553         return ret;
00554     off += ret;
00555 
00556     obj_loc.m_Reference.m_nStreamTag = dsm_conn.tap.assoc_tag;
00557 
00558     /* UKProfile - ignore anything else */
00559 
00560     return off;
00561 }
00562 
00563 int BiopIor::Process(const unsigned char *data)
00564 {
00565     int off = 0, ret;
00566     type_id_len = ((data[0] << 24) | (data[1] << 16) |
00567                    (data[2] << 8)  | (data[3]));
00568     type_id = (char*) malloc(type_id_len);
00569     off += 4;
00570     memcpy(type_id, data + off, type_id_len);
00571     off += type_id_len;
00572 
00573     tagged_profiles_count = ((data[off    ] << 24) | (data[off + 1] << 16) |
00574                              (data[off + 2] <<  8) | (data[off + 3]));
00575     if (tagged_profiles_count < 1)
00576     {
00577         LOG(VB_DSMCC, LOG_WARNING, "[biop] IOR missing taggedProfile");
00578         return 0;
00579     }
00580     off += 4;
00581 
00582     profile_id_tag = ((data[off    ] << 24) | (data[off + 1] << 16) |
00583                       (data[off + 2] <<  8) | (data[off + 3]));
00584     off += 4;
00585 
00586     if (profile_id_tag == 0x49534F06) // profile_id_tag == 0x49534F06
00587     {
00588         m_profile_body = new ProfileBodyFull;
00589         ret = m_profile_body->Process(data + off);
00590         if (ret <= 0)
00591             return ret;
00592         off += ret;
00593     }
00594     else if(profile_id_tag == 0x49534F05) // profile_id_tag == 0x49534F05
00595     {
00596         m_profile_body = new ProfileBodyLite;
00597         ret = m_profile_body->Process(data + off);
00598         if (ret <= 0)
00599             return ret;
00600         off += ret;
00601     }
00602     else
00603     {
00604         /* UKProfile - receiver may ignore other profiles */
00605         LOG(VB_DSMCC, LOG_WARNING, QString("[biop] Unknown Ior profile 0x%1")
00606             .arg(profile_id_tag, 0, 16));
00607         return 0;
00608     }
00609 
00610     return off;
00611 }
00612 
00613 // An IOR may refer to other streams.  We may have to add taps for them.
00614 void BiopIor::AddTap(Dsmcc *pStatus)
00615 {
00616     DSMCCCacheReference *ref = m_profile_body->GetReference();
00617     if (ref != NULL)
00618         pStatus->AddTap(ref->m_nStreamTag, ref->m_nCarouselId);
00619 }
00620 
00621 BiopTap::~BiopTap()
00622 {
00623     free(selector_data);
00624 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends