diff options
Diffstat (limited to 'server/contentDirectory.cpp')
-rw-r--r-- | server/contentDirectory.cpp | 439 |
1 files changed, 439 insertions, 0 deletions
diff --git a/server/contentDirectory.cpp b/server/contentDirectory.cpp new file mode 100644 index 0000000..4855715 --- /dev/null +++ b/server/contentDirectory.cpp @@ -0,0 +1,439 @@ +/* + * contentDirectory.cpp + * + * Created on: 27.08.2012 + * Author: savop + */ + +#include "../include/contentDirectory.h" +#include "../include/media/mediaManager.h" +#include "../include/server.h" +#include <vdr/i18n.h> +#include <upnp/upnptools.h> +#include <sstream> + +namespace upnp { + +#define UPNP_CDS_ACTION_SEARCHCAPABILITIES "GetSearchCapabilities" +#define UPNP_CDS_ACTION_SORTCAPABILITIES "GetSortCapabilities" +#define UPNP_CDS_ACTION_SYSTEMUPDATEID "GetSystemUpdateID" +#define UPNP_CDS_ACTION_BROWSE "Browse" +#define UPNP_CDS_ACTION_SEARCH "Search" +#define UPNP_CDS_ACTION_CREATEOBJECT "CreateObject" +#define UPNP_CDS_ACTION_DESTROYOBJECT "DestroyObject" +#define UPNP_CDS_ACTION_UPDATEOBJECT "UpdateObject" +#define UPNP_CDS_ACTION_IMPORTRESOURCE "ImportResource" +#define UPNP_CDS_ACTION_EXPORTRESOURCE "ExportResource" +#define UPNP_CDS_ACTION_STOPTRANSFERRES "StopTransferResource" +#define UPNP_CDS_ACTION_TRANSFERPROGRESS "GetTransferProgress" +#define UPNP_CDS_ACTION_DELETERESOURCE "DeleteResource" +#define UPNP_CDS_ACTION_CREATEREFERENCE "CreateReference" + +cContentDirectory::cContentDirectory() +: cUPnPService( + cUPnPService::Description( + "urn:schemas-upnp-org:service:ContentDirectory:1", + "urn:upnp-org:serviceId:ContentDirectory", + "cds_scpd.xml", + "cds_control", + "cds_event" + )) +{ + +} + +cContentDirectory::~cContentDirectory(){ + Cancel(1); +} + +void cContentDirectory::Init(cMediaServer* server, UpnpDevice_Handle deviceHandle){ + cUPnPService::Init(server, deviceHandle); + + Start(); +} + +int cContentDirectory::Subscribe(Upnp_Subscription_Request* Request){ + IXML_Document* PropertySet = NULL; + + /* The system update ID */ + UpnpAddToPropertySet(&PropertySet, "SystemUpdateID", + tools::ToString(mMediaServer->GetManager().GetSystemUpdateID()).c_str()); + /* The container update IDs as CSV list */ + UpnpAddToPropertySet(&PropertySet, "ContainerUpdateIDs", + tools::IdListToCSV(mMediaServer->GetManager().GetContainerUpdateIDs()).c_str()); + /* The transfer IDs, which are not supported, i.e. empty */ + UpnpAddToPropertySet(&PropertySet, "TransferIDs", ""); + // Accept subscription + int ret = UpnpAcceptSubscriptionExt(this->mDeviceHandle, Request->UDN, Request->ServiceId, PropertySet, Request->Sid); + + if(ret != UPNP_E_SUCCESS){ + esyslog("UPnP\tSubscription failed (Error code: %d)", ret); + } + + ixmlDocument_free(PropertySet); + return ret; +} + +void cContentDirectory::Action(){ + int Retry = 5; + dsyslog("UPnP\tStart Content directory thread"); + while(this->Running()){ + IXML_Document* PropertySet = NULL; + + /* The system update ID */ + UpnpAddToPropertySet(&PropertySet, "SystemUpdateID", + tools::ToString(mMediaServer->GetManager().GetSystemUpdateID()).c_str()); + /* The container update IDs as CSV list */ + UpnpAddToPropertySet(&PropertySet, "ContainerUpdateIDs", + tools::IdListToCSV(mMediaServer->GetManager().GetContainerUpdateIDs()).c_str()); + int ret = UpnpNotifyExt(this->mDeviceHandle, this->mMediaServer->GetDeviceUUID().c_str(), + this->mServiceDescription.serviceID.c_str(), PropertySet); + ixmlDocument_free(PropertySet); + + if(ret != UPNP_E_SUCCESS){ + Retry--; + esyslog("UPnP\tState change notification failed (Error code: %d)",ret); + esyslog("UPnP\t%d of %d notifications failed", (5-Retry), 5); + } + else { + Retry = 5; + } + if (!Retry){ + esyslog("UPnP\tMaximum retries of notifications reached. Stopping..."); + this->Cancel(); + } + // Sleep 2 seconds + cCondWait::SleepMs(2000); + } +} + +int cContentDirectory::Execute(Upnp_Action_Request* request){ + if (request == NULL) { + esyslog("UPnP\tCMS Action Handler - request is null"); + return UPNP_E_BAD_REQUEST; + } + + if(!strcmp(request->ActionName, UPNP_CDS_ACTION_SEARCHCAPABILITIES)) + return this->GetSearchCapabilities(request); + if(!strcmp(request->ActionName, UPNP_CDS_ACTION_SORTCAPABILITIES)) + return this->GetSortCapabilities(request); + if(!strcmp(request->ActionName, UPNP_CDS_ACTION_SYSTEMUPDATEID)) + return this->GetSystemUpdateID(request); + if(!strcmp(request->ActionName, UPNP_CDS_ACTION_BROWSE)) + return this->Browse(request); + if(!strcmp(request->ActionName, UPNP_CDS_ACTION_SEARCH)) + return this->Search(request); + if(!strcmp(request->ActionName, UPNP_CDS_ACTION_CREATEOBJECT)) + return this->CreateObject(request); + if(!strcmp(request->ActionName, UPNP_CDS_ACTION_DESTROYOBJECT)) + return this->DestroyObject(request); + if(!strcmp(request->ActionName, UPNP_CDS_ACTION_UPDATEOBJECT)) + return this->UpdateObject(request); + if(!strcmp(request->ActionName, UPNP_CDS_ACTION_IMPORTRESOURCE)) + return this->ImportResource(request); + if(!strcmp(request->ActionName, UPNP_CDS_ACTION_EXPORTRESOURCE)) + return this->ExportResource(request); + if(!strcmp(request->ActionName, UPNP_CDS_ACTION_STOPTRANSFERRES)) + return this->StopTransferResource(request); + if(!strcmp(request->ActionName, UPNP_CDS_ACTION_TRANSFERPROGRESS)) + return this->GetTransferProgress(request); + if(!strcmp(request->ActionName, UPNP_CDS_ACTION_DELETERESOURCE)) + return this->DeleteResource(request); + if(!strcmp(request->ActionName, UPNP_CDS_ACTION_CREATEREFERENCE)) + return this->CreateReference(request); + + return UPNP_E_BAD_REQUEST; +} + +int cContentDirectory::CreateReference(Upnp_Action_Request* request){ + SetError(request, UPNP_SOAP_E_ACTION_NOT_IMPLEMENTED); + return request->ErrCode; +} + +int cContentDirectory::DeleteResource(Upnp_Action_Request* request){ + SetError(request, UPNP_SOAP_E_ACTION_NOT_IMPLEMENTED); + return request->ErrCode; +} + +int cContentDirectory::GetTransferProgress(Upnp_Action_Request* request){ + SetError(request, UPNP_SOAP_E_ACTION_NOT_IMPLEMENTED); + return request->ErrCode; +} + +int cContentDirectory::StopTransferResource(Upnp_Action_Request* request){ + SetError(request, UPNP_SOAP_E_ACTION_NOT_IMPLEMENTED); + return request->ErrCode; +} + +int cContentDirectory::ExportResource(Upnp_Action_Request* request){ + SetError(request, UPNP_SOAP_E_ACTION_NOT_IMPLEMENTED); + return request->ErrCode; +} + +int cContentDirectory::ImportResource(Upnp_Action_Request* request){ + SetError(request, UPNP_SOAP_E_ACTION_NOT_IMPLEMENTED); + return request->ErrCode; +} + +int cContentDirectory::UpdateObject(Upnp_Action_Request* request){ + SetError(request, UPNP_SOAP_E_ACTION_NOT_IMPLEMENTED); + return request->ErrCode; +} + +int cContentDirectory::DestroyObject(Upnp_Action_Request* request){ + SetError(request, UPNP_SOAP_E_ACTION_NOT_IMPLEMENTED); + return request->ErrCode; +} + +int cContentDirectory::CreateObject(Upnp_Action_Request* request){ + SetError(request, UPNP_SOAP_E_ACTION_NOT_IMPLEMENTED); + return request->ErrCode; +} + +int cContentDirectory::Search(Upnp_Action_Request* request){ + cMediaManager::SearchRequest searchRequest; + + if(this->ParseIntegerValue(request->ActionRequest, "ContainerID", searchRequest.objectID)){ + esyslog("UPnP\tInvalid arguments. ObjectID missing or wrong"); + this->SetError(request, UPNP_SOAP_E_INVALID_ARGS); + return request->ErrCode; + } + + if(this->ParseStringValue(request->ActionRequest, "BrowseFlag", searchRequest.searchCriteria)){ + esyslog("UPnP\tInvalid arguments. Search criteria missing or wrong"); + this->SetError(request, UPNP_SOAP_E_INVALID_ARGS); + return request->ErrCode; + } + + if(this->ParseStringValue(request->ActionRequest, "Filter", searchRequest.filter)){ + esyslog("UPnP\tInvalid arguments. Filter missing or wrong"); + this->SetError(request, UPNP_SOAP_E_INVALID_ARGS); + return request->ErrCode; + } + + long startIndex; + if(this->ParseIntegerValue(request->ActionRequest, "StartingIndex", startIndex)){ + esyslog("UPnP\tInvalid arguments. Starting index missing or wrong"); + this->SetError(request, UPNP_SOAP_E_INVALID_ARGS); + return request->ErrCode; + } + searchRequest.startIndex = startIndex; + + long requestCount; + if(this->ParseIntegerValue(request->ActionRequest, "RequestedCount", requestCount)){ + esyslog("UPnP\tInvalid arguments. Requested count missing or wrong"); + this->SetError(request, UPNP_SOAP_E_INVALID_ARGS); + return request->ErrCode; + } + searchRequest.requestCount = requestCount; + + if(this->ParseStringValue(request->ActionRequest, "SortCriteria", searchRequest.sortCriteria)){ + esyslog("UPnP\tInvalid arguments. Sort criteria missing or wrong"); + this->SetError(request, UPNP_SOAP_E_INVALID_ARGS); + return request->ErrCode; + } + + int ret = mMediaServer->GetManager().Search(searchRequest); + if(ret!=UPNP_E_SUCCESS){ + esyslog("UPnP\tError while browsing. Code: %d", ret); + this->SetError(request, ret); + return request->ErrCode; + } + + ixml::XmlEscapeSpecialChars(searchRequest.result); + + std::stringstream ss; + + ss << "<u:" << request->ActionName << "Response xmlns:u=\"" << GetServiceDescription().serviceType << "\">" + << " <Result>" << searchRequest.result << "</Result>" + << " <NumberReturned>" << searchRequest.numberReturned << "</NumberReturned>" + << " <TotalMatches>" << searchRequest.totalMatches << "</TotalMatches>" + << " <UpdateID>" << searchRequest.updateID << "</UpdateID>" + << "</u:" << request->ActionName << "Response>"; + + request->ActionResult = ixmlParseBuffer(ss.str().c_str()); + request->ErrCode = UPNP_E_SUCCESS; + + return request->ErrCode; +} + +int cContentDirectory::Browse(Upnp_Action_Request* request){ + cMediaManager::BrowseRequest browseRequest; + + if(this->ParseIntegerValue(request->ActionRequest, "ObjectID", browseRequest.objectID)){ + esyslog("UPnP\tInvalid arguments. ObjectID missing or wrong"); + this->SetError(request, UPNP_SOAP_E_INVALID_ARGS); + return request->ErrCode; + } + + std::string browseFlag; + if(this->ParseStringValue(request->ActionRequest, "BrowseFlag", browseFlag)){ + esyslog("UPnP\tInvalid arguments. Browse flag missing or wrong"); + this->SetError(request, UPNP_SOAP_E_INVALID_ARGS); + return request->ErrCode; + } + if((browseRequest.browseMetadata = cMediaManager::ToBrowseFlag(browseFlag)) == cMediaManager::NumBrowseFlags){ + esyslog("UPnP\tInvalid arguments. Browse flag invalid"); + this->SetError(request, UPNP_SOAP_E_INVALID_ARGS); + return request->ErrCode; + } + + if(this->ParseStringValue(request->ActionRequest, "Filter", browseRequest.filter)){ + esyslog("UPnP\tInvalid arguments. Filter missing or wrong"); + this->SetError(request, UPNP_SOAP_E_INVALID_ARGS); + return request->ErrCode; + } + + long startIndex; + if(this->ParseIntegerValue(request->ActionRequest, "StartingIndex", startIndex)){ + esyslog("UPnP\tInvalid arguments. Starting index missing or wrong"); + this->SetError(request, UPNP_SOAP_E_INVALID_ARGS); + return request->ErrCode; + } + browseRequest.startIndex = startIndex; + + long requestCount; + if(this->ParseIntegerValue(request->ActionRequest, "RequestedCount", requestCount)){ + esyslog("UPnP\tInvalid arguments. Requested count missing or wrong"); + this->SetError(request, UPNP_SOAP_E_INVALID_ARGS); + return request->ErrCode; + } + browseRequest.requestCount = requestCount; + + if(this->ParseStringValue(request->ActionRequest, "SortCriteria", browseRequest.sortCriteria)){ + esyslog("UPnP\tInvalid arguments. Sort criteria missing or wrong"); + this->SetError(request, UPNP_SOAP_E_INVALID_ARGS); + return request->ErrCode; + } + + int ret = mMediaServer->GetManager().Browse(browseRequest); + if(ret!=UPNP_E_SUCCESS){ + esyslog("UPnP\tError while browsing. Code: %d", ret); + this->SetError(request, ret); + return request->ErrCode; + } + + ixml::XmlEscapeSpecialChars(browseRequest.result); + + std::stringstream ss; + + ss << "<u:" << request->ActionName << "Response xmlns:u=\"" << GetServiceDescription().serviceType << "\">" + << " <Result>" << browseRequest.result << "</Result>" + << " <NumberReturned>" << browseRequest.numberReturned << "</NumberReturned>" + << " <TotalMatches>" << browseRequest.totalMatches << "</TotalMatches>" + << " <UpdateID>" << browseRequest.updateID << "</UpdateID>" + << "</u:" << request->ActionName << "Response>"; + + request->ActionResult = ixmlParseBuffer(ss.str().c_str()); + request->ErrCode = UPNP_E_SUCCESS; + + return request->ErrCode; +} + +int cContentDirectory::GetSystemUpdateID(Upnp_Action_Request* request){ + std::stringstream ss; + + ss << "<u:" << request->ActionName << "Response xmlns:u=\"" << GetServiceDescription().serviceType << "\">" + << " <Id>" << mMediaServer->GetManager().GetSystemUpdateID() << "</Id>" + << "</u:" << request->ActionName << "Response>"; + + request->ActionResult = ixmlParseBuffer(ss.str().c_str()); + request->ErrCode = UPNP_E_SUCCESS; + + return request->ErrCode; +} + +int cContentDirectory::GetSortCapabilities(Upnp_Action_Request* request){ + std::stringstream ss; + + ss << "<u:" << request->ActionName << "Response xmlns:u=\"" << GetServiceDescription().serviceType << "\">" + << " <SortCaps>" << tools::StringListToCSV(mMediaServer->GetManager().GetSortCapabilities()) << "</SortCaps>" + << "</u:" << request->ActionName << "Response>"; + + request->ActionResult = ixmlParseBuffer(ss.str().c_str()); + request->ErrCode = UPNP_E_SUCCESS; + + return request->ErrCode; +} + +int cContentDirectory::GetSearchCapabilities(Upnp_Action_Request* request){ + std::stringstream ss; + + ss << "<u:" << request->ActionName << "Response xmlns:u=\"" << GetServiceDescription().serviceType << "\">" + << " <SearchCaps>" << tools::StringListToCSV(mMediaServer->GetManager().GetSearchCapabilities()) << "</SearchCaps>" + << "</u:" << request->ActionName << "Response>"; + + request->ActionResult = ixmlParseBuffer(ss.str().c_str()); + request->ErrCode = UPNP_E_SUCCESS; + + return request->ErrCode; +} + +void cContentDirectory::SetError(Upnp_Action_Request* request, int error){ + request->ErrCode = error; + switch(error){ + case UPNP_CDS_E_BAD_METADATA: + strn0cpy(request->ErrStr,tr("Bad metadata"),LINE_SIZE); + break; + case UPNP_CDS_E_CANT_PROCESS_REQUEST: + strn0cpy(request->ErrStr,tr("Cannot process the request"),LINE_SIZE); + break; + case UPNP_CDS_E_DEST_RESOURCE_ACCESS_DENIED: + strn0cpy(request->ErrStr,tr("Destination resource access denied"),LINE_SIZE); + break; + case UPNP_CDS_E_INVALID_CURRENT_TAG: + strn0cpy(request->ErrStr,tr("Invalid current tag"),LINE_SIZE); + break; + case UPNP_CDS_E_INVALID_NEW_TAG: + strn0cpy(request->ErrStr,tr("Invalid new tag"),LINE_SIZE); + break; + case UPNP_CDS_E_INVALID_SEARCH_CRITERIA: + strn0cpy(request->ErrStr,tr("Invalid or unsupported search criteria"),LINE_SIZE); + break; + case UPNP_CDS_E_INVALID_SORT_CRITERIA: + strn0cpy(request->ErrStr,tr("Invalid or unsupported sort criteria"),LINE_SIZE); + break; + case UPNP_CDS_E_NO_SUCH_CONTAINER: + strn0cpy(request->ErrStr,tr("No such container"),LINE_SIZE); + break; + case UPNP_CDS_E_NO_SUCH_DESTINATION_RESOURCE: + strn0cpy(request->ErrStr,tr("No such destination resource"),LINE_SIZE); + break; + case UPNP_CDS_E_NO_SUCH_FILE_TRANSFER: + strn0cpy(request->ErrStr,tr("No such file transfer"),LINE_SIZE); + break; + case UPNP_CDS_E_NO_SUCH_OBJECT: + strn0cpy(request->ErrStr,tr("No such objectID"),LINE_SIZE); + break; + case UPNP_CDS_E_NO_SUCH_SOURCE_RESOURCE: + strn0cpy(request->ErrStr,tr("No such source resource"),LINE_SIZE); + break; + case UPNP_CDS_E_PARAMETER_MISMATCH: + strn0cpy(request->ErrStr,tr("Parameter mismatch"),LINE_SIZE); + break; + case UPNP_CDS_E_READ_ONLY_TAG: + strn0cpy(request->ErrStr,tr("Read only tag"),LINE_SIZE); + break; + case UPNP_CDS_E_REQUIRED_TAG: + strn0cpy(request->ErrStr,tr("Required tag"),LINE_SIZE); + break; + case UPNP_CDS_E_RESOURCE_ACCESS_DENIED: + strn0cpy(request->ErrStr,tr("Resource access denied"),LINE_SIZE); + break; + case UPNP_CDS_E_RESTRICTED_OBJECT: + strn0cpy(request->ErrStr,tr("Restricted object"),LINE_SIZE); + break; + case UPNP_CDS_E_RESTRICTED_PARENT: + strn0cpy(request->ErrStr,tr("Restricted parent"),LINE_SIZE); + break; + case UPNP_CDS_E_TRANSFER_BUSY: + strn0cpy(request->ErrStr,tr("Transfer busy"),LINE_SIZE); + break; + default: + cUPnPService::SetError(request, error); + break; + } + return; +} + +} // namespace upnp |