void CZapitChannel::dumpBouquetXml(FILE * fd, bool bUser) { // TODO : gui->manage configuration: writeChannelsNames (if nessessary or wanted) in zapit.conf // menu > installation > Servicesscan > under 'Bouquet' => "Write DVB-names in bouquets:" f.e. =>0=never 1=ubouquets 2=bouquets 3=both int write_names = zapitCfg.writeChannelsNames; fprintf(fd, "\t\t<S"); // references (mandatory) if (url.empty()) fprintf(fd, " i=\"%x\" t=\"%x\" on=\"%x\" s=\"%hd\" frq=\"%hd\"",getServiceId(), getTransportStreamId(), getOriginalNetworkId(), getSatellitePosition(), getFreqId()); else fprintf(fd, " u=\"%s\"",convert_UTF8_To_UTF8_XML(url.c_str()).c_str()); // service names if (bUser || !url.empty()) { if ((write_names & CBouquetManager::BWN_UBOUQUETS) == CBouquetManager::BWN_UBOUQUETS) fprintf(fd, " n=\"%s\"", convert_UTF8_To_UTF8_XML(name.c_str()).c_str()); } else { if ((write_names & CBouquetManager::BWN_BOUQUETS) == CBouquetManager::BWN_BOUQUETS) fprintf(fd, " n=\"%s\"", convert_UTF8_To_UTF8_XML(name.c_str()).c_str()); } // usecase optional attributes if (bUser && !uname.empty()) fprintf(fd, " un=\"%s\"", convert_UTF8_To_UTF8_XML(uname.c_str()).c_str()); // TODO : be sure to save bouquets.xml after "l"L is changed only in ubouquets.xml (set dirty_bit ?) if (bLocked!=DEFAULT_CH_LOCKED) fprintf(fd," l=\"%d\"", bLocked ? 1 : 0); fprintf(fd, "/>\n"); }
void CZapitChannel::dumpServiceXml(FILE * fd, const char * action) { if(action) { fprintf(fd, "\t\t\t<S action=\"%s\" i=\"%04x\" n=\"%s\" t=\"%x\" s=\"%d\" num=\"%d\" f=\"%d\"/>\n", action, getServiceId(), convert_UTF8_To_UTF8_XML(name.c_str()).c_str(), getServiceType(), scrambled, number, flags); } else if(getPidsFlag()) { fprintf(fd, "\t\t\t<S i=\"%04x\" n=\"%s\" v=\"%x\" a=\"%x\" p=\"%x\" pmt=\"%x\" tx=\"%x\" t=\"%x\" vt=\"%d\" s=\"%d\" num=\"%d\" f=\"%d\"/>\n", getServiceId(), convert_UTF8_To_UTF8_XML(name.c_str()).c_str(), getVideoPid(), getPreAudioPid(), getPcrPid(), getPmtPid(), getTeletextPid(), getServiceType(true), type, scrambled, number, flags); } else { fprintf(fd, "\t\t\t<S i=\"%04x\" n=\"%s\" t=\"%x\" s=\"%d\" num=\"%d\" f=\"%d\"/>\n", getServiceId(), convert_UTF8_To_UTF8_XML(name.c_str()).c_str(), getServiceType(true), scrambled, number, flags); } }
void SensorResource::callService(const string &service) { int serviceId = getServiceId(service); switch(serviceId){ case NOT_FOUND: //TODO throw exception break; case GET: serviceReturnStorage = getState(); break; } }
int main(int argc, char **argv) { int i, j; struct timeval time_interval; fd_set useRead; fd_set useExcept; int selRet; char errTxt[256]; RsslBuffer errorText = {255, (char*)errTxt}; RsslInProgInfo inProg = RSSL_INIT_IN_PROG_INFO; RsslRet retval = 0; int iargs; RsslErrorInfo rsslErrorInfo; RsslBool cacheOption = RSSL_FALSE; RsslReactorOMMProviderRole providerRole; RsslBindOptions sopts = RSSL_INIT_BIND_OPTS; RsslCreateReactorOptions reactorOpts; RsslReactorDispatchOptions dispatchOpts; time_t nextSendTime; /* Initialize RSSL. The locking mode RSSL_LOCK_GLOBAL_AND_CHANNEL is required to use the RsslReactor. */ if (rsslInitialize(RSSL_LOCK_GLOBAL_AND_CHANNEL, &rsslErrorInfo.rsslError) != RSSL_RET_SUCCESS) { printf("rsslInitialize(): failed <%s>\n",rsslErrorInfo.rsslError.text); /* WINDOWS: wait for user to enter something before exiting */ #ifdef _WIN32 printf("\nPress Enter or Return key to exit application:"); getchar(); #endif exit(RSSL_RET_FAILURE); } rsslClearOMMProviderRole(&providerRole); providerRole.base.channelEventCallback = channelEventCallback; providerRole.base.defaultMsgCallback = defaultMsgCallback; providerRole.loginMsgCallback = loginMsgCallback; providerRole.directoryMsgCallback = directoryMsgCallback; providerRole.dictionaryMsgCallback = dictionaryMsgCallback; providerRole.tunnelStreamListenerCallback = tunnelStreamListenerCallback; rsslClearCreateReactorOptions(&reactorOpts); if (!(pReactor = rsslCreateReactor(&reactorOpts, &rsslErrorInfo))) { printf("Reactor creation failed: %s\n", rsslErrorInfo.rsslError.text); cleanUpAndExit(); } snprintf(portNo, 128, "%s", defaultPortNo); snprintf(serviceName, 128, "%s", defaultServiceName); setServiceId(1); for(iargs = 1; iargs < argc; ++iargs) { if (0 == strcmp("-p", argv[iargs])) { ++iargs; if (iargs == argc) exitWithUsage(); snprintf(portNo, 128, "%s", argv[iargs]); } else if (0 == strcmp("-s", argv[iargs])) { ++iargs; if (iargs == argc) exitWithUsage(); snprintf(serviceName, 128, "%s", argv[iargs]); } else if (0 == strcmp("-id", argv[iargs])) { long tmpId = 0; ++iargs; if (iargs == argc) exitWithUsage(); tmpId = atol(argv[iargs]); if (tmpId < 0) { printf("ServiceId must be positive.\n"); exitWithUsage(); } setServiceId(tmpId); } else if (0 == strcmp("-x", argv[iargs])) { xmlTrace = RSSL_TRUE; snprintf(traceOutputFile, 128, "RsslVAProvider\0"); } else if (0 == strcmp("-runtime", argv[iargs])) { ++iargs; if (iargs == argc) exitWithUsage(); timeToRun = atoi(argv[iargs]); } else if (0 == strcmp("-cache", argv[iargs])) { cacheOption = RSSL_TRUE; } else { printf("Error: Unrecognized option: %s\n\n", argv[iargs]); exitWithUsage(); } } printf("portNo: %s\n", portNo); printf("serviceName: %s\n", serviceName); printf("serviceId: %llu\n", getServiceId()); /* Initialiize client session information */ for (i = 0; i < MAX_CLIENT_SESSIONS; i++) { clearClientSessionInfo(&clientSessions[i]); } initializeCache(cacheOption); /* Initialize login handler */ initLoginHandler(); /* Initialize source directory handler */ initDirectoryHandler(); /* Initialize dictionary provider */ initDictionaryProvider(); /* Initialize market price handler */ initItemHandler(); /* Initialize symbol list item list */ initSymbolListItemList(); /* Initialize market by order items */ initMarketByOrderItems(); /* set service name in directory handler */ setServiceName(serviceName); /* load dictionary */ if (loadDictionary() != RSSL_RET_SUCCESS) { /* exit if dictionary cannot be loaded */ /* WINDOWS: wait for user to enter something before exiting */ #ifdef _WIN32 printf("\nPress Enter or Return key to exit application:"); getchar(); #endif exit(RSSL_RET_FAILURE); } initializeCacheDictionary(); /* Initialize run-time */ initRuntime(); FD_ZERO(&readFds); FD_ZERO(&exceptFds); sopts.guaranteedOutputBuffers = 500; sopts.serviceName = portNo; sopts.majorVersion = RSSL_RWF_MAJOR_VERSION; sopts.minorVersion = RSSL_RWF_MINOR_VERSION; sopts.protocolType = RSSL_RWF_PROTOCOL_TYPE; /* Create the server. */ if (!(rsslSrvr = rsslBind(&sopts, &rsslErrorInfo.rsslError))) { printf("Unable to bind RSSL server: <%s>\n",rsslErrorInfo.rsslError.text); /* WINDOWS: wait for user to enter something before exiting */ #ifdef _WIN32 printf("\nPress Enter or Return key to exit application:"); getchar(); #endif exit(RSSL_RET_FAILURE); } FD_SET(rsslSrvr->socketId, &readFds); FD_SET(pReactor->eventFd, &readFds); rsslClearReactorDispatchOptions(&dispatchOpts); dispatchOpts.maxMessages = MAX_CLIENT_SESSIONS; // initialize next send time nextSendTime = time(NULL) + UPDATE_INTERVAL; /* this is the main loop */ while(RSSL_TRUE) { useRead = readFds; useExcept = exceptFds; time_interval.tv_sec = UPDATE_INTERVAL; time_interval.tv_usec = 0; /* Call select() to check for any messages */ selRet = select(FD_SETSIZE,&useRead, NULL,&useExcept,&time_interval); if (selRet > 0) { RsslRet ret; /* Accept connection, if one is waiting */ if (FD_ISSET(rsslSrvr->socketId, &useRead)) { RsslClientSessionInfo *pClientSessionInfo = NULL; RsslReactorAcceptOptions aopts; rsslClearReactorAcceptOptions(&aopts); /* find an available client session */ for (i = 0; i < MAX_CLIENT_SESSIONS; i++) { if (!clientSessions[i].isInUse) { pClientSessionInfo = &clientSessions[i]; pClientSessionInfo->isInUse = RSSL_TRUE; break; } } /* Reject the channel if we are out of client sessions */ if (!pClientSessionInfo) aopts.rsslAcceptOptions.nakMount = RSSL_TRUE; else aopts.rsslAcceptOptions.userSpecPtr = pClientSessionInfo; printf("Accepting new connection...\n"); if (rsslReactorAccept(pReactor, rsslSrvr, &aopts, (RsslReactorChannelRole*)&providerRole, &rsslErrorInfo) != RSSL_RET_SUCCESS) { printf("rsslReactorAccept() failed: %s(%s)\n", rsslErrorInfo.rsslError.text, rsslErrorInfo.errorLocation); cleanUpAndExit(); } } /* Call rsslReactorDispatch(). This will handle any events that have occurred on its channels. * If there are events or messages for the application to process, they will be delivered * through the callback functions given by the providerRole object. * A return value greater than RSSL_RET_SUCCESS indicates there may be more to process. */ while ((ret = rsslReactorDispatch(pReactor, &dispatchOpts, &rsslErrorInfo)) > RSSL_RET_SUCCESS) ; if (ret < RSSL_RET_SUCCESS) { printf("rsslReactorDispatch() failed: %s\n", rsslErrorInfo.rsslError.text); cleanUpAndExit(); } } else if (selRet < 0) { #ifdef _WIN32 if (WSAGetLastError() == WSAEINTR) continue; printf("Error: select: %d\n", WSAGetLastError()); #else if (errno == EINTR) continue; perror("select"); #endif cleanUpAndExit(); } // send any updates at next send time if (time(NULL) >= nextSendTime) { /* Send market price updates for each connected channel */ updateItemInfo(); for (i = 0; i < MAX_CLIENT_SESSIONS; i++) { if (clientSessions[i].clientChannel != NULL) { if (sendItemUpdates(pReactor, clientSessions[i].clientChannel) != RSSL_RET_SUCCESS) { removeClientSessionForChannel(pReactor, clientSessions[i].clientChannel); } // send any tunnel stream messages for (j = 0; j < MAX_TUNNEL_STREAMS; j++) { if (clientSessions[i].simpleTunnelMsgHandler[j].tunnelStreamHandler.pTunnelStream != NULL) { handleSimpleTunnelMsgHandler(pReactor, clientSessions[i].clientChannel, &clientSessions[i].simpleTunnelMsgHandler[j]); } } } } nextSendTime += UPDATE_INTERVAL; } /* Handle run-time */ handleRuntime(); } }
cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data, bool OnlyRunningStatus) :SI::EIT(Data, false) { if (!CheckCRCAndParse()) return; tChannelID channelID(Source, getOriginalNetworkId(), getTransportStreamId(), getServiceId()); cChannel *channel = Channels.GetByChannelID(channelID, true); if (!channel) return; // only collect data for known channels cSchedule *pSchedule = (cSchedule *)Schedules->GetSchedule(channel, true); bool Empty = true; bool Modified = false; bool HasExternalData = false; time_t SegmentStart = 0; time_t SegmentEnd = 0; time_t Now = time(NULL); struct tm tm_r; struct tm t = *localtime_r(&Now, &tm_r); // this initializes the time zone in 't' if (Now < VALID_TIME) return; // we need the current time for handling PDC descriptors SI::EIT::Event SiEitEvent; for (SI::Loop::Iterator it; eventLoop.getNext(SiEitEvent, it); ) { bool ExternalData = false; time_t StartTime = SiEitEvent.getStartTime(); int Duration = SiEitEvent.getDuration(); // Drop bogus events - but keep NVOD reference events, where all bits of the start time field are set to 1, resulting in a negative number. if (StartTime == 0 || StartTime > 0 && Duration == 0) continue; Empty = false; if (!SegmentStart) SegmentStart = StartTime; SegmentEnd = StartTime + Duration; cEvent *newEvent = NULL; cEvent *rEvent = NULL; cEvent *pEvent = (cEvent *)pSchedule->GetEvent(SiEitEvent.getEventId(), StartTime); if (!pEvent) { if (OnlyRunningStatus) continue; // If we don't have that event yet, we create a new one. // Otherwise we copy the information into the existing event anyway, because the data might have changed. pEvent = newEvent = new cEvent(SiEitEvent.getEventId()); if (!pEvent) continue; } else { // We have found an existing event, either through its event ID or its start time. pEvent->SetSeen(); // If the existing event has a zero table ID it was defined externally and shall // not be overwritten. uchar TableID = pEvent->TableID(); if (TableID == 0x00) { if (pEvent->Version() == getVersionNumber()) continue; HasExternalData = ExternalData = true; } // If the new event has a higher table ID, let's skip it. // The lower the table ID, the more "current" the information. else if (Tid > TableID) continue; // If the new event comes from the same table and has the same version number // as the existing one, let's skip it to avoid unnecessary work. // Unfortunately some stations (like, e.g. "Premiere") broadcast their EPG data on several transponders (like // the actual Premiere transponder and the Sat.1/Pro7 transponder), but use different version numbers on // each of them :-( So if one DVB card is tuned to the Premiere transponder, while an other one is tuned // to the Sat.1/Pro7 transponder, events will keep toggling because of the bogus version numbers. else if (Tid == TableID && pEvent->Version() == getVersionNumber()) continue; } if (!ExternalData) { pEvent->SetEventID(SiEitEvent.getEventId()); // unfortunately some stations use different event ids for the same event in different tables :-( pEvent->SetTableID(Tid); pEvent->SetStartTime(StartTime); pEvent->SetDuration(Duration); } if (newEvent) pSchedule->AddEvent(newEvent); if (Tid == 0x4E) { // we trust only the present/following info on the actual TS if (SiEitEvent.getRunningStatus() >= SI::RunningStatusNotRunning) pSchedule->SetRunningStatus(pEvent, SiEitEvent.getRunningStatus(), channel); } if (OnlyRunningStatus) continue; // do this before setting the version, so that the full update can be done later pEvent->SetVersion(getVersionNumber()); int LanguagePreferenceShort = -1; int LanguagePreferenceExt = -1; bool UseExtendedEventDescriptor = false; SI::Descriptor *d; SI::ExtendedEventDescriptors *ExtendedEventDescriptors = NULL; SI::ShortEventDescriptor *ShortEventDescriptor = NULL; cLinkChannels *LinkChannels = NULL; cComponents *Components = NULL; for (SI::Loop::Iterator it2; (d = SiEitEvent.eventDescriptors.getNext(it2)); ) { if (ExternalData && d->getDescriptorTag() != SI::ComponentDescriptorTag) { delete d; continue; } switch (d->getDescriptorTag()) { case SI::ExtendedEventDescriptorTag: { SI::ExtendedEventDescriptor *eed = (SI::ExtendedEventDescriptor *)d; if (I18nIsPreferredLanguage(Setup.EPGLanguages, eed->languageCode, LanguagePreferenceExt) || !ExtendedEventDescriptors) { delete ExtendedEventDescriptors; ExtendedEventDescriptors = new SI::ExtendedEventDescriptors; UseExtendedEventDescriptor = true; } if (UseExtendedEventDescriptor) { ExtendedEventDescriptors->Add(eed); d = NULL; // so that it is not deleted } if (eed->getDescriptorNumber() == eed->getLastDescriptorNumber()) UseExtendedEventDescriptor = false; } break; case SI::ShortEventDescriptorTag: { SI::ShortEventDescriptor *sed = (SI::ShortEventDescriptor *)d; if (I18nIsPreferredLanguage(Setup.EPGLanguages, sed->languageCode, LanguagePreferenceShort) || !ShortEventDescriptor) { delete ShortEventDescriptor; ShortEventDescriptor = sed; d = NULL; // so that it is not deleted } } break; case SI::ContentDescriptorTag: { SI::ContentDescriptor *cd = (SI::ContentDescriptor *)d; SI::ContentDescriptor::Nibble Nibble; int NumContents = 0; uchar Contents[MAXEVCONTENTS] = { 0 }; for (SI::Loop::Iterator it3; cd->nibbleLoop.getNext(Nibble, it3); ) { if (NumContents < MAXEVCONTENTS) { Contents[NumContents] = ((Nibble.getContentNibbleLevel1() & 0xF) << 4) | (Nibble.getContentNibbleLevel2() & 0xF); NumContents++; } } pEvent->SetContents(Contents); } break; case SI::ParentalRatingDescriptorTag: { int LanguagePreferenceRating = -1; SI::ParentalRatingDescriptor *prd = (SI::ParentalRatingDescriptor *)d; SI::ParentalRatingDescriptor::Rating Rating; for (SI::Loop::Iterator it3; prd->ratingLoop.getNext(Rating, it3); ) { if (I18nIsPreferredLanguage(Setup.EPGLanguages, Rating.languageCode, LanguagePreferenceRating)) { int ParentalRating = (Rating.getRating() & 0xFF); switch (ParentalRating) { // values defined by the DVB standard (minimum age = rating + 3 years): case 0x01 ... 0x0F: ParentalRating += 3; break; // values defined by broadcaster CSAT (now why didn't they just use 0x07, 0x09 and 0x0D?): case 0x11: ParentalRating = 10; break; case 0x12: ParentalRating = 12; break; case 0x13: ParentalRating = 16; break; default: ParentalRating = 0; } pEvent->SetParentalRating(ParentalRating); } } } break; case SI::PDCDescriptorTag: { SI::PDCDescriptor *pd = (SI::PDCDescriptor *)d; t.tm_isdst = -1; // makes sure mktime() will determine the correct DST setting int month = t.tm_mon; t.tm_mon = pd->getMonth() - 1; t.tm_mday = pd->getDay(); t.tm_hour = pd->getHour(); t.tm_min = pd->getMinute(); t.tm_sec = 0; if (month == 11 && t.tm_mon == 0) // current month is dec, but event is in jan t.tm_year++; else if (month == 0 && t.tm_mon == 11) // current month is jan, but event is in dec t.tm_year--; time_t vps = mktime(&t); pEvent->SetVps(vps); } break; case SI::TimeShiftedEventDescriptorTag: { SI::TimeShiftedEventDescriptor *tsed = (SI::TimeShiftedEventDescriptor *)d; cSchedule *rSchedule = (cSchedule *)Schedules->GetSchedule(tChannelID(Source, channel->Nid(), channel->Tid(), tsed->getReferenceServiceId())); if (!rSchedule) break; rEvent = (cEvent *)rSchedule->GetEvent(tsed->getReferenceEventId()); if (!rEvent) break; pEvent->SetTitle(rEvent->Title()); pEvent->SetShortText(rEvent->ShortText()); pEvent->SetDescription(rEvent->Description()); } break; case SI::LinkageDescriptorTag: { SI::LinkageDescriptor *ld = (SI::LinkageDescriptor *)d; tChannelID linkID(Source, ld->getOriginalNetworkId(), ld->getTransportStreamId(), ld->getServiceId()); if (ld->getLinkageType() == 0xB0) { // Premiere World bool hit = StartTime <= Now && Now < StartTime + Duration; if (hit) { char linkName[ld->privateData.getLength() + 1]; strn0cpy(linkName, (const char *)ld->privateData.getData(), sizeof(linkName)); // TODO is there a standard way to determine the character set of this string? cChannel *link = Channels.GetByChannelID(linkID); if (link != channel) { // only link to other channels, not the same one //fprintf(stderr, "Linkage %s %4d %4d %5d %5d %5d %5d %02X '%s'\n", hit ? "*" : "", channel->Number(), link ? link->Number() : -1, SiEitEvent.getEventId(), ld->getOriginalNetworkId(), ld->getTransportStreamId(), ld->getServiceId(), ld->getLinkageType(), linkName);//XXX if (link) { if (Setup.UpdateChannels == 1 || Setup.UpdateChannels >= 3) link->SetName(linkName, "", ""); } else if (Setup.UpdateChannels >= 4) { cChannel *transponder = channel; if (channel->Tid() != ld->getTransportStreamId()) transponder = Channels.GetByTransponderID(linkID); link = Channels.NewChannel(transponder, linkName, "", "", ld->getOriginalNetworkId(), ld->getTransportStreamId(), ld->getServiceId()); //XXX patFilter->Trigger(); } if (link) { if (!LinkChannels) LinkChannels = new cLinkChannels; LinkChannels->Add(new cLinkChannel(link)); } } else channel->SetPortalName(linkName); } } } break; case SI::ComponentDescriptorTag: { SI::ComponentDescriptor *cd = (SI::ComponentDescriptor *)d; uchar Stream = cd->getStreamContent(); uchar Type = cd->getComponentType(); if (1 <= Stream && Stream <= 4 && Type != 0) { // 1=video, 2=audio, 3=subtitles, 4=AC3 if (!Components) Components = new cComponents; char buffer[Utf8BufSize(256)]; Components->SetComponent(Components->NumComponents(), Stream, Type, I18nNormalizeLanguageCode(cd->languageCode), cd->description.getText(buffer, sizeof(buffer))); } } break; default: ; } delete d; } if (!rEvent) { if (ShortEventDescriptor) { char buffer[Utf8BufSize(256)]; pEvent->SetTitle(ShortEventDescriptor->name.getText(buffer, sizeof(buffer))); pEvent->SetShortText(ShortEventDescriptor->text.getText(buffer, sizeof(buffer))); } else if (!HasExternalData) { pEvent->SetTitle(NULL); pEvent->SetShortText(NULL); } if (ExtendedEventDescriptors) { char buffer[Utf8BufSize(ExtendedEventDescriptors->getMaximumTextLength(": ")) + 1]; pEvent->SetDescription(ExtendedEventDescriptors->getText(buffer, sizeof(buffer), ": ")); } else if (!HasExternalData) pEvent->SetDescription(NULL); } delete ExtendedEventDescriptors; delete ShortEventDescriptor; pEvent->SetComponents(Components); if (!HasExternalData) pEvent->FixEpgBugs(); if (LinkChannels) channel->SetLinkChannels(LinkChannels); Modified = true; }
cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data, bool OnlyRunningStatus) :SI::EIT(Data, false) { if (!CheckCRCAndParse()) return; tChannelID channelID(Source, getOriginalNetworkId(), getTransportStreamId(), getServiceId()); cChannel *channel = Channels.GetByChannelID(channelID, true); if (!channel) return; // only collect data for known channels //M7X0 BEGIN AK eEpgMode em = EpgModes.GetModeByChannelID(&channelID)->GetMode(); if ((em == emNone) | ((em == emNowNext) & (Tid != 0x4e) & (Tid != 0x4f))) return; //M7X0 END AK cSchedule *pSchedule = (cSchedule *)Schedules->GetSchedule(channel, true); bool Empty = true; bool Modified = false; bool HasExternalData = false; time_t SegmentStart = 0; time_t SegmentEnd = 0; time_t now = time(NULL); SI::EIT::Event SiEitEvent; for (SI::Loop::Iterator it; eventLoop.getNext(SiEitEvent, it); ) { bool ExternalData = false; // Drop bogus events - but keep NVOD reference events, where all bits of the start time field are set to 1, resulting in a negative number. time_t si_stime = SiEitEvent.getStartTime(); time_t si_dur = SiEitEvent.getDuration(); if (si_stime == 0 || (si_stime > 0 && si_dur == 0)) continue; Empty = false; if (((!SegmentStart) | (si_stime < SegmentStart)) & (si_stime > 0)) SegmentStart = si_stime; if (si_stime + si_dur > SegmentEnd) SegmentEnd = si_stime + si_dur; cEvent *newEvent = NULL; cEvent *rEvent = NULL; cEvent *pEvent = (cEvent *)pSchedule->GetEvent(SiEitEvent.getEventId(), si_stime); if (!pEvent) { bool outdated = (si_stime > 0) & (si_stime + si_dur + Setup.EPGLinger * 60 + 3600 < now); if (OnlyRunningStatus | (em == emForeign) | outdated) continue; // If we don't have that event yet, we create a new one. // Otherwise we copy the information into the existing event anyway, because the data might have changed. pEvent = newEvent = new cEvent(SiEitEvent.getEventId()); if (!pEvent) continue; } else { // We have found an existing event, either through its event ID or its start time. pEvent->SetSeen(); // If the existing event has a zero table ID it was defined externally and shall // not be overwritten. if (pEvent->TableID() == 0x00) { if (pEvent->Version() == getVersionNumber()) continue; HasExternalData = ExternalData = true; } // If the new event has a higher table ID, let's skip it. // The lower the table ID, the more "current" the information. else if (Tid > pEvent->TableID()) continue; // If the new event comes from the same table and has the same version number // as the existing one, let's skip it to avoid unnecessary work. // Unfortunately some stations (like, e.g. "Premiere") broadcast their EPG data on several transponders (like // the actual Premiere transponder and the Sat.1/Pro7 transponder), but use different version numbers on // each of them :-( So if one DVB card is tuned to the Premiere transponder, while an other one is tuned // to the Sat.1/Pro7 transponder, events will keep toggling because of the bogus version numbers. else if (Tid == pEvent->TableID() && pEvent->Version() == getVersionNumber()) continue; } if ((!ExternalData) & (!OnlyRunningStatus)) { pEvent->SetEventID(SiEitEvent.getEventId()); // unfortunately some stations use different event ids for the same event in different tables :-( pEvent->SetTableID(Tid); pEvent->SetStartTime(si_stime); pEvent->SetDuration(si_dur); } if (newEvent) pSchedule->AddEvent(newEvent); if (Tid == 0x4E) { // we trust only the present/following info on the actual TS if (SiEitEvent.getRunningStatus() >= SI::RunningStatusNotRunning) pSchedule->SetRunningStatus(pEvent, SiEitEvent.getRunningStatus(), channel); } if (OnlyRunningStatus) continue; // do this before setting the version, so that the full update can be done later pEvent->SetVersion(getVersionNumber()); int LanguagePreferenceShort = -1; int LanguagePreferenceExt = -1; bool UseExtendedEventDescriptor = false; SI::Descriptor *d; SI::ExtendedEventDescriptors *ExtendedEventDescriptors = NULL; SI::ShortEventDescriptor *ShortEventDescriptor = NULL; cLinkChannels *LinkChannels = NULL; cComponents *Components = NULL; for (SI::Loop::Iterator it2; (d = SiEitEvent.eventDescriptors.getNext(it2)); ) { if (ExternalData && d->getDescriptorTag() != SI::ComponentDescriptorTag) { delete d; continue; } switch (d->getDescriptorTag()) { case SI::ExtendedEventDescriptorTag: { SI::ExtendedEventDescriptor *eed = (SI::ExtendedEventDescriptor *)d; if (I18nIsPreferredLanguage(Setup.EPGLanguages, eed->languageCode, LanguagePreferenceExt) || !ExtendedEventDescriptors) { delete ExtendedEventDescriptors; ExtendedEventDescriptors = new SI::ExtendedEventDescriptors; UseExtendedEventDescriptor = true; } if (UseExtendedEventDescriptor) { ExtendedEventDescriptors->Add(eed); d = NULL; // so that it is not deleted } if (eed->getDescriptorNumber() == eed->getLastDescriptorNumber()) UseExtendedEventDescriptor = false; } break; case SI::ShortEventDescriptorTag: { SI::ShortEventDescriptor *sed = (SI::ShortEventDescriptor *)d; if (I18nIsPreferredLanguage(Setup.EPGLanguages, sed->languageCode, LanguagePreferenceShort) || !ShortEventDescriptor) { delete ShortEventDescriptor; ShortEventDescriptor = sed; d = NULL; // so that it is not deleted } } break; case SI::ContentDescriptorTag: break; case SI::ParentalRatingDescriptorTag: break; case SI::PDCDescriptorTag: { SI::PDCDescriptor *pd = (SI::PDCDescriptor *)d; time_t now = time(NULL); struct tm tm_r; struct tm t = *localtime_r(&now, &tm_r); // this initializes the time zone in 't' t.tm_isdst = -1; // makes sure mktime() will determine the correct DST setting int month = t.tm_mon; t.tm_mon = pd->getMonth() - 1; t.tm_mday = pd->getDay(); t.tm_hour = pd->getHour(); t.tm_min = pd->getMinute(); t.tm_sec = 0; if (month == 11 && t.tm_mon == 0) // current month is dec, but event is in jan t.tm_year++; else if (month == 0 && t.tm_mon == 11) // current month is jan, but event is in dec t.tm_year--; time_t vps = mktime(&t); pEvent->SetVps(vps); } break; case SI::TimeShiftedEventDescriptorTag: { SI::TimeShiftedEventDescriptor *tsed = (SI::TimeShiftedEventDescriptor *)d; cSchedule *rSchedule = (cSchedule *)Schedules->GetSchedule(tChannelID(Source, channel->Nid(), channel->Tid(), tsed->getReferenceServiceId())); if (!rSchedule) break; rEvent = (cEvent *)rSchedule->GetEvent(tsed->getReferenceEventId()); if (!rEvent) break; pEvent->SetTitle(rEvent->Title()); pEvent->SetShortText(rEvent->ShortText()); pEvent->SetDescription(rEvent->Description()); } break; case SI::LinkageDescriptorTag: { SI::LinkageDescriptor *ld = (SI::LinkageDescriptor *)d; tChannelID linkID(Source, ld->getOriginalNetworkId(), ld->getTransportStreamId(), ld->getServiceId()); if (ld->getLinkageType() == 0xB0) { // Premiere World time_t now = time(NULL); bool hit = SiEitEvent.getStartTime() <= now && now < SiEitEvent.getStartTime() + SiEitEvent.getDuration(); if (hit) { char linkName[ld->privateData.getLength() + 1]; strn0cpy(linkName, (const char *)ld->privateData.getData(), sizeof(linkName)); cChannel *link = Channels.GetByChannelID(linkID); if (link != channel) { // only link to other channels, not the same one //fprintf(stderr, "Linkage %s %4d %4d %5d %5d %5d %5d %02X '%s'\n", hit ? "*" : "", channel->Number(), link ? link->Number() : -1, SiEitEvent.getEventId(), ld->getOriginalNetworkId(), ld->getTransportStreamId(), ld->getServiceId(), ld->getLinkageType(), linkName);//XXX if (link) { if (Setup.UpdateChannels == 1 || Setup.UpdateChannels >= 3) link->SetName(linkName, "", ""); } else if (Setup.UpdateChannels >= 4) { link = Channels.NewChannel(channel, linkName, "", "", ld->getOriginalNetworkId(), ld->getTransportStreamId(), ld->getServiceId()); //XXX patFilter->Trigger(); } if (link) { if (!LinkChannels) LinkChannels = new cLinkChannels; LinkChannels->Add(new cLinkChannel(link)); } } else channel->SetPortalName(linkName); } } } break; case SI::ComponentDescriptorTag: { SI::ComponentDescriptor *cd = (SI::ComponentDescriptor *)d; uchar Stream = cd->getStreamContent(); uchar Type = cd->getComponentType(); if (1 <= Stream && Stream <= 2 && Type != 0) { if (!Components) Components = new cComponents; char buffer[256]; Components->SetComponent(Components->NumComponents(), cd->getStreamContent(), cd->getComponentType(), I18nNormalizeLanguageCode(cd->languageCode), cd->description.getText(buffer, sizeof(buffer))); } } break; default: ; } delete d; } if (!rEvent) { if (ShortEventDescriptor) { char buffer[256]; pEvent->SetTitle(ShortEventDescriptor->name.getText(buffer, sizeof(buffer))); pEvent->SetShortText(ShortEventDescriptor->text.getText(buffer, sizeof(buffer))); } else if (!HasExternalData) { pEvent->SetTitle(NULL); pEvent->SetShortText(NULL); } if (ExtendedEventDescriptors) { char buffer[ExtendedEventDescriptors->getMaximumTextLength(": ") + 1]; pEvent->SetDescription(ExtendedEventDescriptors->getText(buffer, sizeof(buffer), ": ")); } else if (!HasExternalData) pEvent->SetDescription(NULL); } delete ExtendedEventDescriptors; delete ShortEventDescriptor; pEvent->SetComponents(Components); if (!HasExternalData) pEvent->FixEpgBugs(); if (LinkChannels) channel->SetLinkChannels(LinkChannels); Modified = true; } if (Empty && Tid == 0x4E && getSectionNumber() == 0) // ETR 211: an empty entry in section 0 of table 0x4E means there is currently no event running pSchedule->ClrRunningStatus(channel); if (Tid == 0x4E) pSchedule->SetPresentSeen(); if (OnlyRunningStatus) return; if (Modified) { pSchedule->Sort(); pSchedule->DropOutdated(SegmentStart, SegmentEnd, Tid, getVersionNumber()); Schedules->SetModified(pSchedule); } }
cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data, bool OnlyRunningStatus) :SI::EIT(Data, false) { if (!CheckCRCAndParse()) return; tChannelID channelID(Source, getOriginalNetworkId(), getTransportStreamId(), getServiceId()); cChannel *channel = Channels.GetByChannelID(channelID, true); if (!channel) return; // only collect data for known channels // Channel marked as not to receive EPG data (noEPG patch) if (!Channels.isEPGAllowed(channelID)) { return; } const char *charset; if(channelID == lastChannelID) { charset = lastCharset; } else { charset = ProviderCharsets.GetCharset(channel->Provider()); lastCharset = charset; } //::printf("======== %s charset: %s ==========\n", channel->Provider(), charset); cSchedule *pSchedule = (cSchedule *)Schedules->GetSchedule(channel, true); bool Empty = true; bool Modified = false; bool HasExternalData = false; time_t SegmentStart = 0; time_t SegmentEnd = 0; time_t now = time(NULL); struct tm tm_r; struct tm t = *localtime_r(&now, &tm_r); // this initializes the time zone in 't' if (now < VALID_TIME) return; // we need the current time for handling PDC descriptors SI::EIT::Event SiEitEvent; for (SI::Loop::Iterator it; eventLoop.getNext(SiEitEvent, it); ) { bool ExternalData = false; // Drop bogus events - but keep NVOD reference events, where all bits of the start time field are set to 1, resulting in a negative number. int startTime = SiEitEvent.getStartTime(); int duration = SiEitEvent.getDuration(); if (startTime == 0 || (startTime > 0 && duration == 0)) continue; Empty = false; if (!SegmentStart) SegmentStart = startTime; SegmentEnd = startTime + duration; cEvent *newEvent = NULL; cEvent *rEvent = NULL; cEvent *pEvent = (cEvent *)pSchedule->GetEvent(SiEitEvent.getEventId(), startTime); if (!pEvent) { if (OnlyRunningStatus) continue; // If we don't have that event yet, we create a new one. // Otherwise we copy the information into the existing event anyway, because the data might have changed. pEvent = newEvent = new cEvent(SiEitEvent.getEventId()); if (!pEvent) continue; } else { // We have found an existing event, either through its event ID or its start time. pEvent->SetSeen(); // If the existing event has a zero table ID it was defined externally and shall // not be overwritten. uchar tableID = pEvent->TableID(); if (tableID == 0x00) { if (pEvent->Version() == getVersionNumber()) continue; HasExternalData = ExternalData = true; } // If the new event has a higher table ID, let's skip it. // The lower the table ID, the more "current" the information. else if (Tid > tableID) continue; // If the new event comes from the same table and has the same version number // as the existing one, let's skip it to avoid unnecessary work. // Unfortunately some stations (like, e.g. "Premiere") broadcast their EPG data on several transponders (like // the actual Premiere transponder and the Sat.1/Pro7 transponder), but use different version numbers on // each of them :-( So if one DVB card is tuned to the Premiere transponder, while an other one is tuned // to the Sat.1/Pro7 transponder, events will keep toggling because of the bogus version numbers. else if (Tid == tableID && pEvent->Version() == getVersionNumber()) continue; } if (!ExternalData) { pEvent->SetEventID(SiEitEvent.getEventId()); // unfortunately some stations use different event ids for the same event in different tables :-( pEvent->SetTableID(Tid); pEvent->SetStartTime(startTime); pEvent->SetDuration(duration); } if (newEvent) pSchedule->AddEvent(newEvent); if (Tid == 0x4E) { // we trust only the present/following info on the actual TS if (SiEitEvent.getRunningStatus() >= SI::RunningStatusNotRunning) pSchedule->SetRunningStatus(pEvent, SiEitEvent.getRunningStatus(), channel); } if (OnlyRunningStatus) continue; // do this before setting the version, so that the full update can be done later pEvent->SetVersion(getVersionNumber()); int LanguagePreferenceShort = -1; int LanguagePreferenceExt = -1; bool UseExtendedEventDescriptor = false; SI::Descriptor *d; SI::ExtendedEventDescriptors *ExtendedEventDescriptors = NULL; SI::ShortEventDescriptor *ShortEventDescriptor = NULL; cLinkChannels *LinkChannels = NULL; cComponents *Components = NULL; for (SI::Loop::Iterator it2; (d = SiEitEvent.eventDescriptors.getNext(it2)); ) { if (ExternalData && d->getDescriptorTag() != SI::ComponentDescriptorTag) { delete d; continue; } switch (d->getDescriptorTag()) { case SI::ExtendedEventDescriptorTag: { SI::ExtendedEventDescriptor *eed = (SI::ExtendedEventDescriptor *)d; if (I18nIsPreferredLanguage(Setup.EPGLanguages, eed->languageCode, LanguagePreferenceExt) || !ExtendedEventDescriptors) { delete ExtendedEventDescriptors; ExtendedEventDescriptors = new SI::ExtendedEventDescriptors; UseExtendedEventDescriptor = true; } if (UseExtendedEventDescriptor) { ExtendedEventDescriptors->Add(eed); d = NULL; // so that it is not deleted } if (eed->getDescriptorNumber() == eed->getLastDescriptorNumber()) UseExtendedEventDescriptor = false; } break; case SI::ShortEventDescriptorTag: { SI::ShortEventDescriptor *sed = (SI::ShortEventDescriptor *)d; if (I18nIsPreferredLanguage(Setup.EPGLanguages, sed->languageCode, LanguagePreferenceShort) || !ShortEventDescriptor) { delete ShortEventDescriptor; ShortEventDescriptor = sed; d = NULL; // so that it is not deleted } } break; case SI::ContentDescriptorTag: break; case SI::ParentalRatingDescriptorTag: break; case SI::PDCDescriptorTag: { SI::PDCDescriptor *pd = (SI::PDCDescriptor *)d; t.tm_isdst = -1; // makes sure mktime() will determine the correct DST setting int month = t.tm_mon; t.tm_mon = pd->getMonth() - 1; t.tm_mday = pd->getDay(); t.tm_hour = pd->getHour(); t.tm_min = pd->getMinute(); t.tm_sec = 0; if (month == 11 && t.tm_mon == 0) // current month is dec, but event is in jan t.tm_year++; else if (month == 0 && t.tm_mon == 11) // current month is jan, but event is in dec t.tm_year--; time_t vps = mktime(&t); pEvent->SetVps(vps); } break; case SI::TimeShiftedEventDescriptorTag: { SI::TimeShiftedEventDescriptor *tsed = (SI::TimeShiftedEventDescriptor *)d; cSchedule *rSchedule = (cSchedule *)Schedules->GetSchedule(tChannelID(Source, channel->Nid(), channel->Tid(), tsed->getReferenceServiceId())); if (!rSchedule) break; rEvent = (cEvent *)rSchedule->GetEvent(tsed->getReferenceEventId()); if (!rEvent) break; pEvent->SetTitle(rEvent->Title()); pEvent->SetShortText(rEvent->ShortText()); pEvent->SetDescription(rEvent->Description()); } break; case SI::LinkageDescriptorTag: { SI::LinkageDescriptor *ld = (SI::LinkageDescriptor *)d; tChannelID linkID(Source, ld->getOriginalNetworkId(), ld->getTransportStreamId(), ld->getServiceId()); #ifdef DBG_EIT_LINKS dsyslog("[eit]: Linkage Type %X (0xB0) == Premiere ", ld->getLinkageType()); #endif if (ld->getLinkageType() == 0xB0) { // Premiere World bool hit = startTime <= now && now < startTime + duration; if (hit) { #ifdef DBG_EIT_LINKS dsyslog("[eit]: get hit \n"); #endif SI::String linkNameStr; linkNameStr.setData(ld->privateData, ld->privateData.getLength()); char linkName[Utf8BufSize(ld->privateData.getLength() + 1)]; linkNameStr.getText(linkName, sizeof(linkName), charset); cChannel *link = Channels.GetByChannelID(linkID); #ifdef DBG_EIT_LINKS dsyslog("[eit]: linkName %s \n", linkName); dsyslog("[eit]: linkName: %s; ID %X Channel: %s, ID %X \n", link->Name(),link->GetChannelID().Sid(), channel->Name(), channel->GetChannelID().Sid()); #endif if (link != channel) { // only link to other channels, not the same one //XXX ? #ifdef DBG_EIT_LINKS dsyslog("[eit] Linkage %s %4d %4d %5d %5d %5d %5d %02X '%s'\n", hit ? "*" : "", channel->Number(), link ? link->Number() : -1, SiEitEvent.getEventId(), ld->getOriginalNetworkId(), ld->getTransportStreamId(), ld->getServiceId(), ld->getLinkageType(), linkName);//XXX #endif if (link) { if (Setup.UpdateChannels == 1 || Setup.UpdateChannels >= 3) // Update in any case! link->SetName(linkName, "", channel->Provider()); } else if (Setup.UpdateChannels >= 4) { if (channel->Tid() != ld->getTransportStreamId()) { cChannel *transponder = Channels.GetByTransponderID(linkID); link = Channels.NewChannel(transponder, linkName, "", channel->Provider(), ld->getOriginalNetworkId(), ld->getTransportStreamId(), ld->getServiceId()); } else link = Channels.NewChannel(channel, linkName, "", channel->Provider(), ld->getOriginalNetworkId(), ld->getTransportStreamId(), ld->getServiceId()); //XXX patFilter->Trigger(); } if (link) { if (!LinkChannels) LinkChannels = new cLinkChannels; #ifdef DBG_EIT_LINKS dsyslog("[eit]: Add new cLinkChannel(link)\n"); #endif LinkChannels->Add(new cLinkChannel(link)); } } else { channel->SetPortalName(linkName); #ifdef DBG_EIT_LINKS dsyslog("[eit]: Set portal name %s to %s hit \n",channel->Name(), linkName); #endif } } } } break; case SI::ComponentDescriptorTag: { SI::ComponentDescriptor *cd = (SI::ComponentDescriptor *)d; uchar Stream = cd->getStreamContent(); uchar Type = cd->getComponentType(); if (1 <= Stream && Stream <= 3 && Type != 0) { // 1=video, 2=audio, 3=subtitles if (!Components) Components = new cComponents; char buffer[Utf8BufSize(256)]; Components->SetComponent(Components->NumComponents(), cd->getStreamContent(), cd->getComponentType(), I18nNormalizeLanguageCode(cd->languageCode), cd->description.getText(buffer, sizeof(buffer), charset)); } } break; default: ; } delete d; } if (!rEvent) { if (ShortEventDescriptor) { char buffer[Utf8BufSize(256)]; pEvent->SetTitle(ShortEventDescriptor->name.getText(buffer, sizeof(buffer), charset)); pEvent->SetShortText(ShortEventDescriptor->text.getText(buffer, sizeof(buffer), charset)); } else if (!HasExternalData) { pEvent->SetTitle(NULL); pEvent->SetShortText(NULL); } if (ExtendedEventDescriptors) { char buffer[Utf8BufSize(ExtendedEventDescriptors->getMaximumTextLength(": ") + 1)]; pEvent->SetDescription(ExtendedEventDescriptors->getText(buffer, sizeof(buffer), charset, ": ")); } else if (!HasExternalData) pEvent->SetDescription(NULL); } delete ExtendedEventDescriptors; delete ShortEventDescriptor; pEvent->SetComponents(Components); if (!HasExternalData) pEvent->FixEpgBugs(); if (LinkChannels) channel->SetLinkChannels(LinkChannels); Modified = true; } if (Tid == 0x4E) { if (Empty && getSectionNumber() == 0) // ETR 211: an empty entry in section 0 of table 0x4E means there is currently no event running pSchedule->ClrRunningStatus(channel); pSchedule->SetPresentSeen(); } if (OnlyRunningStatus) return; if (Modified) { pSchedule->Sort(); if (!HasExternalData) pSchedule->DropOutdated(SegmentStart, SegmentEnd, Tid, getVersionNumber()); Schedules->SetModified(pSchedule); } }
/* * Encodes the batch item request. Returns success if * encoding succeeds or failure if encoding fails. * chnl - The channel to send an item request to * msgBuf - The message buffer to encode the item request into * streamId - The stream id of the item request * isPrivateStream - Flag for private stream request * * This function is only used within the Market Price Handler * and each handler has its own implementation, although much is similar */ static RsslRet encodeBatchItemRequest(RsslChannel* chnl, RsslBuffer* msgBuf, RsslInt32 streamId, RsslBool isPrivateStream) { RsslRet ret = 0; RsslRequestMsg msg = RSSL_INIT_REQUEST_MSG; RsslElementList eList = RSSL_INIT_ELEMENT_LIST; RsslElementEntry eEntry = RSSL_INIT_ELEMENT_ENTRY; RsslArray elementArray = RSSL_INIT_ARRAY; RsslEncodeIterator encodeIter; RsslSourceDirectoryResponseInfo* srcDirRespInfo = 0; RsslBuffer itemName; int i; RsslLoginResponseInfo* loginInfo = getLoginResponseInfo(); if (getSourceDirectoryResponseInfo(getServiceId(), &srcDirRespInfo) != RSSL_RET_SUCCESS) return RSSL_RET_FAILURE; /* clear encode iterator */ rsslClearEncodeIterator(&encodeIter); /* set-up message */ msg.msgBase.msgClass = RSSL_MC_REQUEST; msg.msgBase.streamId = streamId; msg.msgBase.domainType = RSSL_DMT_MARKET_PRICE; msg.msgBase.containerType = RSSL_DT_ELEMENT_LIST; if (snapshotRequest) { msg.flags = RSSL_RQMF_HAS_QOS | RSSL_RQMF_HAS_PRIORITY | RSSL_RQMF_HAS_BATCH; } else { msg.flags = RSSL_RQMF_HAS_QOS | RSSL_RQMF_STREAMING | RSSL_RQMF_HAS_PRIORITY | RSSL_RQMF_HAS_BATCH; } if((loginInfo->SupportViewRequests == RSSL_TRUE) && (viewRequest == RSSL_TRUE)) { msg.flags |= RSSL_RQMF_HAS_VIEW; } if (isPrivateStream) { msg.flags |= RSSL_RQMF_PRIVATE_STREAM; } msg.priorityClass = 1; msg.priorityCount = 1; /* copy the QoS information */ rsslCopyQos(&(msg.qos), &(srcDirRespInfo->ServiceGeneralInfo.QoS[0])); /* specify msgKey members */ msg.msgBase.msgKey.flags = RSSL_MKF_HAS_NAME_TYPE | RSSL_MKF_HAS_SERVICE_ID; msg.msgBase.msgKey.nameType = RDM_INSTRUMENT_NAME_TYPE_RIC; msg.msgBase.msgKey.serviceId = (RsslUInt16)getServiceId(); /* encode message */ if((ret = rsslSetEncodeIteratorBuffer(&encodeIter, msgBuf)) < RSSL_RET_SUCCESS) { printf("rsslSetEncodeIteratorBuffer() failed with return code: %d\n", ret); return ret; } rsslSetEncodeIteratorRWFVersion(&encodeIter, chnl->majorVersion, chnl->minorVersion); /* start the request message encoding */ if ((ret = rsslEncodeMsgInit(&encodeIter, (RsslMsg*)&msg, 0)) < RSSL_RET_SUCCESS) { printf("rsslEncodeMsg() failed with return code: %d\n", ret); return ret; } /* For Batch requests, the message has a payload of an element list that contains an array of the requested items */ eList.flags = RSSL_ELF_HAS_STANDARD_DATA; if((ret = rsslEncodeElementListInit(&encodeIter, &eList, 0, 0)) < RSSL_RET_SUCCESS) { printf("rsslEncodeElementListInit() failed with return code: %d\n", ret); return ret; } eEntry.name = RSSL_ENAME_BATCH_ITEM_LIST; eEntry.dataType = RSSL_DT_ARRAY; if((ret = rsslEncodeElementEntryInit(&encodeIter, &eEntry, 0)) < RSSL_RET_SUCCESS) { printf("rsslEncodeElementEntryInit() failed with return code: %d\n", ret); return ret; } /* Encode the array of requested item names */ elementArray.primitiveType = RSSL_DT_ASCII_STRING; elementArray.itemLength = 0; if((ret = rsslEncodeArrayInit(&encodeIter, &elementArray)) < RSSL_RET_SUCCESS) { printf("rsslEncodeArrayInit() failed with return code: %d\n", ret); return ret; } if (!isPrivateStream) /* non-private stream */ { for(i = 0; i < itemCount; i++) { itemName.data = marketPriceItemInfoList[i].itemname; itemName.length = marketPriceItemInfoList[i].nameLength; marketPriceItemInfoList[i].streamId = ++streamId; if((ret = rsslEncodeArrayEntry(&encodeIter, &itemName, 0)) < RSSL_RET_SUCCESS) { printf("rsslEncodeArrayEntry() failed with return code: %d\n", ret); return ret; } } } else /* private stream */ { for(i = 0; i < privateStreamItemCount; i++) { itemName.data = marketPricePSItemInfoList[i].itemname; itemName.length = marketPricePSItemInfoList[i].nameLength; marketPricePSItemInfoList[i].streamId = ++streamId; if((ret = rsslEncodeArrayEntry(&encodeIter, &itemName, 0)) < RSSL_RET_SUCCESS) { printf("rsslEncodeArrayEntry() failed with return code: %d\n", ret); return ret; } } } if((ret = rsslEncodeArrayComplete(&encodeIter, RSSL_TRUE)) < RSSL_RET_SUCCESS) { printf("rsslEncodeArrayComplete() failed with return code: %d\n", ret); return ret; } if((ret = rsslEncodeElementEntryComplete(&encodeIter, RSSL_TRUE)) < RSSL_RET_SUCCESS) { printf("rsslEncodeElementEntryComplete() failed with return code: %d\n", ret); return ret; } /* * Encode a view request into the list. */ if((loginInfo->SupportViewRequests == RSSL_TRUE) && (viewRequest == RSSL_TRUE) ) encodeViewElementRequest(&encodeIter); if((ret = rsslEncodeElementListComplete(&encodeIter, RSSL_TRUE)) < RSSL_RET_SUCCESS) { printf("rsslEncodeElementListComplete() failed with return code: %d\n", ret); return ret; } if((ret = rsslEncodeMsgComplete(&encodeIter, RSSL_TRUE)) < RSSL_RET_SUCCESS) { printf("rsslEncodeMessageComplete() failed with return code: %d\n", ret); return ret; } msgBuf->length = rsslGetEncodedBufferLength(&encodeIter); return RSSL_RET_SUCCESS; }
/* * Encodes the item request. Returns success if * encoding succeeds or failure if encoding fails. * chnl - The channel to send an item request to * msgBuf - The message buffer to encode the item request into * streamId - The stream id of the item request * isPrivateStream - Flag for private stream request * * This function is only used within the Market Price Handler * and each handler has its own implementation, although much is similar */ static RsslRet encodeItemRequest(RsslChannel* chnl, RsslBuffer* msgBuf, RsslInt32 streamId, RsslBool isPrivateStream) { RsslRet ret = 0; RsslRequestMsg msg = RSSL_INIT_REQUEST_MSG; RsslEncodeIterator encodeIter; RsslElementList eList = RSSL_INIT_ELEMENT_LIST; RsslLoginResponseInfo* loginInfo = getLoginResponseInfo(); RsslSourceDirectoryResponseInfo* srcDirRespInfo = 0; RsslUInt32 listIndex; if (getSourceDirectoryResponseInfo(getServiceId(), &srcDirRespInfo) != RSSL_RET_SUCCESS) return RSSL_RET_FAILURE; /* clear encode iterator */ rsslClearEncodeIterator(&encodeIter); /* set-up message */ msg.msgBase.msgClass = RSSL_MC_REQUEST; msg.msgBase.streamId = streamId; msg.msgBase.domainType = RSSL_DMT_MARKET_PRICE; if((viewRequest == RSSL_TRUE) && (loginInfo->SupportViewRequests == RSSL_TRUE)) msg.msgBase.containerType = RSSL_DT_ELEMENT_LIST; else msg.msgBase.containerType = RSSL_DT_NO_DATA; if (snapshotRequest) { msg.flags = RSSL_RQMF_HAS_QOS | RSSL_RQMF_HAS_PRIORITY; } else { msg.flags = RSSL_RQMF_HAS_QOS | RSSL_RQMF_STREAMING | RSSL_RQMF_HAS_PRIORITY; } if (isPrivateStream) { msg.flags |= RSSL_RQMF_PRIVATE_STREAM; } if((loginInfo->SupportViewRequests == RSSL_TRUE) && (viewRequest == RSSL_TRUE)) msg.flags |= RSSL_RQMF_HAS_VIEW; msg.priorityClass = 1; msg.priorityCount = 1; /* copy the QoS information */ rsslCopyQos(&(msg.qos), &(srcDirRespInfo->ServiceGeneralInfo.QoS[0])); /* specify msgKey members */ msg.msgBase.msgKey.flags = RSSL_MKF_HAS_NAME_TYPE | RSSL_MKF_HAS_NAME | RSSL_MKF_HAS_SERVICE_ID; msg.msgBase.msgKey.nameType = RDM_INSTRUMENT_NAME_TYPE_RIC; if (!isPrivateStream) /* non-private stream */ { listIndex = streamId - MARKETPRICE_STREAM_ID_START; msg.msgBase.msgKey.name.data = marketPriceItemInfoList[listIndex].itemname; msg.msgBase.msgKey.name.length = marketPriceItemInfoList[listIndex].nameLength; } else /* private stream */ { listIndex = streamId - MARKETPRICE_PRIVATE_STREAM_ID_START; msg.msgBase.msgKey.name.data = marketPricePSItemInfoList[listIndex].itemname; msg.msgBase.msgKey.name.length = marketPricePSItemInfoList[listIndex].nameLength; } msg.msgBase.msgKey.serviceId = (RsslUInt16)getServiceId(); /* encode message */ if((ret = rsslSetEncodeIteratorBuffer(&encodeIter, msgBuf)) < RSSL_RET_SUCCESS) { printf("rsslSetEncodeIteratorBuffer() failed with return code: %d\n", ret); return ret; } rsslSetEncodeIteratorRWFVersion(&encodeIter, chnl->majorVersion, chnl->minorVersion); if ((ret = rsslEncodeMsgInit(&encodeIter, (RsslMsg*)&msg, 0)) < RSSL_RET_SUCCESS) { printf("rsslEncodeMsgInit() failed with return code: %d\n", ret); return ret; } if(viewRequest == RSSL_TRUE) { if (loginInfo->SupportViewRequests == RSSL_TRUE) { eList.flags = RSSL_ELF_HAS_STANDARD_DATA; if ((ret = rsslEncodeElementListInit(&encodeIter, &eList, 0, 0)) < RSSL_RET_SUCCESS) { printf("rsslEncodeElementListInit() failed with return code: %d\n", ret); return ret; } encodeViewElementRequest(&encodeIter); if ((ret = rsslEncodeElementListComplete(&encodeIter, RSSL_TRUE)) < RSSL_RET_SUCCESS) { printf("rsslEncodeElementListComplete() failed with return code: %d\n", ret); return ret; } } else { printf("\nConnected Provider does not support Dynamic View requests. Disabling View functionality.\n"); viewRequest = RSSL_FALSE; } } if ((ret = rsslEncodeMsgComplete(&encodeIter, RSSL_TRUE)) < RSSL_RET_SUCCESS) { printf("rsslEncodeMsgComplete() failed with return code: %d\n", ret); return ret; } msgBuf->length = rsslGetEncodedBufferLength(&encodeIter); if (!isPrivateStream) marketPriceItemInfoList[listIndex].streamId = streamId; else marketPricePSItemInfoList[listIndex].streamId = streamId; return RSSL_RET_SUCCESS; }
/* * Sends a source directory response to a channel. This consists * of getting a message buffer, setting the source directory response * information, encoding the source directory response, and sending * the source directory response to the server. * chnl - The channel to send a source directory response to */ RsslRet sendSourceDirectoryResponse(RsslChannel* chnl) { RsslError error; RsslBuffer* msgBuf = 0; RsslSourceDirectoryResponseInfo srcDirRespInfo; RsslUInt16 refreshFlags = 0; RsslMsgKey key = RSSL_INIT_MSG_KEY; /* initialize source directory response info */ initSourceDirRespInfo(&srcDirRespInfo); /* get a buffer for the source directory response */ msgBuf = rsslGetBuffer(chnl, MAX_MSG_SIZE, RSSL_FALSE, &error); if (msgBuf != NULL) { /* provide source directory response information */ /* set refresh flags */ refreshFlags = RSSL_RFMF_HAS_MSG_KEY | RSSL_RFMF_REFRESH_COMPLETE | RSSL_RFMF_CLEAR_CACHE; /* set filter flags */ key.filter = RDM_DIRECTORY_SERVICE_INFO_FILTER | \ RDM_DIRECTORY_SERVICE_STATE_FILTER| \ /*RDM_DIRECTORY_SERVICE_GROUP_FILTER | \ not applicable for refresh message - here for reference*/ RDM_DIRECTORY_SERVICE_LOAD_FILTER | \ /*RDM_DIRECTORY_SERVICE_DATA_FILTER | \ not applicable for non-ANSI Page based provider - here for reference*/ RDM_DIRECTORY_SERVICE_LINK_FILTER; /* StreamId */ srcDirRespInfo.StreamId = SRCDIR_STREAM_ID; /* ServiceId */ srcDirRespInfo.ServiceId = getServiceId(); /* ServiceName */ snprintf(srcDirRespInfo.ServiceGeneralInfo.ServiceName, 256, "%s", serviceName); /* Vendor */ snprintf(srcDirRespInfo.ServiceGeneralInfo.Vendor, 256, "%s", vendorName); /* Capabilities */ srcDirRespInfo.ServiceGeneralInfo.Capabilities[0] = RSSL_DMT_DICTIONARY; srcDirRespInfo.ServiceGeneralInfo.Capabilities[1] = RSSL_DMT_MARKET_PRICE; srcDirRespInfo.ServiceGeneralInfo.Capabilities[2] = RSSL_DMT_MARKET_BY_ORDER; /* DictionariesProvided */ snprintf(srcDirRespInfo.ServiceGeneralInfo.DictionariesProvided[0], 256, "%s", fieldDictionaryName); snprintf(srcDirRespInfo.ServiceGeneralInfo.DictionariesProvided[1], 256, "%s", enumTypeDictionaryName); /* DictionariesUsed */ snprintf(srcDirRespInfo.ServiceGeneralInfo.DictionariesUsed[0], 256, "%s", fieldDictionaryName); snprintf(srcDirRespInfo.ServiceGeneralInfo.DictionariesUsed[1], 256, "%s", enumTypeDictionaryName); /* Qos */ srcDirRespInfo.ServiceGeneralInfo.QoS[0].dynamic = RSSL_FALSE; srcDirRespInfo.ServiceGeneralInfo.QoS[0].rate = RSSL_QOS_RATE_TICK_BY_TICK; srcDirRespInfo.ServiceGeneralInfo.QoS[0].timeliness = RSSL_QOS_TIME_REALTIME; /* ItemList */ snprintf(srcDirRespInfo.ServiceGeneralInfo.ItemList, 256, ""); /* Service StateInfo Status */ srcDirRespInfo.ServiceStateInfo.Status.streamState = RSSL_STREAM_OPEN; srcDirRespInfo.ServiceStateInfo.Status.dataState = RSSL_DATA_OK; srcDirRespInfo.ServiceStateInfo.Status.code = RSSL_SC_NONE; srcDirRespInfo.ServiceStateInfo.Status.text.data = (char *)"OK"; srcDirRespInfo.ServiceStateInfo.Status.text.length = (RsslUInt32)strlen("OK"); /* OpenLimit */ srcDirRespInfo.ServiceLoadInfo.OpenLimit = OPEN_LIMIT; srcDirRespInfo.ServiceLoadInfo.OpenWindow = 0; /* Don't send OpenWindow. */ /* Link Name */ snprintf(srcDirRespInfo.ServiceLinkInfo[0].LinkName, 256, "%s", linkName); /* Link Text */ snprintf(srcDirRespInfo.ServiceLinkInfo[0].Text, 256, "Link state is up"); /* keep default values for all others */ /* encode source directory response */ if (encodeSourceDirectoryResponse(chnl, &srcDirRespInfo, &key, msgBuf, refreshFlags) != RSSL_RET_SUCCESS) { rsslReleaseBuffer(msgBuf, &error); printf("\nencodeSourceDirectoryResponse() failed\n"); return RSSL_RET_FAILURE; } /* send source directory response */ if (sendMessage(chnl, msgBuf) != RSSL_RET_SUCCESS) return RSSL_RET_FAILURE; } else { printf("rsslGetBuffer(): Failed <%s>\n", error.text); return RSSL_RET_FAILURE; } return RSSL_RET_SUCCESS; }