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:[email protected]";>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:[email protected]";>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:[email protected]";>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:[email protected]";>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:[email protected]";>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:[email protected]";>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
+  <[email protected]>.  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 <[email protected]>.
+  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
+  [email protected]
+
+ */
+/* $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
+  <[email protected]>.  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

Reply via email to