diff options
Diffstat (limited to 'server')
-rw-r--r-- | server/connection.cpp | 139 | ||||
-rw-r--r-- | server/connection.o | bin | 0 -> 57880 bytes | |||
-rw-r--r-- | server/connectionManager.cpp | 253 | ||||
-rw-r--r-- | server/connectionManager.o | bin | 0 -> 313200 bytes | |||
-rw-r--r-- | server/contentDirectory.cpp | 439 | ||||
-rw-r--r-- | server/contentDirectory.o | bin | 0 -> 232952 bytes | |||
-rw-r--r-- | server/server.cpp | 337 | ||||
-rw-r--r-- | server/server.o | bin | 0 -> 327792 bytes | |||
-rw-r--r-- | server/service.cpp | 117 | ||||
-rw-r--r-- | server/service.o | bin | 0 -> 84424 bytes | |||
-rw-r--r-- | server/webserver.cpp | 166 | ||||
-rw-r--r-- | server/webserver.o | bin | 0 -> 549288 bytes |
12 files changed, 1451 insertions, 0 deletions
diff --git a/server/connection.cpp b/server/connection.cpp new file mode 100644 index 0000000..bd2d78c --- /dev/null +++ b/server/connection.cpp @@ -0,0 +1,139 @@ +/* + * connection.cpp + * + * Created on: 31.07.2012 + * Author: savop + */ + +#ifndef CONNECTION_CPP_ +#define CONNECTION_CPP_ + +#include <stdlib.h> +#include <limits.h> +#include <time.h> +#include "../include/connection.h" + +using namespace upnp; + +cVirtualConnection::cVirtualConnection( + int32_t connectionID, + const std::string& remoteProtocolInfo, + const std::string& peerConnectionManager, + int32_t peerConnectionID, + Direction direction) : + mRemoteProtocolInfo(remoteProtocolInfo), + mPeerConnectionManager(peerConnectionManager), + mPeerConnectionID(peerConnectionID), + mConnectionID(connectionID), + mAVTransportID(-1), + mRcsID(-1), + mDirection(direction), + mStatus(VC_OKAY) +{ +} + +cVirtualConnection::cVirtualConnection(const cVirtualConnection & other) : + mRemoteProtocolInfo(other.mRemoteProtocolInfo), + mPeerConnectionManager(other.mPeerConnectionManager), + mPeerConnectionID(other.mPeerConnectionID), + mConnectionID(other.mConnectionID), + mAVTransportID(other.mAVTransportID), + mRcsID(other.mRcsID), + mDirection(other.mDirection), + mStatus(other.mStatus) +{ +} + +cVirtualConnection & cVirtualConnection::operator =(const cVirtualConnection & other) +{ + mConnectionID = other.mConnectionID; + mAVTransportID = other.mAVTransportID; + mPeerConnectionID = other.mPeerConnectionID; + mRcsID = other.mRcsID; + mDirection = other.mDirection; + mStatus = other.mStatus; + mPeerConnectionManager = other.mPeerConnectionManager; + mRemoteProtocolInfo = other.mRemoteProtocolInfo; + + return *this; +} + +cVirtualConnection* cVirtualConnection::GenerateVirtualConnection( + const std::string & remoteProtocolInfo, + const std::string & peerConnectionManager, + int32_t peerConnectionID, + const std::string & direction) +{ + Direction eDirection; + + if (direction.compare("Input")==0){ + eDirection = VC_INPUT; + } else if (direction.compare("Output")==0){ + eDirection = VC_OUTPUT; + } else { + return NULL; + } + + cVirtualConnection* connnection = new cVirtualConnection( + cVirtualConnection::NextConnectionID(), + remoteProtocolInfo, peerConnectionManager, + peerConnectionID, eDirection ); + + return connnection; +} + +cVirtualConnection* cVirtualConnection::GenerateVirtualConnection( + const std::string & remoteProtocolInfo, + const std::string & peerConnectionManager, + int32_t peerConnectionID, + Direction direction) +{ + cVirtualConnection* connnection = new cVirtualConnection( + cVirtualConnection::NextConnectionID(), + remoteProtocolInfo, peerConnectionManager, + peerConnectionID, direction ); + + return connnection; +} + +void cVirtualConnection::DestroyVirtualConnection(cVirtualConnection* connection){ + delete connection; +} + +int32_t cVirtualConnection::NextConnectionID(){ + static int32_t lastConnectionID = 0; + + if(lastConnectionID == INT_MAX) lastConnectionID = 1; + + return lastConnectionID++; +} + +std::string cVirtualConnection::GetDirectionString() const { + switch (mDirection){ + case VC_INPUT: + return "Input"; + case VC_OUTPUT: + return "Output"; + default: + return NULL; + } +} + +std::string cVirtualConnection::GetStatusString() const { + switch (mStatus){ + case VC_CONTENT_FORMAT_MISMATCH: + return "ContentFormatMismatch"; + case VC_INSUFFICIENT_BANDWIDTH: + return "InsufficientBandwidth"; + case VC_OKAY: + return "OK"; + case VC_UNKNOWN: + return "Unknown"; + case VC_UNRELIABLE_CHANNEL: + return "UnreliableChannel"; + default: + return NULL; + } +} + +#endif /* CONNECTION_CPP_ */ diff --git a/server/connection.o b/server/connection.o Binary files differnew file mode 100644 index 0000000..03f6ec5 --- /dev/null +++ b/server/connection.o diff --git a/server/connectionManager.cpp b/server/connectionManager.cpp new file mode 100644 index 0000000..fd16d97 --- /dev/null +++ b/server/connectionManager.cpp @@ -0,0 +1,253 @@ +/* + * connectionManager.cpp + * + * Created on: 27.08.2012 + * Author: savop + */ + +#include "../include/connectionManager.h" +#include "../include/tools.h" +#include "../include/server.h" +#include "../include/media/mediaManager.h" +#include <vdr/i18n.h> +#include <upnp/upnptools.h> +#include <string> +#include <sstream> + +namespace upnp { + +#define UPNP_CMS_ACTION_GETPROTOCOLINFO "GetProtocolInfo" +#define UPNP_CMS_ACTION_GETCURRENTCONNECTIONIDS "GetCurrentConnectionIDs" +#define UPNP_CMS_ACTION_GETCURRENTCONNECTIONINFO "GetCurrentConnectionInfo" +#define UPNP_CMS_ACTION_PREPAREFORCONNECTION "PrepareForConnection" +#define UPNP_CMS_ACTION_CONNECTIONCOMPLETE "ConnectionComplete" + +cConnectionManager::cConnectionManager() +: cUPnPService( + cUPnPService::Description( + "urn:schemas-upnp-org:service:ConnectionManager:1", + "urn:upnp-org:serviceId:ConnectionManager", + "cms_scpd.xml", + "cms_control", + "cms_event" + )) +{ + + cVirtualConnection* connection = cVirtualConnection::GenerateVirtualConnection(std::string(), std::string(), + -1, cVirtualConnection::VC_OUTPUT); + mVirtualConnections[connection->GetConnectionID()] = connection; +} + +cConnectionManager::~cConnectionManager(){ + DeleteConnections(); +} + +int cConnectionManager::Subscribe(Upnp_Subscription_Request* request){ + IXML_Document* PropertySet = NULL; + + std::string protocolInfo = tools::StringListToCSV(mMediaServer->GetManager().GetSupportedProtocolInfos()); + + /* The protocol infos which this server supports */ + UpnpAddToPropertySet(&PropertySet, "SourceProtocolInfo", protocolInfo.c_str()); + /* Not set, this field is only used by Media Renderers */ + UpnpAddToPropertySet(&PropertySet, "SinkProtocolInfo", ""); + /* The current connection IDs of all virtual connections */ + UpnpAddToPropertySet(&PropertySet, "CurrentConnectionIDs", GetConnectionIDsCVS().c_str()); + // 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; +} + +int cConnectionManager::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_CMS_ACTION_GETPROTOCOLINFO)) + return this->GetProtocolInfo(request); + if(!strcmp(request->ActionName, UPNP_CMS_ACTION_GETCURRENTCONNECTIONIDS)) + return this->GetCurrentConnectionIDs(request); + if(!strcmp(request->ActionName, UPNP_CMS_ACTION_GETCURRENTCONNECTIONINFO)) + return this->GetCurrentConnectionInfo(request); + if(!strcmp(request->ActionName, UPNP_CMS_ACTION_PREPAREFORCONNECTION)) + return this->PrepareForConnection(request); + if(!strcmp(request->ActionName, UPNP_CMS_ACTION_CONNECTIONCOMPLETE)) + return this->ConnectionComplete(request); + + return UPNP_E_BAD_REQUEST; +} + +int cConnectionManager::GetCurrentConnectionIDs(Upnp_Action_Request* request){ + std::string IDs = this->GetConnectionIDsCVS(); + if(IDs.empty()){ + SetError(request, UPNP_E_INTERNAL_ERROR); + return request->ErrCode; + } + + std::stringstream ss; + + ss << "<u:" << request->ActionName << "Response xmlns:u=\"" << GetServiceDescription().serviceType << "\">" + << " <ConnectionIDs>" << IDs << "</ConnectionIDs>" + << "</u:" << request->ActionName << "Response>"; + + request->ActionResult = ixmlParseBuffer(ss.str().c_str()); + request->ErrCode = UPNP_E_SUCCESS; + return request->ErrCode; +} + +int cConnectionManager::GetCurrentConnectionInfo(Upnp_Action_Request* request){ + + long id; + if(ParseIntegerValue(request->ActionRequest, "ConnectionID", id) != UPNP_E_SUCCESS){ + esyslog("UPnP\tInvalid arguments. ConnectionID missing or wrong"); + SetError(request, UPNP_SOAP_E_INVALID_ARGS); + return request->ErrCode; + } + int32_t connectionID = id; + + cVirtualConnection* connection = mVirtualConnections[connectionID]; + + if(connection == NULL){ + esyslog("UPnP\tNo valid connection found with given ID=%d!", connectionID); + SetError(request, UPNP_CMS_E_INVALID_CONNECTION_REFERENCE); + return request->ErrCode; + } + + std::stringstream ss; + ss << "<u:" << request->ActionName << "Response xmlns:u=\"" << GetServiceDescription().serviceType << "\">" + << " <ProtocolInfo>" << connection->GetRemoteProtocolInfo() << "</ProtocolInfo>" + << " <PeerConnectionManager>" << connection->GetPeerConnectionManager() << "</PeerConnectionManager>" + << " <PeerConnectionID>" << connection->GetPeerConnectionID() << "</PeerConnectionID>" + << " <Direction>" << connection->GetDirectionString() << "</Direction>" + << " <RcsID>" << connection->GetRcsID() << "</RcsID>" + << " <AVTransportID>" << connection->GetAVTransportID() << "</AVTransportID>" + << " <Status>" << connection->GetStatusString() << "</Status>" + << "</u:" << request->ActionName << "Response>"; + + request->ActionResult = ixmlParseBuffer(ss.str().c_str()); + request->ErrCode = UPNP_E_SUCCESS; + return request->ErrCode; +} + +int cConnectionManager::GetProtocolInfo(Upnp_Action_Request* request){ + std::stringstream ss; + + std::string protocolInfo = tools::StringListToCSV(mMediaServer->GetManager().GetSupportedProtocolInfos()); + + ss << "<u:" << request->ActionName << "Response xmlns:u=\"" << GetServiceDescription().serviceType << "\">" + << " <Source>" << protocolInfo.c_str() << "</Source>" + << " <Sink></Sink>" + << "</u:" << request->ActionName << "Response>"; + + request->ActionResult = ixmlParseBuffer(ss.str().c_str()); + request->ErrCode = UPNP_E_SUCCESS; + return request->ErrCode; +} + +int cConnectionManager::ConnectionComplete(Upnp_Action_Request* request){ + SetError(request, UPNP_SOAP_E_ACTION_NOT_IMPLEMENTED); + return request->ErrCode; +} + +int cConnectionManager::PrepareForConnection(Upnp_Action_Request* request){ + SetError(request, UPNP_SOAP_E_ACTION_NOT_IMPLEMENTED); + return request->ErrCode; +} + +const std::string cConnectionManager::GetConnectionIDsCVS(){ + std::stringstream ss; + + ConnectionList::iterator it = mVirtualConnections.begin(); + ss << (*it).second->GetConnectionID(); + for(++it; it != mVirtualConnections.end(); ++it){ + ss << "," << (*it).second->GetConnectionID(); + } + + return ss.str(); +} + +void cConnectionManager::DeleteConnections(){ + for(ConnectionList::iterator it = mVirtualConnections.begin(); it != mVirtualConnections.end();++it){ + cVirtualConnection::DestroyVirtualConnection((*it).second); + } + mVirtualConnections.clear(); +} + +bool cConnectionManager::DeleteConnection(int32_t connectionID){ + if(connectionID == 0){ + esyslog("UPnP\tCannot delete default connection with connectionID = 0"); + return false; + } + + cVirtualConnection::DestroyVirtualConnection(mVirtualConnections[connectionID]); + mVirtualConnections.erase(connectionID); + + return OnConnectionChange(); +} + +bool cConnectionManager::CreateConnection(const std::string & remoteProtocolInfo, + const std::string & peerConnectionManager, + int32_t peerConnectionID, + const std::string & direction) +{ + cVirtualConnection* connection = cVirtualConnection::GenerateVirtualConnection( + remoteProtocolInfo, peerConnectionManager, + peerConnectionID, direction); + + mVirtualConnections[connection->GetConnectionID()] = connection; + + return OnConnectionChange(); +} + +bool cConnectionManager::OnConnectionChange(){ + IXML_Document* PropertySet = NULL; + UpnpAddToPropertySet(&PropertySet, "CurrentConnectionIDs", GetConnectionIDsCVS().c_str()); + int ret = UpnpNotifyExt(mDeviceHandle, mMediaServer->GetDeviceUUID().c_str(), mServiceDescription.serviceID.c_str(), PropertySet); + ixmlDocument_free(PropertySet); + + if(ret != UPNP_E_SUCCESS){ + esyslog("UPnP\tState change notification failed (Error code: %d)",ret); + return false; + } + + return true; +} + +void cConnectionManager::SetError(Upnp_Action_Request* request, int error){ + request->ErrCode = error; + switch(error){ + case UPNP_CMS_E_INCOMPATIBLE_PROTOCOL_INFO: + strn0cpy(request->ErrStr,tr("Incompatible protocol info"),LINE_SIZE); + break; + case UPNP_CMS_E_INCOMPATIBLE_DIRECTIONS: + strn0cpy(request->ErrStr,tr("Incompatible directions"),LINE_SIZE); + break; + case UPNP_CMS_E_INSUFFICIENT_RESOURCES: + strn0cpy(request->ErrStr,tr("Insufficient network resources"),LINE_SIZE); + break; + case UPNP_CMS_E_LOCAL_RESTRICTIONS: + strn0cpy(request->ErrStr,tr("Local restrictions"),LINE_SIZE); + break; + case UPNP_CMS_E_ACCESS_DENIED: + strn0cpy(request->ErrStr,tr("Access denied"),LINE_SIZE); + break; + case UPNP_CMS_E_INVALID_CONNECTION_REFERENCE: + strn0cpy(request->ErrStr,tr("Invalid connection reference"),LINE_SIZE); + break; + case UPNP_CMS_E_NOT_IN_NETWORK: + strn0cpy(request->ErrStr,tr("Not in network"),LINE_SIZE); + break; + default: + cUPnPService::SetError(request, error); + break; + } +} + +} // namespace upnp diff --git a/server/connectionManager.o b/server/connectionManager.o Binary files differnew file mode 100644 index 0000000..e3b3e75 --- /dev/null +++ b/server/connectionManager.o 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 diff --git a/server/contentDirectory.o b/server/contentDirectory.o Binary files differnew file mode 100644 index 0000000..488881a --- /dev/null +++ b/server/contentDirectory.o diff --git a/server/server.cpp b/server/server.cpp new file mode 100644 index 0000000..a211c1c --- /dev/null +++ b/server/server.cpp @@ -0,0 +1,337 @@ +/* + * server.cpp + * + * Created on: 31.07.2012 + * Author: savop + */ + +#include <vdr/tools.h> +#include <string> +#include <sstream> +#include "../include/server.h" +#include "../include/service.h" +#include "../include/tools.h" +#include "../include/media/mediaManager.h" +#include "../upnp.h" + +using namespace upnp; +using namespace std; + +cMediaServer* cMediaServer::GetInstance(){ + static cMediaServer server; + return &server; +} + +cMediaServer::serviceMap cMediaServer::mServices; + +cMediaServer::cMediaServer() +: mServerDescription("VDR UPnP/DLNA MS", "Denis Loh", "http://upnp.vdr-developer.org", + DESCRIPTION, "VDR UPnP/DLNA MS", VERSION, + "http://projects.vdr-developer.org/projects/plg-upnp/files", VERSION) +, mDeviceHandle(0) +, mAnnounceMaxAge(1800) +, mMaxContentLength(KB(20)) +, mIsRunning(false) +, mWebserver(NULL) +, mMediaManager(NULL) +{ + mServerIcons.push_back(ServerIcon(image::DLNA_ICON_PNG_SM_24A, "images/upnpIconSm.png")); + mServerIcons.push_back(ServerIcon(image::DLNA_ICON_PNG_LRG_24A, "images/upnpIconLrg.png")); + mServerIcons.push_back(ServerIcon(image::DLNA_ICON_JPEG_SM_24, "images/upnpIconSm.jpeg")); + mServerIcons.push_back(ServerIcon(image::DLNA_ICON_JPEG_LRG_24, "images/upnpIconLrg.jpeg")); +} + +cMediaServer::~cMediaServer(){ + delete mWebserver; + delete mMediaManager; +} + +bool cMediaServer::IsRunning() const { + return mIsRunning; +} + +bool cMediaServer::Start(){ + + isyslog("UPnP\tStarting UPnP media server"); + + int ret; + + // Disable internal webserver, we don't need it. + UpnpEnableWebserver(false); + + if(!mWebserver->Start()){ + esyslog("UPnP\tFailed to start the web server"); + return false; + } + + isyslog("UPnP\tRegistering UPnP media server"); + + string description = GetDeviceDescriptionUrl(); + + ret = UpnpRegisterRootDevice2(UPNPREG_URL_DESC, + description.c_str(), + description.size(), + 0, + &cMediaServer::ActionCallback, + this, + &mDeviceHandle); + + if(ret != UPNP_E_SUCCESS){ + esyslog("UPnP\tFailed to register the device. Error code: %d", ret); + return false; + } + + ret = UpnpUnRegisterRootDevice(mDeviceHandle); + if (ret != UPNP_E_SUCCESS) { + esyslog("UPnP\tUnregistering old devices failed"); + return false; + } + + ret = UpnpRegisterRootDevice2(UPNPREG_URL_DESC, + description.c_str(), + description.size(), + 0, + &cMediaServer::ActionCallback, + this, + &mDeviceHandle); + + if(ret != UPNP_E_SUCCESS){ + esyslog("UPnP\tFailed to register the device. Error code: %d", ret); + return false; + } + + isyslog("UPnP\tInitialising services..."); + for(serviceMap::iterator it = cMediaServer::mServices.begin(); it != cMediaServer::mServices.end(); ++it){ + isyslog("UPnP\t...%s", (*it).second->GetServiceDescription().serviceType.c_str()); + (*it).second->Init(this, mDeviceHandle); + } + + //send first advertisments + isyslog("UPnP\tSend first advertisements to publish start in network"); + ret = UpnpSendAdvertisement(mDeviceHandle, GetAnnounceMaxAge()); + if (ret != UPNP_E_SUCCESS) { + esyslog("UPnP\tError while sending first advertisments - Errorcode: %d", ret); + return false; + } + + mIsRunning = true; + + return IsRunning(); +} + +bool cMediaServer::Stop(){ + + isyslog("UPnP\tStopping UPnP media server"); + + int ret = 0; + + UpnpUnRegisterRootDevice(mDeviceHandle); + if (ret != UPNP_E_SUCCESS) { + esyslog("UPnP\tError while sending first advertisments - Errorcode: %d", ret); + return false; + } + + UpnpFinish(); + + if(mWebserver){ + mWebserver->Stop(); + + delete mWebserver; + mWebserver = NULL; + } + + if(mMediaManager){ + delete mMediaManager; + mMediaManager = NULL; + } + + mIsRunning = false; + + return !IsRunning(); +} + +bool cMediaServer::Initialize(){ + isyslog("UPnP\tInitializing UPnP media server"); + + string address = mCurrentConfiguration.bindToAddress + ? mCurrentConfiguration.address + : tools::GetAddressByInterface(mCurrentConfiguration.interface); + + if(!address.compare("0.0.0.0")) + address = tools::GetAddressByInterface(tools::GetNetworkInterfaceByIndex(0, true)); + + int ret = 0; + + ret = UpnpInit(address.c_str(), mCurrentConfiguration.port); + + if(ret != UPNP_E_SUCCESS && ret != UPNP_E_INIT){ + esyslog("UPnP\tFailed to initialise UPnP media server. Error code: %d", ret); + return false; + } + + mWebserver = new cWebserver(GetServerIPAddress()); + + if(mCurrentConfiguration.expertSettings){ + + if(mCurrentConfiguration.maxContentLength) + SetMaxContentLength(mCurrentConfiguration.maxContentLength); + + if(mCurrentConfiguration.announceMaxAge) + SetAnnounceMaxAge(mCurrentConfiguration.announceMaxAge); + + if(!mCurrentConfiguration.webServerRoot.empty()) + mWebserver->SetWebserverRootDir(mCurrentConfiguration.webServerRoot, + mCurrentConfiguration.staticContentURL, + mCurrentConfiguration.presentationURL); + + if(mCurrentConfiguration.webServerPort) + mWebserver->SetListenerPort(mCurrentConfiguration.webServerPort); + } + + mMediaManager = new cMediaManager(); + + ret = UpnpSetMaxContentLength(GetMaxContentLength()); + + if(ret != UPNP_E_SUCCESS){ + esyslog("UPnP\tFailed to set max. content length of SOAP messages. Error code: %d", ret); + return false; + } + + isyslog("UPnP\tInitialising webserver"); + if(!mWebserver->Initialise()){ + esyslog("UPnP\tFailed to initialise the web server."); + return false; + } + + isyslog("UPnP\tInitialising media manager"); + if(!mMediaManager->Initialise()){ + esyslog("UPnP\tFailed to initialise the media manager."); + return false; + } + + return true; +} + +void cMediaServer::SetAnnounceMaxAge(int announceMaxAge){ + mAnnounceMaxAge = (announceMaxAge != 0) ? announceMaxAge : 1800; +} + +void cMediaServer::SetMaxContentLength(size_t maxContentLength){ + mMaxContentLength = (maxContentLength != 0) ? maxContentLength : KB(20); +} + +void cMediaServer::SetConfiguration(upnp::cConfig newConfig){ + mCurrentConfiguration = newConfig; +} + +upnp::cConfig cMediaServer::GetConfiguration() const { + return mCurrentConfiguration; +} + +const char* cMediaServer::GetServerIPAddress() const { + return UpnpGetServerIpAddress(); +} + +uint16_t cMediaServer::GetServerPort() const { + return UpnpGetServerPort(); +} + +string cMediaServer::GetDeviceDescriptionUrl() const { + return mWebserver->GetBaseUrl() + mCurrentConfiguration.serviceURL + "deviceDescription.xml"; +} + +void cMediaServer::RegisterService(cUPnPService* service){ + if(service != NULL){ + cout << "Registered service: " << service->GetServiceDescription().serviceType << endl; + mServices[service->GetServiceDescription().serviceID] = service; + } +} + +int cMediaServer::ActionCallback(Upnp_EventType eventtype, void *event, void *cookie){ + Upnp_Subscription_Request* eventRequest = NULL; + Upnp_Action_Request* actionRequest = NULL; + + cMediaServer* mediaServer = (cMediaServer*)cookie; + + //check committed event variable + if (event == NULL) { + esyslog("UPnP\tUPnP Callback - NULL request"); + return UPNP_E_BAD_REQUEST; + } + + cUPnPService* service; + + switch(eventtype){ + case UPNP_CONTROL_ACTION_REQUEST: + actionRequest = (Upnp_Action_Request*) event; + + dsyslog("UPnP\tAction request: %s", actionRequest->ActionName); + + if(!mediaServer->CheckDeviceUUID(actionRequest->DevUDN)){ + esyslog("UPnP\tUPnP Callback - action request not for this device"); + return UPNP_E_BAD_REQUEST; + } + + service = cMediaServer::mServices[actionRequest->ServiceID]; + + if(service == NULL){ + esyslog("UPnP\tCallback - unsupported service called for control"); + return UPNP_E_BAD_REQUEST; + } + + return service->Execute(actionRequest); + + case UPNP_EVENT_SUBSCRIPTION_REQUEST: + eventRequest = (Upnp_Subscription_Request*) event; + + dsyslog("UPnP\tSubscription request: %s", eventRequest->ServiceId); + + if(!mediaServer->CheckDeviceUUID(eventRequest->UDN)){ + esyslog("UPnP\tUPnP Callback - event request not for this device"); + return UPNP_E_BAD_REQUEST; + } + + service = cMediaServer::mServices[eventRequest->ServiceId]; + + if(service == NULL){ + esyslog("UPnP\tCallback - unsupported service called for eventing"); + return UPNP_E_BAD_REQUEST; + } + + return service->Subscribe(eventRequest); + + default: + esyslog("UPnP\tUPnP Action Callback - Unsupported Event"); + return UPNP_E_BAD_REQUEST; + } + +} + +const char* cMediaServer::RuntimeException::what() const throw() { + return "Runtime error: media server is not running"; +} + +bool cMediaServer::CheckDeviceUUID(string deviceUUID) const { + return deviceUUID.compare(mCurrentConfiguration.deviceUUID) == 0; +} + +cMediaServer::Description::Description( + string fn, string m, string murl, + string mod, string mon, string mono, + string mourl, string sno) +: friendlyName(fn) +, manufacturer(m) +, manufacturerURL(murl) +, modelDescription(mod) +, modelName(mon) +, modelNumber(mono) +, modelURL(mourl) +, serialNumber(sno) +{ +} + +cMediaServer::ServerIcon::ServerIcon(image::cIcon profile, string filename) +: profile(profile) +, filename(filename) +{ +} diff --git a/server/server.o b/server/server.o Binary files differnew file mode 100644 index 0000000..f603bbb --- /dev/null +++ b/server/server.o diff --git a/server/service.cpp b/server/service.cpp new file mode 100644 index 0000000..7185170 --- /dev/null +++ b/server/service.cpp @@ -0,0 +1,117 @@ +/* + * service.cpp + * + * Created on: 27.08.2012 + * Author: savop + */ + +#include "../include/server.h" +#include "../include/service.h" +#include "../include/tools.h" +#include <vdr/i18n.h> + +namespace upnp { + +cUPnPService::cUPnPService(Description serviceDescription) +: mMediaServer(NULL) +, mDeviceHandle(0) +, mServiceDescription(serviceDescription) +{ + cMediaServer::RegisterService(this); +} + +cUPnPService::~cUPnPService(){} + +void cUPnPService::Init(cMediaServer* server, UpnpDevice_Handle deviceHandle){ + mMediaServer = server; + mDeviceHandle = deviceHandle; +} + +void cUPnPService::SetError(Upnp_Action_Request* request, int error){ + request->ErrCode = error; + switch(error){ + case UPNP_SOAP_E_INVALID_ACTION: + strn0cpy(request->ErrStr,tr("Invalid action"),LINE_SIZE); + break; + case UPNP_SOAP_E_INVALID_ARGS: + strn0cpy(request->ErrStr,tr("Invalid args"),LINE_SIZE); + break; + case UPNP_SOAP_E_INVALID_VAR: + strn0cpy(request->ErrStr,tr("Invalid var"),LINE_SIZE); + break; + case UPNP_SOAP_E_ACTION_FAILED: + strn0cpy(request->ErrStr,tr("Action failed"),LINE_SIZE); + break; + case UPNP_SOAP_E_ARGUMENT_INVALID: + strn0cpy(request->ErrStr,tr("Argument value invalid"),LINE_SIZE); + break; + case UPNP_SOAP_E_ARGUMENT_OUT_OF_RANGE: + strn0cpy(request->ErrStr,tr("Argument value out of range"),LINE_SIZE); + break; + case UPNP_SOAP_E_ACTION_NOT_IMPLEMENTED: + strn0cpy(request->ErrStr,tr("Optional action not implemented"),LINE_SIZE); + break; + case UPNP_SOAP_E_OUT_OF_MEMORY: + strn0cpy(request->ErrStr,tr("Out of memory"),LINE_SIZE); + break; + case UPNP_SOAP_E_HUMAN_INTERVENTION: + strn0cpy(request->ErrStr,tr("Human intervention required"),LINE_SIZE); + break; + case UPNP_SOAP_E_STRING_TO_LONG: + strn0cpy(request->ErrStr,tr("String argument to long"),LINE_SIZE); + break; + case UPNP_SOAP_E_NOT_AUTHORIZED: + strn0cpy(request->ErrStr,tr("Action not authorized"),LINE_SIZE); + break; + case UPNP_SOAP_E_SIGNATURE_FAILURE: + strn0cpy(request->ErrStr,tr("Signature failure"),LINE_SIZE); + break; + case UPNP_SOAP_E_SIGNATURE_MISSING: + strn0cpy(request->ErrStr,tr("Signature missing"),LINE_SIZE); + break; + case UPNP_SOAP_E_NOT_ENCRYPTED: + strn0cpy(request->ErrStr,tr("Not encrypted"),LINE_SIZE); + break; + case UPNP_SOAP_E_INVALID_SEQUENCE: + strn0cpy(request->ErrStr,tr("Invalid sequence"),LINE_SIZE); + break; + case UPNP_SOAP_E_INVALID_CONTROL_URL: + strn0cpy(request->ErrStr,tr("Invalid control URL"),LINE_SIZE); + break; + case UPNP_SOAP_E_NO_SUCH_SESSION: + strn0cpy(request->ErrStr,tr("No such session"),LINE_SIZE); + break; + case UPNP_SOAP_E_OUT_OF_SYNC: + default: + strn0cpy(request->ErrStr,tr("Unknown error code. Contact the device manufacturer"),LINE_SIZE); + break; + } +} + +int cUPnPService::ParseIntegerValue(IN IXML_Document* Document, IN std::string Item, OUT long& Value){ + std::string Val; + int error = ixml::IxmlGetFirstDocumentItem(Document, Item, Val); + + if(error) return error; + else { + Value = atol(Val.c_str()); + return 0; + } +} + +int cUPnPService::ParseStringValue(IN IXML_Document* Document, IN std::string Item, OUT std::string& Value){ + return ixml::IxmlGetFirstDocumentItem(Document, Item, Value); +} + +cUPnPService::Description::Description(string type, string id, string scpd, string control, string event) +: serviceType(type) +, serviceID(id) +, SCPDXML(scpd) +, controlDescriptor(control) +, eventSubscriberDescriptor(event) +{ +} + +} // namespace upnp + + diff --git a/server/service.o b/server/service.o Binary files differnew file mode 100644 index 0000000..a130cda --- /dev/null +++ b/server/service.o diff --git a/server/webserver.cpp b/server/webserver.cpp new file mode 100644 index 0000000..ce8acda --- /dev/null +++ b/server/webserver.cpp @@ -0,0 +1,166 @@ +/* + * webserver.cpp + * + * Created on: 06.08.2012 + * Author: savop + */ + +#include "../include/webserver.h" +#include "../upnp.h" +#include <sstream> + +namespace upnp { + +cWebserver::cWebserver(std::string address) +: mListenerAddress(address) +, mListenerPort(7649) +, mWebserverThread(*this) +{ + SetWebserverRootDir(string(), string(), string()); + SetServiceUrl("services/", string()); +} + +cWebserver::~cWebserver(){ + +} + +bool cWebserver::Start(){ + return mWebserverThread.Start(); +} + +void cWebserver::Stop(){ + try { + mApplication.shutdown(); + } catch (const std::exception& e){ + esyslog("UPnP\tError while stopping web server: %s", e.what()); + } +} + +bool cWebserver::Initialise(){ + + try { + // Map static contents + stringstream ss1, ss2; + + mApplication.listen(mListenerAddress.c_str(), mListenerPort); + + mApplication.mapUrl("^/$", "index"); + + mApplication.mapUrl("^/index.html", "index"); + + ss1.clear(); ss1.str(string()); + ss1 << "^/" << mServiceUrl << "([^/.]+).xml$"; + + mApplication.mapUrl(ss1.str(), "$1"); + + // Map static contents + ss1.clear(); ss1.str(string()); + ss1 << "^/" << mStaticContentUrl << "(.*)"; + + ss2.clear(); ss2.str(string()); + ss2 << mWebserverRootDir << "$1"; + + mApplication.mapUrl(ss1.str(), ss2.str(), "static@tntnet"); + + // Map static contents + ss1.clear(); ss1.str(string()); + ss1 << "^/" << mServiceUrl << "([^/.]+)"; + + ss2.clear(); ss2.str(string()); + ss2 << mServiceUrl << "$1"; + + mApplication.mapUrl(ss1.str(), ss2.str(), "serviceRedirect"); + + isyslog("UPnP\tUsing %s for static content delivery.", mWebserverRootDir.c_str()); + + } catch (const std::exception& e){ + esyslog("UPnP\tError while initialising web server: %s", e.what()); + return false; + } + + return true; +} + +void cWebserver::SetListenerPort(uint16_t port){ + if(mWebserverThread.Active()) return; + + mListenerPort = port ? port : 7649; +} + +void cWebserver::SetWebserverRootDir(std::string rootDirectory, std::string staticContentUrl, std::string presentationUrl){ + if(mWebserverThread.Active()) return; + + if(rootDirectory.empty()) + mWebserverRootDir = std::string(cPluginUpnp::ConfigDirectory(PLUGIN_NAME_I18N)) + "/httpdocs/"; + else + mWebserverRootDir = rootDirectory; + + if(staticContentUrl.empty()) + mStaticContentUrl = "http/"; + else + mStaticContentUrl = staticContentUrl; + + if(presentationUrl.empty()) + mPresentationUrl = "index.html"; + else + mPresentationUrl = presentationUrl; +} + +void cWebserver::SetServiceUrl(std::string descriptionUrl, std::string controlUrl){ + if(mWebserverThread.Active()) return; + + if(descriptionUrl.empty()) + mServiceUrl = "services/"; + else + mServiceUrl = descriptionUrl; + + if(controlUrl.empty()){ + stringstream s; + s << "http://" << UpnpGetServerIpAddress() << ":" << UpnpGetServerPort() << "/" << mServiceUrl; + + mControlUrl = s.str(); + } else { + mControlUrl = controlUrl; + } +} + +const std::string cWebserver::GetBaseUrl() const { + stringstream s; + s << "http://" << mListenerAddress << ":" << mListenerPort << "/"; + + return s.str(); +} + +const std::string cWebserver::GetServiceUrl() const { + return mServiceUrl; +} + +const std::string cWebserver::GetControlUrl() const { + return mControlUrl; +} + +const std::string cWebserver::GetPresentationUrl() const { + return mPresentationUrl; +} + +const std::string cWebserver::GetStaticContentUrl() const { + return mStaticContentUrl; +} + +cWebserver::cWSThread::cWSThread(cWebserver& webServer) +: mWebserver(webServer) +{ + +} + +void cWebserver::cWSThread::Action(){ + try { + mWebserver.mApplication.run(); + } catch (const std::exception& e){ + esyslog("UPnP\tError while starting web server: %s", e.what()); + } +} + +} // namespace upnp + + diff --git a/server/webserver.o b/server/webserver.o Binary files differnew file mode 100644 index 0000000..c6789ea --- /dev/null +++ b/server/webserver.o |