aboutsummaryrefslogtreecommitdiff
path: root/Src/replicant/ssdp
diff options
context:
space:
mode:
Diffstat (limited to 'Src/replicant/ssdp')
-rw-r--r--Src/replicant/ssdp/Android.mk18
-rw-r--r--Src/replicant/ssdp/SSDPAPI.cpp436
-rw-r--r--Src/replicant/ssdp/SSDPAPI.h61
-rw-r--r--Src/replicant/ssdp/api__ssdp.h20
-rw-r--r--Src/replicant/ssdp/api_ssdp.h32
-rw-r--r--Src/replicant/ssdp/cb_ssdp.h21
-rw-r--r--Src/replicant/ssdp/main.cpp88
-rw-r--r--Src/replicant/ssdp/main.h1
-rw-r--r--Src/replicant/ssdp/resource.h14
-rw-r--r--Src/replicant/ssdp/ssdp.rc76
-rw-r--r--Src/replicant/ssdp/ssdp.vcxproj302
-rw-r--r--Src/replicant/ssdp/ssdp.vcxproj.filters49
-rw-r--r--Src/replicant/ssdp/version.rc239
13 files changed, 1157 insertions, 0 deletions
diff --git a/Src/replicant/ssdp/Android.mk b/Src/replicant/ssdp/Android.mk
new file mode 100644
index 00000000..659d0126
--- /dev/null
+++ b/Src/replicant/ssdp/Android.mk
@@ -0,0 +1,18 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+include $(ROOT_REPLICANT)/PlatformName.mk
+
+LOCAL_MODULE := ssdp
+LOCAL_MODULE_FILENAME := lib$(LOCAL_MODULE).$(PLATFORM_NAME).w6c
+
+LOCAL_C_INCLUDES := $(ROOT_REPLICANT)
+LOCAL_CFLAGS := -fvisibility=hidden
+
+LOCAL_STATIC_LIBRARIES := nu foundation
+LOCAL_SHARED_LIBRARIES := libjnet nx
+
+LOCAL_SRC_FILES := main.cpp SSDPAPI.cpp
+
+
+LOCAL_LDFLAGS = -llog
+include $(BUILD_SHARED_LIBRARY)
diff --git a/Src/replicant/ssdp/SSDPAPI.cpp b/Src/replicant/ssdp/SSDPAPI.cpp
new file mode 100644
index 00000000..b3574c83
--- /dev/null
+++ b/Src/replicant/ssdp/SSDPAPI.cpp
@@ -0,0 +1,436 @@
+#include "api__ssdp.h"
+#include "SSDPAPI.h"
+#include "foundation/error.h"
+#include "jnetlib/jnetlib.h"
+#include "nx/nxsleep.h"
+#include "nswasabi/AutoCharNX.h"
+#include "nswasabi/ReferenceCounted.h"
+#include <time.h>
+#include <stdio.h>
+#ifdef __ANDROID__
+#include <android/log.h>
+#endif
+
+#ifdef _WIN32
+#define snprintf _snprintf
+#endif
+
+SSDPAPI::SSDPAPI()
+{
+ listener=0;
+ user_agent=0;
+}
+
+SSDPAPI::~SSDPAPI()
+{
+ jnl_udp_release(listener);
+
+ for (ServiceList::iterator itr=services.begin();itr!=services.end();itr++)
+ {
+ NXURIRelease(itr->location);
+ NXStringRelease(itr->type);
+ NXStringRelease(itr->usn);
+ }
+
+ for (ServiceList::iterator itr=found_services.begin();itr!=found_services.end();itr++)
+ {
+ NXURIRelease(itr->location);
+ NXStringRelease(itr->type);
+ NXStringRelease(itr->usn);
+ }
+}
+
+int SSDPAPI::Initialize()
+{
+ user_agent=WASABI2_API_APP->GetUserAgent();
+ NXThreadCreate(&ssdp_thread, SSDPThread, this);
+ return NErr_Success;
+}
+
+int SSDPAPI::SSDP_RegisterService(nx_uri_t location, nx_string_t type, nx_string_t usn)
+{
+ nu::AutoLock auto_lock(services_lock);
+ Service service = {0};
+ service.location = NXURIRetain(location);
+ service.type = NXStringRetain(type);
+ service.usn = NXStringRetain(usn);
+ services.push_back(service);
+
+ return NErr_Success;
+}
+
+int SSDPAPI::SSDP_RegisterCallback(cb_ssdp *callback)
+{
+ if (!callback)
+ {
+ return NErr_BadParameter;
+ }
+
+ threadloop_node_t *node = thread_loop.GetAPC();
+ if (!node)
+ {
+ return NErr_OutOfMemory;
+ }
+
+ node->func = APC_RegisterCallback;
+ node->param1 = this;
+ node->param2 = callback;
+ callback->Retain();
+ thread_loop.Schedule(node);
+ return NErr_Success;
+}
+
+int SSDPAPI::SSDP_UnregisterCallback(cb_ssdp *callback)
+{
+ if (!callback)
+ {
+ return NErr_BadParameter;
+ }
+
+ threadloop_node_t *node = thread_loop.GetAPC();
+ if (!node)
+ {
+ return NErr_OutOfMemory;
+ }
+
+ node->func = APC_UnregisterCallback;
+ node->param1 = this;
+ node->param2 = callback;
+ // since we don't actually know if the callback is registered until the other thread runs
+ // we can't guarantee that we have a reference. so we'll add one!
+ callback->Retain();
+ thread_loop.Schedule(node);
+ return NErr_Success;
+}
+
+int SSDPAPI::SSDP_Search(nx_string_t type)
+{
+ if (!type)
+ {
+ return NErr_BadParameter;
+ }
+
+ threadloop_node_t *node = thread_loop.GetAPC();
+ if (!node)
+ {
+ return NErr_OutOfMemory;
+ }
+
+ node->func = APC_Search;
+ node->param1 = this;
+ node->param2 = NXStringRetain(type);
+ thread_loop.Schedule(node);
+ return NErr_Success;
+}
+
+int SSDPAPI::FindUSN(ServiceList &service_list, const char *usn, Service *&service)
+{
+ for (ServiceList::iterator itr = service_list.begin(); itr != service_list.end(); itr++)
+ {
+ if (!NXStringKeywordCompareWithCString(itr->usn, usn))
+ {
+ service = &(* itr);
+ return NErr_Success;
+ }
+ }
+
+ size_t num_services = service_list.size();
+ Service new_service = {0};
+ NXStringCreateWithUTF8(&new_service.usn, usn);
+ service_list.push_back(new_service);
+ service = &service_list.at(num_services);
+
+ return NErr_Empty;
+}
+
+nx_thread_return_t SSDPAPI::SSDPThread(nx_thread_parameter_t parameter)
+{
+ return ((SSDPAPI *)parameter)->Internal_Run();
+}
+
+void SSDPAPI::Internal_RegisterCallback(cb_ssdp *callback)
+{
+ callbacks.push_back(callback);
+ nu::AutoLock auto_lock(services_lock);
+ for (ServiceList::iterator itr=found_services.begin();itr!=found_services.end();itr++)
+ {
+ callback->OnServiceConnected(itr->location, itr->type, itr->usn);
+ }
+}
+
+void SSDPAPI::Internal_UnregisterCallback(cb_ssdp *callback)
+{
+ // TODO: verify that our list actually contains the callback?
+ //callbacks.eraseObject(callback);
+ auto it = std::find(callbacks.begin(), callbacks.end(), callback);
+ if (it != callbacks.end())
+ {
+ callbacks.erase(it);
+ }
+
+ callback->Release(); // release the reference retained on the other thread
+ callback->Release(); // release _our_ reference
+}
+
+nx_thread_return_t SSDPAPI::Internal_Run()
+{
+ addrinfo *addr = 0;
+ jnl_dns_resolve_now("239.255.255.250", 1900, &addr, SOCK_DGRAM);
+ int ret = jnl_udp_create_multicast_listener(&listener, "239.255.255.250", 1900);
+ if (ret != NErr_Success || !addr)
+ return (nx_thread_return_t)ret;
+
+ jnl_httpu_request_t httpu;
+ ret = jnl_httpu_request_create(&httpu);
+ if (ret != NErr_Success)
+ {
+
+ return (nx_thread_return_t)ret;
+ }
+
+ time_t last_notify = 0;
+
+ for (;;)
+ {
+ time_t now = time(0);
+ if ((now - last_notify) > 15)
+ {
+ Internal_Notify(0, addr->ai_addr, (socklen_t)addr->ai_addrlen);
+ if (ret != NErr_Success)
+ {
+ // TODO: ?
+ }
+ last_notify = time(0);
+#if 0
+#if defined(_DEBUG) && defined(_WIN32)
+ FILE *f = fopen("c:/services.txt", "wb");
+ if (f)
+ {
+ for (ServiceList::iterator itr=found_services.begin();itr!=found_services.end();itr++)
+ {
+
+ fprintf(f, "-----\r\n");
+ fprintf(f, "ST: %s\r\n", AutoCharPrintfUTF8(itr->type));
+ fprintf(f, "Location: %s\r\n", AutoCharPrintfUTF8(itr->location));
+ fprintf(f, "USN: %s\r\n", AutoCharPrintfUTF8(itr->usn));
+ }
+ fclose(f);
+ }
+#elif defined(__ANDROID__)
+ for (ServiceList::iterator itr=found_services.begin();itr!=found_services.end();itr++)
+ {
+
+ __android_log_print(ANDROID_LOG_INFO, "libreplicant", "-----\r\n");
+ __android_log_print(ANDROID_LOG_INFO, "libreplicant", "ST: %s\r\n", AutoCharPrintfUTF8(itr->type));
+ __android_log_print(ANDROID_LOG_INFO, "libreplicant", "Location: %s\r\n", AutoCharPrintfUTF8(itr->location));
+ __android_log_print(ANDROID_LOG_INFO, "libreplicant", "USN: %s\r\n", AutoCharPrintfUTF8(itr->usn));
+ }
+#endif
+#endif
+ }
+
+ thread_loop.Step(100);
+
+ for (;;)
+ {
+ size_t bytes_received=0;
+
+ jnl_udp_run(listener, 0, 8192, 0, &bytes_received);
+ if (bytes_received)
+ {
+ jnl_httpu_request_process(httpu, listener);
+ const char *method = jnl_httpu_request_get_method(httpu);
+ if (method)
+ {
+ if (!strcmp(method, "NOTIFY"))
+ {
+
+ unsigned int max_age=0;
+ const char *cache_control = jnl_httpu_request_get_header(httpu, "cache-control");
+ if (cache_control)
+ {
+ if (strncasecmp(cache_control, "max-age=", 8) == 0)
+ {
+ max_age = strtoul(cache_control+8, 0, 10);
+ }
+ }
+ const char *location = jnl_httpu_request_get_header(httpu, "location");
+ const char *nt = jnl_httpu_request_get_header(httpu, "nt");
+ const char *nts = jnl_httpu_request_get_header(httpu, "nts");
+ const char *usn = jnl_httpu_request_get_header(httpu, "usn");
+
+ // a hack to work with older android wifi sync protocol
+ if (!usn)
+ usn = jnl_httpu_request_get_header(httpu, "id");
+ if (usn && nt && location && nts && !strcmp(nts, "ssdp:alive"))
+ {
+ Service *service = 0;
+ int ret = FindUSN(found_services, usn, service);
+ if (ret == NErr_Success) // found an existing one
+ {
+ // update the last seen time and expiration date
+ // TODO: should we double check that the location didn't change?
+ bool changed=false;
+ ReferenceCountedNXString old_location;
+
+ if (service->location)
+ NXURIGetNXString(&old_location, service->location);
+ if (!service->location || NXStringKeywordCompareWithCString(old_location, location))
+ {
+ NXURIRelease(service->location);
+ NXURICreateWithUTF8(&service->location, location);
+ changed=true;
+ }
+
+ service->last_seen = time(0);
+ if (max_age)
+ service->expiry = service->last_seen + max_age;
+ else
+ service->expiry = (time_t)-1;
+
+ if (changed)
+ {
+ // notify clients
+ for (CallbackList::iterator itr=callbacks.begin();itr!=callbacks.end();itr++)
+ {
+ (*itr)->OnServiceDisconnected(service->usn);
+ (*itr)->OnServiceConnected(service->location, service->type, service->usn);
+ }
+ }
+ }
+ else if (ret == NErr_Empty) // new one
+ {
+ NXURICreateWithUTF8(&service->location, location);
+ NXStringCreateWithUTF8(&service->type, nt);
+ service->last_seen = time(0);
+ if (max_age)
+ service->expiry = service->last_seen + max_age;
+ else
+ service->expiry = (time_t)-1;
+
+ // notify clients
+ for (CallbackList::iterator itr=callbacks.begin();itr!=callbacks.end();itr++)
+ {
+ (*itr)->OnServiceConnected(service->location, service->type, service->usn);
+ }
+ }
+ }
+ }
+ else if (!strcmp(method, "M-SEARCH"))
+ {
+ sockaddr *addr; socklen_t addr_length;
+ jnl_udp_get_address(listener, &addr, &addr_length);
+ const char *st = jnl_httpu_request_get_header(httpu, "st");
+ Internal_Notify(st, addr, addr_length);
+ }
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ // check for expirations
+again:
+ nu::AutoLock auto_lock(services_lock);
+ for (ServiceList::iterator itr=found_services.begin();itr!=found_services.end();itr++)
+ {
+ if (itr->expiry < now)
+ {
+ for (CallbackList::iterator itr2=callbacks.begin();itr2!=callbacks.end();itr2++)
+ {
+ (*itr2)->OnServiceDisconnected(itr->usn);
+ }
+
+ NXURIRelease(itr->location);
+ NXStringRelease(itr->usn);
+ NXStringRelease(itr->type);
+ found_services.erase(itr);
+ goto again;
+ }
+ }
+
+ }
+
+ return 0;
+}
+
+static char notify_request[] = "NOTIFY * HTTP/1.1\r\n";
+static char notify_host[] = "HOST: 239.255.255.250:1900\r\n";
+static char notify_cache_control[] = "CACHE-CONTROL:max-age=600\r\n";
+static char notify_nts[] = "NTS:ssdp:alive\r\n";
+
+static char search_request[] = "NOTIFY * HTTP/1.1\r\n";
+static char search_man[] = "MAN:\"ssdp:discover\"\r\n";
+
+ns_error_t SSDPAPI::Internal_Notify(const char *st, sockaddr *addr, socklen_t addr_length)
+{
+ jnl_udp_set_peer_address(listener, addr, addr_length);
+ nu::AutoLock auto_lock(services_lock);
+ for (ServiceList::iterator itr=services.begin();itr!=services.end();itr++)
+ {
+ if (st && NXStringKeywordCompareWithCString(itr->type, st))
+ continue;
+
+ jnl_udp_send(listener, notify_request, strlen(notify_request));
+ jnl_udp_send(listener, notify_host, strlen(notify_host));
+ jnl_udp_send(listener, notify_cache_control, strlen(notify_cache_control));
+ jnl_udp_send(listener, notify_nts, strlen(notify_nts));
+ char header[512] = {0};
+ snprintf(header, 511, "LOCATION:%s\r\n", AutoCharPrintfUTF8(itr->location));
+ header[511]=0;
+ jnl_udp_send(listener, header, strlen(header));
+ if (itr->usn)
+ {
+ snprintf(header, 511, "USN:%s\r\n", AutoCharPrintfUTF8(itr->usn));
+ header[511]=0;
+ jnl_udp_send(listener, header, strlen(header));
+ }
+ if (itr->type)
+ {
+ snprintf(header, 511, "NT:%s\r\n", AutoCharPrintfUTF8(itr->type));
+ header[511]=0;
+ jnl_udp_send(listener, header, strlen(header));
+ }
+ if (user_agent)
+ {
+ snprintf(header, 511, "SERVER:%s\r\n",user_agent);
+ header[511]=0;
+ jnl_udp_send(listener, header, strlen(header));
+ }
+ jnl_udp_send(listener, "\r\n", 2);
+
+ size_t bytes_sent=0;
+ do
+ {
+ jnl_udp_run(listener, 8192, 0, &bytes_sent, 0); // TODO: error check
+ if (bytes_sent == 0)
+ NXSleep(100);
+ } while (bytes_sent == 0);
+ }
+ return NErr_Success;
+}
+
+void SSDPAPI::Internal_Search(nx_string_t st)
+{
+ addrinfo *addr;
+ jnl_dns_resolve_now("239.255.255.250", 1900, &addr, SOCK_DGRAM);
+ jnl_udp_set_peer_address(listener, addr->ai_addr, (socklen_t)addr->ai_addrlen);
+ jnl_udp_send(listener, notify_request, strlen(notify_request));
+
+ jnl_udp_send(listener, search_request, strlen(search_request));
+ jnl_udp_send(listener, notify_host, strlen(notify_host));
+ jnl_udp_send(listener, search_man, strlen(search_man));
+ char header[512] = {0};
+ sprintf(header, "ST:%s\r\n", AutoCharPrintfUTF8(st));
+ header[511]=0;
+ jnl_udp_send(listener, header, strlen(header));
+ size_t bytes_sent=0;
+ do
+ {
+ jnl_udp_run(listener, 8192, 0, &bytes_sent, 0); // TODO: error check
+ if (bytes_sent == 0)
+ NXSleep(100);
+ } while (bytes_sent == 0);
+}
diff --git a/Src/replicant/ssdp/SSDPAPI.h b/Src/replicant/ssdp/SSDPAPI.h
new file mode 100644
index 00000000..d4d37f13
--- /dev/null
+++ b/Src/replicant/ssdp/SSDPAPI.h
@@ -0,0 +1,61 @@
+#pragma once
+#include "nx/nxstring.h"
+#include "nx/nxuri.h"
+#include <vector>
+#include "nu/AutoLock.h"
+#include "nx/nxthread.h"
+#include "foundation/error.h"
+#include "jnetlib/jnetlib.h"
+#include "cb_ssdp.h"
+#include "nu/ThreadLoop.h"
+#include "api_ssdp.h"
+#include "nswasabi/ServiceName.h"
+
+class SSDPAPI : public api_ssdp
+{
+public:
+ SSDPAPI();
+ ~SSDPAPI();
+ WASABI_SERVICE_NAME("SSDP API");
+ int Initialize();
+
+ int WASABICALL SSDP_RegisterService(nx_uri_t location, nx_string_t st, nx_string_t usn);
+ int WASABICALL SSDP_RegisterCallback(cb_ssdp *callback);
+ int WASABICALL SSDP_UnregisterCallback(cb_ssdp *callback);
+ int WASABICALL SSDP_Search(nx_string_t st);
+private:
+ struct Service
+ {
+ nx_uri_t location;
+ nx_string_t type;
+ nx_string_t usn;
+ time_t last_seen;
+ time_t expiry;
+ };
+
+ // TODO: map it off of USN
+ typedef std::vector<Service> ServiceList;
+ typedef std::vector<cb_ssdp*> CallbackList;
+ nx_thread_return_t Internal_Run();
+ ns_error_t Internal_Notify(const char *st, sockaddr *addr, socklen_t length);
+ void Internal_RegisterCallback(cb_ssdp *callback);
+ void Internal_UnregisterCallback(cb_ssdp *callback);
+ void Internal_Search(nx_string_t st);
+ static nx_thread_return_t NXTHREADCALL SSDPThread(nx_thread_parameter_t parameter);
+ int FindUSN(ServiceList &service_list, const char *usn, Service *&service);
+
+ ThreadLoop thread_loop;
+ CallbackList callbacks;
+ ServiceList services;
+ ServiceList found_services;
+ nu::LockGuard services_lock;
+ nx_thread_t ssdp_thread;
+ jnl_udp_t listener;
+ const char *user_agent;
+
+
+
+ static void APC_RegisterCallback(void *_this, void *_callback, double) { ((SSDPAPI *)_this)->Internal_RegisterCallback((cb_ssdp *)_callback); }
+ static void APC_UnregisterCallback(void *_this, void *_callback, double) { ((SSDPAPI *)_this)->Internal_UnregisterCallback((cb_ssdp *)_callback); }
+ static void APC_Search(void *_this, void *st, double) { ((SSDPAPI *)_this)->Internal_Search((nx_string_t)st); }
+};
diff --git a/Src/replicant/ssdp/api__ssdp.h b/Src/replicant/ssdp/api__ssdp.h
new file mode 100644
index 00000000..a3b1568d
--- /dev/null
+++ b/Src/replicant/ssdp/api__ssdp.h
@@ -0,0 +1,20 @@
+#pragma once
+#include <stdio.h>
+#include <stdlib.h>
+#include <foundation/types.h>
+
+#include "service/api_service.h"
+extern api_service *serviceManager;
+#define WASABI2_API_SVC serviceManager
+
+#include "application/api_application.h"
+extern api_application *applicationApi;
+#define WASABI2_API_APP applicationApi
+
+#include "syscb/api_syscb.h"
+extern api_syscb *syscbApi;
+#define WASABI2_API_SYSCB syscbApi
+
+//#include "application/api_android.h"
+//extern api_android *androidApi;
+//#define WASABI2_API_ANDROID androidApi
diff --git a/Src/replicant/ssdp/api_ssdp.h b/Src/replicant/ssdp/api_ssdp.h
new file mode 100644
index 00000000..adf25ea4
--- /dev/null
+++ b/Src/replicant/ssdp/api_ssdp.h
@@ -0,0 +1,32 @@
+#pragma once
+#include "service/types.h"
+#include "nx/nxuri.h"
+#include "nx/nxstring.h"
+#include "cb_ssdp.h"
+
+// {A2EF43B6-5044-4D44-AE38-71C2CE20587B}
+static const GUID ssdp_api_service_guid =
+{ 0xa2ef43b6, 0x5044, 0x4d44, { 0xae, 0x38, 0x71, 0xc2, 0xce, 0x20, 0x58, 0x7b } };
+
+class api_ssdp : public Wasabi2::Dispatchable
+{
+protected:
+ api_ssdp() : Wasabi2::Dispatchable(DISPATCHABLE_VERSION) {}
+ ~api_ssdp() {}
+public:
+ static GUID GetServiceType() { return SVC_TYPE_UNIQUE; }
+ static GUID GetServiceGUID() { return ssdp_api_service_guid; }
+ int RegisterService(nx_uri_t location, nx_string_t st, nx_string_t usn) { return SSDP_RegisterService(location, st, usn); }
+ int RegisterCallback(cb_ssdp *callback) { return SSDP_RegisterCallback(callback); }
+ int UnregisterCallback(cb_ssdp *callback) { return SSDP_UnregisterCallback(callback); }
+ int Search(nx_string_t st) { return SSDP_Search(st); }
+private:
+ virtual int WASABICALL SSDP_RegisterService(nx_uri_t location, nx_string_t st, nx_string_t usn)=0;
+ virtual int WASABICALL SSDP_RegisterCallback(cb_ssdp *callback)=0;
+ virtual int WASABICALL SSDP_UnregisterCallback(cb_ssdp *callback)=0;
+ virtual int WASABICALL SSDP_Search(nx_string_t st)=0;
+ enum
+ {
+ DISPATCHABLE_VERSION=0,
+ };
+}; \ No newline at end of file
diff --git a/Src/replicant/ssdp/cb_ssdp.h b/Src/replicant/ssdp/cb_ssdp.h
new file mode 100644
index 00000000..75e24978
--- /dev/null
+++ b/Src/replicant/ssdp/cb_ssdp.h
@@ -0,0 +1,21 @@
+#pragma once
+#include "foundation/dispatch.h"
+
+class cb_ssdp : public Wasabi2::Dispatchable
+{
+protected:
+ cb_ssdp() : Wasabi2::Dispatchable(DISPATCHABLE_VERSION) {}
+ ~cb_ssdp() {}
+
+public:
+ void OnServiceConnected(nx_uri_t location, nx_string_t type, nx_string_t usn) { return SSDPCallback_OnServiceConnected(location, type, usn); }
+ void OnServiceDisconnected(nx_string_t usn) { return SSDPCallback_OnServiceDisconnected(usn); }
+
+ enum
+ {
+ DISPATCHABLE_VERSION=0,
+ };
+private:
+ virtual void WASABICALL SSDPCallback_OnServiceConnected(nx_uri_t location, nx_string_t type, nx_string_t usn)=0;
+ virtual void WASABICALL SSDPCallback_OnServiceDisconnected(nx_string_t usn)=0;
+}; \ No newline at end of file
diff --git a/Src/replicant/ssdp/main.cpp b/Src/replicant/ssdp/main.cpp
new file mode 100644
index 00000000..e3d2ff67
--- /dev/null
+++ b/Src/replicant/ssdp/main.cpp
@@ -0,0 +1,88 @@
+#include "api__ssdp.h"
+#include "foundation/export.h"
+#include "component/ifc_component.h"
+#include "nx/nxuri.h"
+#include "nswasabi/ReferenceCounted.h"
+#include "nswasabi/singleton.h"
+#include "SSDPAPI.h"
+
+api_service *WASABI2_API_SVC=0;
+api_application *WASABI2_API_APP=0;
+api_syscb *WASABI2_API_SYSCB=0;
+//api_android *WASABI2_API_ANDROID=0;
+
+SSDPAPI ssdpapi;
+static SingletonServiceFactory<SSDPAPI, api_ssdp> ssdp_factory;
+
+
+// {F47F99AB-F90F-4623-B8BE-454555A8FC79}
+static const GUID ssdp_component_guid =
+{ 0xf47f99ab, 0xf90f, 0x4623, { 0xb8, 0xbe, 0x45, 0x45, 0x55, 0xa8, 0xfc, 0x79 } };
+
+
+class SSDPComponent : public ifc_component
+{
+public:
+ SSDPComponent() : ifc_component(ssdp_component_guid) {}
+ int WASABICALL Component_Initialize(api_service *service);
+ int WASABICALL Component_RegisterServices(api_service *service);
+ void WASABICALL Component_DeregisterServices(api_service *service);
+ int WASABICALL Component_Quit(api_service *service);
+};
+
+
+int SSDPComponent::Component_Initialize(api_service *service)
+{
+ WASABI2_API_SVC = service;
+
+ int ret = jnl_init();
+ if (ret != NErr_Success)
+ {
+ return ret;
+ }
+ return NErr_Success;
+}
+
+int SSDPComponent::Component_RegisterServices(api_service *service)
+{
+ WASABI2_API_SVC = service;
+ if (WASABI2_API_SVC)
+ {
+ WASABI2_API_SVC->GetService(&WASABI2_API_APP);
+ WASABI2_API_SVC->GetService(&WASABI2_API_SYSCB);
+ //WASABI2_API_SVC->GetService(&WASABI2_API_ANDROID);
+ }
+
+ ssdpapi.Initialize();
+ ssdp_factory.Register(WASABI2_API_SVC, &ssdpapi);
+ return NErr_Success;
+}
+
+void SSDPComponent::Component_DeregisterServices(api_service *service)
+{
+ if (WASABI2_API_SVC)
+ WASABI2_API_SVC->Release();
+
+ if (WASABI2_API_APP)
+ WASABI2_API_APP->Release();
+
+ if (WASABI2_API_SYSCB)
+ WASABI2_API_SYSCB->Release();
+
+ //if (WASABI2_API_ANDROID)
+ // WASABI2_API_ANDROID->Release();
+
+ ssdp_factory.Deregister(WASABI2_API_SVC);
+}
+
+int SSDPComponent::Component_Quit(api_service *_service_manager)
+{
+ jnl_quit();
+ return NErr_Success;
+}
+
+static SSDPComponent component;
+extern "C" DLLEXPORT ifc_component *GetWasabi2Component()
+{
+ return &component;
+}
diff --git a/Src/replicant/ssdp/main.h b/Src/replicant/ssdp/main.h
new file mode 100644
index 00000000..6f70f09b
--- /dev/null
+++ b/Src/replicant/ssdp/main.h
@@ -0,0 +1 @@
+#pragma once
diff --git a/Src/replicant/ssdp/resource.h b/Src/replicant/ssdp/resource.h
new file mode 100644
index 00000000..96878ea2
--- /dev/null
+++ b/Src/replicant/ssdp/resource.h
@@ -0,0 +1,14 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by ssdp.rc
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 101
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/Src/replicant/ssdp/ssdp.rc b/Src/replicant/ssdp/ssdp.rc
new file mode 100644
index 00000000..fcff7711
--- /dev/null
+++ b/Src/replicant/ssdp/ssdp.rc
@@ -0,0 +1,76 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.K.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "#include ""version.rc2""\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // English (U.K.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+#include "version.rc2"
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/Src/replicant/ssdp/ssdp.vcxproj b/Src/replicant/ssdp/ssdp.vcxproj
new file mode 100644
index 00000000..1c55a8dc
--- /dev/null
+++ b/Src/replicant/ssdp/ssdp.vcxproj
@@ -0,0 +1,302 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <VCProjectVersion>17.0</VCProjectVersion>
+ <ProjectGuid>{05DA3583-A0EC-4BD3-AF29-9703289F033C}</ProjectGuid>
+ <RootNamespace>ssdp</RootNamespace>
+ <Keyword>Win32Proj</Keyword>
+ <WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>17.0.32203.90</_ProjectFileVersion>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ <LinkIncremental>false</LinkIncremental>
+ <IncludePath>$(IncludePath)</IncludePath>
+ <LibraryPath>$(LibraryPath)</LibraryPath>
+ <TargetExt>.w6c</TargetExt>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ <LinkIncremental>false</LinkIncremental>
+ <GenerateManifest>false</GenerateManifest>
+ <IncludePath>$(IncludePath)</IncludePath>
+ <LibraryPath>$(LibraryPath)</LibraryPath>
+ <TargetExt>.w6c</TargetExt>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ <LinkIncremental>false</LinkIncremental>
+ <TargetExt>.w6c</TargetExt>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ <LinkIncremental>false</LinkIncremental>
+ <GenerateManifest>false</GenerateManifest>
+ <TargetExt>.w6c</TargetExt>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg">
+ <VcpkgEnableManifest>false</VcpkgEnableManifest>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgConfiguration>Debug</VcpkgConfiguration>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ <VcpkgConfiguration>Debug</VcpkgConfiguration>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_UNICODE;UNICODE;WIN32;_DEBUG;_WINDOWS;_USRDLL;SSDP_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>false</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <PrecompiledHeader />
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ </ClCompile>
+ <Link>
+ <OutputFile>$(OutDir)$(ProjectName)$(TargetExt)</OutputFile>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <SubSystem>Windows</SubSystem>
+ <ImportLibrary>$(IntDir)$(ProjectName).lib</ImportLibrary>
+ <TargetMachine>MachineX86</TargetMachine>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Components\
+xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Components\</Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <Optimization>MinSpace</Optimization>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_UNICODE;UNICODE;WIN32;NDEBUG;_WINDOWS;_USRDLL;SSDP_EXPORTS;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <BufferSecurityCheck>true</BufferSecurityCheck>
+ <PrecompiledHeader />
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>None</DebugInformationFormat>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ </ClCompile>
+ <Link>
+ <OutputFile>$(OutDir)$(ProjectName)$(TargetExt)</OutputFile>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <SubSystem>Windows</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(IntDir)$(ProjectName).lib</ImportLibrary>
+ <TargetMachine>MachineX86</TargetMachine>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <IgnoreSpecificDefaultLibraries>
+ </IgnoreSpecificDefaultLibraries>
+ <IgnoreAllDefaultLibraries>
+ </IgnoreAllDefaultLibraries>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Components\</Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Midl>
+ <TargetEnvironment>X64</TargetEnvironment>
+ </Midl>
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_UNICODE;UNICODE;WIN32;WIN64;_DEBUG;_WINDOWS;_USRDLL;SSDP_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>false</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <PrecompiledHeader />
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ </ClCompile>
+ <Link>
+ <OutputFile>$(OutDir)$(ProjectName)$(TargetExt)</OutputFile>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <SubSystem>Windows</SubSystem>
+ <ImportLibrary>$(IntDir)$(ProjectName).lib</ImportLibrary>
+ <TargetMachine>MachineX64</TargetMachine>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Components\
+xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Components\</Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Midl>
+ <TargetEnvironment>X64</TargetEnvironment>
+ </Midl>
+ <ClCompile>
+ <Optimization>MinSpace</Optimization>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_UNICODE;UNICODE;WIN32;WIN64;NDEBUG;_WINDOWS;_USRDLL;SSDP_EXPORTS;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <BufferSecurityCheck>true</BufferSecurityCheck>
+ <PrecompiledHeader />
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>None</DebugInformationFormat>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ </ClCompile>
+ <Link>
+ <OutputFile>$(OutDir)$(ProjectName)$(TargetExt)</OutputFile>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <SubSystem>Windows</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(IntDir)$(ProjectName).lib</ImportLibrary>
+ <TargetMachine>MachineX64</TargetMachine>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <IgnoreSpecificDefaultLibraries>
+ </IgnoreSpecificDefaultLibraries>
+ <IgnoreAllDefaultLibraries>
+ </IgnoreAllDefaultLibraries>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Components\</Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\jnetlib\jnetlib.vcxproj">
+ <Project>{e105a0a2-7391-47c5-86ac-718003524c3d}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\nu\nu.vcxproj">
+ <Project>{f1f5cd60-0d5b-4cea-9eeb-2f87ff9aa915}</Project>
+ <CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
+ <ReferenceOutputAssembly>true</ReferenceOutputAssembly>
+ </ProjectReference>
+ <ProjectReference Include="..\nx\nx.vcxproj">
+ <Project>{57c90706-b25d-4aca-9b33-95cdb2427c27}</Project>
+ <CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
+ <ReferenceOutputAssembly>true</ReferenceOutputAssembly>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="main.cpp" />
+ <ClCompile Include="SSDPAPI.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="api__ssdp.h" />
+ <ClInclude Include="api_ssdp.h" />
+ <ClInclude Include="cb_ssdp.h" />
+ <ClInclude Include="main.h" />
+ <ClInclude Include="resource.h" />
+ <ClInclude Include="SSDPAPI.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="ssdp.rc" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/Src/replicant/ssdp/ssdp.vcxproj.filters b/Src/replicant/ssdp/ssdp.vcxproj.filters
new file mode 100644
index 00000000..dea8193a
--- /dev/null
+++ b/Src/replicant/ssdp/ssdp.vcxproj.filters
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{82598013-881a-4b89-82bf-dc514bcc744a}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="main.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="SSDPAPI.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="api__ssdp.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="api_ssdp.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="cb_ssdp.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="main.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="SSDPAPI.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="resource.h">
+ <Filter>Resource Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="ssdp.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/Src/replicant/ssdp/version.rc2 b/Src/replicant/ssdp/version.rc2
new file mode 100644
index 00000000..59f23d28
--- /dev/null
+++ b/Src/replicant/ssdp/version.rc2
@@ -0,0 +1,39 @@
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+#include "../../Winamp/buildType.h"
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION WINAMP_PRODUCTVER
+ PRODUCTVERSION WINAMP_PRODUCTVER
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "Winamp SA"
+ VALUE "FileDescription", "Winamp 5.x Replicant Component"
+ VALUE "FileVersion", STR_WINAMP_PRODUCTVER
+ VALUE "InternalName", "ssdp.w6c"
+ VALUE "LegalCopyright", "Copyright © 2012-2014 Winamp SA"
+ VALUE "LegalTrademarks", "Nullsoft and Winamp are trademarks of Winamp SA"
+ VALUE "OriginalFilename", "ssdp.w6c"
+ VALUE "ProductName", "Winamp SSDP API Service"
+ VALUE "ProductVersion", STR_WINAMP_PRODUCTVER
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END