Esempio n. 1
0
TUint CpiDeviceDv::Subscribe(CpiSubscription& aSubscription, const OpenHome::Uri& /*aSubscriber*/)
{
    Brh sid;
    iDeviceDv.CreateSid(sid);
    Brn tmp(sid);
    Brh transfer(tmp);
    aSubscription.SetSid(transfer);
    TUint durationSecs = iDeviceCp->GetCpStack().Env().InitParams()->SubscriptionDurationSecs();
    DviSubscription* subscriptionDv = new DviSubscription(iDeviceDv.GetDvStack(), iDeviceDv, *this, NULL, sid);
    subscriptionDv->AddRef(); // guard against subscription expiring before client tries to renew or unsubscribe
    iDeviceDv.GetDvStack().SubscriptionManager().AddSubscription(*subscriptionDv);
    subscriptionDv->SetDuration(durationSecs);

    iLock.Wait();
    if (iSubscriptions.size() == 0) {
        iShutdownSem.Wait(); // consume shutdown signal now the map is non-empty
    }
    Brn sid2(subscriptionDv->Sid());
    Subscription* subscription = new Subscription(aSubscription, subscriptionDv);
    iSubscriptions.insert(std::pair<Brn,Subscription*>(sid2, subscription));
    iDeviceCp->AddRef();
    iLock.Signal();

    DviService* service = iDeviceDv.ServiceReference(aSubscription.ServiceType());
    ASSERT(service != NULL);
    service->AddSubscription(subscriptionDv);
    service->RemoveRef();

    return durationSecs;
}
Esempio n. 2
0
CpiSubscription* CpiSubscriptionManager::FindSubscription(const Brx& aSid)
{
    AutoMutex a(iLock);
    Brn sid(aSid);
    Map::iterator it = iMap.find(sid);
    if (it == iMap.end()) {
        return NULL;
    }
    CpiSubscription* subscription = it->second;
    subscription->AddRef();
    return subscription;
}
Esempio n. 3
0
void CpiDeviceUpnp::Unsubscribe(CpiSubscription& aSubscription, const Brx& aSid)
{
    Uri uri;
    GetServiceUri(uri, "eventSubURL", aSubscription.ServiceType());
    EventUpnp eventUpnp(iDevice->GetCpStack(), aSubscription);
    eventUpnp.Unsubscribe(uri, aSid);
}
Esempio n. 4
0
TUint CpiDeviceUpnp::Renew(CpiSubscription& aSubscription)
{
    TUint durationSecs = iDevice->GetCpStack().Env().InitParams()->SubscriptionDurationSecs();
    Uri uri;
    GetServiceUri(uri, "eventSubURL", aSubscription.ServiceType());
    EventUpnp eventUpnp(iDevice->GetCpStack(), aSubscription);
    eventUpnp.RenewSubscription(uri, durationSecs);
    return durationSecs;
}
Esempio n. 5
0
TUint CpiDeviceUpnp::Renew(CpiSubscription& aSubscription)
{
    TUint durationSecs = 30 * 60; // 30 minutes
    Uri uri;
    GetServiceUri(uri, "eventSubURL", aSubscription.ServiceType());
    EventUpnp eventUpnp(aSubscription);
    eventUpnp.RenewSubscription(uri, durationSecs);
    return durationSecs;
}
Esempio n. 6
0
TUint CpiDeviceUpnp::Subscribe(CpiSubscription& aSubscription, const Uri& aSubscriber)
{
    TUint durationSecs = CpiSubscription::kDefaultDurationSecs;
    Uri uri;
    GetServiceUri(uri, "eventSubURL", aSubscription.ServiceType());
    EventUpnp eventUpnp(aSubscription);
    eventUpnp.Subscribe(uri, aSubscriber, durationSecs);
    return durationSecs;
}
Esempio n. 7
0
TUint CpiDeviceUpnp::Subscribe(CpiSubscription& aSubscription, const Uri& aSubscriber)
{
    TUint durationSecs = iDevice->GetCpStack().Env().InitParams().SubscriptionDurationSecs();
    Uri uri;
    GetServiceUri(uri, "eventSubURL", aSubscription.ServiceType());
    EventUpnp eventUpnp(iDevice->GetCpStack(), aSubscription);
    eventUpnp.Subscribe(uri, aSubscriber, durationSecs);
    return durationSecs;
}
Esempio n. 8
0
void CpiSubscriptionManager::Add(CpiSubscription& aSubscription)
{
    iLock.Wait();
    Brn sid(aSubscription.Sid());
    ASSERT(sid.Bytes() > 0);
    iMap.insert(std::pair<Brn,CpiSubscription*>(sid, &aSubscription));
    RemovePendingAdds(sid);
    iLock.Signal();
}
Esempio n. 9
0
TUint CpiDeviceDv::Renew(CpiSubscription& aSubscription)
{
    Brn sid(aSubscription.Sid());
    TUint durationSecs = iDeviceCp->GetCpStack().Env().InitParams()->SubscriptionDurationSecs();
    AutoMutex _(iLock);
    SubscriptionMap::iterator it = iSubscriptions.find(sid);
    if (it != iSubscriptions.end()) {
        it->second->iDv->Renew(durationSecs);
    }
    return durationSecs;
}
Esempio n. 10
0
void CpiDeviceLpec::Unsubscribe(CpiSubscription& aSubscription, const Brx& /*aSid*/)
{
    AutoMutex a(iLock);
    iWriteBuffer->Write(Lpec::kMethodUnsubscribe);
    iWriteBuffer->Write(' ');
    iWriteBuffer->Write(iLpecName);
    iWriteBuffer->Write('/');
    iWriteBuffer->Write(aSubscription.ServiceType().Name());
    iWriteBuffer->Write(Lpec::kMsgTerminator);
    iWriteBuffer->WriteFlush();

    // no great benefit in waiting for a response
}
Esempio n. 11
0
TUint CpiDeviceLpec::Subscribe(CpiSubscription& aSubscription, const OpenHome::Uri& /*aSubscriber*/)
{
    Semaphore sem("CLS2", 0);
    SubscriptionResponse resp(sem);
    AutoMutex a(iLock);
    iResponseHandler = &resp;
    iWriteBuffer->Write(Lpec::kMethodSubscribe);
    iWriteBuffer->Write(' ');
    iWriteBuffer->Write(iLpecName);
    iWriteBuffer->Write('/');
    iWriteBuffer->Write(aSubscription.ServiceType().Name());
    iWriteBuffer->Write(Lpec::kMsgTerminator);
    iWriteBuffer->WriteFlush();

    sem.Wait();
    Bws<128> sid(iDevice->Udn());
    sid.Append('-');
    sid.Append(resp.SidFragment());
    Brh sid2(sid);
    aSubscription.SetSid(sid2);

    iResponseHandler = NULL;
    return UINT_MAX; // subscription never expires so report the longest possible duration
}
Esempio n. 12
0
void CpiSubscriptionManager::Remove(CpiSubscription& aSubscription)
{
    iLock.Wait();
    Brn sid(aSubscription.Sid());
    Map::iterator it = iMap.find(sid);
    if (it != iMap.end()) {
        it->second = NULL;
        iMap.erase(it);
    }
    TBool shutdownSignal = ReadyForShutdown();
    iLock.Signal();
    if (shutdownSignal) {
        iShutdownSem.Signal();
    }
}
Esempio n. 13
0
void CpiDeviceDv::Unsubscribe(CpiSubscription& aSubscription, const Brx& aSid)
{
    iLock.Wait();
    Brn sid(aSid);
    SubscriptionMap::iterator it = iSubscriptions.find(sid);
    if (it == iSubscriptions.end()) {
        iLock.Signal();
        return;
    }
    Subscription* subscription = it->second;
    iLock.Signal();
    DviService* service = iDeviceDv.ServiceReference(aSubscription.ServiceType());
    if (service != NULL) {
        service->RemoveSubscription(aSid);
        service->RemoveRef();
    }
    subscription->iCp = NULL;
    subscription->iDv->RemoveRef();
    // can't safely access subscription now - RemoveRef() above may have resulted in it being deleted
}
Esempio n. 14
0
void EventSessionUpnp::Run()
{
    CpiSubscription* subscription = NULL;
    iErrorStatus = &HttpStatus::kOk;
    try {
        iReaderRequest->Flush();
        iReaderRequest->Read();
        // check headers
        if (iReaderRequest->MethodNotAllowed()) {
            Error(HttpStatus::kBadRequest);
        }

        if (!iHeaderNt.Received() || !iHeaderNts.Received()) {
            Error(HttpStatus::kBadRequest);
        }

        if (iHeaderNt.Value() != kExpectedNt || iHeaderNts.Value() != kExpectedNts ||
            !iHeaderSid.Received() || iHeaderSid.Sid().Bytes() == 0 || !iHeaderSeq.Received()) {
            Error(HttpStatus::kPreconditionFailed);
        }

        subscription = CpiSubscriptionManager::FindSubscription(iHeaderSid.Sid());
        if (subscription == NULL) {
            /* the UPnP spec contains a potential race condition where the first NOTIFY
               message can be processed ahead of the SUBSCRIBE reply which provides
               the sid.  Wait until any in-progress subscriptions complete and try
               again in case that's what has happened here */
            CpiSubscriptionManager::WaitForPendingAdds();
            subscription = CpiSubscriptionManager::FindSubscription(iHeaderSid.Sid());
            if (subscription == NULL) {
                LOG2(kEvent, kError, "notification for unexpected device - ")
                LOG2(kEvent, kError, iHeaderSid.Sid());
                LOG2(kEvent, kError, "\n");
                Error(HttpStatus::kPreconditionFailed);
            }
        }

        if (!subscription->UpdateSequenceNumber(iHeaderSeq.Seq())) {
            subscription->SetNotificationError();
            subscription->RemoveRef();
            subscription = NULL;
        }
    }
    catch(HttpError) {}
    catch(ReaderError) {}

    try {
        // write response
        Sws<128> writerBuffer(*this);
        WriterHttpResponse response(writerBuffer);
        response.WriteStatus(*iErrorStatus, Http::eHttp11);
        response.WriteFlush();

        // read entity
        if (subscription != NULL) {
            Bwh entity;
            if (iHeaderTransferEncoding.IsChunked()) {
                ReaderHttpChunked dechunker(*iReadBuffer);
                dechunker.Read();
                dechunker.TransferTo(entity);
            }
            else {
                TUint length = iHeaderContentLength.ContentLength();
                if (length == 0) {
                    THROW(HttpError);
                }
                entity.Grow(length);
                while (length > 0) {
                    TUint readBytes = (length<kMaxReadBytes? length : kMaxReadBytes);
                    entity.Append(iReadBuffer->Read(readBytes));
                    length -= readBytes;
                }
            }

            // process entity
            LOG(kEvent, "EventSessionUpnp::Run, sid - ");
            LOG(kEvent, iHeaderSid.Sid());
            LOG(kEvent, " seq - %u\n", iHeaderSeq.Seq());
            ProcessNotification(*subscription, entity);
        }
    }
    catch(HttpError) {
        LogError(subscription, "HttpError");
    }
    catch(ReaderError) {
        LogError(subscription, "ReaderError");
    }
    catch(WriterError) {
        LogError(subscription, "WriterError");
    }
    catch(NetworkError) {
        LogError(subscription, "NetworkError");
    }
    catch(XmlError) {
        LogError(subscription, "XmlError");
    }
    if (subscription != NULL) {
        subscription->RemoveRef();
    }    
}
Esempio n. 15
0
void EventSessionUpnp::Run()
{
    AutoSemaphore a(iShutdownSem);
    CpiSubscription* subscription = NULL;
    iErrorStatus = &HttpStatus::kOk;
    iDechunker->SetChunked(false);
    iDechunker->ReadFlush();
    try {
        iReaderRequest->Flush();
        iReaderRequest->Read(kReadTimeoutMs);
        // check headers
        if (iReaderRequest->MethodNotAllowed()) {
            Error(HttpStatus::kBadRequest);
        }

        if (!iHeaderNt.Received() || !iHeaderNts.Received()) {
            Error(HttpStatus::kBadRequest);
        }

        if (iHeaderNt.Value() != kExpectedNt || iHeaderNts.Value() != kExpectedNts ||
            !iHeaderSid.Received() || iHeaderSid.Sid().Bytes() == 0 || !iHeaderSeq.Received()) {
            Error(HttpStatus::kPreconditionFailed);
        }

        Parser parser(iReaderRequest->Uri());
        (void)parser.Next('/');
        Brn idBuf = parser.Next('/');
        TUint id = 0;
        try {
            id = Ascii::Uint(idBuf);
        }
        catch (AsciiError&) {
            const Brx& sid = iHeaderSid.Sid();
            LOG2(kEvent, kError, "notification for %.*s failed to include id in path\n", PBUF(sid));
            Error(HttpStatus::kPreconditionFailed);
        }
        subscription = iCpStack.SubscriptionManager().FindSubscription(id);
        if (subscription == NULL) {
            const Brx& sid = iHeaderSid.Sid();
            LOG2(kEvent, kError, "notification for unexpected device - %.*s\n", PBUF(sid))
            Error(HttpStatus::kPreconditionFailed);
        }
    }
    catch(HttpError&) {}
    catch(ReaderError&) {}

    try {
        // write response
        Sws<128> writerBuffer(*this);
        WriterHttpResponse response(writerBuffer);
        response.WriteStatus(*iErrorStatus, Http::eHttp11);
        response.WriteFlush();

        // read entity
        if (subscription != NULL) {
            Bwh entity;
            WriterBwh writer(1024);
            if (iHeaderTransferEncoding.IsChunked()) {
                iDechunker->SetChunked(true);
                for (;;) {
                    Brn buf = iDechunker->Read(kMaxReadBytes);
                    writer.Write(buf);
                    if (buf.Bytes() == 0) { // end of stream
                        break;
                    }
                }
            }
            else {
                TUint length = iHeaderContentLength.ContentLength();
                if (length == 0) {
                    // no Content-Length header, so read until remote socket closed (so ReaderError is thrown)
                    try {
                        for (;;) {
                            writer.Write(iReaderUntil->Read(kMaxReadBytes));
                        }
                    }
                    catch (ReaderError&) {
                    }
                } else {
                    TUint remaining = length;
                    do {
                        Brn buf = iReaderUntil->Read(kMaxReadBytes);
                        remaining -= buf.Bytes();
                        writer.Write(buf);
                    } while (remaining > 0);
                }
            }
            writer.TransferTo(entity);

            // process entity
            {
                const Brx& sid = iHeaderSid.Sid();
                LOG(kEvent, "EventSessionUpnp::Run, sid - %.*s seq - %u\n", PBUF(sid), iHeaderSeq.Seq());
            }

            /* defer validating the seq number till now to avoid holding subscription's lock during
               potentially long-running network reads */
            if (subscription->UpdateSequenceNumber(iHeaderSeq.Seq())) {
                try {
                    ProcessNotification(*subscription, entity);
                }
                catch (Exception& ex) {
                    Log::Print("EventSessionUpnp::Run() unexpected exception %s from %s:%u\n", ex.Message(), ex.File(), ex.Line());
                    ASSERTS(); // ProcessNotification isn't expected to throw
                }
                subscription->Unlock();
            }
            else {
                subscription->SetNotificationError();
            }
        }
    }
    catch(HttpError&) {
        LogError(subscription, "HttpError");
    }
    catch(ReaderError&) {
        LogError(subscription, "ReaderError");
    }
    catch(WriterError&) {
        LogError(subscription, "WriterError");
    }
    catch(NetworkError&) {
        LogError(subscription, "NetworkError");
    }
    catch(XmlError&) {
        LogError(subscription, "XmlError");
    }
    if (subscription != NULL) {
        subscription->RemoveRef();
    }    
}
Esempio n. 16
0
void CpiDeviceLpec::HandleEventedUpdate(const Brx& aUpdate)
{
    Parser parser(aUpdate);
    Brn lpecId = parser.Next(' ');
    Bws<128> sid(iDevice->Udn());
    sid.Append('-');
    sid.Append(lpecId);
    CpiSubscription* subscription = iCpStack.SubscriptionManager().FindSubscription(sid);
    if (subscription == NULL) {
        /* There is a very short window between Subscribe() returning and the new
           subscription being added to its manager.  As a lazy workaround for this,
           sleep for a short period and retry before rejecting the update */
        Thread::Sleep(1000);
        subscription = iCpStack.SubscriptionManager().FindSubscription(sid);
    }
    if (subscription == NULL) {
        LOG(kLpec, "LPEC: evented update received for unknown subscription - ");
        LOG(kLpec, sid);
        LOG(kLpec, "\n");
        return;
    }
    Brn seqBuf = parser.Next(' ');
    TUint seq;
    try {
        seq = Ascii::Uint(seqBuf);
    }
    catch (AsciiError&) {
        LOG(kLpec, "LPEC: invalid sequence number - ");
        LOG(kLpec, seqBuf);
        LOG(kLpec, "in evented update\n");
        subscription->RemoveRef();
        return;
    }
    if (!subscription->UpdateSequenceNumber(seq)) {
        LOG(kLpec, "LPEC: out of sequence update (%d) for ", seq);
        LOG(kLpec, sid);
        LOG(kLpec, "\n");
        subscription->SetNotificationError();
        subscription->RemoveRef();
        return;
    }
    IEventProcessor* processor = static_cast<IEventProcessor*>(subscription);
    processor->EventUpdateStart();
    OutputProcessor outputProcessor;
    try {
        for (;;) {
            Brn propName = parser.Next(' ');
            if (propName.Bytes() == 0) {
                // processed entire update
                break;
            }
            (void)parser.Next(Lpec::kArgumentDelimiter);
            Brn propVal = parser.Next(Lpec::kArgumentDelimiter);
            processor->EventUpdate(propName, propVal, outputProcessor);
        }
        processor->EventUpdateEnd();
    }
    catch (AsciiError&) {
        LOG2(kLpec, kError, "LPEC: Invalid evented update - ");
        LOG2(kLpec, kError, aUpdate);
        LOG2(kLpec, kError, "\n");
        processor->EventUpdateError();
    }
    subscription->Unlock();
    subscription->RemoveRef();
}