summaryrefslogtreecommitdiff
path: root/server
diff options
context:
space:
mode:
Diffstat (limited to 'server')
-rw-r--r--server/connection.cpp139
-rw-r--r--server/connection.obin0 -> 57880 bytes
-rw-r--r--server/connectionManager.cpp253
-rw-r--r--server/connectionManager.obin0 -> 313200 bytes
-rw-r--r--server/contentDirectory.cpp439
-rw-r--r--server/contentDirectory.obin0 -> 232952 bytes
-rw-r--r--server/server.cpp337
-rw-r--r--server/server.obin0 -> 327792 bytes
-rw-r--r--server/service.cpp117
-rw-r--r--server/service.obin0 -> 84424 bytes
-rw-r--r--server/webserver.cpp166
-rw-r--r--server/webserver.obin0 -> 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
new file mode 100644
index 0000000..03f6ec5
--- /dev/null
+++ b/server/connection.o
Binary files differ
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
new file mode 100644
index 0000000..e3b3e75
--- /dev/null
+++ b/server/connectionManager.o
Binary files differ
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
new file mode 100644
index 0000000..488881a
--- /dev/null
+++ b/server/contentDirectory.o
Binary files differ
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
new file mode 100644
index 0000000..f603bbb
--- /dev/null
+++ b/server/server.o
Binary files differ
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
new file mode 100644
index 0000000..a130cda
--- /dev/null
+++ b/server/service.o
Binary files differ
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
new file mode 100644
index 0000000..c6789ea
--- /dev/null
+++ b/server/webserver.o
Binary files differ