/*---------------------------------------------------------------------- | PLT_SsdpSender::SendSsdp +---------------------------------------------------------------------*/ NPT_Result PLT_SsdpSender::SendSsdp(NPT_HttpResponse& response, const char* usn, const char* target, NPT_UdpSocket& socket, bool notify, const NPT_SocketAddress* addr /* = NULL */) { NPT_CHECK_SEVERE(FormatPacket(response, usn, target, socket, notify)); // logging NPT_LOG_FINE("Sending SSDP:"); PLT_LOG_HTTP_MESSAGE(NPT_LOG_LEVEL_FINE, &response); // use a memory stream to write all the data NPT_MemoryStream stream; NPT_Result res = response.Emit(stream); if (NPT_FAILED(res)) return res; // copy stream into a data packet and send it NPT_LargeSize size; stream.GetSize(size); if (size != (NPT_Size)size) return NPT_ERROR_OUT_OF_RANGE; NPT_DataBuffer packet(stream.GetData(), (NPT_Size)size); return socket.Send(packet, addr); }
/*---------------------------------------------------------------------- | PLT_MediaBrowser::OnDeviceRemoved +---------------------------------------------------------------------*/ NPT_Result PLT_MediaBrowser::OnDeviceRemoved(PLT_DeviceDataReference& device) { PLT_DeviceDataReference data; { NPT_AutoLock lock(m_MediaServers); // only release if we have kept it around NPT_String uuid = device->GetUUID(); // is it a new device? if (NPT_FAILED(NPT_ContainerFind(m_MediaServers, PLT_DeviceDataFinder(uuid), data))) { NPT_LOG_WARNING_1("Device (%s) not found in our list!", (const char*)uuid); return NPT_FAILURE; } NPT_LOG_FINE("Device Removed:"); device->ToLog(NPT_LOG_LEVEL_FINE); m_MediaServers.Remove(device); } if (m_Listener) { m_Listener->OnMSAddedRemoved(device, 0); } return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | CMediaCrawler::ProcessFileRequest +---------------------------------------------------------------------*/ NPT_Result CMediaCrawler::ProcessFileRequest(NPT_HttpRequest& request, NPT_HttpResponse& response, NPT_SocketInfo& info) { NPT_COMPILER_UNUSED(info); NPT_LOG_FINE("CMediaCrawler::ProcessFileRequest Received Request:"); PLT_LOG_HTTP_MESSAGE(NPT_LOG_LEVEL_FINE, &request); if (request.GetMethod().Compare("GET") && request.GetMethod().Compare("HEAD")) { response.SetStatus(500, "Internal Server Error"); return NPT_SUCCESS; } // add the user agent header, some stupid media servers like YME needs it if (!request.GetHeaders().GetHeader(NPT_HTTP_HEADER_USER_AGENT)) { request.GetHeaders().SetHeader(NPT_HTTP_HEADER_USER_AGENT, "Platinum/" PLT_PLATINUM_VERSION_STRING); } // File requested NPT_HttpResponse* out_response = NULL; NPT_HttpUrlQuery query(request.GetUrl().GetQuery()); const char* url = query.GetField("url"); if (url) { // look for handler CStreamHandler* handler = NULL; NPT_ContainerFind(m_StreamHandlers, CStreamHandlerFinder(NULL, url), handler); if (handler && NPT_SUCCEEDED(handler->ProcessFileRequest(request, out_response)) && out_response) { // copy response code and reason response.SetStatus(out_response->GetStatusCode(), out_response->GetReasonPhrase()); // copy headers NPT_List<NPT_HttpHeader*>::Iterator headers = out_response->GetHeaders().GetHeaders().GetFirstItem(); while (headers) { response.GetHeaders().SetHeader((*headers)->GetName(), (*headers)->GetValue()); ++headers; } response.SetEntity(new NPT_HttpEntity(response.GetHeaders())); // update inputstream NPT_HttpEntity* out_entity; if ((out_entity = out_response->GetEntity()) != NULL) { NPT_InputStreamReference inputstream; out_entity->GetInputStream(inputstream); if (!inputstream.IsNull()) { // set the stream but do not update the content length response.GetEntity()->SetInputStream(inputstream, false); } } delete out_response; return NPT_SUCCESS; } } response.SetStatus(404, "File Not Found"); return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | NPT_DynamicLibrary::Load +---------------------------------------------------------------------*/ NPT_Result NPT_DynamicLibrary::Load(const char* name, NPT_Flags flags, NPT_DynamicLibrary*& library) { NPT_WIN32_USE_CHAR_CONVERSION; NPT_COMPILER_UNUSED(flags); if (name == NULL) return NPT_ERROR_INVALID_PARAMETERS; // default return value library = NULL; // load the lib NPT_LOG_FINE_2("loading library %s, flags=%x", name, flags); HMODULE handle = LoadLibraryW(NPT_WIN32_A2W(name)); if (handle == NULL) { NPT_LOG_FINE("library not found"); return NPT_FAILURE; } // instantiate the object NPT_LOG_FINE_1("library %s loaded", name); library = new NPT_DynamicLibrary(new NPT_Win32DynamicLibrary(handle, name)); return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | main +---------------------------------------------------------------------*/ int main(int, char**) { NPT_LogManager::GetDefault().Configure("plist:.level=ALL;"); NPT_LOG_L(MyLogger, NPT_LOG_LEVEL_WARNING, "blabla"); NPT_LOG_L2(MyLogger, NPT_LOG_LEVEL_WARNING, "blabla %d %d", 8, 9); NPT_LOG(NPT_LOG_LEVEL_WARNING, "blibli"); NPT_LOG_2(NPT_LOG_LEVEL_INFO, "fofo %d %d", 5, 7); NPT_LOG_SEVERE("this is severe!"); NPT_LOG_SEVERE_1("this is severe (%d)", 9); NPT_LOG_SEVERE_L(MyLogger, "this is severe!"); NPT_LOG_SEVERE_L1(MyLogger, "this is severe (%d)", 9); NPT_LOG_SEVERE_L(FooLogger, "this is severe!"); NPT_LOG_SEVERE_L1(FooLogger, "this is severe (%d)", 9); NPT_LOG_SEVERE("severe"); NPT_LOG_WARNING("warning"); NPT_LOG_INFO("info"); NPT_LOG_FINE("fine"); NPT_LOG_FINER("finer"); NPT_LOG_FINEST("finest"); NPT_LOG_SEVERE_L(FooLogger, "severe"); NPT_LOG_WARNING_L(FooLogger, "warning"); NPT_LOG_INFO_L(FooLogger, "info"); NPT_LOG_FINE_L(FooLogger, "fine"); NPT_LOG_FINER_L(FooLogger, "finer"); NPT_LOG_FINEST_L(FooLogger, "finest"); TestLargeBuffer(); TestCheck(); TestCheckSevere(); TestCheckWarning(); TestCheckInfo(); TestCheckFine(); TestCheckFiner(); TestCheckFinest(); TestCheckL(); TestCheckSevereL(); TestCheckWarningL(); TestCheckInfoL(); TestCheckFineL(); TestCheckFinerL(); TestCheckFinestL(); return 0; }
/*---------------------------------------------------------------------- | PLT_FileMediaServer::ProcessFileRequest +---------------------------------------------------------------------*/ NPT_Result PLT_FileMediaServer::ProcessFileRequest(NPT_HttpRequest& request, NPT_HttpResponse& response, NPT_SocketInfo& client_info) { NPT_COMPILER_UNUSED(client_info); NPT_LOG_FINE("PLT_FileMediaServer::ProcessFileRequest Received Request:"); PLT_LOG_HTTP_MESSAGE(NPT_LOG_LEVEL_FINE, &request); response.GetHeaders().SetHeader("Accept-Ranges", "bytes"); if (request.GetMethod().Compare("GET") && request.GetMethod().Compare("HEAD")) { response.SetStatus(500, "Internal Server Error"); return NPT_SUCCESS; } // File requested NPT_String path = m_FileBaseUri.GetPath(); NPT_String strUri = NPT_Uri::PercentDecode(request.GetUrl().GetPath()); NPT_HttpUrlQuery query(request.GetUrl().GetQuery()); NPT_String file_path = query.GetField("path"); // hack for XBMC support for 360, we urlencoded the ? to that the 360 doesn't strip out the query // but then the query ends being parsed as part of the path int index = strUri.Find("path="); if (index>0) file_path = strUri.Right(strUri.GetLength()-index-5); if (file_path.GetLength() == 0) goto failure; // HACK for wmp: somehow they inverse our slashes ! // do it only if we're on windows if (m_DirDelimiter == "\\") { file_path.Replace('/', '\\'); } if (path.Compare(strUri.Left(path.GetLength()), true) == 0) { NPT_Integer start, end; PLT_HttpHelper::GetRange(&request, start, end); return PLT_FileServer::ServeFile(m_Path + file_path, &response, start, end, !request.GetMethod().Compare("HEAD")); } // Album Art requested path = m_AlbumArtBaseUri.GetPath(); if (path.Compare(strUri.Left(path.GetLength()), true) == 0) { return OnAlbumArtRequest(m_Path + file_path, response); } failure: response.SetStatus(404, "File Not Found"); return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | PLT_MediaServer::ParseTagList +---------------------------------------------------------------------*/ NPT_Result PLT_MediaServer::ParseTagList(const NPT_String& updates, NPT_Map<NPT_String,NPT_String>& tags) { // reset output params first tags.Clear(); NPT_List<NPT_String> split = updates.Split(","); NPT_XmlNode* node = NULL; NPT_XmlElementNode* didl_partial = NULL; NPT_XmlParser parser; // as these are single name value pairs, separated by commas we wrap in a tag // to create a valid tree NPT_String xml("<TagValueList>"); for (NPT_List<NPT_String>::Iterator entry = split.GetFirstItem(); entry; entry++) { NPT_String& element = (*entry); if (element.IsEmpty()) xml.Append("<empty>empty</empty>"); else xml.Append(element); } xml.Append("</TagValueList>"); NPT_LOG_FINE("Parsing TagList..."); NPT_CHECK_LABEL_SEVERE(parser.Parse(xml, node), cleanup); if (!node || !node->AsElementNode()) { NPT_LOG_SEVERE("Invalid node type"); goto cleanup; } didl_partial = node->AsElementNode(); if (didl_partial->GetTag().Compare("TagValueList", true)) { NPT_LOG_SEVERE("Invalid node tag"); goto cleanup; } for (NPT_List<NPT_XmlNode*>::Iterator children = didl_partial->GetChildren().GetFirstItem(); children; children++) { NPT_XmlElementNode* child = (*children)->AsElementNode(); if (!child) continue; tags[child->GetTag()] = *child->GetText(); } return NPT_SUCCESS; cleanup: if (node) delete node; return NPT_FAILURE; }
/*---------------------------------------------------------------------- | PLT_MediaBrowser::OnDeviceAdded +---------------------------------------------------------------------*/ NPT_Result PLT_MediaBrowser::OnDeviceAdded(PLT_DeviceDataReference& device) { // verify the device implements the function we need PLT_Service* serviceCDS; PLT_Service* serviceCMR; NPT_String type; type = "urn:schemas-upnp-org:service:ContentDirectory:1"; if (NPT_FAILED(device->FindServiceByType(type, serviceCDS))) { NPT_LOG_WARNING_1("Service %s not found", (const char*)type); return NPT_FAILURE; } type = "urn:schemas-upnp-org:service:ConnectionManager:1"; if (NPT_FAILED(device->FindServiceByType(type, serviceCMR))) { NPT_LOG_WARNING_1("Service %s not found", (const char*)type); return NPT_FAILURE; } { NPT_AutoLock lock(m_MediaServers); PLT_DeviceDataReference data; NPT_String uuid = device->GetUUID(); // is it a new device? if (NPT_SUCCEEDED(NPT_ContainerFind(m_MediaServers, PLT_DeviceDataFinder(uuid), data))) { NPT_LOG_WARNING_1("Device (%s) is already in our list!", (const char*)uuid); return NPT_FAILURE; } NPT_LOG_FINE("Device Found:"); device->ToLog(NPT_LOG_LEVEL_FINE); m_MediaServers.Add(device); } if (m_Listener) { m_Listener->OnMSAddedRemoved(device, 1); } m_CtrlPoint->Subscribe(serviceCDS); m_CtrlPoint->Subscribe(serviceCMR); return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | PLT_FileMediaServer::ProcessFileRequest +---------------------------------------------------------------------*/ NPT_Result PLT_FileMediaServer::ProcessFileRequest(NPT_HttpRequest& request, const NPT_HttpRequestContext& context, NPT_HttpResponse& response) { NPT_LOG_FINE("PLT_FileMediaServer::ProcessFileRequest Received Request:"); PLT_LOG_HTTP_MESSAGE(NPT_LOG_LEVEL_FINE, &request); response.GetHeaders().SetHeader("Accept-Ranges", "bytes"); if (request.GetMethod().Compare("GET") && request.GetMethod().Compare("HEAD")) { response.SetStatus(500, "Internal Server Error"); return NPT_SUCCESS; } // Extract uri path from url NPT_String uri_path = NPT_Uri::PercentDecode(request.GetUrl().GetPath()); // extract file path from query NPT_HttpUrlQuery query(request.GetUrl().GetQuery()); NPT_String file_path = query.GetField("path"); // hack for XBMC support for 360, we urlencoded the ? to that the 360 doesn't strip out the query // but then the query ends being parsed as part of the path int index = uri_path.Find("path="); if (index>0) file_path = uri_path.Right(uri_path.GetLength()-index-5); if (file_path.GetLength() == 0) goto failure; NPT_CHECK_LABEL_WARNING(ServeFile(request, context, response, uri_path, file_path), failure); return NPT_SUCCESS; failure: response.SetStatus(404, "File Not Found"); return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | PLT_MediaController::OnDeviceAdded +---------------------------------------------------------------------*/ NPT_Result PLT_MediaController::OnDeviceAdded(PLT_DeviceDataReference& device) { PLT_DeviceDataReference data; NPT_String uuid = device->GetUUID(); // is it a new device? if (NPT_SUCCEEDED(NPT_ContainerFind(m_MediaRenderers, PLT_DeviceDataFinder(uuid), data))) { NPT_LOG_FINE_1("Device (%s) is already in our list!", (const char*)uuid); return NPT_FAILURE; } NPT_LOG_FINE("Device Found:"); device->ToLog(NPT_LOG_LEVEL_FINE); // verify the device implements the function we need PLT_Service* serviceAVT; PLT_Service* serviceCMR; NPT_String type; type = "urn:schemas-upnp-org:service:AVTransport:1"; if (NPT_FAILED(device->FindServiceByType(type, serviceAVT))) { NPT_LOG_FINE_1("Service %s not found", (const char*)type); return NPT_FAILURE; } type = "urn:schemas-upnp-org:service:ConnectionManager:1"; if (NPT_FAILED(device->FindServiceByType(type, serviceCMR))) { NPT_LOG_FINE_1("Service %s not found", (const char*)type); return NPT_FAILURE; } m_MediaRenderers.Add(device); if (m_Listener) { m_Listener->OnMRAddedRemoved(device, 1); } // subscribe to AVT eventing m_CtrlPoint->Subscribe(serviceAVT); return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | PLT_HttpClient::SendRequest +---------------------------------------------------------------------*/ NPT_Result PLT_HttpClient::SendRequest(NPT_OutputStreamReference& output_stream, NPT_HttpRequest& request, NPT_Timeout timeout) { NPT_COMPILER_UNUSED(timeout); // connect to the server NPT_LOG_FINE("Sending:"); PLT_LOG_HTTP_MESSAGE(NPT_LOG_LEVEL_FINE, &request); // add any headers that may be missing NPT_HttpHeaders& headers = request.GetHeaders(); //headers.SetHeader(NPT_HTTP_HEADER_CONNECTION, "close"); if (!headers.GetHeader(NPT_HTTP_HEADER_USER_AGENT)) { headers.SetHeader(NPT_HTTP_HEADER_USER_AGENT, "Platinum/" PLT_PLATINUM_VERSION_STRING); } // set host only if not already set if (!headers.GetHeader(NPT_HTTP_HEADER_HOST)) { NPT_String host = request.GetUrl().GetHost(); if (request.GetUrl().GetPort() != NPT_HTTP_DEFAULT_PORT) { host += ":"; host += NPT_String::FromInteger(request.GetUrl().GetPort()); } headers.SetHeader(NPT_HTTP_HEADER_HOST, host); } // get the request entity to set additional headers NPT_InputStreamReference body_stream; NPT_HttpEntity* entity = request.GetEntity(); if (entity && NPT_SUCCEEDED(entity->GetInputStream(body_stream))) { // content length headers.SetHeader(NPT_HTTP_HEADER_CONTENT_LENGTH, NPT_String::FromInteger(entity->GetContentLength())); // content type NPT_String content_type = entity->GetContentType(); if (!content_type.IsEmpty()) { headers.SetHeader(NPT_HTTP_HEADER_CONTENT_TYPE, content_type); } // content encoding NPT_String content_encoding = entity->GetContentEncoding(); if (!content_encoding.IsEmpty()) { headers.SetHeader(NPT_HTTP_HEADER_CONTENT_ENCODING, content_encoding); } } else { // force content length to 0 is there is no message body headers.SetHeader(NPT_HTTP_HEADER_CONTENT_LENGTH, "0"); } // create a memory stream to buffer the headers NPT_MemoryStream header_stream; // emit the request headers into the header buffer request.Emit(header_stream); // send the headers NPT_CHECK_SEVERE(output_stream->WriteFully(header_stream.GetData(), header_stream.GetDataSize())); // send request body if (!body_stream.IsNull() && entity->GetContentLength()) { NPT_CHECK_SEVERE(NPT_StreamToStreamCopy(*body_stream.AsPointer(), *output_stream.AsPointer())); } // flush the output stream so that everything is sent to the server output_stream->Flush(); return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | PLT_Didl::FromDidl +---------------------------------------------------------------------*/ NPT_Result PLT_Didl::FromDidl(const char* xml, PLT_MediaObjectListReference& objects) { NPT_String str; PLT_MediaObject* object = NULL; NPT_XmlNode* node = NULL; NPT_XmlElementNode* didl = NULL; NPT_XmlParser parser; NPT_LOG_FINE("Parsing Didl..."); NPT_CHECK_LABEL_SEVERE(parser.Parse(xml, node), cleanup); if (!node || !node->AsElementNode()) { NPT_LOG_SEVERE("Invalid node type"); goto cleanup; } didl = node->AsElementNode(); if (didl->GetTag().Compare("DIDL-Lite", true)) { NPT_LOG_SEVERE("Invalid node tag"); goto cleanup; } // create entry list objects = new PLT_MediaObjectList(); // for each child, find out if it's a container or not // and then invoke the FromDidl on it for (NPT_List<NPT_XmlNode*>::Iterator children = didl->GetChildren().GetFirstItem(); children; children++) { NPT_XmlElementNode* child = (*children)->AsElementNode(); if (!child) continue; if (child->GetTag().Compare("Container", true) == 0) { object = new PLT_MediaContainer(); } else if (child->GetTag().Compare("item", true) == 0) { object = new PLT_MediaItem(); } else { NPT_LOG_WARNING("Invalid node tag"); continue; } if (NPT_FAILED(object->FromDidl(child))) { NPT_LOG_WARNING_1("Invalid didl for object: %s", (const char*) PLT_XmlHelper::Serialize(*child, false)); continue; } objects->Add(object); object = NULL; // reset to make sure it doesn't get deleted twice in case of error } delete node; return NPT_SUCCESS; cleanup: objects = NULL; delete node; delete object; return NPT_FAILURE; }
/*---------------------------------------------------------------------- | CMediaCrawler::UpdateDidl +---------------------------------------------------------------------*/ NPT_String CMediaCrawler::UpdateDidl(const char* server_uuid, const NPT_String& didl, NPT_SocketInfo* info) { NPT_String new_didl; NPT_String str; NPT_XmlNode* node = NULL; NPT_XmlWriter writer; NPT_OutputStreamReference stream(new NPT_StringOutputStream(&new_didl)); NPT_LOG_FINE("Parsing Didl..."); NPT_XmlElementNode* tree = NULL; NPT_XmlParser parser; if (NPT_FAILED(parser.Parse(didl, node)) || !node || !node->AsElementNode()) { goto cleanup; } tree = node->AsElementNode(); NPT_LOG_FINE("Processing Didl xml..."); if (tree->GetTag().Compare("DIDL-Lite", true)) { goto cleanup; } // iterate through children NPT_Result res; for (NPT_List<NPT_XmlNode*>::Iterator children = tree->GetChildren().GetFirstItem(); children; children++) { NPT_XmlElementNode* child = (*children)->AsElementNode(); if (!child) continue; // object id remapping NPT_XmlAttribute* attribute_id; res = PLT_XmlHelper::GetAttribute(child, "id", attribute_id); if (NPT_SUCCEEDED(res) && attribute_id) { attribute_id->SetValue(FormatObjectId(server_uuid, attribute_id->GetValue())); } // parent ID remapping NPT_XmlAttribute* attribute_parent_id; res = PLT_XmlHelper::GetAttribute(child, "parentID", attribute_parent_id); if (NPT_SUCCEEDED(res)) { attribute_parent_id->SetValue(attribute_parent_id->GetValue().Compare("-1")?FormatObjectId(server_uuid, attribute_parent_id->GetValue()):"0"); } // resources remapping NPT_Array<NPT_XmlElementNode*> res; PLT_XmlHelper::GetChildren(child, res, "res"); if (res.GetItemCount() > 0) { for (unsigned int i=0; i<res.GetItemCount(); i++) { NPT_XmlElementNode* resource = res[i]; NPT_XmlAttribute* attribute_prot; const NPT_String* url; if (NPT_SUCCEEDED(PLT_XmlHelper::GetAttribute(resource, "protocolInfo", attribute_prot)) && (url = resource->GetText())) { // special case for Windows Media Connect // When a browse is done on the same machine, WMC uses localhost // instead of the IP for all resources urls which means we cannot advertise that // since it would be useless for a remote device // so we try to replace it with the right IP address by looking at which interface we received the // initial browse request on to make sure the remote device will be able to access the modified resource // urls (in case the local PC has more than 1 NICs) // replace the url NPT_List<NPT_XmlNode*>& children = resource->GetChildren(); NPT_HttpUrl http_url(NPT_Uri::PercentDecode(*url)); if ((http_url.GetHost() == "localhost" || http_url.GetHost() == "127.0.0.1") && info) { if (info->local_address.GetIpAddress().AsLong()) { http_url.SetHost(info->local_address.GetIpAddress().ToString()); // replace text children.Apply(NPT_ObjectDeleter<NPT_XmlNode>()); children.Clear(); resource->AddText(http_url.ToString()); url = resource->GetText(); } } CStreamHandler* handler = NULL; NPT_Result res = NPT_ContainerFind(m_StreamHandlers, CStreamHandlerFinder(attribute_prot->GetValue(), *url), handler); if (NPT_SUCCEEDED(res)) { handler->ModifyResource(resource); } } } } } // serialize modified node into new didl writer.Serialize(*node, *stream); delete node; return new_didl; cleanup: delete node; return didl; }