You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@celix.apache.org by pn...@apache.org on 2017/11/21 20:08:08 UTC

[11/19] celix git commit: CELIX-417: Refactor for CMake usage in RSA, PSA and Docker. mostly trying to identify the api and common libraries

http://git-wip-us.apache.org/repos/asf/celix/blob/2a670f26/remote_services/discovery_common/src/desc.xml
----------------------------------------------------------------------
diff --git a/remote_services/discovery_common/src/desc.xml b/remote_services/discovery_common/src/desc.xml
new file mode 100644
index 0000000..5998992
--- /dev/null
+++ b/remote_services/discovery_common/src/desc.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements.  See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership.  The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ -->
+<endpoint-descriptions xmlns="http://www.osgi.org/xmlns/rsa/v1.0.0">
+	<endpoint-description>
+		<property name="service.intents">
+			<list>
+				<value>SOAP</value>
+				<value>HTTP</value>
+			</list>
+		</property>
+		<property name="endpoint.id" value="http://ws.acme.com:9000/hello" />
+		<property name="objectClass" value="com.acme.Foo" />
+		<property name="endpoint.package.version.com.acme" value="4.2" />
+		<property name="service.imported.configs" value="com.acme" />
+		<property name="com.acme.ws.xml">
+			<xml>
+				<config xmlns="http://acme.com/defs">
+					<port>1029</port>
+					<host>www.acme.com</host>
+				</config>
+			</xml>
+		</property>
+	</endpoint-description>
+</endpoint-descriptions>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/celix/blob/2a670f26/remote_services/discovery_common/src/discovery.c
----------------------------------------------------------------------
diff --git a/remote_services/discovery_common/src/discovery.c b/remote_services/discovery_common/src/discovery.c
new file mode 100644
index 0000000..d124c15
--- /dev/null
+++ b/remote_services/discovery_common/src/discovery.c
@@ -0,0 +1,234 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*
+ * discovery.c
+ *
+ * \date        Aug 8, 2014
+ * \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ * \copyright	Apache License, Version 2.0
+ */
+#include <stdio.h>
+#include <stdbool.h>
+#include <netdb.h>
+#include <string.h>
+
+#include "celix_threads.h"
+#include "bundle_context.h"
+#include "log_helper.h"
+#include "discovery.h"
+#include "endpoint_discovery_server.h"
+#include "discovery_impl.h" //TODO rename impl
+
+
+celix_status_t discovery_endpointAdded(void *handle, endpoint_description_pt endpoint, char *matchedFilter) {
+	celix_status_t status;
+	discovery_pt discovery = handle;
+
+	logHelper_log(discovery->loghelper, OSGI_LOGSERVICE_INFO, "Endpoint for %s, with filter \"%s\" added...", endpoint->service, matchedFilter);
+
+	status = endpointDiscoveryServer_addEndpoint(discovery->server, endpoint);
+
+	return status;
+}
+
+celix_status_t discovery_endpointRemoved(void *handle, endpoint_description_pt endpoint, char *matchedFilter) {
+	celix_status_t status;
+	discovery_pt discovery = handle;
+
+	logHelper_log(discovery->loghelper, OSGI_LOGSERVICE_INFO, "Endpoint for %s, with filter \"%s\" removed...", endpoint->service, matchedFilter);
+
+	status = endpointDiscoveryServer_removeEndpoint(discovery->server, endpoint);
+
+	return status;
+}
+
+celix_status_t discovery_endpointListenerAdding(void* handle, service_reference_pt reference, void** service) {
+	celix_status_t status = CELIX_SUCCESS;
+	discovery_pt discovery = handle;
+
+	bundleContext_getService(discovery->context, reference, service);
+
+	return status;
+}
+
+celix_status_t discovery_endpointListenerAdded(void* handle, service_reference_pt reference, void* service) {
+	celix_status_t status = CELIX_SUCCESS;
+	discovery_pt discovery = handle;
+
+	const char *discoveryListener = NULL;
+	serviceReference_getProperty(reference, "DISCOVERY", &discoveryListener);
+	const char *scope = NULL;
+	serviceReference_getProperty(reference, OSGI_ENDPOINT_LISTENER_SCOPE, &scope);
+
+	filter_pt filter = filter_create(scope);
+
+	if (discoveryListener != NULL && strcmp(discoveryListener, "true") == 0) {
+		logHelper_log(discovery->loghelper, OSGI_LOGSERVICE_INFO, "EndpointListener Ignored - Discovery listener");
+	} else {
+		celixThreadMutex_lock(&discovery->discoveredServicesMutex);
+
+		hash_map_iterator_pt iter = hashMapIterator_create(discovery->discoveredServices);
+		while (hashMapIterator_hasNext(iter)) {
+			endpoint_description_pt endpoint = hashMapIterator_nextValue(iter);
+
+			bool matchResult = false;
+			filter_match(filter, endpoint->properties, &matchResult);
+			if (matchResult) {
+				endpoint_listener_pt listener = service;
+
+				logHelper_log(discovery->loghelper, OSGI_LOGSERVICE_INFO, "EndpointListener Added - Add Scope");
+
+				listener->endpointAdded(listener->handle, endpoint, NULL);
+			}
+		}
+		hashMapIterator_destroy(iter);
+
+		celixThreadMutex_unlock(&discovery->discoveredServicesMutex);
+
+		celixThreadMutex_lock(&discovery->listenerReferencesMutex);
+
+		hashMap_put(discovery->listenerReferences, reference, NULL);
+
+		celixThreadMutex_unlock(&discovery->listenerReferencesMutex);
+	}
+
+	filter_destroy(filter);
+
+	return status;
+}
+
+celix_status_t discovery_endpointListenerModified(void * handle, service_reference_pt reference, void * service) {
+	celix_status_t status;
+
+	status = discovery_endpointListenerRemoved(handle, reference, service);
+	if (status == CELIX_SUCCESS) {
+        status = discovery_endpointListenerAdded(handle, reference, service);
+	}
+
+	return status;
+}
+
+celix_status_t discovery_endpointListenerRemoved(void * handle, service_reference_pt reference, void * service) {
+    celix_status_t status;
+    discovery_pt discovery = handle;
+
+    status = celixThreadMutex_lock(&discovery->listenerReferencesMutex);
+
+    if (status == CELIX_SUCCESS) {
+        if (discovery->listenerReferences != NULL) {
+            if (hashMap_remove(discovery->listenerReferences, reference)) {
+                logHelper_log(discovery->loghelper, OSGI_LOGSERVICE_INFO, "EndpointListener Removed");
+            }
+        }
+
+        status = celixThreadMutex_unlock(&discovery->listenerReferencesMutex);
+    }
+
+	return status;
+}
+
+celix_status_t discovery_informEndpointListeners(discovery_pt discovery, endpoint_description_pt endpoint, bool endpointAdded) {
+	celix_status_t status;
+
+	// Inform listeners of new endpoint
+	status = celixThreadMutex_lock(&discovery->listenerReferencesMutex);
+
+    if (status == CELIX_SUCCESS) {
+        if (discovery->listenerReferences != NULL) {
+            hash_map_iterator_pt iter = hashMapIterator_create(discovery->listenerReferences);
+            while (hashMapIterator_hasNext(iter)) {
+                hash_map_entry_pt entry = hashMapIterator_nextEntry(iter);
+
+                service_reference_pt reference = hashMapEntry_getKey(entry);
+                endpoint_listener_pt listener = NULL;
+
+                const char* scope = NULL;
+                serviceReference_getProperty(reference, OSGI_ENDPOINT_LISTENER_SCOPE, &scope);
+
+                filter_pt filter = filter_create(scope);
+                bool matchResult = false;
+
+                status = filter_match(filter, endpoint->properties, &matchResult);
+                if (status == CELIX_SUCCESS) {
+                    if (matchResult) {
+                        bundleContext_getService(discovery->context, reference, (void **) &listener);
+                        if (endpointAdded) {
+                            logHelper_log(discovery->loghelper, OSGI_LOGSERVICE_INFO, "Adding service (%s)", endpoint->service);
+
+                            listener->endpointAdded(listener->handle, endpoint, (char*)scope);
+                        } else {
+                            logHelper_log(discovery->loghelper, OSGI_LOGSERVICE_INFO, "Removing service (%s)", endpoint->service);
+
+                            listener->endpointRemoved(listener->handle, endpoint, (char*)scope);
+                        }
+                    }
+
+                    filter_destroy(filter);
+                }
+            }
+            hashMapIterator_destroy(iter);
+        }
+
+        status = celixThreadMutex_unlock(&discovery->listenerReferencesMutex);
+    }
+
+	return status;
+}
+
+celix_status_t discovery_addDiscoveredEndpoint(discovery_pt discovery, endpoint_description_pt endpoint) {
+	celix_status_t status;
+
+	status = celixThreadMutex_lock(&discovery->discoveredServicesMutex);
+
+    if (status == CELIX_SUCCESS) {
+        char *endpointId = endpoint->id;
+        bool exists = hashMap_get(discovery->discoveredServices, endpointId) != NULL;
+        if (!exists) {
+            hashMap_put(discovery->discoveredServices, endpointId, endpoint);
+        }
+
+        status = celixThreadMutex_unlock(&discovery->discoveredServicesMutex);
+
+        if (!exists) {
+            // notify our listeners that a new endpoint is available...
+            discovery_informEndpointListeners(discovery, endpoint, true /* addingService */);
+        }
+    }
+
+	return status;
+}
+
+celix_status_t discovery_removeDiscoveredEndpoint(discovery_pt discovery, endpoint_description_pt endpoint) {
+	celix_status_t status;
+
+	status = celixThreadMutex_lock(&discovery->discoveredServicesMutex);
+
+    if (status == CELIX_SUCCESS) {
+        char *endpointId = endpoint->id;
+        void *oldValue = hashMap_remove(discovery->discoveredServices, endpointId);
+
+        status = celixThreadMutex_unlock(&discovery->discoveredServicesMutex);
+
+        if (oldValue) {
+            status = discovery_informEndpointListeners(discovery, endpoint, false /* removeService */);
+        }
+    }
+
+	return status;
+}

http://git-wip-us.apache.org/repos/asf/celix/blob/2a670f26/remote_services/discovery_common/src/discovery_activator.c
----------------------------------------------------------------------
diff --git a/remote_services/discovery_common/src/discovery_activator.c b/remote_services/discovery_common/src/discovery_activator.c
new file mode 100644
index 0000000..3267d25
--- /dev/null
+++ b/remote_services/discovery_common/src/discovery_activator.c
@@ -0,0 +1,186 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*
+ * discovery_activator.c
+ *
+ * \date        Aug 8, 2014
+ * \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ * \copyright	Apache License, Version 2.0
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#include "bundle_activator.h"
+#include "service_tracker.h"
+#include "constants.h"
+
+#include "log_helper.h"
+#include "discovery.h"
+#include "remote_constants.h"
+
+struct activator {
+	bundle_context_pt context;
+	discovery_pt discovery;
+	log_helper_pt loghelper;
+
+	service_tracker_pt endpointListenerTracker;
+	endpoint_listener_pt endpointListener;
+	service_registration_pt endpointListenerService;
+};
+
+celix_status_t bundleActivator_createEPLTracker(struct activator *activator, service_tracker_pt *tracker) {
+	celix_status_t status;
+
+	service_tracker_customizer_pt customizer = NULL;
+
+	status = serviceTrackerCustomizer_create(activator->discovery, discovery_endpointListenerAdding, discovery_endpointListenerAdded, discovery_endpointListenerModified,
+			discovery_endpointListenerRemoved, &customizer);
+
+	if (status == CELIX_SUCCESS) {
+		status = serviceTracker_create(activator->context, (char *) OSGI_ENDPOINT_LISTENER_SERVICE, customizer, tracker);
+	}
+
+	return status;
+}
+
+celix_status_t bundleActivator_create(bundle_context_pt context, void **userData) {
+	celix_status_t status;
+
+	struct activator* activator = calloc(1,sizeof(struct activator));
+	if (!activator) {
+		return CELIX_ENOMEM;
+	}
+
+	status = discovery_create(context, &activator->discovery);
+	if (status == CELIX_SUCCESS) {
+		activator->context = context;
+
+		logHelper_create(context, &activator->loghelper);
+
+		status = bundleActivator_createEPLTracker(activator, &activator->endpointListenerTracker);
+		if(status==CELIX_SUCCESS){
+			*userData = activator;
+		}
+		else{
+			bundleActivator_destroy(activator,context);
+		}
+	}
+	else{
+		free(activator);
+	}
+
+	return status;
+}
+
+celix_status_t bundleActivator_start(void * userData, bundle_context_pt context) {
+	celix_status_t status;
+	struct activator *activator = userData;
+	const char *uuid = NULL;
+
+	logHelper_start(activator->loghelper);
+
+	status = bundleContext_getProperty(context, OSGI_FRAMEWORK_FRAMEWORK_UUID, &uuid);
+	if (!uuid) {
+		logHelper_log(activator->loghelper, OSGI_LOGSERVICE_DEBUG, "no framework UUID defined?!");
+		return CELIX_ILLEGAL_STATE;
+	}
+
+	size_t len = 11 + strlen(OSGI_FRAMEWORK_OBJECTCLASS) + strlen(OSGI_RSA_ENDPOINT_FRAMEWORK_UUID) + strlen(uuid);
+	char *scope = malloc(len + 1);
+	if (!scope) {
+		return CELIX_ENOMEM;
+	}
+
+	sprintf(scope, "(&(%s=*)(%s=%s))", OSGI_FRAMEWORK_OBJECTCLASS, OSGI_RSA_ENDPOINT_FRAMEWORK_UUID, uuid);
+	scope[len] = 0;
+
+	logHelper_log(activator->loghelper, OSGI_LOGSERVICE_DEBUG, "using scope %s.", scope);
+
+	properties_pt props = properties_create();
+	properties_set(props, "DISCOVERY", "true");
+	properties_set(props, (char *) OSGI_ENDPOINT_LISTENER_SCOPE, scope);
+
+	if (status == CELIX_SUCCESS) {
+		status = serviceTracker_open(activator->endpointListenerTracker);
+	}
+
+	if (status == CELIX_SUCCESS) {
+		status = discovery_start(activator->discovery);
+	}
+
+	if (status == CELIX_SUCCESS) {
+		endpoint_listener_pt endpointListener = calloc(1, sizeof(struct endpoint_listener));
+
+		if (endpointListener) {
+			endpointListener->handle = activator->discovery;
+			endpointListener->endpointAdded = discovery_endpointAdded;
+			endpointListener->endpointRemoved = discovery_endpointRemoved;
+
+			status = bundleContext_registerService(context, (char *) OSGI_ENDPOINT_LISTENER_SERVICE, endpointListener, props, &activator->endpointListenerService);
+
+			if (status == CELIX_SUCCESS) {
+				activator->endpointListener = endpointListener;
+			}
+		}
+	}
+	// We can release the scope, as properties_set makes a copy of the key & value...
+	free(scope);
+
+	return status;
+}
+
+celix_status_t bundleActivator_stop(void * userData, bundle_context_pt context) {
+	celix_status_t status;
+	struct activator *activator = userData;
+
+	status = discovery_stop(activator->discovery);
+
+	status = serviceTracker_close(activator->endpointListenerTracker);
+
+	status = serviceRegistration_unregister(activator->endpointListenerService);
+	free(activator->endpointListener);
+
+	logHelper_stop(activator->loghelper);
+
+	return status;
+}
+
+celix_status_t bundleActivator_destroy(void * userData, bundle_context_pt context) {
+	celix_status_t status;
+	struct activator *activator = userData;
+
+	status = serviceTracker_destroy(activator->endpointListenerTracker);
+
+	status = discovery_destroy(activator->discovery);
+
+	logHelper_destroy(&activator->loghelper);
+
+	activator->loghelper = NULL;
+	activator->endpointListenerTracker = NULL;
+	activator->endpointListenerService = NULL;
+	activator->discovery = NULL;
+	activator->context = NULL;
+
+	free(activator);
+
+	return status;
+}

http://git-wip-us.apache.org/repos/asf/celix/blob/2a670f26/remote_services/discovery_common/src/endpoint_descriptor_reader.c
----------------------------------------------------------------------
diff --git a/remote_services/discovery_common/src/endpoint_descriptor_reader.c b/remote_services/discovery_common/src/endpoint_descriptor_reader.c
new file mode 100644
index 0000000..ea176bf
--- /dev/null
+++ b/remote_services/discovery_common/src/endpoint_descriptor_reader.c
@@ -0,0 +1,387 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements.  See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership.  The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+/*
+ * endpoint_descriptor_reader.c
+ *
+ *  \date       24 Jul 2014
+ *  \author     <a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright  Apache License, Version 2.0
+ */
+
+#include <stdbool.h>
+#include <string.h>
+#include <libxml/xmlreader.h>
+
+#include "log_helper.h"
+#include "remote_constants.h"
+
+#include "endpoint_description.h"
+#include "endpoint_descriptor_common.h"
+#include "endpoint_descriptor_reader.h"
+
+struct endpoint_descriptor_reader {
+    xmlTextReaderPtr reader;
+    log_helper_pt* loghelper;
+};
+
+static valueType valueTypeFromString(char *name);
+
+celix_status_t endpointDescriptorReader_create(endpoint_discovery_poller_pt poller, endpoint_descriptor_reader_pt *reader) {
+    celix_status_t status = CELIX_SUCCESS;
+
+    *reader = malloc(sizeof(**reader));
+    if (!*reader) {
+        status = CELIX_ENOMEM;
+    } else {
+        (*reader)->reader = NULL;
+        (*reader)->loghelper = poller->loghelper;
+    }
+
+    return status;
+}
+
+celix_status_t endpointDescriptorReader_destroy(endpoint_descriptor_reader_pt reader) {
+    celix_status_t status = CELIX_SUCCESS;
+
+    reader->loghelper = NULL;
+
+    free(reader);
+
+    return status;
+}
+
+void endpointDescriptorReader_addSingleValuedProperty(properties_pt properties, const xmlChar* name, const xmlChar* value) {
+	properties_set(properties, (char *) name, (char*) value);
+}
+
+void endpointDescriptorReader_addMultiValuedProperty(properties_pt properties, const xmlChar* name, array_list_pt values) {
+	char *value = calloc(256, sizeof(*value));
+	if (value) {
+		unsigned int size = arrayList_size(values);
+        unsigned int i;
+        for (i = 0; i < size; i++) {
+			char* item = (char*) arrayList_get(values, i);
+			if (i > 0) {
+				value = strcat(value, ",");
+			}
+			value = strcat(value, item);
+		}
+
+		properties_set(properties, (char *) name, value);
+
+		free(value);
+	}
+}
+
+celix_status_t endpointDescriptorReader_parseDocument(endpoint_descriptor_reader_pt reader, char *document, array_list_pt *endpoints) {
+    celix_status_t status = CELIX_SUCCESS;
+
+    reader->reader = xmlReaderForMemory(document, (int) strlen(document), NULL, "UTF-8", 0);
+    if (reader->reader == NULL) {
+        status = CELIX_BUNDLE_EXCEPTION;
+    } else {
+        bool inProperty = false;
+        bool inXml = false;
+        bool inArray = false;
+        bool inList = false;
+        bool inSet = false;
+        bool inValue = false;
+
+        const xmlChar *propertyName = NULL;
+        const xmlChar *propertyValue = NULL;
+        valueType propertyType = VALUE_TYPE_STRING;
+        xmlChar *valueBuffer = xmlMalloc(256);
+        valueBuffer[0] = '\0';
+
+        array_list_pt propertyValues = NULL;
+        arrayList_create(&propertyValues);
+
+        array_list_pt endpointDescriptions = NULL;
+        if (*endpoints) {
+        	// use the given arraylist...
+        	endpointDescriptions = *endpoints;
+        } else {
+			arrayList_create(&endpointDescriptions);
+			// return the read endpoints...
+			*endpoints = endpointDescriptions;
+        }
+
+        properties_pt endpointProperties = NULL;
+
+        int read = xmlTextReaderRead(reader->reader);
+        while (read == XML_TEXTREADER_MODE_INTERACTIVE) {
+            int type = xmlTextReaderNodeType(reader->reader);
+
+            if (type == XML_READER_TYPE_ELEMENT) {
+                const xmlChar *localname = xmlTextReaderConstLocalName(reader->reader);
+
+                if (inXml) {
+                    valueBuffer = xmlStrcat(valueBuffer, BAD_CAST "<");
+                    valueBuffer = xmlStrcat(valueBuffer, localname);
+
+                    int i = xmlTextReaderMoveToFirstAttribute(reader->reader);
+                    while (i == 1) {
+                        const xmlChar *name = xmlTextReaderConstName(reader->reader);
+                        const xmlChar *value = xmlTextReaderConstValue(reader->reader);
+
+                        valueBuffer = xmlStrcat(valueBuffer, BAD_CAST " ");
+                        valueBuffer = xmlStrcat(valueBuffer, name);
+                        valueBuffer = xmlStrcat(valueBuffer, BAD_CAST "=\"");
+                        valueBuffer = xmlStrcat(valueBuffer, BAD_CAST value);
+                        valueBuffer = xmlStrcat(valueBuffer, BAD_CAST "\"");
+
+                        i = xmlTextReaderMoveToNextAttribute(reader->reader);
+                    }
+
+                    valueBuffer = xmlStrcat(valueBuffer, BAD_CAST ">");
+                } else if (xmlStrcmp(localname, ENDPOINT_DESCRIPTION) == 0) {
+
+                	if (endpointProperties != NULL)
+                		properties_destroy(endpointProperties);
+
+                    endpointProperties = properties_create();
+                } else if (xmlStrcmp(localname, PROPERTY) == 0) {
+                    inProperty = true;
+
+                    propertyName = xmlTextReaderGetAttribute(reader->reader, NAME);
+                    propertyValue = xmlTextReaderGetAttribute(reader->reader, VALUE);
+                    xmlChar *vtype = xmlTextReaderGetAttribute(reader->reader, VALUE_TYPE);
+                    propertyType = valueTypeFromString((char*) vtype);
+                    arrayList_clear(propertyValues);
+
+                    if (xmlTextReaderIsEmptyElement(reader->reader)) {
+                        inProperty = false;
+
+                        if (propertyValue != NULL) {
+                        	endpointDescriptorReader_addSingleValuedProperty(endpointProperties, propertyName, propertyValue);
+                        }
+
+                        xmlFree((void *) propertyName);
+                        xmlFree((void *) propertyValue);
+                        xmlFree((void *) vtype);
+                    }
+                } else {
+                    valueBuffer[0] = 0;
+                    inArray |= inProperty && xmlStrcmp(localname, ARRAY) == 0;
+                    inList |= inProperty && xmlStrcmp(localname, LIST) == 0;
+                    inSet |= inProperty && xmlStrcmp(localname, SET) == 0;
+                    inXml |= inProperty && xmlStrcmp(localname, XML) == 0;
+                    inValue |= inProperty && xmlStrcmp(localname, VALUE) == 0;
+				}
+			} else if (type == XML_READER_TYPE_END_ELEMENT) {
+				const xmlChar *localname = xmlTextReaderConstLocalName(reader->reader);
+
+                if (inXml) {
+                    if (xmlStrcmp(localname, XML) != 0)  {
+                    	valueBuffer = xmlStrcat(valueBuffer, BAD_CAST "</");
+                    	valueBuffer = xmlStrcat(valueBuffer, localname);
+                    	valueBuffer = xmlStrcat(valueBuffer, BAD_CAST ">");
+                    }
+                    else {
+                        inXml = false;
+                    }
+                } else if (xmlStrcmp(localname, ENDPOINT_DESCRIPTION) == 0) {
+                    endpoint_description_pt endpointDescription = NULL;
+                    // Completely parsed endpoint description, add it to our list of results...
+                    if(endpointDescription_create(endpointProperties, &endpointDescription) == CELIX_SUCCESS){
+			arrayList_add(endpointDescriptions, endpointDescription);
+                    }
+
+                    endpointProperties = properties_create();
+                } else if (xmlStrcmp(localname, PROPERTY) == 0) {
+                    inProperty = false;
+
+                    if (inArray || inList || inSet) {
+						endpointDescriptorReader_addMultiValuedProperty(endpointProperties, propertyName, propertyValues);
+                    }
+                    else if (propertyValue != NULL) {
+                    	if (propertyType != VALUE_TYPE_STRING) {
+                    		logHelper_log(*reader->loghelper, OSGI_LOGSERVICE_WARNING, "ENDPOINT_DESCRIPTOR_READER: Only string support for %s\n", propertyName);
+                    	}
+                    	endpointDescriptorReader_addSingleValuedProperty(endpointProperties, propertyName, propertyValue);
+
+                        xmlFree((void *) propertyValue);
+                    }
+                    else {
+                    	endpointDescriptorReader_addSingleValuedProperty(endpointProperties, propertyName, valueBuffer);
+                    }
+
+                    xmlFree((void *) propertyName);
+					unsigned int k=0;
+					for(;k<arrayList_size(propertyValues);k++){
+						free(arrayList_get(propertyValues,k));
+					}
+                    arrayList_clear(propertyValues);
+
+                    propertyType = VALUE_TYPE_STRING;
+                    inArray = false;
+                    inList = false;
+                    inSet = false;
+                    inXml = false;
+                } else if (xmlStrcmp(localname, VALUE) == 0) {
+                    arrayList_add(propertyValues, strdup((char*) valueBuffer));
+                    valueBuffer[0] = 0;
+                    inValue = false;
+                }
+            } else if (type == XML_READER_TYPE_TEXT) {
+                if (inValue || inXml) {
+                    const xmlChar *value = xmlTextReaderValue(reader->reader);
+                    valueBuffer = xmlStrcat(valueBuffer, value);
+                    xmlFree((void *)value);
+                }
+            }
+
+            read = xmlTextReaderRead(reader->reader);
+        }
+
+		if(endpointProperties!=NULL){
+			properties_destroy(endpointProperties);
+		}
+
+		unsigned int k=0;
+		for(;k<arrayList_size(propertyValues);k++){
+			free(arrayList_get(propertyValues,k));
+		}
+        arrayList_destroy(propertyValues);
+        xmlFree(valueBuffer);
+
+        xmlFreeTextReader(reader->reader);
+    }
+
+    return status;
+}
+
+static valueType valueTypeFromString(char *name) {
+    if (name == NULL || strcmp(name, "") == 0 || strcmp(name, "String") == 0) {
+        return VALUE_TYPE_STRING;
+    } else if (strcmp(name, "long") == 0 || strcmp(name, "Long") == 0) {
+        return VALUE_TYPE_LONG;
+    } else if (strcmp(name, "double") == 0 || strcmp(name, "Double") == 0) {
+        return VALUE_TYPE_DOUBLE;
+    } else if (strcmp(name, "float") == 0 || strcmp(name, "Float") == 0) {
+        return VALUE_TYPE_FLOAT;
+    } else if (strcmp(name, "int") == 0 || strcmp(name, "integer") == 0 || strcmp(name, "Integer") == 0) {
+        return VALUE_TYPE_INTEGER;
+    } else if (strcmp(name, "short") == 0 || strcmp(name, "Short") == 0) {
+        return VALUE_TYPE_SHORT;
+    } else if (strcmp(name, "byte") == 0 || strcmp(name, "Byte") == 0) {
+        return VALUE_TYPE_BYTE;
+    } else if (strcmp(name, "char") == 0 || strcmp(name, "Character") == 0) {
+        return VALUE_TYPE_CHAR;
+    } else if (strcmp(name, "boolean") == 0 || strcmp(name, "Boolean") == 0) {
+        return VALUE_TYPE_BOOLEAN;
+    } else {
+        return VALUE_TYPE_STRING;
+    }
+}
+
+#ifdef RSA_ENDPOINT_TEST_READER
+int main() {
+    array_list_pt list = NULL;
+    endpoint_descriptor_reader_pt reader = NULL;
+
+    char *doc = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+"<endpoint-descriptions xmlns=\"http://www.osgi.org/xmlns/rsa/v1.0.0\">"
+    "<endpoint-description>"
+    	"<property name=\"endpoint.service.id\" value-type=\"long\" value=\"6\"/>"
+		"<property name=\"endpoint.framework.uuid\" value=\"2983D849-93B1-4C2C-AC6D-5BCDA93ACB96\"/>"
+        "<property name=\"service.intents\">"
+            "<list>"
+                "<value>SOAP</value>"
+                "<value>HTTP</value>"
+            "</list>"
+        "</property>"
+        "<property name=\"endpoint.id\" value=\"11111111-1111-1111-1111-111111111111\" />"
+        "<property name=\"objectClass\"><array><value>com.acme.Foo</value></array></property>"
+        "<property name=\"endpoint.package.version.com.acme\" value=\"4.2\" />"
+        "<property name=\"service.imported.configs\" value=\"com.acme\" />"
+    	"<property name=\"service.imported\" value=\"true\"/>"
+        "<property name=\"com.acme.ws.xml\">"
+            "<xml>"
+                "<config xmlns=\"http://acme.com/defs\">"
+                    "<port>1029</port>"
+                    "<host>www.acme.com</host>"
+                "</config>"
+            "</xml>"
+        "</property>"
+    "</endpoint-description>"
+		"<endpoint-description>"
+        	"<property name=\"endpoint.service.id\" value-type=\"long\" value=\"5\"/>"
+    		"<property name=\"endpoint.framework.uuid\" value=\"2983D849-93B1-4C2C-AC6D-5BCDA93ACB96\"/>"
+			"<property name=\"service.intents\">"
+				"<list>"
+					"<value>SOAP</value>"
+					"<value>HTTP</value>"
+				"</list>"
+			"</property>"
+			"<property name=\"endpoint.id\" value=\"22222222-2222-2222-2222-222222222222\" />"
+            "<property name=\"objectClass\"><array><value>com.acme.Bar</value></array></property>"
+			"<property name=\"endpoint.package.version.com.acme\" value=\"4.2\" />"
+			"<property name=\"service.imported.configs\" value=\"com.acme\" />"
+			"<property name=\"com.acme.ws.xml\">"
+				"<xml>"
+					"<config xmlns=\"http://acme.com/defs\">"
+						"<port>1029</port>"
+						"<host>www.acme.com</host>"
+					"</config>"
+				"</xml>"
+			"</property>"
+		"</endpoint-description>"
+	"</endpoint-descriptions>";
+
+	endpointDescriptorReader_create(&reader);
+
+	endpointDescriptorReader_parseDocument(reader, doc, &list);
+
+	int i;
+	for (i = 0; i < arrayList_size(list); i++) {
+		printf("\nEndpoint description #%d:\n", (i+1));
+		endpoint_description_pt edp = arrayList_get(list, i);
+		printf("Id: %s\n", edp->id);
+		printf("Service Id: %lu\n", edp->serviceId);
+		printf("Framework UUID: %s\n", edp->frameworkUUID);
+		printf("Service: %s\n", edp->service);
+
+		properties_pt props = edp->properties;
+		if (props) {
+			printf("Service properties:\n");
+			hash_map_iterator_pt iter = hashMapIterator_create(props);
+			while (hashMapIterator_hasNext(iter)) {
+				hash_map_entry_pt entry = hashMapIterator_nextEntry(iter);
+
+				printf("- %s => '%s'\n", hashMapEntry_getKey(entry), hashMapEntry_getValue(entry));
+			}
+			hashMapIterator_destroy(iter);
+		} else {
+			printf("No service properties...\n");
+		}
+
+
+		endpointDescription_destroy(edp);
+	}
+
+	if (list != NULL) {
+		arrayList_destroy(list);
+	}
+
+	endpointDescriptorReader_destroy(reader);
+
+    return 0;
+}
+#endif

http://git-wip-us.apache.org/repos/asf/celix/blob/2a670f26/remote_services/discovery_common/src/endpoint_descriptor_writer.c
----------------------------------------------------------------------
diff --git a/remote_services/discovery_common/src/endpoint_descriptor_writer.c b/remote_services/discovery_common/src/endpoint_descriptor_writer.c
new file mode 100644
index 0000000..71b07b4
--- /dev/null
+++ b/remote_services/discovery_common/src/endpoint_descriptor_writer.c
@@ -0,0 +1,233 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements.  See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership.  The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+/*
+ * endpoint_descriptor_writer.c
+ *
+ *  \date       26 Jul 2014
+ *  \author     <a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright  Apache License, Version 2.0
+ */
+#include <stdlib.h>
+#include <string.h>
+#include <libxml/xmlwriter.h>
+
+#include "constants.h"
+#include "remote_constants.h"
+
+#include "endpoint_description.h"
+#include "endpoint_descriptor_common.h"
+#include "endpoint_descriptor_writer.h"
+
+struct endpoint_descriptor_writer {
+    xmlBufferPtr buffer;
+    xmlTextWriterPtr writer;
+};
+
+static celix_status_t endpointDescriptorWriter_writeEndpoint(endpoint_descriptor_writer_pt writer, endpoint_description_pt endpoint);
+
+static char* valueTypeToString(valueType type);
+
+celix_status_t endpointDescriptorWriter_create(endpoint_descriptor_writer_pt *writer) {
+    celix_status_t status = CELIX_SUCCESS;
+
+    *writer = malloc(sizeof(**writer));
+    if (!*writer) {
+        status = CELIX_ENOMEM;
+    } else {
+        (*writer)->buffer = xmlBufferCreate();
+        if ((*writer)->buffer == NULL) {
+            status = CELIX_BUNDLE_EXCEPTION;
+        } else {
+            (*writer)->writer = xmlNewTextWriterMemory((*writer)->buffer, 0);
+            if ((*writer)->writer == NULL) {
+                status = CELIX_BUNDLE_EXCEPTION;
+            }
+        }
+    }
+
+    return status;
+}
+
+celix_status_t endpointDescriptorWriter_destroy(endpoint_descriptor_writer_pt writer) {
+    xmlFreeTextWriter(writer->writer);
+    xmlBufferFree(writer->buffer);
+    free(writer);
+    return CELIX_SUCCESS;
+}
+
+celix_status_t endpointDescriptorWriter_writeDocument(endpoint_descriptor_writer_pt writer, array_list_pt endpoints, char **document) {
+    celix_status_t status = CELIX_SUCCESS;
+    int rc;
+
+    rc = xmlTextWriterStartDocument(writer->writer, NULL, "UTF-8", NULL);
+    if (rc < 0) {
+        status = CELIX_BUNDLE_EXCEPTION;
+    } else {
+        rc = xmlTextWriterStartElementNS(writer->writer, NULL, ENDPOINT_DESCRIPTIONS, XMLNS);
+        if (rc < 0) {
+            status = CELIX_BUNDLE_EXCEPTION;
+        } else {
+            unsigned int i;
+            for (i = 0; i < arrayList_size(endpoints); i++) {
+                endpoint_description_pt endpoint = arrayList_get(endpoints, i);
+                status = endpointDescriptorWriter_writeEndpoint(writer, endpoint);
+            }
+            if (status == CELIX_SUCCESS) {
+                rc = xmlTextWriterEndElement(writer->writer);
+                if (rc < 0) {
+                    status = CELIX_BUNDLE_EXCEPTION;
+                } else {
+                    rc = xmlTextWriterEndDocument(writer->writer);
+                    if (rc < 0) {
+                        status = CELIX_BUNDLE_EXCEPTION;
+                    } else {
+                        *document = (char *) writer->buffer->content;
+                    }
+                }
+            }
+        }
+    }
+
+    return status;
+}
+
+static celix_status_t endpointDescriptorWriter_writeArrayValue(xmlTextWriterPtr writer, const xmlChar* value) {
+    xmlTextWriterStartElement(writer, ARRAY);
+    xmlTextWriterStartElement(writer, VALUE);
+    xmlTextWriterWriteString(writer, value);
+    xmlTextWriterEndElement(writer); // value
+    xmlTextWriterEndElement(writer); // array
+
+	return CELIX_SUCCESS;
+}
+
+static celix_status_t endpointDescriptorWriter_writeTypedValue(xmlTextWriterPtr writer, valueType type, const xmlChar* value) {
+	xmlTextWriterWriteAttribute(writer, VALUE_TYPE, (const xmlChar*) valueTypeToString(type));
+	xmlTextWriterWriteAttribute(writer, VALUE, value);
+
+	return CELIX_SUCCESS;
+}
+
+static celix_status_t endpointDescriptorWriter_writeUntypedValue(xmlTextWriterPtr writer, const xmlChar* value) {
+	xmlTextWriterWriteAttribute(writer, VALUE, value);
+
+	return CELIX_SUCCESS;
+}
+
+static celix_status_t endpointDescriptorWriter_writeEndpoint(endpoint_descriptor_writer_pt writer, endpoint_description_pt endpoint) {
+    celix_status_t status = CELIX_SUCCESS;
+
+    if (endpoint == NULL || writer == NULL) {
+        status = CELIX_ILLEGAL_ARGUMENT;
+    } else {
+        xmlTextWriterStartElement(writer->writer, ENDPOINT_DESCRIPTION);
+
+        hash_map_iterator_pt iter = hashMapIterator_create(endpoint->properties);
+        while (hashMapIterator_hasNext(iter)) {
+            hash_map_entry_pt entry = hashMapIterator_nextEntry(iter);
+
+            void* propertyName = hashMapEntry_getKey(entry);
+			const xmlChar* propertyValue = (const xmlChar*) hashMapEntry_getValue(entry);
+
+            xmlTextWriterStartElement(writer->writer, PROPERTY);
+            xmlTextWriterWriteAttribute(writer->writer, NAME, propertyName);
+
+            if (strcmp(OSGI_FRAMEWORK_OBJECTCLASS, (char*) propertyName) == 0) {
+            	// objectClass *must* be represented as array of string values...
+            	endpointDescriptorWriter_writeArrayValue(writer->writer, propertyValue);
+            } else if (strcmp(OSGI_RSA_ENDPOINT_SERVICE_ID, (char*) propertyName) == 0) {
+            	// endpoint.service.id *must* be represented as long value...
+            	endpointDescriptorWriter_writeTypedValue(writer->writer, VALUE_TYPE_LONG, propertyValue);
+            } else {
+            	// represent all other values as plain string values...
+            	endpointDescriptorWriter_writeUntypedValue(writer->writer, propertyValue);
+            }
+
+            xmlTextWriterEndElement(writer->writer);
+        }
+        hashMapIterator_destroy(iter);
+
+        xmlTextWriterEndElement(writer->writer);
+    }
+
+    return status;
+}
+
+
+static char* valueTypeToString(valueType type) {
+	switch (type) {
+		case VALUE_TYPE_BOOLEAN:
+			return "boolean";
+		case VALUE_TYPE_BYTE:
+			return "byte";
+		case VALUE_TYPE_CHAR:
+			return "char";
+		case VALUE_TYPE_DOUBLE:
+			return "double";
+		case VALUE_TYPE_FLOAT:
+			return "float";
+		case VALUE_TYPE_INTEGER:
+			return "int";
+		case VALUE_TYPE_LONG:
+			return "long";
+		case VALUE_TYPE_SHORT:
+			return "short";
+		case VALUE_TYPE_STRING:
+			// FALL-THROUGH!
+		default:
+			return "string";
+	}
+}
+
+#ifdef RSA_ENDPOINT_TEST_WRITER
+int main() {
+    endpoint_descriptor_writer_pt writer = NULL;
+    endpointDescriptorWriter_create(&writer);
+    array_list_pt list = NULL;
+    arrayList_create(&list);
+
+    properties_pt props = properties_create();
+    properties_set(props, "objectClass", "com.acme.Foo");
+    properties_set(props, "endpoint.service.id", "3");
+    properties_set(props, "endpoint.id", "abcdefghijklmnopqrstuvwxyz");
+    properties_set(props, "endpoint.framework.uuid", "2983D849-93B1-4C2C-AC6D-5BCDA93ACB96");
+    endpoint_description_pt epd = NULL;
+    endpointDescription_create(props, &epd);
+    arrayList_add(list, epd);
+
+    properties_pt props2 = properties_create();
+    properties_set(props2, "objectClass", "com.acme.Bar");
+    properties_set(props, "endpoint.service.id", "4");
+    properties_set(props, "endpoint.id", "abcdefghijklmnopqrstuvwxyz");
+    properties_set(props, "endpoint.framework.uuid", "2983D849-93B1-4C2C-AC6D-5BCDA93ACB96");
+    endpoint_description_pt epd2 = NULL;
+    endpointDescription_create(props2, &epd2);
+    arrayList_add(list, epd2);
+
+    char *buffer = NULL;
+    endpointDescriptorWriter_writeDocument(writer, list, &buffer);
+
+    arrayList_destroy(list);
+    endpointDescription_destroy(epd);
+    endpointDescription_destroy(epd2);
+    endpointDescriptorWriter_destroy(writer);
+
+    printf("%s\n", buffer);
+}
+#endif

http://git-wip-us.apache.org/repos/asf/celix/blob/2a670f26/remote_services/discovery_common/src/endpoint_discovery_poller.c
----------------------------------------------------------------------
diff --git a/remote_services/discovery_common/src/endpoint_discovery_poller.c b/remote_services/discovery_common/src/endpoint_discovery_poller.c
new file mode 100644
index 0000000..73fb7ba
--- /dev/null
+++ b/remote_services/discovery_common/src/endpoint_discovery_poller.c
@@ -0,0 +1,403 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*
+ * endpoint_discovery_poller.c
+ *
+ * \date       3 Jul 2014
+ * \author     <a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ * \copyright  Apache License, Version 2.0
+ */
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <curl/curl.h>
+
+#include "bundle_context.h"
+#include "log_helper.h"
+#include "utils.h"
+
+#include "discovery_impl.h"
+
+#include "endpoint_descriptor_reader.h"
+
+
+#define DISCOVERY_POLL_INTERVAL "DISCOVERY_CFG_POLL_INTERVAL"
+#define DEFAULT_POLL_INTERVAL "10"
+
+
+static void *endpointDiscoveryPoller_performPeriodicPoll(void *data);
+celix_status_t endpointDiscoveryPoller_poll(endpoint_discovery_poller_pt poller, char *url, array_list_pt currentEndpoints);
+static celix_status_t endpointDiscoveryPoller_getEndpoints(endpoint_discovery_poller_pt poller, char *url, array_list_pt *updatedEndpoints);
+static celix_status_t endpointDiscoveryPoller_endpointDescriptionEquals(const void *endpointPtr, const void *comparePtr, bool *equals);
+
+/**
+ * Allocates memory and initializes a new endpoint_discovery_poller instance.
+ */
+celix_status_t endpointDiscoveryPoller_create(discovery_pt discovery, bundle_context_pt context, endpoint_discovery_poller_pt *poller) {
+	celix_status_t status;
+
+	*poller = malloc(sizeof(struct endpoint_discovery_poller));
+	if (!*poller) {
+		return CELIX_ENOMEM;
+	}
+
+	(*poller)->loghelper = &discovery->loghelper;
+
+	status = celixThreadMutex_create(&(*poller)->pollerLock, NULL);
+	if (status != CELIX_SUCCESS) {
+		return status;
+	}
+
+	const char* interval = NULL;
+	status = bundleContext_getProperty(context, DISCOVERY_POLL_INTERVAL, &interval);
+	if (!interval) {
+		interval = DEFAULT_POLL_INTERVAL;
+	}
+
+	const char* endpointsProp = NULL;
+	status = bundleContext_getProperty(context, DISCOVERY_POLL_ENDPOINTS, &endpointsProp);
+	if (!endpointsProp) {
+		endpointsProp = DEFAULT_POLL_ENDPOINTS;
+	}
+	// we're going to mutate the string with strtok, so create a copy...
+	char* endpoints = strdup(endpointsProp);
+
+	(*poller)->poll_interval = atoi(interval);
+	(*poller)->discovery = discovery;
+	(*poller)->running = false;
+	(*poller)->entries = hashMap_create(utils_stringHash, NULL, utils_stringEquals, NULL);
+
+	const char* sep = ",";
+	char *save_ptr = NULL;
+	char* tok = strtok_r(endpoints, sep, &save_ptr);
+	while (tok) {
+		endpointDiscoveryPoller_addDiscoveryEndpoint(*poller, utils_stringTrim(tok));
+		tok = strtok_r(NULL, sep, &save_ptr);
+	}
+	// Clean up after ourselves...
+	free(endpoints);
+
+	status = celixThreadMutex_lock(&(*poller)->pollerLock);
+	if (status != CELIX_SUCCESS) {
+		return CELIX_BUNDLE_EXCEPTION;
+	}
+
+	(*poller)->running = true;
+
+	status += celixThread_create(&(*poller)->pollerThread, NULL, endpointDiscoveryPoller_performPeriodicPoll, *poller);
+	status += celixThreadMutex_unlock(&(*poller)->pollerLock);
+
+	if(status != CELIX_SUCCESS){
+		status = CELIX_BUNDLE_EXCEPTION;
+	}
+
+	return status;
+}
+
+/**
+ * Destroys and frees up memory for a given endpoint_discovery_poller struct.
+ */
+celix_status_t endpointDiscoveryPoller_destroy(endpoint_discovery_poller_pt poller) {
+	celix_status_t status;
+
+	poller->running = false;
+
+	celixThread_join(poller->pollerThread, NULL);
+
+	hash_map_iterator_pt iterator = hashMapIterator_create(poller->entries);
+	while (hashMapIterator_hasNext(iterator)) {
+		hash_map_entry_pt entry = hashMapIterator_nextEntry(iterator);
+
+		if ( endpointDiscoveryPoller_removeDiscoveryEndpoint(poller, (char*) hashMapEntry_getKey(entry)) == CELIX_SUCCESS) {
+			hashMapIterator_destroy(iterator);
+			iterator = hashMapIterator_create(poller->entries);
+		}
+	}
+	hashMapIterator_destroy(iterator);
+
+	status = celixThreadMutex_lock(&poller->pollerLock);
+
+	if (status != CELIX_SUCCESS) {
+		return CELIX_BUNDLE_EXCEPTION;
+	}
+
+	hashMap_destroy(poller->entries, true, false);
+
+	status = celixThreadMutex_unlock(&poller->pollerLock);
+
+	poller->loghelper = NULL;
+
+	free(poller);
+
+	return status;
+}
+
+
+celix_status_t endpointDiscoveryPoller_getDiscoveryEndpoints(endpoint_discovery_poller_pt poller, array_list_pt urls) {
+	celixThreadMutex_lock(&(poller)->pollerLock);
+
+	hash_map_iterator_pt iterator = hashMapIterator_create(poller->entries);
+
+	while(hashMapIterator_hasNext(iterator))  {
+		hash_map_entry_pt entry = hashMapIterator_nextEntry(iterator);
+		char* toAdd = strdup((char*) hashMapEntry_getKey(entry));
+		arrayList_add(urls, toAdd);
+	}
+
+	hashMapIterator_destroy(iterator);
+
+	celixThreadMutex_unlock(&(poller)->pollerLock);
+
+	return CELIX_SUCCESS;
+}
+
+/**
+ * Adds a new endpoint URL to the list of polled endpoints.
+ */
+celix_status_t endpointDiscoveryPoller_addDiscoveryEndpoint(endpoint_discovery_poller_pt poller, char *url) {
+	celix_status_t status;
+
+	status = celixThreadMutex_lock(&(poller)->pollerLock);
+	if (status != CELIX_SUCCESS) {
+		return CELIX_BUNDLE_EXCEPTION;
+	}
+
+	// Avoid memory leaks when adding an already existing URL...
+	array_list_pt endpoints = hashMap_get(poller->entries, url);
+	if (endpoints == NULL) {
+		status = arrayList_createWithEquals(endpointDiscoveryPoller_endpointDescriptionEquals, &endpoints);
+
+		if (status == CELIX_SUCCESS) {
+			logHelper_log(*poller->loghelper, OSGI_LOGSERVICE_DEBUG, "ENDPOINT_POLLER: add new discovery endpoint with url %s", url);
+			hashMap_put(poller->entries, strdup(url), endpoints);
+			endpointDiscoveryPoller_poll(poller, url, endpoints);
+		}
+	}
+
+	status = celixThreadMutex_unlock(&poller->pollerLock);
+
+	return status;
+}
+
+/**
+ * Removes an endpoint URL from the list of polled endpoints.
+ */
+celix_status_t endpointDiscoveryPoller_removeDiscoveryEndpoint(endpoint_discovery_poller_pt poller, char *url) {
+	celix_status_t status = CELIX_SUCCESS;
+
+	if (celixThreadMutex_lock(&poller->pollerLock) != CELIX_SUCCESS) {
+		status = CELIX_BUNDLE_EXCEPTION;
+	} else {
+		hash_map_entry_pt entry = hashMap_getEntry(poller->entries, url);
+
+		if (entry == NULL) {
+			logHelper_log(*poller->loghelper, OSGI_LOGSERVICE_DEBUG, "ENDPOINT_POLLER: There was no entry found belonging to url %s - maybe already removed?", url);
+		} else {
+			char* origKey = hashMapEntry_getKey(entry);
+
+			logHelper_log(*poller->loghelper, OSGI_LOGSERVICE_DEBUG, "ENDPOINT_POLLER: remove discovery endpoint with url %s", url);
+
+			array_list_pt entries = hashMap_remove(poller->entries, url);
+
+			if (entries != NULL) {
+				for (unsigned int i = arrayList_size(entries); i > 0; i--) {
+					endpoint_description_pt endpoint = arrayList_get(entries, i - 1);
+					discovery_removeDiscoveredEndpoint(poller->discovery, endpoint);
+					arrayList_remove(entries, i - 1);
+					endpointDescription_destroy(endpoint);
+				}
+				arrayList_destroy(entries);
+			}
+
+			free(origKey);
+		}
+		status = celixThreadMutex_unlock(&poller->pollerLock);
+	}
+
+	return status;
+}
+
+
+
+
+celix_status_t endpointDiscoveryPoller_poll(endpoint_discovery_poller_pt poller, char *url, array_list_pt currentEndpoints) {
+	celix_status_t status;
+	array_list_pt updatedEndpoints = NULL;
+
+	// create an arraylist with a custom equality test to ensure we can find endpoints properly...
+	arrayList_createWithEquals(endpointDiscoveryPoller_endpointDescriptionEquals, &updatedEndpoints);
+	status = endpointDiscoveryPoller_getEndpoints(poller, url, &updatedEndpoints);
+
+	if (status == CELIX_SUCCESS) {
+		if (updatedEndpoints!=NULL) {
+			for (unsigned int i = arrayList_size(currentEndpoints); i > 0; i--) {
+				endpoint_description_pt endpoint = arrayList_get(currentEndpoints, i - 1);
+
+				if (!arrayList_contains(updatedEndpoints, endpoint)) {
+					status = discovery_removeDiscoveredEndpoint(poller->discovery, endpoint);
+					arrayList_remove(currentEndpoints, i - 1);
+					endpointDescription_destroy(endpoint);
+				}
+			}
+
+			for (int i = arrayList_size(updatedEndpoints); i > 0; i--) {
+				endpoint_description_pt endpoint = arrayList_remove(updatedEndpoints, 0);
+
+				if (!arrayList_contains(currentEndpoints, endpoint)) {
+					arrayList_add(currentEndpoints, endpoint);
+					status = discovery_addDiscoveredEndpoint(poller->discovery, endpoint);
+				} else {
+					endpointDescription_destroy(endpoint);
+
+				}
+			}
+		}
+	}
+
+	if(updatedEndpoints!=NULL){
+		arrayList_destroy(updatedEndpoints);
+	}
+
+	return status;
+}
+
+static void *endpointDiscoveryPoller_performPeriodicPoll(void *data) {
+	endpoint_discovery_poller_pt poller = (endpoint_discovery_poller_pt) data;
+
+	useconds_t interval = (useconds_t) (poller->poll_interval * 1000000L);
+
+	while (poller->running) {
+		usleep(interval);
+		celix_status_t status = celixThreadMutex_lock(&poller->pollerLock);
+
+		if (status != CELIX_SUCCESS) {
+			logHelper_log(*poller->loghelper, OSGI_LOGSERVICE_WARNING, "ENDPOINT_POLLER: failed to obtain lock; retrying...");
+		} else {
+			hash_map_iterator_pt iterator = hashMapIterator_create(poller->entries);
+
+			while (hashMapIterator_hasNext(iterator)) {
+				hash_map_entry_pt entry = hashMapIterator_nextEntry(iterator);
+
+				char *url = hashMapEntry_getKey(entry);
+				array_list_pt currentEndpoints = hashMapEntry_getValue(entry);
+
+				endpointDiscoveryPoller_poll(poller, url, currentEndpoints);
+			}
+
+			hashMapIterator_destroy(iterator);
+		}
+
+		status = celixThreadMutex_unlock(&poller->pollerLock);
+		if (status != CELIX_SUCCESS) {
+			logHelper_log(*poller->loghelper, OSGI_LOGSERVICE_WARNING, "ENDPOINT_POLLER: failed to release lock; retrying...");
+		}
+	}
+
+	return NULL;
+}
+
+
+
+struct MemoryStruct {
+	char *memory;
+	size_t size;
+};
+
+static size_t endpointDiscoveryPoller_writeMemory(void *contents, size_t size, size_t nmemb, void *memoryPtr) {
+	size_t realsize = size * nmemb;
+	struct MemoryStruct *mem = (struct MemoryStruct *)memoryPtr;
+
+	mem->memory = realloc(mem->memory, mem->size + realsize + 1);
+	if(mem->memory == NULL) {
+		printf("ENDPOINT_POLLER: not enough memory (realloc returned NULL)!");
+		return 0;
+	}
+
+	memcpy(&(mem->memory[mem->size]), contents, realsize);
+	mem->size += realsize;
+	mem->memory[mem->size] = 0;
+
+	return realsize;
+}
+
+static celix_status_t endpointDiscoveryPoller_getEndpoints(endpoint_discovery_poller_pt poller, char *url, array_list_pt *updatedEndpoints) {
+	celix_status_t status = CELIX_SUCCESS;
+
+
+	CURL *curl = NULL;
+	CURLcode res = CURLE_OK;
+
+	struct MemoryStruct chunk;
+	chunk.memory = malloc(1);
+	chunk.size = 0;
+
+	curl = curl_easy_init();
+	if (!curl) {
+		status = CELIX_ILLEGAL_STATE;
+	} else {
+		curl_easy_setopt(curl, CURLOPT_URL, url);
+		curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
+		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, endpointDiscoveryPoller_writeMemory);
+		curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
+		curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 5L);
+		curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L);
+		res = curl_easy_perform(curl);
+
+		curl_easy_cleanup(curl);
+	}
+
+	// process endpoints file
+	if (res == CURLE_OK) {
+		endpoint_descriptor_reader_pt reader = NULL;
+
+		status = endpointDescriptorReader_create(poller, &reader);
+		if (status == CELIX_SUCCESS) {
+			status = endpointDescriptorReader_parseDocument(reader, chunk.memory, updatedEndpoints);
+		}
+
+		if (reader) {
+			endpointDescriptorReader_destroy(reader);
+		}
+	} else {
+		logHelper_log(*poller->loghelper, OSGI_LOGSERVICE_ERROR, "ENDPOINT_POLLER: unable to read endpoints from %s, reason: %s", url, curl_easy_strerror(res));
+	}
+
+	// clean up endpoints file
+	if (chunk.memory) {
+		free(chunk.memory);
+	}
+
+	return status;
+}
+
+static celix_status_t endpointDiscoveryPoller_endpointDescriptionEquals(const void *endpointPtr, const void *comparePtr, bool *equals) {
+	endpoint_description_pt endpoint = (endpoint_description_pt) endpointPtr;
+	endpoint_description_pt compare = (endpoint_description_pt) comparePtr;
+
+	if (strcmp(endpoint->id, compare->id) == 0) {
+		*equals = true;
+	} else {
+		*equals = false;
+	}
+
+	return CELIX_SUCCESS;
+}

http://git-wip-us.apache.org/repos/asf/celix/blob/2a670f26/remote_services/discovery_common/src/endpoint_discovery_server.c
----------------------------------------------------------------------
diff --git a/remote_services/discovery_common/src/endpoint_discovery_server.c b/remote_services/discovery_common/src/endpoint_discovery_server.c
new file mode 100644
index 0000000..f5f82af
--- /dev/null
+++ b/remote_services/discovery_common/src/endpoint_discovery_server.c
@@ -0,0 +1,450 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*
+ * endpoint_discovery_server.c
+ *
+ * \date		Aug 12, 2014
+ * \author		<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ * \copyright	Apache License, Version 2.0
+ */
+#include <stdlib.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#ifndef ANDROID
+#include <ifaddrs.h>
+#endif
+#include "civetweb.h"
+#include "celix_errno.h"
+#include "utils.h"
+#include "log_helper.h"
+#include "discovery.h"
+#include "discovery_impl.h"
+
+#include "endpoint_descriptor_writer.h"
+
+// defines how often the webserver is restarted (with an increased port number)
+#define MAX_NUMBER_OF_RESTARTS 	15
+#define DEFAULT_SERVER_THREADS "1"
+
+#define CIVETWEB_REQUEST_NOT_HANDLED 0
+#define CIVETWEB_REQUEST_HANDLED 1
+
+static const char *response_headers =
+		"HTTP/1.1 200 OK\r\n"
+		"Cache: no-cache\r\n"
+		"Content-Type: application/xml;charset=utf-8\r\n"
+		"\r\n";
+
+struct endpoint_discovery_server {
+	log_helper_pt* loghelper;
+	hash_map_pt entries; // key = endpointId, value = endpoint_descriptor_pt
+
+	celix_thread_mutex_t serverLock;
+
+	const char* path;
+	const char *port;
+	const char* ip;
+	struct mg_context* ctx;
+};
+
+// Forward declarations...
+static int endpointDiscoveryServer_callback(struct mg_connection *conn);
+static char* format_path(const char* path);
+
+#ifndef ANDROID
+static celix_status_t endpointDiscoveryServer_getIpAdress(char* interface, char** ip);
+#endif
+
+celix_status_t endpointDiscoveryServer_create(discovery_pt discovery, bundle_context_pt context, endpoint_discovery_server_pt *server) {
+	celix_status_t status;
+
+	const char *port = NULL;
+	const char *ip = NULL;
+	char *detectedIp = NULL;
+	const char *path = NULL;
+	const char *retries = NULL;
+
+	int max_ep_num = MAX_NUMBER_OF_RESTARTS;
+
+	*server = malloc(sizeof(struct endpoint_discovery_server));
+	if (!*server) {
+		return CELIX_ENOMEM;
+	}
+
+	(*server)->loghelper = &discovery->loghelper;
+	(*server)->entries = hashMap_create(&utils_stringHash, NULL, &utils_stringEquals, NULL);
+	if (!(*server)->entries) {
+		return CELIX_ENOMEM;
+	}
+
+	status = celixThreadMutex_create(&(*server)->serverLock, NULL);
+	if (status != CELIX_SUCCESS) {
+		return CELIX_BUNDLE_EXCEPTION;
+	}
+
+	bundleContext_getProperty(context, DISCOVERY_SERVER_IP, &ip);
+#ifndef ANDROID
+	if (ip == NULL) {
+		const char *interface = NULL;
+
+		bundleContext_getProperty(context, DISCOVERY_SERVER_INTERFACE, &interface);
+		if ((interface != NULL) && (endpointDiscoveryServer_getIpAdress((char*)interface, &detectedIp) != CELIX_SUCCESS)) {
+			logHelper_log(*(*server)->loghelper, OSGI_LOGSERVICE_WARNING, "Could not retrieve IP adress for interface %s", interface);
+		}
+
+		if (detectedIp == NULL) {
+			endpointDiscoveryServer_getIpAdress(NULL, &detectedIp);
+		}
+
+		ip = detectedIp;
+	}
+#endif
+
+	if (ip != NULL) {
+		logHelper_log(*(*server)->loghelper, OSGI_LOGSERVICE_INFO, "Using %s for service annunciation", ip);
+		(*server)->ip = strdup(ip);
+	}
+	else {
+		logHelper_log(*(*server)->loghelper, OSGI_LOGSERVICE_WARNING, "No IP address for service annunciation set. Using %s", DEFAULT_SERVER_IP);
+		(*server)->ip = strdup((char*) DEFAULT_SERVER_IP);
+	}
+
+	if (detectedIp != NULL) {
+		free(detectedIp);
+	}
+
+	bundleContext_getProperty(context, DISCOVERY_SERVER_PORT, &port);
+	if (port == NULL) {
+		port = DEFAULT_SERVER_PORT;
+	}
+
+	bundleContext_getProperty(context, DISCOVERY_SERVER_PATH, &path);
+	if (path == NULL) {
+		path = DEFAULT_SERVER_PATH;
+	}
+
+	bundleContext_getProperty(context, DISCOVERY_SERVER_MAX_EP, &retries);
+	if (retries != NULL) {
+		errno=0;
+		max_ep_num = strtol(retries,NULL,10);
+		if(errno!=0 || max_ep_num<=0){
+			max_ep_num=MAX_NUMBER_OF_RESTARTS;
+		}
+	}
+
+	(*server)->path = format_path(path);
+
+	const struct mg_callbacks callbacks = {
+			.begin_request = endpointDiscoveryServer_callback,
+	};
+
+	unsigned int port_counter = 0;
+	char newPort[10];
+
+	do {
+		const char *options[] = {
+				"listening_ports", port,
+				"num_threads", DEFAULT_SERVER_THREADS,
+				NULL
+		};
+
+		(*server)->ctx = mg_start(&callbacks, (*server), options);
+
+		if ((*server)->ctx != NULL)
+		{
+			logHelper_log(discovery->loghelper, OSGI_LOGSERVICE_INFO, "Starting discovery server on port %s...", port);
+		}
+		else {
+			errno = 0;
+			char* endptr = (char*)port;
+			long currentPort = strtol(port, &endptr, 10);
+
+			if (*endptr || errno != 0) {
+				currentPort = strtol(DEFAULT_SERVER_PORT, NULL, 10);
+			}
+
+			port_counter++;
+			snprintf(&newPort[0], 10,  "%ld", (currentPort+1));
+
+			logHelper_log(discovery->loghelper, OSGI_LOGSERVICE_ERROR, "Error while starting discovery server on port %s - retrying on port %s...", port, newPort);
+			port = newPort;
+
+		}
+
+	} while(((*server)->ctx == NULL) && (port_counter < max_ep_num));
+
+	(*server)->port = strdup(port);
+
+	return status;
+}
+
+celix_status_t endpointDiscoveryServer_getUrl(endpoint_discovery_server_pt server, char* url)
+{
+	celix_status_t status = CELIX_BUNDLE_EXCEPTION;
+
+	if (server->ip && server->port && server->path) {
+		sprintf(url, "http://%s:%s/%s", server->ip, server->port, server->path);
+		status = CELIX_SUCCESS;
+	}
+
+	return status;
+}
+
+celix_status_t endpointDiscoveryServer_destroy(endpoint_discovery_server_pt server) {
+	celix_status_t status;
+
+	// stop & block until the actual server is shut down...
+	if (server->ctx != NULL) {
+		mg_stop(server->ctx);
+		server->ctx = NULL;
+	}
+
+	status = celixThreadMutex_lock(&server->serverLock);
+
+	hashMap_destroy(server->entries, true /* freeKeys */, false /* freeValues */);
+
+	status = celixThreadMutex_unlock(&server->serverLock);
+	status = celixThreadMutex_destroy(&server->serverLock);
+
+	free((void*) server->path);
+	free((void*) server->port);
+	free((void*) server->ip);
+
+	free(server);
+
+	return status;
+}
+
+celix_status_t endpointDiscoveryServer_addEndpoint(endpoint_discovery_server_pt server, endpoint_description_pt endpoint) {
+	celix_status_t status;
+
+	status = celixThreadMutex_lock(&server->serverLock);
+	if (status != CELIX_SUCCESS) {
+		return CELIX_BUNDLE_EXCEPTION;
+	}
+
+	// create a local copy of the endpointId which we can control...
+	char* endpointId = strdup(endpoint->id);
+	endpoint_description_pt cur_value = hashMap_get(server->entries, endpointId);
+	if (!cur_value) {
+		logHelper_log(*server->loghelper, OSGI_LOGSERVICE_INFO, "exposing new endpoint \"%s\"...", endpointId);
+
+		hashMap_put(server->entries, endpointId, endpoint);
+	}
+
+	status = celixThreadMutex_unlock(&server->serverLock);
+	if (status != CELIX_SUCCESS) {
+		return CELIX_BUNDLE_EXCEPTION;
+	}
+
+	return status;
+}
+
+celix_status_t endpointDiscoveryServer_removeEndpoint(endpoint_discovery_server_pt server, endpoint_description_pt endpoint) {
+	celix_status_t status;
+
+	status = celixThreadMutex_lock(&server->serverLock);
+	if (status != CELIX_SUCCESS) {
+		return CELIX_BUNDLE_EXCEPTION;
+	}
+
+	hash_map_entry_pt entry = hashMap_getEntry(server->entries, endpoint->id);
+	if (entry) {
+		char* key = hashMapEntry_getKey(entry);
+
+		logHelper_log(*server->loghelper, OSGI_LOGSERVICE_INFO, "removing endpoint \"%s\"...\n", key);
+
+		hashMap_remove(server->entries, key);
+
+		// we've made this key, see _addEnpoint above...
+		free((void*) key);
+	}
+
+	status = celixThreadMutex_unlock(&server->serverLock);
+	if (status != CELIX_SUCCESS) {
+		return CELIX_BUNDLE_EXCEPTION;
+	}
+
+	return status;
+}
+
+static char* format_path(const char* path) {
+	char* result = strdup(path);
+	result = utils_stringTrim(result);
+	// check whether the path starts with a leading slash...
+	if (result[0] != '/') {
+		size_t len = strlen(result);
+		result = realloc(result, len + 2);
+		memmove(result + 1, result, len);
+		result[0] = '/';
+		result[len + 1] = 0;
+	}
+	return result;
+}
+
+static celix_status_t endpointDiscoveryServer_getEndpoints(endpoint_discovery_server_pt server, const char* the_endpoint_id, array_list_pt *endpoints) {
+	celix_status_t status;
+
+	status = arrayList_create(endpoints);
+	if (status != CELIX_SUCCESS) {
+		return CELIX_ENOMEM;
+	}
+
+
+	hash_map_iterator_pt iter = hashMapIterator_create(server->entries);
+	while (hashMapIterator_hasNext(iter)) {
+		hash_map_entry_pt entry = hashMapIterator_nextEntry(iter);
+
+		char* endpoint_id = hashMapEntry_getKey(entry);
+		if (the_endpoint_id == NULL || strcmp(the_endpoint_id, endpoint_id) == 0) {
+			endpoint_description_pt endpoint = hashMapEntry_getValue(entry);
+
+			arrayList_add(*endpoints, endpoint);
+		}
+	}
+	hashMapIterator_destroy(iter);
+
+	return status;
+}
+
+static int endpointDiscoveryServer_writeEndpoints(struct mg_connection* conn, array_list_pt endpoints) {
+	celix_status_t status;
+	int rv = CIVETWEB_REQUEST_NOT_HANDLED;
+
+	endpoint_descriptor_writer_pt writer = NULL;
+	status = endpointDescriptorWriter_create(&writer);
+	if (status == CELIX_SUCCESS) {
+
+		char *buffer = NULL;
+		status = endpointDescriptorWriter_writeDocument(writer, endpoints, &buffer);
+		if (buffer) {
+			mg_write(conn, response_headers, strlen(response_headers));
+			mg_write(conn, buffer, strlen(buffer));
+		}
+
+		rv = CIVETWEB_REQUEST_HANDLED;
+	}
+
+	if(writer!=NULL){
+		endpointDescriptorWriter_destroy(writer);
+	}
+
+	return rv;
+}
+
+// returns all endpoints as XML...
+static int endpointDiscoveryServer_returnAllEndpoints(endpoint_discovery_server_pt server, struct mg_connection* conn) {
+	int status = CIVETWEB_REQUEST_NOT_HANDLED;
+
+	array_list_pt endpoints = NULL;
+
+	if (celixThreadMutex_lock(&server->serverLock) == CELIX_SUCCESS) {
+		endpointDiscoveryServer_getEndpoints(server, NULL, &endpoints);
+		if (endpoints) {
+			status = endpointDiscoveryServer_writeEndpoints(conn, endpoints);
+
+			arrayList_destroy(endpoints);
+		}
+
+
+		celixThreadMutex_unlock(&server->serverLock);
+	}
+
+	return status;
+}
+
+// returns a single endpoint as XML...
+static int endpointDiscoveryServer_returnEndpoint(endpoint_discovery_server_pt server, struct mg_connection* conn, const char* endpoint_id) {
+	int status = CIVETWEB_REQUEST_NOT_HANDLED;
+
+	array_list_pt endpoints = NULL;
+
+	if (celixThreadMutex_lock(&server->serverLock) == CELIX_SUCCESS) {
+		endpointDiscoveryServer_getEndpoints(server, endpoint_id, &endpoints);
+		if (endpoints) {
+			status = endpointDiscoveryServer_writeEndpoints(conn, endpoints);
+
+			arrayList_destroy(endpoints);
+		}
+
+		celixThreadMutex_unlock(&server->serverLock);
+	}
+
+	return status;
+}
+
+static int endpointDiscoveryServer_callback(struct mg_connection* conn) {
+	int status = CIVETWEB_REQUEST_NOT_HANDLED;
+
+	const struct mg_request_info *request_info = mg_get_request_info(conn);
+	if (request_info->uri != NULL && strcmp("GET", request_info->request_method) == 0) {
+		endpoint_discovery_server_pt server = request_info->user_data;
+
+		const char *uri = request_info->uri;
+		const size_t path_len = strlen(server->path);
+		const size_t uri_len = strlen(uri);
+
+		if (strncmp(server->path, uri, strlen(server->path)) == 0) {
+			// Be lenient when it comes to the trailing slash...
+			if (path_len == uri_len || (uri_len == (path_len + 1) && uri[path_len] == '/')) {
+				status = endpointDiscoveryServer_returnAllEndpoints(server, conn);
+			} else {
+				const char* endpoint_id = uri + path_len + 1; // right after the slash...
+
+				status = endpointDiscoveryServer_returnEndpoint(server, conn, endpoint_id);
+			}
+		}
+	}
+
+	return status;
+}
+
+#ifndef ANDROID
+static celix_status_t endpointDiscoveryServer_getIpAdress(char* interface, char** ip) {
+	celix_status_t status = CELIX_BUNDLE_EXCEPTION;
+
+	struct ifaddrs *ifaddr, *ifa;
+	char host[NI_MAXHOST];
+
+	if (getifaddrs(&ifaddr) != -1)
+	{
+		for (ifa = ifaddr; ifa != NULL && status != CELIX_SUCCESS; ifa = ifa->ifa_next)
+		{
+			if (ifa->ifa_addr == NULL)
+				continue;
+
+			if ((getnameinfo(ifa->ifa_addr,sizeof(struct sockaddr_in), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) == 0) && (ifa->ifa_addr->sa_family == AF_INET)) {
+				if (interface == NULL) {
+					*ip = strdup(host);
+					status = CELIX_SUCCESS;
+				}
+				else if (strcmp(ifa->ifa_name, interface) == 0) {
+					*ip = strdup(host);
+					status = CELIX_SUCCESS;
+				}
+			}
+		}
+
+		freeifaddrs(ifaddr);
+	}
+
+	return status;
+}
+#endif

http://git-wip-us.apache.org/repos/asf/celix/blob/2a670f26/remote_services/discovery_common/src/md5.inl
----------------------------------------------------------------------
diff --git a/remote_services/discovery_common/src/md5.inl b/remote_services/discovery_common/src/md5.inl
new file mode 100644
index 0000000..4da933d
--- /dev/null
+++ b/remote_services/discovery_common/src/md5.inl
@@ -0,0 +1,461 @@
+/*
+ * This an amalgamation of md5.c and md5.h into a single file
+ * with all static declaration to reduce linker conflicts
+ * in Civetweb.
+ *
+ * The MD5_STATIC declaration was added to facilitate static
+ * inclusion.
+ * No Face Press, LLC
+ */
+
+/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */
+/*
+  Independent implementation of MD5 (RFC 1321).
+
+  This code implements the MD5 Algorithm defined in RFC 1321, whose
+  text is available at
+	http://www.ietf.org/rfc/rfc1321.txt
+  The code is derived from the text of the RFC, including the test suite
+  (section A.5) but excluding the rest of Appendix A.  It does not include
+  any code or documentation that is identified in the RFC as being
+  copyrighted.
+
+  The original and principal author of md5.h is L. Peter Deutsch
+  <gh...@aladdin.com>.  Other authors are noted in the change history
+  that follows (in reverse chronological order):
+
+  2002-04-13 lpd Removed support for non-ANSI compilers; removed
+	references to Ghostscript; clarified derivation from RFC 1321;
+	now handles byte order either statically or dynamically.
+  1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+  1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
+	added conditionalization for C++ compilation from Martin
+	Purschke <pu...@bnl.gov>.
+  1999-05-03 lpd Original version.
+ */
+
+#ifndef md5_INCLUDED
+#  define md5_INCLUDED
+
+/*
+ * This package supports both compile-time and run-time determination of CPU
+ * byte order.  If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
+ * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
+ * defined as non-zero, the code will be compiled to run only on big-endian
+ * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
+ * run on either big- or little-endian CPUs, but will run slightly less
+ * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
+ */
+
+typedef unsigned char md5_byte_t; /* 8-bit byte */
+typedef unsigned int md5_word_t; /* 32-bit word */
+
+/* Define the state of the MD5 Algorithm. */
+typedef struct md5_state_s {
+    md5_word_t count[2];	/* message length in bits, lsw first */
+    md5_word_t abcd[4];		/* digest buffer */
+    md5_byte_t buf[64];		/* accumulate block */
+} md5_state_t;
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* Initialize the algorithm. */
+MD5_STATIC void md5_init(md5_state_t *pms);
+
+/* Append a string to the message. */
+MD5_STATIC void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes);
+
+/* Finish the message and return the digest. */
+MD5_STATIC void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
+
+#ifdef __cplusplus
+}  /* end extern "C" */
+#endif
+
+#endif /* md5_INCLUDED */
+
+/*
+  Copyright (C) 1999, 2000, 2002 Aladdin Enterprises.  All rights reserved.
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  L. Peter Deutsch
+  ghost@aladdin.com
+
+ */
+/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */
+/*
+  Independent implementation of MD5 (RFC 1321).
+
+  This code implements the MD5 Algorithm defined in RFC 1321, whose
+  text is available at
+	http://www.ietf.org/rfc/rfc1321.txt
+  The code is derived from the text of the RFC, including the test suite
+  (section A.5) but excluding the rest of Appendix A.  It does not include
+  any code or documentation that is identified in the RFC as being
+  copyrighted.
+
+  The original and principal author of md5.c is L. Peter Deutsch
+  <gh...@aladdin.com>.  Other authors are noted in the change history
+  that follows (in reverse chronological order):
+
+  2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
+	either statically or dynamically; added missing #include <string.h>
+	in library.
+  2002-03-11 lpd Corrected argument list for main(), and added int return
+	type, in test program and T value program.
+  2002-02-21 lpd Added missing #include <stdio.h> in test program.
+  2000-07-03 lpd Patched to eliminate warnings about "constant is
+	unsigned in ANSI C, signed in traditional"; made test program
+	self-checking.
+  1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+  1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
+  1999-05-03 lpd Original version.
+ */
+
+#ifndef MD5_STATIC
+#include <string.h>
+#endif
+
+#undef BYTE_ORDER	/* 1 = big-endian, -1 = little-endian, 0 = unknown */
+#ifdef ARCH_IS_BIG_ENDIAN
+#  define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
+#else
+#  define BYTE_ORDER 0
+#endif
+
+#define T_MASK ((md5_word_t)~0)
+#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
+#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
+#define T3    0x242070db
+#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
+#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
+#define T6    0x4787c62a
+#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
+#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
+#define T9    0x698098d8
+#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
+#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
+#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
+#define T13    0x6b901122
+#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
+#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
+#define T16    0x49b40821
+#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
+#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
+#define T19    0x265e5a51
+#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
+#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
+#define T22    0x02441453
+#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
+#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
+#define T25    0x21e1cde6
+#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
+#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
+#define T28    0x455a14ed
+#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
+#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
+#define T31    0x676f02d9
+#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
+#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
+#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
+#define T35    0x6d9d6122
+#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
+#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
+#define T38    0x4bdecfa9
+#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
+#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
+#define T41    0x289b7ec6
+#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
+#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
+#define T44    0x04881d05
+#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
+#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
+#define T47    0x1fa27cf8
+#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
+#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
+#define T50    0x432aff97
+#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
+#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
+#define T53    0x655b59c3
+#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
+#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
+#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
+#define T57    0x6fa87e4f
+#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
+#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
+#define T60    0x4e0811a1
+#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
+#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
+#define T63    0x2ad7d2bb
+#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
+
+
+static void
+md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
+{
+    md5_word_t
+    a = pms->abcd[0], b = pms->abcd[1],
+    c = pms->abcd[2], d = pms->abcd[3];
+    md5_word_t t;
+#if BYTE_ORDER > 0
+    /* Define storage only for big-endian CPUs. */
+    md5_word_t X[16];
+#else
+    /* Define storage for little-endian or both types of CPUs. */
+    md5_word_t xbuf[16];
+    const md5_word_t *X;
+#endif
+
+    {
+#if BYTE_ORDER == 0
+        /*
+         * Determine dynamically whether this is a big-endian or
+         * little-endian machine, since we can use a more efficient
+         * algorithm on the latter.
+         */
+        static const int w = 1;
+
+        if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
+#endif
+#if BYTE_ORDER <= 0		/* little-endian */
+        {
+            /*
+             * On little-endian machines, we can process properly aligned
+             * data without copying it.
+             */
+            if (!((data - (const md5_byte_t *)0) & 3)) {
+                /* data are properly aligned */
+                X = (const md5_word_t *)data;
+            } else {
+                /* not aligned */
+                memcpy(xbuf, data, 64);
+                X = xbuf;
+            }
+        }
+#endif
+#if BYTE_ORDER == 0
+        else			/* dynamic big-endian */
+#endif
+#if BYTE_ORDER >= 0		/* big-endian */
+        {
+            /*
+             * On big-endian machines, we must arrange the bytes in the
+             * right order.
+             */
+            const md5_byte_t *xp = data;
+            int i;
+
+#  if BYTE_ORDER == 0
+            X = xbuf;		/* (dynamic only) */
+#  else
+#    define xbuf X		/* (static only) */
+#  endif
+            for (i = 0; i < 16; ++i, xp += 4)
+                xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
+        }
+#endif
+    }
+
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+
+    /* Round 1. */
+    /* Let [abcd k s i] denote the operation
+       a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
+#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
+#define SET(a, b, c, d, k, s, Ti)\
+  t = a + F(b,c,d) + X[k] + Ti;\
+  a = ROTATE_LEFT(t, s) + b
+    /* Do the following 16 operations. */
+    SET(a, b, c, d,  0,  7,  T1);
+    SET(d, a, b, c,  1, 12,  T2);
+    SET(c, d, a, b,  2, 17,  T3);
+    SET(b, c, d, a,  3, 22,  T4);
+    SET(a, b, c, d,  4,  7,  T5);
+    SET(d, a, b, c,  5, 12,  T6);
+    SET(c, d, a, b,  6, 17,  T7);
+    SET(b, c, d, a,  7, 22,  T8);
+    SET(a, b, c, d,  8,  7,  T9);
+    SET(d, a, b, c,  9, 12, T10);
+    SET(c, d, a, b, 10, 17, T11);
+    SET(b, c, d, a, 11, 22, T12);
+    SET(a, b, c, d, 12,  7, T13);
+    SET(d, a, b, c, 13, 12, T14);
+    SET(c, d, a, b, 14, 17, T15);
+    SET(b, c, d, a, 15, 22, T16);
+#undef SET
+
+    /* Round 2. */
+    /* Let [abcd k s i] denote the operation
+         a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
+#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
+#define SET(a, b, c, d, k, s, Ti)\
+  t = a + G(b,c,d) + X[k] + Ti;\
+  a = ROTATE_LEFT(t, s) + b
+    /* Do the following 16 operations. */
+    SET(a, b, c, d,  1,  5, T17);
+    SET(d, a, b, c,  6,  9, T18);
+    SET(c, d, a, b, 11, 14, T19);
+    SET(b, c, d, a,  0, 20, T20);
+    SET(a, b, c, d,  5,  5, T21);
+    SET(d, a, b, c, 10,  9, T22);
+    SET(c, d, a, b, 15, 14, T23);
+    SET(b, c, d, a,  4, 20, T24);
+    SET(a, b, c, d,  9,  5, T25);
+    SET(d, a, b, c, 14,  9, T26);
+    SET(c, d, a, b,  3, 14, T27);
+    SET(b, c, d, a,  8, 20, T28);
+    SET(a, b, c, d, 13,  5, T29);
+    SET(d, a, b, c,  2,  9, T30);
+    SET(c, d, a, b,  7, 14, T31);
+    SET(b, c, d, a, 12, 20, T32);
+#undef SET
+
+    /* Round 3. */
+    /* Let [abcd k s t] denote the operation
+         a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define SET(a, b, c, d, k, s, Ti)\
+  t = a + H(b,c,d) + X[k] + Ti;\
+  a = ROTATE_LEFT(t, s) + b
+    /* Do the following 16 operations. */
+    SET(a, b, c, d,  5,  4, T33);
+    SET(d, a, b, c,  8, 11, T34);
+    SET(c, d, a, b, 11, 16, T35);
+    SET(b, c, d, a, 14, 23, T36);
+    SET(a, b, c, d,  1,  4, T37);
+    SET(d, a, b, c,  4, 11, T38);
+    SET(c, d, a, b,  7, 16, T39);
+    SET(b, c, d, a, 10, 23, T40);
+    SET(a, b, c, d, 13,  4, T41);
+    SET(d, a, b, c,  0, 11, T42);
+    SET(c, d, a, b,  3, 16, T43);
+    SET(b, c, d, a,  6, 23, T44);
+    SET(a, b, c, d,  9,  4, T45);
+    SET(d, a, b, c, 12, 11, T46);
+    SET(c, d, a, b, 15, 16, T47);
+    SET(b, c, d, a,  2, 23, T48);
+#undef SET
+
+    /* Round 4. */
+    /* Let [abcd k s t] denote the operation
+         a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+#define SET(a, b, c, d, k, s, Ti)\
+  t = a + I(b,c,d) + X[k] + Ti;\
+  a = ROTATE_LEFT(t, s) + b
+    /* Do the following 16 operations. */
+    SET(a, b, c, d,  0,  6, T49);
+    SET(d, a, b, c,  7, 10, T50);
+    SET(c, d, a, b, 14, 15, T51);
+    SET(b, c, d, a,  5, 21, T52);
+    SET(a, b, c, d, 12,  6, T53);
+    SET(d, a, b, c,  3, 10, T54);
+    SET(c, d, a, b, 10, 15, T55);
+    SET(b, c, d, a,  1, 21, T56);
+    SET(a, b, c, d,  8,  6, T57);
+    SET(d, a, b, c, 15, 10, T58);
+    SET(c, d, a, b,  6, 15, T59);
+    SET(b, c, d, a, 13, 21, T60);
+    SET(a, b, c, d,  4,  6, T61);
+    SET(d, a, b, c, 11, 10, T62);
+    SET(c, d, a, b,  2, 15, T63);
+    SET(b, c, d, a,  9, 21, T64);
+#undef SET
+
+    /* Then perform the following additions. (That is increment each
+       of the four registers by the value it had before this block
+       was started.) */
+    pms->abcd[0] += a;
+    pms->abcd[1] += b;
+    pms->abcd[2] += c;
+    pms->abcd[3] += d;
+}
+
+MD5_STATIC void
+md5_init(md5_state_t *pms)
+{
+    pms->count[0] = pms->count[1] = 0;
+    pms->abcd[0] = 0x67452301;
+    pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
+    pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
+    pms->abcd[3] = 0x10325476;
+}
+
+MD5_STATIC void
+md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)
+{
+    const md5_byte_t *p = data;
+    int left = nbytes;
+    int offset = (pms->count[0] >> 3) & 63;
+    md5_word_t nbits = (md5_word_t)(nbytes << 3);
+
+    if (nbytes <= 0)
+        return;
+
+    /* Update the message length. */
+    pms->count[1] += nbytes >> 29;
+    pms->count[0] += nbits;
+    if (pms->count[0] < nbits)
+        pms->count[1]++;
+
+    /* Process an initial partial block. */
+    if (offset) {
+        int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
+
+        memcpy(pms->buf + offset, p, copy);
+        if (offset + copy < 64)
+            return;
+        p += copy;
+        left -= copy;
+        md5_process(pms, pms->buf);
+    }
+
+    /* Process full blocks. */
+    for (; left >= 64; p += 64, left -= 64)
+        md5_process(pms, p);
+
+    /* Process a final partial block. */
+    if (left)
+        memcpy(pms->buf, p, left);
+}
+
+MD5_STATIC void
+md5_finish(md5_state_t *pms, md5_byte_t digest[16])
+{
+    static const md5_byte_t pad[64] = {
+        0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+    };
+    md5_byte_t data[8];
+    int i;
+
+    /* Save the length before padding. */
+    for (i = 0; i < 8; ++i)
+        data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
+    /* Pad to 56 bytes mod 64. */
+    md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
+    /* Append the length. */
+    md5_append(pms, data, 8);
+    for (i = 0; i < 16; ++i)
+        digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
+}

http://git-wip-us.apache.org/repos/asf/celix/blob/2a670f26/remote_services/discovery_configured/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/remote_services/discovery_configured/CMakeLists.txt b/remote_services/discovery_configured/CMakeLists.txt
index b9f849d..e0f3e9b 100644
--- a/remote_services/discovery_configured/CMakeLists.txt
+++ b/remote_services/discovery_configured/CMakeLists.txt
@@ -19,39 +19,19 @@ if (RSA_DISCOVERY_CONFIGURED)
     find_package(CURL REQUIRED)
     find_package(LibXml2 REQUIRED)
 
-    include_directories("${CURL_INCLUDE_DIR}")
-    include_directories("${LIBXML2_INCLUDE_DIR}")
-    include_directories("${PROJECT_SOURCE_DIR}/utils/public/include")
-    include_directories("${PROJECT_SOURCE_DIR}/remote_services/utils/private/include")
-    include_directories("${PROJECT_SOURCE_DIR}/remote_services/utils/public/include")
-    include_directories("${PROJECT_SOURCE_DIR}/remote_services/discovery/private/include")
-    include_directories("${PROJECT_SOURCE_DIR}/remote_services/discovery_configured/private/include")
-    include_directories("${PROJECT_SOURCE_DIR}/remote_services/endpoint_listener/public/include")
-    include_directories("${PROJECT_SOURCE_DIR}/remote_services/remote_service_admin/public/include")
-    include_directories("${PROJECT_SOURCE_DIR}/log_service/public/include")
-    include_directories(private/include)
-
     add_bundle(discovery_configured 
-    VERSION 0.9.0
-    SYMBOLIC_NAME "apache_celix_rsa_discovery_configured"
-    NAME "Apache Celix RSA Configured Discovery"    
-    SOURCES
-
-	private/src/discovery_impl.c
-	${PROJECT_SOURCE_DIR}/remote_services/discovery/private/src/discovery_activator.c
-	${PROJECT_SOURCE_DIR}/remote_services/discovery/private/src/discovery.c
-	${PROJECT_SOURCE_DIR}/remote_services/discovery/private/src/endpoint_descriptor_reader.c
-	${PROJECT_SOURCE_DIR}/remote_services/discovery/private/src/endpoint_descriptor_writer.c
-	${PROJECT_SOURCE_DIR}/remote_services/discovery/private/src/endpoint_discovery_poller.c
-	${PROJECT_SOURCE_DIR}/remote_services/discovery/private/src/endpoint_discovery_server.c
-	${PROJECT_SOURCE_DIR}/remote_services/remote_service_admin/private/src/endpoint_description.c
-	${PROJECT_SOURCE_DIR}/remote_services/utils/private/src/civetweb.c
+        VERSION 0.9.0
+        SYMBOLIC_NAME "apache_celix_rsa_discovery_configured"
+        NAME "Apache Celix RSA Configured Discovery"
+        SOURCES
+	        src/discovery_impl.c
     )
-    target_link_libraries(discovery_configured PRIVATE Celix::log_helper)
+    target_include_directories(discovery_configured PRIVATE src)
+    target_link_libraries(discovery_configured PRIVATE ${CURL_LIBRARIES} ${LIBXML2_LIBRARIES} Celix::log_helper discovery_common)
 
     install_bundle(discovery_configured)
 
-    target_link_libraries(discovery_configured PRIVATE ${CURL_LIBRARIES} ${LIBXML2_LIBRARIES})
+
 
     if (RSA_ENDPOINT_TEST_READER)
         add_executable(descparser