You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@celix.apache.org by rb...@apache.org on 2022/01/09 19:57:51 UTC

[celix] branch feature/add_pubsub_udp created (now 372049a)

This is an automated email from the ASF dual-hosted git repository.

rbulter pushed a change to branch feature/add_pubsub_udp
in repository https://gitbox.apache.org/repos/asf/celix.git.


      at 372049a  Add pubsub udp admin

This branch includes the following new commits:

     new 372049a  Add pubsub udp admin

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


[celix] 01/01: Add pubsub udp admin

Posted by rb...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rbulter pushed a commit to branch feature/add_pubsub_udp
in repository https://gitbox.apache.org/repos/asf/celix.git

commit 372049a062dee046c975bb8d1c9988a267b6ef58
Author: Roy Bulter <ro...@gmail.com>
AuthorDate: Sun Jan 9 20:57:05 2022 +0100

    Add pubsub udp admin
---
 CMakeLists.txt                                     |   2 +-
 bundles/pubsub/CMakeLists.txt                      |   5 +
 bundles/pubsub/README.md                           |  25 +-
 bundles/pubsub/examples/CMakeLists.txt             |  80 ++
 bundles/pubsub/integration/CMakeLists.txt          |  84 ++
 .../integration/gtest/sut_endpoint_activator.c     |   4 +-
 .../pubsub/integration/meta_data/ping.properties   |   6 +
 .../pubsub/integration/meta_data/ping2.properties  |   3 +
 .../pubsub/integration/meta_data/ping3.properties  |   2 +
 .../pubsub/integration/meta_data/pong2.properties  |   4 +
 .../pubsub/integration/meta_data/pong3.properties  |   4 +
 bundles/pubsub/pubsub_admin_tcp/CMakeLists.txt     |   2 -
 bundles/pubsub/pubsub_admin_tcp/README.md          | 112 +++
 .../pubsub/pubsub_admin_tcp/src/pubsub_tcp_admin.c |  29 +-
 .../pubsub_admin_tcp/src/pubsub_tcp_common.c       |  38 -
 .../pubsub_admin_tcp/src/pubsub_tcp_common.h       |  33 -
 .../pubsub_admin_tcp/src/pubsub_tcp_handler.h      |  92 --
 .../src/pubsub_tcp_topic_receiver.c                |  46 +-
 .../src/pubsub_tcp_topic_receiver.h                |   4 +-
 .../pubsub_admin_tcp/src/pubsub_tcp_topic_sender.c |  42 +-
 .../pubsub_admin_tcp/src/pubsub_tcp_topic_sender.h |   4 +-
 .../CMakeLists.txt                                 |  26 +-
 bundles/pubsub/pubsub_admin_udp/README.md          | 149 ++++
 .../pubsub/pubsub_admin_udp/src/psa_activator.c    | 129 +++
 .../src/pubsub_psa_udp_constants.h                 | 136 +++
 .../src/pubsub_udp_admin.c}                        | 387 ++++----
 .../pubsub/pubsub_admin_udp/src/pubsub_udp_admin.h |  88 ++
 .../src/pubsub_udp_topic_receiver.c}               | 341 ++++---
 .../src/pubsub_udp_topic_receiver.h}               |  34 +-
 .../src/pubsub_udp_topic_sender.c}                 | 250 ++++--
 .../src/pubsub_udp_topic_sender.h}                 |  33 +-
 bundles/pubsub/pubsub_utils/CMakeLists.txt         |   1 +
 .../pubsub_utils/include/pubsub_skt_handler.h      | 103 +++
 .../pubsub/pubsub_utils/include/pubsub_utils_url.h |   5 +-
 .../src/pubsub_skt_handler.c}                      | 983 ++++++++++++++-------
 bundles/pubsub/pubsub_utils/src/pubsub_utils_url.c |  34 +-
 36 files changed, 2346 insertions(+), 974 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index deea4e5..a3e2cb8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -33,7 +33,7 @@ IF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} EQUAL 3.3 AND ${CMAKE_GENERATO
 ENDIF()
 
 # Options
-option(ENABLE_TESTING "Enables unit/bundle testing" FALSE)
+option(ENABLE_TESTING "Enables unit/bundle testing" TRUE)
 if (ENABLE_TESTING)
     find_package(GTest CONFIG QUIET)
     if (NOT GTest_FOUND)
diff --git a/bundles/pubsub/CMakeLists.txt b/bundles/pubsub/CMakeLists.txt
index 39275c5..d0b157d 100644
--- a/bundles/pubsub/CMakeLists.txt
+++ b/bundles/pubsub/CMakeLists.txt
@@ -29,6 +29,11 @@ if (PUBSUB)
         add_subdirectory(pubsub_admin_tcp)
     endif (BUILD_PUBSUB_PSA_TCP)
 
+    option(BUILD_PUBSUB_PSA_UDP "Build UDP PubSub Admin" ON)
+    if (BUILD_PUBSUB_PSA_UDP)
+        add_subdirectory(pubsub_admin_udp)
+    endif (BUILD_PUBSUB_PSA_UDP)
+
     option(BUILD_PUBSUB_PSA_UDP_MC "Build UDP MC PubSub Admin" ON)
     if (BUILD_PUBSUB_PSA_UDP_MC)
         add_subdirectory(pubsub_admin_udp_mc)
diff --git a/bundles/pubsub/README.md b/bundles/pubsub/README.md
index 744cfd9..797f5a5 100644
--- a/bundles/pubsub/README.md
+++ b/bundles/pubsub/README.md
@@ -39,7 +39,8 @@ The publisher/subscriber implementation supports sending of a single message and
 ## Getting started
 
 The publisher/subscriber implementation contains 3 different PubSubAdmins for managing connections:
-  * PubsubAdminUDP: This pubsub admin is using udp (multicast) linux sockets to setup a connection.
+  * PubsubAdminUDPMC: This pubsub admin is using udp (multicast) linux sockets to setup a connection.
+  * PubsubAdminUDP: This pubsub admin is using udp (unicast/multicast/broadcast) linux sockets to setup a connection.
   * PubsubAdminTCP: This pubsub admin is using tcp linux sockets to setup a connection.
   * PubsubAdminZMQ (LGPL License): This pubsub admin is using ZeroMQ and is disabled as default. This is a because the pubsub admin is using ZeroMQ which is licensed as LGPL ([View ZeroMQ License](https://github.com/zeromq/libzmq#license)).
   
@@ -60,6 +61,26 @@ The publisher/subscriber implementation contains 3 different PubSubAdmins for ma
 
 Design information can be found at pubsub\_admin\_udp\_mc/README.md
 
+### Running PSA UDP
+
+1. Open a terminal
+1. Run `cd runtimes/pubsub/udp`
+1. Run `sh start.sh`
+
+### Properties PSA UDP
+
+Some properties can be set to configure the PSA-UDP. If not configured defaults will be used. These
+properties can be set in the config.properties file (<PROPERTY>=<VALUE> format)
+
+
+    PSA_IP                              The url address to be used by the UDP admin to publish its data. Default the first IP not on localhost
+                                        This can be hostname / IP address / IP address with postfix, e.g. 192.168.1.0/24
+                                        For Multicast use 224.100.0.0/24@192.168.1.0/24, the last digit of the multicast address will be 
+                                        the same as the last digit of the interface. 
+                                        Note when interface is not set, the last digit of the multicast address is generated. 
+
+
+Detailed information can be found at pubsub_admin_udp/README.md
 
 ### Running PSA TCP
 
@@ -77,6 +98,8 @@ properties can be set in the config.properties file (<PROPERTY>=<VALUE> format)
                                         This can be hostname / IP address / IP address with postfix, e.g. 192.168.1.0/24
 
 
+Detailed information can be found at pubsub_admin_tcp/README.md
+
 ### Running PSA ZMQ
 
 For ZeroMQ without encryption, skip the steps 1-12 below
diff --git a/bundles/pubsub/examples/CMakeLists.txt b/bundles/pubsub/examples/CMakeLists.txt
index a34a28b..7e1d0e5 100644
--- a/bundles/pubsub/examples/CMakeLists.txt
+++ b/bundles/pubsub/examples/CMakeLists.txt
@@ -97,6 +97,86 @@ if (BUILD_PUBSUB_PSA_UDP_MC)
     endif ()
 endif()
 
+if (BUILD_PUBSUB_PSA_UDP)
+    # TCP
+    add_celix_container(pubsub_publisher_udp
+        GROUP pubsub
+        BUNDLES
+        Celix::log_admin
+        Celix::shell
+        Celix::shell_tui
+        Celix::celix_pubsub_serializer_json
+        Celix::celix_pubsub_discovery_etcd
+        Celix::celix_pubsub_topology_manager
+        Celix::celix_pubsub_admin_udp
+        Celix::celix_pubsub_protocol_wire_v2
+        celix_pubsub_poi_publisher
+        celix_pubsub_poi_publisher2
+        PROPERTIES
+        PSA_UDP_VERBOSE=true
+        PSA_IP=224.100.0.0/24@192.168.1.0/24
+        PUBSUB_ETCD_DISCOVERY_VERBOSE=true
+        PUBSUB_TOPOLOGY_MANAGER_VERBOSE=true
+        )
+    target_link_libraries(pubsub_publisher_udp PRIVATE ${PUBSUB_CONTAINER_LIBS})
+
+    add_celix_container(pubsub_subscriber_udp
+        GROUP pubsub
+        BUNDLES
+        Celix::log_admin
+        Celix::shell
+        Celix::shell_tui
+        Celix::celix_pubsub_serializer_json
+        Celix::celix_pubsub_discovery_etcd
+        Celix::celix_pubsub_topology_manager
+        Celix::celix_pubsub_admin_udp
+        Celix::celix_pubsub_protocol_wire_v2
+        celix_pubsub_poi_subscriber
+        PROPERTIES
+        PSA_UDP_VERBOSE=true
+        PSA_IP=224.100.0.0/24@192.168.1.0/24
+        PUBSUB_ETCD_DISCOVERY_VERBOSE=true
+        PUBSUB_TOPOLOGY_MANAGER_VERBOSE=true
+        )
+    target_link_libraries(pubsub_subscriber_udp PRIVATE ${PUBSUB_CONTAINER_LIBS})
+
+    add_celix_container(pubsub_subscriber2_udp
+        GROUP pubsub
+        BUNDLES
+        Celix::log_admin
+        Celix::shell
+        Celix::shell_tui
+        Celix::celix_pubsub_serializer_json
+        Celix::celix_pubsub_discovery_etcd
+        Celix::celix_pubsub_topology_manager
+        Celix::celix_pubsub_admin_udp
+        Celix::celix_pubsub_protocol_wire_v2
+        celix_pubsub_poi_subscriber
+        PROPERTIES
+        PSA_UDP_VERBOSE=true
+        PSA_IP=224.100.0.0/24@192.168.1.0/24
+        PUBSUB_ETCD_DISCOVERY_VERBOSE=true
+        PUBSUB_TOPOLOGY_MANAGER_VERBOSE=true
+        )
+    target_link_libraries(pubsub_subscriber2_udp PRIVATE ${PUBSUB_CONTAINER_LIBS})
+
+    if (ETCD_CMD AND XTERM_CMD)
+        # Runtime starting a publish and subscriber for tcp
+        add_celix_runtime(pubsub_rt_udp
+            NAME udp
+            GROUP pubsub
+            CONTAINERS
+            pubsub_publisher_udp
+            pubsub_subscriber_udp
+            pubsub_subscriber2_udp
+            COMMANDS
+            etcd
+            USE_TERM
+            )
+    endif ()
+endif()
+
+
 if (BUILD_PUBSUB_PSA_TCP)
     # TCP
     add_celix_container(pubsub_publisher_tcp
diff --git a/bundles/pubsub/integration/CMakeLists.txt b/bundles/pubsub/integration/CMakeLists.txt
index cc675e1..9083582 100644
--- a/bundles/pubsub/integration/CMakeLists.txt
+++ b/bundles/pubsub/integration/CMakeLists.txt
@@ -188,6 +188,90 @@ if (BUILD_PUBSUB_PSA_UDP_MC)
     #setup_target_for_coverage(pubsub_udpmc_tests SCAN_DIR ..)
 endif()
 
+if (BUILD_PUBSUB_PSA_UDP)
+    add_celix_container(pubsub_udp_tests
+        USE_CONFIG #ensures that a config.properties will be created with the launch bundles.
+        LAUNCHER_SRC ${CMAKE_CURRENT_LIST_DIR}/gtest/PubSubIntegrationTestSuite.cc
+        DIR ${CMAKE_CURRENT_BINARY_DIR}
+        PROPERTIES
+        LOGHELPER_STDOUT_FALLBACK_INCLUDE_DEBUG=true
+        CELIX_LOGGING_DEFAULT_ACTIVE_LOG_LEVEL=trace
+        BUNDLES
+        Celix::celix_pubsub_serializer_json
+        Celix::celix_pubsub_protocol_wire_v2
+        Celix::celix_pubsub_topology_manager
+        Celix::celix_pubsub_admin_udp
+        Celix::shell
+        Celix::shell_tui
+        pubsub_sut
+        pubsub_tst
+        )
+    target_link_libraries(pubsub_udp_tests PRIVATE Celix::pubsub_api Jansson Celix::dfi GTest::gtest GTest::gtest_main)
+    target_include_directories(pubsub_udp_tests SYSTEM PRIVATE gtest)
+
+    add_celix_container(pstm_deadlock_udp_test
+        USE_CONFIG #ensures that a config.properties will be created with the launch bundles.
+        LAUNCHER_SRC ${CMAKE_CURRENT_LIST_DIR}/pstm_deadlock_test/test_runner.cc
+        DIR ${CMAKE_CURRENT_BINARY_DIR}
+        PROPERTIES
+        LOGHELPER_STDOUT_FALLBACK_INCLUDE_DEBUG=true
+        CELIX_LOGGING_DEFAULT_ACTIVE_LOG_LEVEL=trace
+        BUNDLES
+        Celix::celix_pubsub_serializer_json
+        Celix::celix_pubsub_protocol_wire_v2
+        Celix::celix_pubsub_topology_manager
+        Celix::celix_pubsub_admin_udp
+        Celix::shell
+        Celix::shell_tui
+        )
+    target_compile_definitions(pstm_deadlock_udp_test PRIVATE -DDEADLOCK_SUT_BUNDLE_FILE=\"${DEADLOCK_SUT_BUNDLE_FILE}\")
+    target_link_libraries(pstm_deadlock_udp_test PRIVATE Celix::pubsub_api Jansson Celix::dfi GTest::gtest GTest::gtest_main)
+    target_include_directories(pstm_deadlock_udp_test SYSTEM PRIVATE pstm_deadlock_udp_test)
+
+    #Note we do not link to bundles, as result (to ensure a bundle zip file is created) an dependency on the bundle is needed.
+    add_dependencies(pstm_deadlock_udp_test pubsub_deadlock_sut_bundle)
+
+    #Framework "bundle" has no cache dir. Default as "cache dir" the cwd is used.
+    configure_file(${CMAKE_CURRENT_SOURCE_DIR}/meta_data/msg.descriptor ${CMAKE_CURRENT_BINARY_DIR}/pstm_deadlock_udp_gtest/META-INF/descriptors/msg.descriptor COPYONLY)
+    configure_file(${CMAKE_CURRENT_SOURCE_DIR}/meta_data/deadlock.scope.properties ${CMAKE_CURRENT_BINARY_DIR}/pstm_deadlock_udp_gtest/META-INF/topics/pub/deadlock.properties COPYONLY)
+
+    add_test(NAME pstm_deadlock_udp_test COMMAND pstm_deadlock_udp_test WORKING_DIRECTORY $<TARGET_PROPERTY:pstm_deadlock_udp_test,CONTAINER_LOC>)
+    setup_target_for_coverage(pstm_deadlock_udp_test SCAN_DIR ..)
+
+    add_test(NAME pubsub_udp_tests COMMAND pubsub_udp_tests WORKING_DIRECTORY $<TARGET_PROPERTY:pubsub_udp_tests,CONTAINER_LOC>)
+    setup_target_for_coverage(pubsub_udp_tests SCAN_DIR ..)
+
+    add_celix_container(pubsub_udp_v2_endpoint_tests
+        USE_CONFIG #ensures that a config.properties will be created with the launch bundles.
+        LAUNCHER_SRC ${CMAKE_CURRENT_LIST_DIR}/gtest/PubSubEndpointIntegrationTestSuite.cc
+        DIR ${CMAKE_CURRENT_BINARY_DIR}
+        PROPERTIES
+        LOGHELPER_STDOUT_FALLBACK_INCLUDE_DEBUG=true
+        CELIX_LOGGING_DEFAULT_ACTIVE_LOG_LEVEL=trace
+        BUNDLES
+        Celix::shell
+        Celix::shell_tui
+        Celix::celix_pubsub_serializer_json
+        Celix::celix_pubsub_protocol_wire_v2
+        Celix::celix_pubsub_topology_manager
+        Celix::celix_pubsub_admin_udp
+        pubsub_endpoint_tst
+        pubsub_endpoint_sut
+        pubsub_loopback
+        pubsub_serializer
+        )
+    target_link_libraries(pubsub_udp_v2_endpoint_tests PRIVATE Celix::pubsub_api Celix::dfi GTest::gtest GTest::gtest_main)
+    target_include_directories(pubsub_udp_v2_endpoint_tests SYSTEM PRIVATE gtest)
+
+    #TCP Endpoint test is disabled because the test is not stable when running on Travis
+    if (ENABLE_PUBSUB_PSA_UDP_ENDPOINT_TEST)
+        add_test(NAME pubsub_udp_v2_endpoint_tests COMMAND pubsub_udp_v2_endpoint_tests WORKING_DIRECTORY $<TARGET_PROPERTY:pubsub_udp_v2_endpoint_tests,CONTAINER_LOC>)
+        setup_target_for_coverage(pubsub_udp_v2_endpoint_tests SCAN_DIR ..)
+    endif()
+
+
+endif()
+
 if (BUILD_PUBSUB_PSA_TCP)
     # TCP v2 tests
 
diff --git a/bundles/pubsub/integration/gtest/sut_endpoint_activator.c b/bundles/pubsub/integration/gtest/sut_endpoint_activator.c
index 53c7559..44bfafa 100644
--- a/bundles/pubsub/integration/gtest/sut_endpoint_activator.c
+++ b/bundles/pubsub/integration/gtest/sut_endpoint_activator.c
@@ -44,9 +44,9 @@ celix_status_t bnd_start(struct activator *act, celix_bundle_context_t *ctx) {
 	char filter[512];
     bool useNegativeScopeFilter = celix_bundleContext_getPropertyAsBool(ctx, "CELIX_PUBSUB_TEST_USE_NEGATIVE_SCOPE_FILTER", true);
     if (useNegativeScopeFilter) {
-        snprintf(filter, 512, "(%s=%s)(!(scope=*))", PUBSUB_PUBLISHER_TOPIC, "ping");
+        snprintf(filter, 512, "(%s=%s)(!(scope=*))", PUBSUB_PUBLISHER_TOPIC, "ping2");
     } else {
-        snprintf(filter, 512, "(%s=%s)", PUBSUB_PUBLISHER_TOPIC, "ping");
+        snprintf(filter, 512, "(%s=%s)", PUBSUB_PUBLISHER_TOPIC, "ping2");
     }
 	celix_service_tracking_options_t opts = CELIX_EMPTY_SERVICE_TRACKING_OPTIONS;
 	opts.set = sut_pubSet;
diff --git a/bundles/pubsub/integration/meta_data/ping.properties b/bundles/pubsub/integration/meta_data/ping.properties
index 8114413..69019ae 100644
--- a/bundles/pubsub/integration/meta_data/ping.properties
+++ b/bundles/pubsub/integration/meta_data/ping.properties
@@ -18,6 +18,12 @@ zmq.static.bind.url=ipc:///tmp/pubsub-pingtest
 zmq.static.connect.urls=ipc:///tmp/pubsub-pingtest
 tcp.static.bind.url=tcp://localhost:9000
 tcp.static.connect.urls=tcp://localhost:9000
+
+#udp.static.bind.url=udp://224.100.0.1:50678
+#udp.static.connect.urls=udp://224.100.0.1:50678
+udp.static.bind.url=udp://localhost:50679
+udp.static.connect.urls=udp://localhost:50679@localhost:50678
+
 udpmc.static.bind.port=50678
 udpmc.static.connect.socket_addresses=224.100.0.1:50678
 websocket.static.connect.socket_addresses=127.0.0.1:58080
diff --git a/bundles/pubsub/integration/meta_data/ping2.properties b/bundles/pubsub/integration/meta_data/ping2.properties
index ff0dbed..2b7e11b 100644
--- a/bundles/pubsub/integration/meta_data/ping2.properties
+++ b/bundles/pubsub/integration/meta_data/ping2.properties
@@ -17,6 +17,9 @@
 tcp.static.bind.url=tcp://localhost:9500
 tcp.passive.key=tcp://localhost:9500
 
+udp.static.connect.urls=udp://localhost:9500
+udp.passive.key=udp://localhost:9500
+
 #note only effective if run as root
 thread.realtime.sched=SCHED_FIFO
 thread.realtime.prio=50
diff --git a/bundles/pubsub/integration/meta_data/ping3.properties b/bundles/pubsub/integration/meta_data/ping3.properties
index 5571705..f4e87a7 100644
--- a/bundles/pubsub/integration/meta_data/ping3.properties
+++ b/bundles/pubsub/integration/meta_data/ping3.properties
@@ -16,6 +16,8 @@
 # under the License.
 tcp.passive.key=tcp://localhost
 tcp.passive.configured=true
+udp.passive.key=udp://localhost
+udp.passive.configured=true
 #note only effective if run as root
 thread.realtime.sched=SCHED_FIFO
 thread.realtime.prio=50
diff --git a/bundles/pubsub/integration/meta_data/pong2.properties b/bundles/pubsub/integration/meta_data/pong2.properties
index b95f3bc..50c82ac 100644
--- a/bundles/pubsub/integration/meta_data/pong2.properties
+++ b/bundles/pubsub/integration/meta_data/pong2.properties
@@ -17,6 +17,10 @@
 tcp.static.connect.urls=tcp://localhost:9500
 tcp.passive.key=tcp://localhost
 
+#udp.static.connect.urls=udp://localhost:9500
+udp.static.bind.url=udp://localhost:9500
+udp.passive.key=udp://localhost
+
 #note only effective if run as root
 thread.realtime.sched=SCHED_FIFO
 thread.realtime.prio=50
diff --git a/bundles/pubsub/integration/meta_data/pong3.properties b/bundles/pubsub/integration/meta_data/pong3.properties
index cb64543..b4153d4 100644
--- a/bundles/pubsub/integration/meta_data/pong3.properties
+++ b/bundles/pubsub/integration/meta_data/pong3.properties
@@ -16,6 +16,10 @@
 # under the License.
 tcp.passive.key=tcp://localhost:9500
 tcp.passive.configured=true
+
+udp.passive.key=udp://localhost:9500
+udp.passive.configured=true
+
 #note only effective if run as root
 thread.realtime.sched=SCHED_FIFO
 thread.realtime.prio=50
diff --git a/bundles/pubsub/pubsub_admin_tcp/CMakeLists.txt b/bundles/pubsub/pubsub_admin_tcp/CMakeLists.txt
index c3e032c..b98a704 100644
--- a/bundles/pubsub/pubsub_admin_tcp/CMakeLists.txt
+++ b/bundles/pubsub/pubsub_admin_tcp/CMakeLists.txt
@@ -26,8 +26,6 @@ add_celix_bundle(celix_pubsub_admin_tcp
         src/pubsub_tcp_admin.c
         src/pubsub_tcp_topic_sender.c
         src/pubsub_tcp_topic_receiver.c
-        src/pubsub_tcp_handler.c
-        src/pubsub_tcp_common.c
 )
 
 target_link_libraries(celix_pubsub_admin_tcp PRIVATE Celix::pubsub_spi Celix::pubsub_utils)
diff --git a/bundles/pubsub/pubsub_admin_tcp/README.md b/bundles/pubsub/pubsub_admin_tcp/README.md
new file mode 100644
index 0000000..128bf55
--- /dev/null
+++ b/bundles/pubsub/pubsub_admin_tcp/README.md
@@ -0,0 +1,112 @@
+---
+title: PSA TCP 
+---
+
+<!--
+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.
+-->
+
+# PUBSUB-Admin TCP 
+
+---
+
+## Description
+
+The scope of this description is the TCP PubSub admin. 
+
+The TCP pubsub admin is used to transfer user data transparent via TCP.
+
+### IP Addresses 
+
+To use TCP, 1 IP address is needed:
+This is the IP address that is bound to an (ethernet) interface (from the publisher). 
+This IP address is defined with  the `PSA_IP` property.
+For example: `PSA_IP=192.168.1.0/24`.
+Note the example uses CIDR notation, the CIDR notation specifies the IP range that is used
+by the pubsub admin for searching the network interfaces.
+
+Note the port will be automatically assigned, when none is specified.
+A fixed port can be assigned for example with: `PSA_IP=192.168.1.0/24:34000`.
+
+
+### Discovery
+
+When a publisher wants to publish a topic a TopicSender and publisher endpoint is created by the Pubsub Topology Manager.
+When a subscriber wants to subscribe to topic a TopicReceiver and subscriber endpoint is created by the Pubsub Topology Manager.
+The endpoints are published by the PubSubDiscovery within its topic in ETCD (i.e. udp://192.168.1.20:40123).
+A subscriber, interested in the topic, is informed by the TopologyManager that there is a new endpoint. 
+The TopicReceiver at the subscriber side creates a listening socket based on this endpoint.
+Now a data-connection is created and data send by the publisher will be received by the subscriber.  
+
+### Static endpoint
+
+TCP pubsub admin also be used as a static endpoint that can be used to communicate with external
+TCP publish/subsribers that don't use Discovery.
+---
+With the `tcp.static.bind.url` property, the static UDP bind can be configured. 
+For TCP the publisher topic properties should configure the `udp.static.bind.url` property to configure TCP bind interface
+that accepts incomming connections.
+
+---
+With the `udp.static.connect.urls` property, the static TCP connections can be configured. (Note The urls are space separate)
+For TCP the subscriber topic properties should configure the `udp.static.connect.urls` property 
+to configure TCP connections that subsribe to the data.
+
+---
+Note a special/dedicated protocol service implemenation can be used to communcate with external publisher/subscribers 
+
+---
+
+## Passive Endpoints
+
+Each TCP pubsub publisher/subscriber can be comfigured as a passive endpoint. 
+A passive endpoint reuses an existing socket of a publisher/subscriber using properties.
+This can be used to support full duplex socket connections.
+This can be used for both discovery and static end points.
+
+The topic `tcp.passive.key` property defines the unique key to select the socket.
+The `tcp.passive.key` property needs to be defined both in the topic properties of the topic connections that will be shared.
+and the topic properties of the 'passive' topic that will re-use the connection.
+The `tcp.passive.configured` topic property will indicate that is topic is passive and will re-use the connections
+indicated with the `tcp.passive.key` property
+
+For example: `tcp.passive.key=udp://localhost:9500` and `tcp.passive.configured=true`
+
+## IOVEC 
+
+The TCP pubsub uses the socket function calls sendnsg / recvmsg with iovec for sending/receiving messages.
+When the serialisation service supports iovec serialisation.
+iovec serialisation can be used for high throughput and low latency serialisation with avoiding of copying 
+of data. Because of iovec limitations the protocol service should support message segmentation.
+
+## Properties
+
+<table border="1">
+    <tr><th>Property</th><th>Description</th></tr>
+    <tr><td>PSA_IP</td><td>IP address that is used by the bundle</td></tr>
+    <tr><td>tcp.static.bind.url</td><td>The static interface url of the bind interface</td></tr>
+    <tr><td>tcp.static.connect.urls</td><td>a space seperated list with static connections urls</td></tr>
+    <tr><td>tcp.passive.key</td><td>key of the shared connection</td></tr>
+    <tr><td>tcp.passive.configured</td><td>Indicates if the connection is passive and reuses the connection</td></tr>
+    <tr><td>thread.realtime.prio</td><td>Configures the thread priority of the receive thread</td></tr>
+    <tr><td>thread.realtime.sched</td><td>Configures the thread scheduling type of the receive thread</td></tr>
+
+</table>
+
+---
+
+
+
diff --git a/bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_admin.c b/bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_admin.c
index 9806991..79e52fc 100644
--- a/bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_admin.c
+++ b/bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_admin.c
@@ -25,7 +25,7 @@
 #include <pubsub_matching.h>
 #include "pubsub_utils.h"
 #include "pubsub_tcp_admin.h"
-#include "pubsub_tcp_handler.h"
+#include "pubsub_skt_handler.h"
 #include "pubsub_psa_tcp_constants.h"
 #include "pubsub_tcp_topic_sender.h"
 #include "pubsub_tcp_topic_receiver.h"
@@ -79,7 +79,7 @@ struct pubsub_tcp_admin {
         hash_map_t *map; //key = pubsub message serialization marker svc id (long), pubsub_serialization_handler_t*.
     } serializationHandlers;
 
-    pubsub_tcp_endPointStore_t endpointStore;
+    pubsub_sktHandler_endPointStore_t endpointStore;
 };
 
 typedef struct psa_tcp_protocol_entry {
@@ -144,8 +144,8 @@ void pubsub_tcpAdmin_destroy(pubsub_tcp_admin_t *psa) {
     celixThreadMutex_lock(&psa->endpointStore.mutex);
     hash_map_iterator_t iter = hashMapIterator_construct(psa->endpointStore.map);
     while (hashMapIterator_hasNext(&iter)) {
-        pubsub_tcpHandler_t *tcpHandler = hashMapIterator_nextValue(&iter);
-        pubsub_tcpHandler_destroy(tcpHandler);
+        pubsub_sktHandler_t *tcpHandler = hashMapIterator_nextValue(&iter);
+        pubsub_sktHandler_destroy(tcpHandler);
     }
     celixThreadMutex_unlock(&psa->endpointStore.mutex);
 
@@ -219,7 +219,7 @@ void pubsub_tcpAdmin_addProtocolSvc(void *handle, void *svc, const celix_propert
     long svcId = celix_properties_getAsLong(props, OSGI_FRAMEWORK_SERVICE_ID, -1L);
 
     if (protType == NULL) {
-        L_INFO("[PSA_tcp] Ignoring protocol service without %s property", PUBSUB_PROTOCOL_TYPE_KEY);
+        L_INFO("[PSA_TCP] Ignoring protocol service without %s property", PUBSUB_PROTOCOL_TYPE_KEY);
         return;
     }
 
@@ -486,15 +486,18 @@ celix_status_t pubsub_tcpAdmin_setupTopicReceiver(void *handle, const char *scop
     celixThreadMutex_unlock(&psa->protocols.mutex);
 
     if (receiver != NULL && newEndpoint != NULL) {
-        celixThreadMutex_lock(&psa->discoveredEndpoints.mutex);
-        hash_map_iterator_t iter = hashMapIterator_construct(psa->discoveredEndpoints.map);
-        while (hashMapIterator_hasNext(&iter)) {
-            celix_properties_t *endpoint = hashMapIterator_nextValue(&iter);
-            if (pubsub_tcpAdmin_endpointIsPublisher(endpoint) && pubsubEndpoint_matchWithTopicAndScope(endpoint, topic, scope)) {
-                pubsub_tcpAdmin_connectEndpointToReceiver(psa, receiver, endpoint);
-            }
+        if (pubsub_tcpAdmin_endpointIsPublisher(newEndpoint) && pubsubEndpoint_matchWithTopicAndScope(newEndpoint, topic, scope)) {
+            pubsub_tcpAdmin_connectEndpointToReceiver(psa, receiver, newEndpoint);
         }
-        celixThreadMutex_unlock(&psa->discoveredEndpoints.mutex);
+        //celixThreadMutex_lock(&psa->discoveredEndpoints.mutex);
+        //hash_map_iterator_t iter = hashMapIterator_construct(psa->discoveredEndpoints.map);
+        //while (hashMapIterator_hasNext(&iter)) {
+        //    celix_properties_t *endpoint = hashMapIterator_nextValue(&iter);
+        //    if (pubsub_tcpAdmin_endpointIsPublisher(endpoint) && pubsubEndpoint_matchWithTopicAndScope(endpoint, topic, scope)) {
+        //        pubsub_tcpAdmin_connectEndpointToReceiver(psa, receiver, endpoint);
+        //    }
+        //}
+        //celixThreadMutex_unlock(&psa->discoveredEndpoints.mutex);
     }
 
     if (newEndpoint != NULL && outSubscriberEndpoint != NULL) {
diff --git a/bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_common.c b/bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_common.c
deleted file mode 100644
index d8f05f7..0000000
--- a/bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_common.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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.
- */
-#include <stdio.h>
-#include <string.h>
-#include "pubsub_tcp_common.h"
-
-
-bool psa_tcp_isPassive(const char* buffer) {
-    bool isPassive = false;
-    // Parse Properties
-    if (buffer != NULL) {
-        char buf[32];
-        snprintf(buf, 32, "%s", buffer);
-        char *trimmed = utils_stringTrim(buf);
-        if (strncasecmp("true", trimmed, strlen("true")) == 0) {
-            isPassive = true;
-        } else if (strncasecmp("false", trimmed, strlen("false")) == 0) {
-            isPassive = false;
-        }
-    }
-    return isPassive;
-}
diff --git a/bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_common.h b/bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_common.h
deleted file mode 100644
index 9ea31db..0000000
--- a/bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_common.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef CELIX_PUBSUB_TCP_COMMON_H
-#define CELIX_PUBSUB_TCP_COMMON_H
-
-#include <utils.h>
-#include <hash_map.h>
-
-typedef struct pubsub_tcp_endPointStore {
-    celix_thread_mutex_t mutex;
-    hash_map_t *map;
-} pubsub_tcp_endPointStore_t;
-
-bool psa_tcp_isPassive(const char* buffer);
-
-#endif //CELIX_PUBSUB_TCP_COMMON_H
diff --git a/bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_handler.h b/bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_handler.h
deleted file mode 100644
index 2d97634..0000000
--- a/bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_handler.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * 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.
- */
-/*
- * pubsub_tcp_handler.h
- *
- *  \date       July 18, 2016
- *  \author     <a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
- *  \copyright  Apache License, Version 2.0
- */
-
-#ifndef _PUBSUB_TCP_BUFFER_HANDLER_H_
-#define _PUBSUB_TCP_BUFFER_HANDLER_H_
-
-#include <stdbool.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <celix_log_helper.h>
-#include "celix_threads.h"
-#include "pubsub_utils_url.h"
-#include <pubsub_protocol.h>
-
-#ifndef MIN
-#define MIN(a, b) ((a<b) ? (a) : (b))
-#endif
-
-#ifndef MAX
-#define MAX(a, b) ((a>b) ? (a) : (b))
-#endif
-
-typedef struct pubsub_tcpHandler pubsub_tcpHandler_t;
-typedef void(*pubsub_tcpHandler_processMessage_callback_t)
-    (void *payload, const pubsub_protocol_message_t *header, bool *release, struct timespec *receiveTime);
-typedef void (*pubsub_tcpHandler_receiverConnectMessage_callback_t)(void *payload, const char *url, bool lock);
-typedef void (*pubsub_tcpHandler_acceptConnectMessage_callback_t)(void *payload, const char *url);
-
-pubsub_tcpHandler_t *pubsub_tcpHandler_create(pubsub_protocol_service_t *protocol, celix_log_helper_t *logHelper);
-void pubsub_tcpHandler_destroy(pubsub_tcpHandler_t *handle);
-int pubsub_tcpHandler_open(pubsub_tcpHandler_t *handle, char *url);
-int pubsub_tcpHandler_close(pubsub_tcpHandler_t *handle, int fd);
-int pubsub_tcpHandler_connect(pubsub_tcpHandler_t *handle, char *url);
-int pubsub_tcpHandler_disconnect(pubsub_tcpHandler_t *handle, char *url);
-int pubsub_tcpHandler_listen(pubsub_tcpHandler_t *handle, char *url);
-int pubsub_tcpHandler_setReceiveBufferSize(pubsub_tcpHandler_t *handle, unsigned int size);
-int pubsub_tcpHandler_setMaxMsgSize(pubsub_tcpHandler_t *handle, unsigned int size);
-void pubsub_tcpHandler_setTimeout(pubsub_tcpHandler_t *handle, unsigned int timeout);
-void pubsub_tcpHandler_setSendRetryCnt(pubsub_tcpHandler_t *handle, unsigned int count);
-void pubsub_tcpHandler_setReceiveRetryCnt(pubsub_tcpHandler_t *handle, unsigned int count);
-void pubsub_tcpHandler_setSendTimeOut(pubsub_tcpHandler_t *handle, double timeout);
-void pubsub_tcpHandler_setReceiveTimeOut(pubsub_tcpHandler_t *handle, double timeout);
-void pubsub_tcpHandler_enableReceiveEvent(pubsub_tcpHandler_t *handle, bool enable);
-
-int pubsub_tcpHandler_read(pubsub_tcpHandler_t *handle, int fd);
-int pubsub_tcpHandler_write(pubsub_tcpHandler_t *handle,
-                            pubsub_protocol_message_t *message,
-                            struct iovec *msg_iovec,
-                            size_t msg_iov_len,
-                            int flags);
-int pubsub_tcpHandler_addMessageHandler(pubsub_tcpHandler_t *handle,
-                                        void *payload,
-                                        pubsub_tcpHandler_processMessage_callback_t processMessageCallback);
-int pubsub_tcpHandler_addReceiverConnectionCallback(pubsub_tcpHandler_t *handle,
-                                                    void *payload,
-                                                    pubsub_tcpHandler_receiverConnectMessage_callback_t connectMessageCallback,
-                                                    pubsub_tcpHandler_receiverConnectMessage_callback_t disconnectMessageCallback);
-int pubsub_tcpHandler_addAcceptConnectionCallback(pubsub_tcpHandler_t *handle,
-                                                  void *payload,
-                                                  pubsub_tcpHandler_acceptConnectMessage_callback_t connectMessageCallback,
-                                                  pubsub_tcpHandler_acceptConnectMessage_callback_t disconnectMessageCallback);
-char *pubsub_tcpHandler_get_interface_url(pubsub_tcpHandler_t *handle);
-char *pubsub_tcpHandler_get_connection_url(pubsub_tcpHandler_t *handle);
-void pubsub_tcpHandler_setThreadPriority(pubsub_tcpHandler_t *handle, long prio, const char *sched);
-void pubsub_tcpHandler_setThreadName(pubsub_tcpHandler_t *handle, const char *topic, const char *scope);
-
-#endif /* _PUBSUB_TCP_BUFFER_HANDLER_H_ */
diff --git a/bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_topic_receiver.c b/bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_topic_receiver.c
index 597e4ff..d64c79c 100644
--- a/bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_topic_receiver.c
+++ b/bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_topic_receiver.c
@@ -25,11 +25,9 @@
 #include <memory.h>
 #include <arpa/inet.h>
 #include <celix_log_helper.h>
-#include "pubsub_tcp_handler.h"
+#include "pubsub_skt_handler.h"
 #include "pubsub_tcp_topic_receiver.h"
 #include "pubsub_psa_tcp_constants.h"
-#include "pubsub_tcp_common.h"
-#include "pubsub_tcp_admin.h"
 
 #include <uuid/uuid.h>
 #include <pubsub_utils.h>
@@ -62,8 +60,8 @@ struct pubsub_tcp_topic_receiver {
     void *admin;
     size_t timeout;
     bool isPassive;
-    pubsub_tcpHandler_t *socketHandler;
-    pubsub_tcpHandler_t *sharedSocketHandler;
+    pubsub_sktHandler_t *socketHandler;
+    pubsub_sktHandler_t *sharedSocketHandler;
     pubsub_interceptors_handler_t *interceptorsHandler;
 
     struct {
@@ -114,7 +112,7 @@ pubsub_tcp_topic_receiver_t *pubsub_tcpTopicReceiver_create(celix_bundle_context
                                                             pubsub_serializer_handler_t* serializerHandler,
                                                             void *admin,
                                                             const celix_properties_t *topicProperties,
-                                                            pubsub_tcp_endPointStore_t *handlerStore,
+                                                            pubsub_sktHandler_endPointStore_t *handlerStore,
                                                             long protocolSvcId,
                                                             pubsub_protocol_service_t *protocol) {
     pubsub_tcp_topic_receiver_t *receiver = calloc(1, sizeof(*receiver));
@@ -133,7 +131,7 @@ pubsub_tcp_topic_receiver_t *pubsub_tcpTopicReceiver_create(celix_bundle_context
     const char *passiveKey = pubsub_getEnvironmentVariableWithScopeTopic(ctx, PUBSUB_TCP_PASSIVE_SELECTION_KEY, topic, scope);
 
     if (isPassive) {
-        receiver->isPassive = psa_tcp_isPassive(isPassive);
+        receiver->isPassive = pubsub_sktHandler_isPassive(isPassive);
     }
     if (topicProperties != NULL) {
         if(staticConnectUrls == NULL) {
@@ -154,10 +152,10 @@ pubsub_tcp_topic_receiver_t *pubsub_tcpTopicReceiver_create(celix_bundle_context
     /* When it's an endpoint share the socket with the sender */
     if (passiveKey != NULL) {
         celixThreadMutex_lock(&handlerStore->mutex);
-        pubsub_tcpHandler_t *entry = hashMap_get(handlerStore->map, passiveKey);
+        pubsub_sktHandler_t *entry = hashMap_get(handlerStore->map, passiveKey);
         if (entry == NULL) {
             if (receiver->socketHandler == NULL)
-                receiver->socketHandler = pubsub_tcpHandler_create(receiver->protocol, receiver->logHelper);
+                receiver->socketHandler = pubsub_sktHandler_create(receiver->protocol, receiver->logHelper);
             entry = receiver->socketHandler;
             receiver->sharedSocketHandler = receiver->socketHandler;
             hashMap_put(handlerStore->map, (void *) passiveKey, entry);
@@ -167,7 +165,7 @@ pubsub_tcp_topic_receiver_t *pubsub_tcpTopicReceiver_create(celix_bundle_context
         }
         celixThreadMutex_unlock(&handlerStore->mutex);
     } else {
-        receiver->socketHandler = pubsub_tcpHandler_create(receiver->protocol, receiver->logHelper);
+        receiver->socketHandler = pubsub_sktHandler_create(receiver->protocol, receiver->logHelper);
     }
 
     if (receiver->socketHandler != NULL) {
@@ -180,15 +178,15 @@ pubsub_tcp_topic_receiver_t *pubsub_tcpTopicReceiver_create(celix_bundle_context
                                                                  PSA_TCP_DEFAULT_RECV_BUFFER_SIZE);
         long timeout = celix_bundleContext_getPropertyAsLong(ctx, PSA_TCP_TIMEOUT, PSA_TCP_DEFAULT_TIMEOUT);
 
-        pubsub_tcpHandler_setThreadName(receiver->socketHandler, topic, scope);
-        pubsub_tcpHandler_setReceiveBufferSize(receiver->socketHandler, (unsigned int) bufferSize);
-        pubsub_tcpHandler_setTimeout(receiver->socketHandler, (unsigned int) timeout);
-        pubsub_tcpHandler_addMessageHandler(receiver->socketHandler, receiver, processMsg);
-        pubsub_tcpHandler_addReceiverConnectionCallback(receiver->socketHandler, receiver, psa_tcp_connectHandler,
+        pubsub_sktHandler_setThreadName(receiver->socketHandler, topic, scope);
+        pubsub_sktHandler_setReceiveBufferSize(receiver->socketHandler, (unsigned int) bufferSize);
+        pubsub_sktHandler_setTimeout(receiver->socketHandler, (unsigned int) timeout);
+        pubsub_sktHandler_addMessageHandler(receiver->socketHandler, receiver, processMsg);
+        pubsub_sktHandler_addReceiverConnectionCallback(receiver->socketHandler, receiver, psa_tcp_connectHandler,
                                                         psa_tcp_disConnectHandler);
-        pubsub_tcpHandler_setThreadPriority(receiver->socketHandler, prio, sched);
-        pubsub_tcpHandler_setReceiveRetryCnt(receiver->socketHandler, (unsigned int) retryCnt);
-        pubsub_tcpHandler_setReceiveTimeOut(receiver->socketHandler, rcvTimeout);
+        pubsub_sktHandler_setThreadPriority(receiver->socketHandler, prio, sched);
+        pubsub_sktHandler_setReceiveRetryCnt(receiver->socketHandler, (unsigned int) retryCnt);
+        pubsub_sktHandler_setReceiveTimeOut(receiver->socketHandler, rcvTimeout);
     }
     celixThreadMutex_create(&receiver->subscribers.mutex, NULL);
     celixThreadMutex_create(&receiver->requestedConnections.mutex, NULL);
@@ -281,10 +279,10 @@ void pubsub_tcpTopicReceiver_destroy(pubsub_tcp_topic_receiver_t *receiver) {
         celixThreadMutex_destroy(&receiver->requestedConnections.mutex);
         celixThreadMutex_destroy(&receiver->thread.mutex);
 
-        pubsub_tcpHandler_addMessageHandler(receiver->socketHandler, NULL, NULL);
-        pubsub_tcpHandler_addReceiverConnectionCallback(receiver->socketHandler, NULL, NULL, NULL);
+        pubsub_sktHandler_addMessageHandler(receiver->socketHandler, NULL, NULL);
+        pubsub_sktHandler_addReceiverConnectionCallback(receiver->socketHandler, NULL, NULL, NULL);
         if ((receiver->socketHandler) && (receiver->sharedSocketHandler == NULL)) {
-            pubsub_tcpHandler_destroy(receiver->socketHandler);
+            pubsub_sktHandler_destroy(receiver->socketHandler);
             receiver->socketHandler = NULL;
         }
         pubsubInterceptorsHandler_destroy(receiver->interceptorsHandler);
@@ -316,7 +314,7 @@ void pubsub_tcpTopicReceiver_listConnections(pubsub_tcp_topic_receiver_t *receiv
                                              celix_array_list_t *unconnectedUrls) {
     celixThreadMutex_lock(&receiver->requestedConnections.mutex);
     if (receiver->isPassive) {
-        char* interface_url = pubsub_tcpHandler_get_interface_url(receiver->socketHandler);
+        char* interface_url = pubsub_sktHandler_get_interface_url(receiver->socketHandler);
         char *url = NULL;
         asprintf(&url, "%s (passive)", interface_url ? interface_url : "");
         if (interface_url) {
@@ -378,7 +376,7 @@ void pubsub_tcpTopicReceiver_disconnectFrom(pubsub_tcp_topic_receiver_t *receive
     celixThreadMutex_lock(&receiver->requestedConnections.mutex);
     psa_tcp_requested_connection_entry_t *entry = hashMap_remove(receiver->requestedConnections.map, url);
     if (entry != NULL) {
-        int rc = pubsub_tcpHandler_disconnect(receiver->socketHandler, entry->url);
+        int rc = pubsub_sktHandler_disconnect(receiver->socketHandler, entry->url);
         if (rc < 0)
             L_WARN("[PSA_TCP] Error disconnecting from tcp url %s. (%s)", url, strerror(errno));
     }
@@ -582,7 +580,7 @@ static void psa_tcp_connectToAllRequestedConnections(pubsub_tcp_topic_receiver_t
         while (hashMapIterator_hasNext(&iter)) {
             psa_tcp_requested_connection_entry_t *entry = hashMapIterator_nextValue(&iter);
             if ((entry) && (!entry->connected) && (!receiver->isPassive)) {
-                int rc = pubsub_tcpHandler_connect(entry->parent->socketHandler, entry->url);
+                int rc = pubsub_sktHandler_tcp_connect(entry->parent->socketHandler, entry->url);
                 if (rc < 0) {
                     allConnected = false;
                 }
diff --git a/bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_topic_receiver.h b/bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_topic_receiver.h
index 35c14c6..9fbd59a 100644
--- a/bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_topic_receiver.h
+++ b/bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_topic_receiver.h
@@ -23,7 +23,7 @@
 #include "pubsub_admin_metrics.h"
 #include "celix_bundle_context.h"
 #include "pubsub_protocol.h"
-#include "pubsub_tcp_common.h"
+#include "pubsub_skt_handler.h"
 #include "pubsub_serializer_handler.h"
 
 typedef struct pubsub_tcp_topic_receiver pubsub_tcp_topic_receiver_t;
@@ -35,7 +35,7 @@ pubsub_tcp_topic_receiver_t *pubsub_tcpTopicReceiver_create(celix_bundle_context
                                                             pubsub_serializer_handler_t* serializerHandler,
                                                             void *admin,
                                                             const celix_properties_t *topicProperties,
-                                                            pubsub_tcp_endPointStore_t *handlerStore,
+                                                            pubsub_sktHandler_endPointStore_t *handlerStore,
                                                             long protocolSvcId,
                                                             pubsub_protocol_service_t *protocol);
 void pubsub_tcpTopicReceiver_destroy(pubsub_tcp_topic_receiver_t *receiver);
diff --git a/bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_topic_sender.c b/bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_topic_sender.c
index e318829..cdcdb8f 100644
--- a/bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_topic_sender.c
+++ b/bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_topic_sender.c
@@ -29,13 +29,11 @@
 #include <celix_log_helper.h>
 #include "pubsub_psa_tcp_constants.h"
 #include "pubsub_tcp_topic_sender.h"
-#include "pubsub_tcp_handler.h"
-#include "pubsub_tcp_common.h"
+#include "pubsub_skt_handler.h"
 #include <uuid/uuid.h>
 #include "celix_constants.h"
 #include <pubsub_utils.h>
 #include "pubsub_interceptors_handler.h"
-#include "pubsub_tcp_admin.h"
 
 #define TCP_BIND_MAX_RETRY                      10
 
@@ -54,8 +52,8 @@ struct pubsub_tcp_topic_sender {
     long protocolSvcId;
     pubsub_protocol_service_t *protocol;
     uuid_t fwUUID;
-    pubsub_tcpHandler_t *socketHandler;
-    pubsub_tcpHandler_t *sharedSocketHandler;
+    pubsub_sktHandler_t *socketHandler;
+    pubsub_sktHandler_t *sharedSocketHandler;
     pubsub_interceptors_handler_t *interceptorsHandler;
     pubsub_serializer_handler_t* serializerHandler;
 
@@ -108,7 +106,7 @@ pubsub_tcp_topic_sender_t *pubsub_tcpTopicSender_create(
     pubsub_serializer_handler_t* serializerHandler,
     void *admin,
     const celix_properties_t *topicProperties,
-    pubsub_tcp_endPointStore_t *handlerStore,
+    pubsub_sktHandler_endPointStore_t *handlerStore,
     long protocolSvcId,
     pubsub_protocol_service_t *protocol) {
     pubsub_tcp_topic_sender_t *sender = calloc(1, sizeof(*sender));
@@ -132,7 +130,7 @@ pubsub_tcp_topic_sender_t *pubsub_tcpTopicSender_create(
     const char *passiveKey = pubsub_getEnvironmentVariableWithScopeTopic(ctx, PUBSUB_TCP_PASSIVE_SELECTION_KEY, topic, scope);
 
     if (isPassive) {
-        sender->isPassive = psa_tcp_isPassive(isPassive);
+        sender->isPassive = pubsub_sktHandler_isPassive(isPassive);
     }
     if (topicProperties != NULL) {
         if (discUrl == NULL) {
@@ -148,10 +146,10 @@ pubsub_tcp_topic_sender_t *pubsub_tcpTopicSender_create(
     /* When it's an endpoint share the socket with the receiver */
     if (passiveKey != NULL) {
         celixThreadMutex_lock(&handlerStore->mutex);
-        pubsub_tcpHandler_t *entry = hashMap_get(handlerStore->map, passiveKey);
+        pubsub_sktHandler_t *entry = hashMap_get(handlerStore->map, passiveKey);
         if (entry == NULL) {
             if (sender->socketHandler == NULL)
-                sender->socketHandler = pubsub_tcpHandler_create(sender->protocol, sender->logHelper);
+                sender->socketHandler = pubsub_sktHandler_create(sender->protocol, sender->logHelper);
             entry = sender->socketHandler;
             sender->sharedSocketHandler = sender->socketHandler;
             hashMap_put(handlerStore->map, (void *) passiveKey, entry);
@@ -161,7 +159,7 @@ pubsub_tcp_topic_sender_t *pubsub_tcpTopicSender_create(
         }
         celixThreadMutex_unlock(&handlerStore->mutex);
     } else {
-        sender->socketHandler = pubsub_tcpHandler_create(sender->protocol, sender->logHelper);
+        sender->socketHandler = pubsub_sktHandler_create(sender->protocol, sender->logHelper);
     }
 
     if ((sender->socketHandler != NULL) && (topicProperties != NULL)) {
@@ -172,15 +170,15 @@ pubsub_tcp_topic_sender_t *pubsub_tcpTopicSender_create(
         long maxMsgSize = celix_properties_getAsLong(topicProperties, PSA_TCP_MAX_MESSAGE_SIZE, PSA_TCP_DEFAULT_MAX_MESSAGE_SIZE);
         long timeout = celix_bundleContext_getPropertyAsLong(ctx, PSA_TCP_TIMEOUT, PSA_TCP_DEFAULT_TIMEOUT);
         sender->send_delay = celix_bundleContext_getPropertyAsLong(ctx,  PUBSUB_UTILS_PSA_SEND_DELAY, PUBSUB_UTILS_PSA_DEFAULT_SEND_DELAY);
-        pubsub_tcpHandler_setThreadName(sender->socketHandler, topic, scope);
-        pubsub_tcpHandler_setThreadPriority(sender->socketHandler, prio, sched);
-        pubsub_tcpHandler_setSendRetryCnt(sender->socketHandler, (unsigned int) retryCnt);
-        pubsub_tcpHandler_setSendTimeOut(sender->socketHandler, sendTimeout);
-        pubsub_tcpHandler_setMaxMsgSize(sender->socketHandler, (unsigned int) maxMsgSize);
+        pubsub_sktHandler_setThreadName(sender->socketHandler, topic, scope);
+        pubsub_sktHandler_setThreadPriority(sender->socketHandler, prio, sched);
+        pubsub_sktHandler_setSendRetryCnt(sender->socketHandler, (unsigned int) retryCnt);
+        pubsub_sktHandler_setSendTimeOut(sender->socketHandler, sendTimeout);
+        pubsub_sktHandler_setMaxMsgSize(sender->socketHandler, (unsigned int) maxMsgSize);
         // When passiveKey is specified, enable receive event for full-duplex connection using key.
         // Because the topic receiver is already started, enable the receive event.
-        pubsub_tcpHandler_enableReceiveEvent(sender->socketHandler, (passiveKey) ? true : false);
-        pubsub_tcpHandler_setTimeout(sender->socketHandler, (unsigned int) timeout);
+        pubsub_sktHandler_enableReceiveEvent(sender->socketHandler, (passiveKey) ? true : false);
+        pubsub_sktHandler_setTimeout(sender->socketHandler, (unsigned int) timeout);
     }
 
     if (!sender->isPassive) {
@@ -203,7 +201,7 @@ pubsub_tcp_topic_sender_t *pubsub_tcpTopicSender_create(
                 int retry = 0;
                 while (url && retry < TCP_BIND_MAX_RETRY) {
                     pubsub_utils_url_t *urlInfo = pubsub_utils_url_parse(url);
-                    int rc = pubsub_tcpHandler_listen(sender->socketHandler, urlInfo->url);
+                    int rc = pubsub_sktHandler_tcp_listen(sender->socketHandler, urlInfo->url);
                     if (rc < 0) {
                         L_WARN("Error for tcp_bind using dynamic bind url '%s'. %s", urlInfo->url, strerror(errno));
                     } else {
@@ -214,7 +212,7 @@ pubsub_tcp_topic_sender_t *pubsub_tcpTopicSender_create(
                 }
             }
             free(urlsCopy);
-            sender->url = pubsub_tcpHandler_get_interface_url(sender->socketHandler);
+            sender->url = pubsub_sktHandler_get_interface_url(sender->socketHandler);
         }
         free(urls);
     }
@@ -269,7 +267,7 @@ void pubsub_tcpTopicSender_destroy(pubsub_tcp_topic_sender_t *sender) {
 
         pubsubInterceptorsHandler_destroy(sender->interceptorsHandler);
         if ((sender->socketHandler) && (sender->sharedSocketHandler == NULL)) {
-            pubsub_tcpHandler_destroy(sender->socketHandler);
+            pubsub_sktHandler_destroy(sender->socketHandler);
             sender->socketHandler = NULL;
         }
 
@@ -300,7 +298,7 @@ const char* pubsub_tcpTopicSender_serializerType(pubsub_tcp_topic_sender_t *send
 
 const char *pubsub_tcpTopicSender_url(pubsub_tcp_topic_sender_t *sender) {
     if (sender->isPassive) {
-        return pubsub_tcpHandler_get_connection_url(sender->socketHandler);
+        return pubsub_sktHandler_get_connection_url(sender->socketHandler);
     } else {
         return sender->url;
     }
@@ -411,7 +409,7 @@ psa_tcp_topicPublicationSend(void *handle, unsigned int msgTypeId, const void *i
     }
     bool sendOk = true;
     {
-        int rc = pubsub_tcpHandler_write(sender->socketHandler, &message, serializedIoVecOutput, serializedIoVecOutputLen, 0);
+        int rc = pubsub_sktHandler_write(sender->socketHandler, &message, serializedIoVecOutput, serializedIoVecOutputLen, 0);
         if (rc < 0) {
             status = -1;
             sendOk = false;
diff --git a/bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_topic_sender.h b/bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_topic_sender.h
index 57b13a6..1a4962e 100644
--- a/bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_topic_sender.h
+++ b/bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_topic_sender.h
@@ -23,7 +23,7 @@
 #include "celix_bundle_context.h"
 #include "pubsub_admin_metrics.h"
 #include "pubsub_protocol.h"
-#include "pubsub_tcp_common.h"
+#include "pubsub_skt_handler.h"
 #include "pubsub_serializer_handler.h"
 
 typedef struct pubsub_tcp_topic_sender pubsub_tcp_topic_sender_t;
@@ -36,7 +36,7 @@ pubsub_tcp_topic_sender_t *pubsub_tcpTopicSender_create(
     pubsub_serializer_handler_t* serializerHandler,
     void *admin,
     const celix_properties_t *topicProperties,
-    pubsub_tcp_endPointStore_t *handlerStore,
+    pubsub_sktHandler_endPointStore_t *handlerStore,
     long protocolSvcId,
     pubsub_protocol_service_t *prot);
 
diff --git a/bundles/pubsub/pubsub_admin_tcp/CMakeLists.txt b/bundles/pubsub/pubsub_admin_udp/CMakeLists.txt
similarity index 59%
copy from bundles/pubsub/pubsub_admin_tcp/CMakeLists.txt
copy to bundles/pubsub/pubsub_admin_udp/CMakeLists.txt
index c3e032c..fba7211 100644
--- a/bundles/pubsub/pubsub_admin_tcp/CMakeLists.txt
+++ b/bundles/pubsub/pubsub_admin_udp/CMakeLists.txt
@@ -17,27 +17,25 @@
 
 find_package(UUID REQUIRED)
 
-add_celix_bundle(celix_pubsub_admin_tcp
-    BUNDLE_SYMBOLICNAME "apache_celix_pubsub_admin_tcp"
+add_celix_bundle(celix_pubsub_admin_udp
+    BUNDLE_SYMBOLICNAME "apache_celix_pubsub_admin_udp"
     VERSION "2.0.0"
     GROUP "Celix/PubSub"
     SOURCES
         src/psa_activator.c
-        src/pubsub_tcp_admin.c
-        src/pubsub_tcp_topic_sender.c
-        src/pubsub_tcp_topic_receiver.c
-        src/pubsub_tcp_handler.c
-        src/pubsub_tcp_common.c
+        src/pubsub_udp_admin.c
+        src/pubsub_udp_topic_sender.c
+        src/pubsub_udp_topic_receiver.c
 )
 
-target_link_libraries(celix_pubsub_admin_tcp PRIVATE Celix::pubsub_spi Celix::pubsub_utils)
-target_link_libraries(celix_pubsub_admin_tcp PRIVATE Celix::framework Celix::log_helper)
-target_link_libraries(celix_pubsub_admin_tcp PRIVATE Celix::shell_api)
-target_include_directories(celix_pubsub_admin_tcp PRIVATE src)
+target_link_libraries(celix_pubsub_admin_udp PRIVATE Celix::pubsub_spi Celix::pubsub_utils)
+target_link_libraries(celix_pubsub_admin_udp PRIVATE Celix::framework Celix::log_helper)
+target_link_libraries(celix_pubsub_admin_udp PRIVATE Celix::shell_api)
+target_include_directories(celix_pubsub_admin_udp PRIVATE src)
 # cmake find package UUID set the wrong include dir for OSX
 if (NOT APPLE)
-    target_link_libraries(celix_pubsub_admin_tcp PRIVATE UUID::lib)
+    target_link_libraries(celix_pubsub_admin_udp PRIVATE UUID::lib)
 endif()
 
-install_celix_bundle(celix_pubsub_admin_tcp EXPORT celix COMPONENT pubsub)
-add_library(Celix::celix_pubsub_admin_tcp ALIAS celix_pubsub_admin_tcp)
+install_celix_bundle(celix_pubsub_admin_udp EXPORT celix COMPONENT pubsub)
+add_library(Celix::celix_pubsub_admin_udp ALIAS celix_pubsub_admin_udp)
diff --git a/bundles/pubsub/pubsub_admin_udp/README.md b/bundles/pubsub/pubsub_admin_udp/README.md
new file mode 100644
index 0000000..5e96625
--- /dev/null
+++ b/bundles/pubsub/pubsub_admin_udp/README.md
@@ -0,0 +1,149 @@
+---
+title: PSA UDP 
+---
+
+<!--
+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.
+-->
+
+# PUBSUB-Admin UDP 
+
+---
+
+## Description
+
+The scope of this description is the UDP PubSub admin. 
+
+The UDP pubsub admin is used to transfer user data transparent via UDP unicast, UDP broadcast and UDP multicast.
+UDP support packets with a maximum of 64kB . To overcome this limit the admin uses a protocol service on top of UDP 
+which fragments the data to be send and these fragments are reassembled at the reception side.
+
+### IP Addresses Unicast
+
+To use UDP-unicast, 1 IP address is needed:
+This is the IP address that is bound to an (ethernet) interface (from the subscriber). 
+This IP address is defined with  the `PSA_IP` property.
+For example: `PSA_IP=192.168.1.0/24`.
+Note the example uses CIDR notation, the CIDR notation specifies the IP range that is used
+by the pubsub admin for searching the network interfaces.
+
+Note the port will be automatically assigned, when none is specified.
+A fixed port can be assigned for example with: `PSA_IP=192.168.1.0/24:34000`.
+
+### IP Address Mulicast
+
+To use UDP-multicast 2 IP addresses are needed:
+
+1. The multicast address (in the range 224.X.X.X - 239.X.X.X)
+2. IP address which is bound to an (ethernet) interface (from the publisher)
+
+These IP address are defined with the `PSA_IP` property, 
+with the definition multicast ip address at (ethernet) interface ip address
+For example: `PSA_IP=224.100.0.0/24@192.168.1.0/24`.
+Note the example uses CIDR notation, the CIDR notation specifies the IP range that is used
+by the pubsub admin for searching the network interfaces. 
+The multicast address will use the last digits of the network interface IP address 
+for an unique multicast address.   
+
+Note the port will be automatically assigned, when none is specified.
+A fixed port can be assigned for example with: `PSA_IP=224.100.0.0/24:34000@192.168.1.0/24`.
+
+### IP Address Broadcast
+
+To use UDP-broad 2 IP addresses are needed:
+
+1. The broadcast address (X.X.X.255)
+2. IP address which is bound to an (ethernet) interface (from the publisher)
+
+These IP address are defined with the `PSA_IP` property,
+with the definition broadcast ip address at (etnernet) interface ip address
+For example: `PSA_IP=192.168.1.255@192.168.1.0/24`.
+Note the example uses CIDR notation, the CIDR notation specifies the IP range that is used
+by the pubsub admin for searching the network interfaces. 
+
+Note the port will be automatically assigned, when none is specified.
+A fixed port can be assigned for example with: `PSA_IP=192.168.1.255:34000@192.168.1.0/24:34000`.
+
+
+### Discovery
+
+When a publisher wants to publish a topic a TopicSender and publisher endpoint is created by the PubSub Topology Manager.
+When a subscriber wants to subscribe to topic a TopicReceiver and subscriber endpoint is created by the Pubsub Topology Manager.
+The endpoints are published by the PubSubDiscovery within its topic in ETCD (i.e. udp://192.168.1.20:40123).
+A subscriber, interested in the topic, is informed by the TopologyManager that there is a new endpoint. 
+The TopicReceiver at the subscriber side creates a listening socket based on this endpoint.
+Now a data-connection is created and data send by the publisher will be received by the subscriber.  
+
+
+### Static endpoint
+
+UDP pubsub admin also be used as a static endpoint that can be used to communicate with external
+UDP publish/subsribers that don't use Discovery.
+---
+With the `udp.static.bind.url` property, the static UDP bind can be configured.
+1. For UDP unicast the subscriber topic properties should configure the `udp.static.bind.url` property to configure UDP destination.
+2. For UDP multicast the publisher topic properties should configure the `udp.static.bind.url` property to configure UDP multicast bind interface.
+3. For UDP broadcast the publisher topic properties should configure the `udp.static.bind.url` property to configure UDP broadcast bind interface.
+---
+With the `udp.static.connect.urls` property, the static UDP connections can be configured. (Note The urls are space separate)
+1. For UDP unicast the publisher topic properties should configure the `udp.static.connect.urls` property to configure UDP connections were to send the data.
+2. For UDP multicast the subscriber topic properties should configure the `udp.static.connect.urls` property to configure UDP multicast connection.
+3. For UDP broadcast the subscriber topic properties should configure the `udp.static.connect.urls` property to configure UDP broadcast connection.
+---
+Note a special/dedicated protocol service implemenation can be used to communcate with external publisher/subscribers 
+
+---
+
+## Passive Endpoints
+
+Each UDP pubsub publisher/subscriber can be comfigured as a passive endpoint. 
+A passive endpoint reuses an existing socket of a publisher/subscriber using properties.
+This can be used to support full duplex socket connections.
+This can be used for both discovery and static end points.
+
+The topic `udp.passive.key` property defines the unique key to select the socket.
+The `udp.passive.key` property needs to be defined both in the topic properties of the topic connections that will be shared.
+and the topic properties of the 'passive' topic that will re-use the connection.
+The `udp.passive.configured` topic property will indicate that is topic is passive and will re-use the connections
+indicated with the `udp.passive.key` property
+
+For example: `udp.passive.key=udp://localhost:9500` and `udp.passive.configured=true`
+
+## IOVEC 
+
+The UDP pubsub uses the socket function calls sendnsg / recvmsg with iovec for sending/receiving messages.
+When the serialisation service supports iovec serialisation.
+iovec serialisation can be used for high throughput and low latency serialisation with avoiding of copying 
+of data. Because of iovec limitations the protocol service should support message segmentation.
+
+## Properties
+
+<table border="1">
+    <tr><th>Property</th><th>Description</th></tr>
+    <tr><td>PSA_IP</td><td>Unicast/Multicast/Broadcast IP address that is used by the bundle</td></tr>
+    <tr><td>udp.static.bind.url</td><td>The static interface url of the bind interface</td></tr>
+    <tr><td>udp.static.connect.urls</td><td>a space seperated list with static connections urls</td></tr>
+    <tr><td>udp.passive.key</td><td>key of the shared connection</td></tr>
+    <tr><td>udp.passive.configured</td><td>Indicates if the connection is passive and reuses the connection</td></tr>
+    <tr><td>thread.realtime.prio</td><td>Configures the thread priority of the receive thread</td></tr>
+    <tr><td>thread.realtime.sched</td><td>Configures the thread scheduling type of the receive thread</td></tr>
+
+</table>
+
+---
+
+
+
diff --git a/bundles/pubsub/pubsub_admin_udp/src/psa_activator.c b/bundles/pubsub/pubsub_admin_udp/src/psa_activator.c
new file mode 100644
index 0000000..c6a9c10
--- /dev/null
+++ b/bundles/pubsub/pubsub_admin_udp/src/psa_activator.c
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ */
+
+#include <stdlib.h>
+
+#include "celix_api.h"
+#include "pubsub_protocol.h"
+#include "celix_log_helper.h"
+
+#include "pubsub_admin.h"
+#include "pubsub_admin_metrics.h"
+#include "pubsub_udp_admin.h"
+#include "celix_shell_command.h"
+
+typedef struct psa_udp_activator {
+    celix_log_helper_t *logHelper;
+
+    pubsub_udp_admin_t *admin;
+
+    long protocolsTrackerId;
+
+    pubsub_admin_service_t adminService;
+    long adminSvcId;
+
+    pubsub_admin_metrics_service_t adminMetricsService;
+    long adminMetricsSvcId;
+
+    celix_shell_command_t cmdSvc;
+    long cmdSvcId;
+} psa_udp_activator_t;
+
+int psa_udp_start(psa_udp_activator_t *act, celix_bundle_context_t *ctx) {
+    act->adminSvcId = -1L;
+    act->cmdSvcId = -1L;
+    act->protocolsTrackerId = -1L;
+
+    act->logHelper = celix_logHelper_create(ctx, "celix_psa_admin_udp_v2");
+
+    act->admin = pubsub_udpAdmin_create(ctx, act->logHelper);
+    celix_status_t status = act->admin != NULL ? CELIX_SUCCESS : CELIX_BUNDLE_EXCEPTION;
+
+    //track protocols
+    if (status == CELIX_SUCCESS) {
+        celix_service_tracking_options_t opts = CELIX_EMPTY_SERVICE_TRACKING_OPTIONS;
+        opts.filter.serviceName = PUBSUB_PROTOCOL_SERVICE_NAME;
+        opts.filter.ignoreServiceLanguage = true;
+        opts.callbackHandle = act->admin;
+        opts.addWithProperties = pubsub_udpAdmin_addProtocolSvc;
+        opts.removeWithProperties = pubsub_udpAdmin_removeProtocolSvc;
+        act->protocolsTrackerId = celix_bundleContext_trackServicesWithOptions(ctx, &opts);
+    }
+
+    //register pubsub admin service
+    if (status == CELIX_SUCCESS) {
+        pubsub_admin_service_t *psaSvc = &act->adminService;
+        psaSvc->handle = act->admin;
+        psaSvc->matchPublisher = pubsub_udpAdmin_matchPublisher;
+        psaSvc->matchSubscriber = pubsub_udpAdmin_matchSubscriber;
+        psaSvc->matchDiscoveredEndpoint = pubsub_udpAdmin_matchDiscoveredEndpoint;
+        psaSvc->setupTopicSender = pubsub_udpAdmin_setupTopicSender;
+        psaSvc->teardownTopicSender = pubsub_udpAdmin_teardownTopicSender;
+        psaSvc->setupTopicReceiver = pubsub_udpAdmin_setupTopicReceiver;
+        psaSvc->teardownTopicReceiver = pubsub_udpAdmin_teardownTopicReceiver;
+        psaSvc->addDiscoveredEndpoint = pubsub_udpAdmin_addDiscoveredEndpoint;
+        psaSvc->removeDiscoveredEndpoint = pubsub_udpAdmin_removeDiscoveredEndpoint;
+
+        celix_properties_t *props = celix_properties_create();
+        celix_properties_set(props, PUBSUB_ADMIN_SERVICE_TYPE, PUBSUB_UDP_ADMIN_TYPE);
+
+        act->adminSvcId = celix_bundleContext_registerService(ctx, psaSvc, PUBSUB_ADMIN_SERVICE_NAME, props);
+    }
+
+    if (status == CELIX_SUCCESS) {
+        act->adminMetricsService.handle = act->admin;
+        act->adminMetricsService.metrics = pubsub_udpAdmin_metrics;
+
+        celix_properties_t *props = celix_properties_create();
+        celix_properties_set(props, PUBSUB_ADMIN_SERVICE_TYPE, PUBSUB_UDP_ADMIN_TYPE);
+
+        act->adminMetricsSvcId =
+            celix_bundleContext_registerService(ctx,
+                                                &act->adminMetricsService,
+                                                PUBSUB_ADMIN_METRICS_SERVICE_NAME,
+                                                props);
+    }
+
+    //register shell command service
+    {
+        act->cmdSvc.handle = act->admin;
+        act->cmdSvc.executeCommand = pubsub_udpAdmin_executeCommand;
+        celix_properties_t *props = celix_properties_create();
+        celix_properties_set(props, CELIX_SHELL_COMMAND_NAME, "celix::psa_udp");
+        celix_properties_set(props, CELIX_SHELL_COMMAND_USAGE, "psa_udp");
+        celix_properties_set(props, CELIX_SHELL_COMMAND_DESCRIPTION, "Print the information about the TopicSender and TopicReceivers for the udp PSA");
+        act->cmdSvcId = celix_bundleContext_registerService(ctx, &act->cmdSvc, CELIX_SHELL_COMMAND_SERVICE_NAME, props);
+    }
+
+    return status;
+}
+
+int psa_udp_stop(psa_udp_activator_t *act, celix_bundle_context_t *ctx) {
+    celix_bundleContext_unregisterService(ctx, act->adminSvcId);
+    celix_bundleContext_unregisterService(ctx, act->cmdSvcId);
+    celix_bundleContext_unregisterService(ctx, act->adminMetricsSvcId);
+    celix_bundleContext_stopTracker(ctx, act->protocolsTrackerId);
+    pubsub_udpAdmin_destroy(act->admin);
+
+    celix_logHelper_destroy(act->logHelper);
+
+    return CELIX_SUCCESS;
+}
+
+CELIX_GEN_BUNDLE_ACTIVATOR(psa_udp_activator_t, psa_udp_start, psa_udp_stop);
diff --git a/bundles/pubsub/pubsub_admin_udp/src/pubsub_psa_udp_constants.h b/bundles/pubsub/pubsub_admin_udp/src/pubsub_psa_udp_constants.h
new file mode 100644
index 0000000..a79d2f0
--- /dev/null
+++ b/bundles/pubsub/pubsub_admin_udp/src/pubsub_psa_udp_constants.h
@@ -0,0 +1,136 @@
+/*
+ * 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.
+ */
+
+#ifndef PUBSUB_PSA_UDP_CONSTANTS_H_
+#define PUBSUB_PSA_UDP_CONSTANTS_H_
+
+#define PSA_UDP_BASE_PORT                       "PSA_UDP_BASE_PORT"
+#define PSA_UDP_MAX_PORT                        "PSA_UDP_MAX_PORT"
+
+#define PSA_UDP_MAX_MESSAGE_SIZE                "PSA_UDP_MAX_MESSAGE_SIZE"
+#define PSA_UDP_RECV_BUFFER_SIZE                "PSA_UDP_RECV_BUFFER_SIZE"
+#define PSA_UDP_TIMEOUT                         "PSA_UDP_TIMEOUT"
+#define PSA_UDP_SUBSCRIBER_CONNECTION_TIMEOUT   "PSA_UDP_SUBSCRIBER_CONNECTION_TIMEOUT"
+
+#define PSA_UDP_DEFAULT_BASE_PORT               5501
+#define PSA_UDP_DEFAULT_MAX_PORT                6000
+
+#define PSA_UDP_DEFAULT_MAX_MESSAGE_SIZE        64 * 1024
+#define PSA_UDP_DEFAULT_RECV_BUFFER_SIZE        64 * 1024
+#define PSA_UDP_DEFAULT_TIMEOUT                 2000 // 2 seconds
+#define PSA_UDP_SUBSCRIBER_CONNECTION_DEFAULT_TIMEOUT 250 // 250 ms
+
+#define PSA_UDP_DEFAULT_QOS_SAMPLE_SCORE        30
+#define PSA_UDP_DEFAULT_QOS_CONTROL_SCORE       70
+#define PSA_UDP_DEFAULT_SCORE                   30
+
+#define PSA_UDP_QOS_SAMPLE_SCORE_KEY            "PSA_UDP_QOS_SAMPLE_SCORE"
+#define PSA_UDP_QOS_CONTROL_SCORE_KEY           "PSA_UDP_QOS_CONTROL_SCORE"
+#define PSA_UDP_DEFAULT_SCORE_KEY               "PSA_UDP_DEFAULT_SCORE"
+
+#define PUBSUB_UDP_VERBOSE_KEY                  "PSA_UDP_VERBOSE"
+#define PUBSUB_UDP_VERBOSE_DEFAULT              false
+
+#define PUBSUB_UDP_PUBLISHER_RETRY_CNT_KEY      "PUBSUB_UDP_PUBLISHER_RETRY_COUNT"
+#define PUBSUB_UDP_PUBLISHER_RETRY_CNT_DEFAULT  5
+
+#define PUBSUB_UDP_SUBSCRIBER_RETRY_CNT_KEY     "PUBSUB_UDP_SUBSCRIBER_RETRY_COUNT"
+#define PUBSUB_UDP_SUBSCRIBER_RETRY_CNT_DEFAULT 5
+
+
+//Time-out settings are only for BLOCKING connections
+#define PUBSUB_UDP_PUBLISHER_SNDTIMEO_KEY       "PUBSUB_UDP_PUBLISHER_SEND_TIMEOUT"
+#define PUBSUB_UDP_PUBLISHER_SNDTIMEO_DEFAULT   5.0
+
+#define PUBSUB_UDP_SUBSCRIBER_RCVTIMEO_KEY      "PUBSUB_UDP_SUBSCRIBER_RCV_TIMEOUT"
+#define PUBSUB_UDP_SUBSCRIBER_RCVTIMEO_DEFAULT  5.0
+
+#define PUBSUB_UDP_PSA_IP_KEY                   "PSA_IP"
+#define PUBSUB_UDP_ADMIN_TYPE                   "udp"
+
+/**
+ * The UDP url key for the topic sender endpoints
+ */
+#define PUBSUB_UDP_URL_KEY                      "udp.url"
+
+/**
+ * Can be set in the topic properties to fix a static bind url
+ */
+#define PUBSUB_UDP_STATIC_BIND_URL              "udp.static.bind.url"
+
+/**
+ * Name of environment variable with ip/url to bind to
+ * e.g. PSA_UDP_STATIC_BIND_FOR_topic_scope="UDP://0.0.0.0:4444"
+ */
+#define PUBSUB_UDP_STATIC_BIND_URL_FOR          "PSA_UDP_STATIC_BIND_URL_FOR_"
+
+/**
+ * Can be set in the topic properties to fix a static url used for discovery
+ */
+#define PUBSUB_UDP_STATIC_DISCOVER_URL          "udp.static.bind.url"
+
+/**
+ * If set true on the endpoint, the UDP TopicSender bind and/or discovery url is statically configured.
+ */
+#define PUBSUB_UDP_STATIC_CONFIGURED            "udp.static.configured"
+
+/**
+ * The static url which a subscriber should try to connect to.
+ * The urls are space separated.
+ * Can be set in the topic properties
+ */
+#define PUBSUB_UDP_STATIC_CONNECT_URLS          "udp.static.connect.urls"
+
+
+/**
+ * Defines if the publisher / subscriber is a passive endpoint and shares
+ * the connection with publisher / subscriber endpoint with the matching (passive) key
+ * e.g. UDP.passive.configured="true" means that a publisher / subscriber is passive,
+ * when a publisher / subscriber is found with a matching key (for example UDP.passive.key="localhost").
+ * This creates full-duplex connection using a single socket.
+ */
+#define PUBSUB_UDP_PASSIVE_CONFIGURED            "udp.passive.configured"
+#define PUBSUB_UDP_PASSIVE_KEY                   "udp.passive.key"
+
+/**
+ * Name of environment variable to indicate that passive endpoint is configured
+ * e.g. PSA_UDP_PASSIVE_CONFIGURED_topic_scope="true"
+ */
+#define PUBSUB_UDP_PASSIVE_ENABLED               "PSA_UDP_PASSIVE_CONFIGURED_"
+/**
+ * Name of environment variable to configure the passive key (see PUBSUB_UDP_PASSIVE_KEY )
+ * e.g. PSA_UDP_PASSIVE_KEY__topic_scope="UDP://localhost:4444"
+ */
+#define PUBSUB_UDP_PASSIVE_SELECTION_KEY         "PSA_UDP_PASSIVE_KEY_"
+
+/**
+ * Name of environment variable with space-separated list of ips/urls to connect to
+ * e.g. PSA_UDP_STATIC_CONNECT_FOR_topic_scope="udp://127.0.0.1:4444 udp://127.0.0.2:4444"
+ */
+#define PUBSUB_UDP_STATIC_CONNECT_URLS_FOR       "PSA_UDP_STATIC_CONNECT_URL_FOR_"
+
+/**
+ * Realtime thread prio and scheduling information. This is used to setup the thread prio/sched of the
+ * internal UDP threads.
+ * Can be set in the topic properties.
+ */
+#define PUBSUB_UDP_THREAD_REALTIME_PRIO         "thread.realtime.prio"
+#define PUBSUB_UDP_THREAD_REALTIME_SCHED        "thread.realtime.sched"
+
+#endif /* PUBSUB_PSA_UDP_CONSTANTS_H_ */
diff --git a/bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_admin.c b/bundles/pubsub/pubsub_admin_udp/src/pubsub_udp_admin.c
similarity index 63%
copy from bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_admin.c
copy to bundles/pubsub/pubsub_admin_udp/src/pubsub_udp_admin.c
index 9806991..44d53c6 100644
--- a/bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_admin.c
+++ b/bundles/pubsub/pubsub_admin_udp/src/pubsub_udp_admin.c
@@ -24,11 +24,12 @@
 
 #include <pubsub_matching.h>
 #include "pubsub_utils.h"
-#include "pubsub_tcp_admin.h"
-#include "pubsub_tcp_handler.h"
-#include "pubsub_psa_tcp_constants.h"
-#include "pubsub_tcp_topic_sender.h"
-#include "pubsub_tcp_topic_receiver.h"
+#include "pubsub_udp_admin.h"
+#include "pubsub_skt_handler.h"
+#include "pubsub_psa_udp_constants.h"
+#include "pubsub_udp_topic_sender.h"
+#include "pubsub_udp_topic_receiver.h"
+#include "celix_properties.h"
 
 #define L_DEBUG(...) \
     celix_logHelper_log(psa->log, CELIX_LOG_LEVEL_DEBUG, __VA_ARGS__)
@@ -39,7 +40,7 @@
 #define L_ERROR(...) \
     celix_logHelper_log(psa->log, CELIX_LOG_LEVEL_ERROR, __VA_ARGS__)
 
-struct pubsub_tcp_admin {
+struct pubsub_udp_admin {
     celix_bundle_context_t *ctx;
     celix_log_helper_t *log;
     const char *fwUUID;
@@ -56,17 +57,17 @@ struct pubsub_tcp_admin {
 
     struct {
         celix_thread_mutex_t mutex;
-        hash_map_t *map; //key = svcId, value = psa_tcp_protocol_entry_t*
+        hash_map_t *map; //key = svcId, value = psa_udp_protocol_entry_t*
     } protocols;
 
     struct {
         celix_thread_mutex_t mutex;
-        hash_map_t *map; //key = scope:topic key, value = pubsub_tcp_topic_sender_t*
+        hash_map_t *map; //key = scope:topic key, value = pubsub_udp_topic_sender_t*
     } topicSenders;
 
     struct {
         celix_thread_mutex_t mutex;
-        hash_map_t *map; //key = scope:topic key, value = pubsub_tcp_topic_sender_t*
+        hash_map_t *map; //key = scope:topic key, value = pubsub_udp_topic_sender_t*
     } topicReceivers;
 
     struct {
@@ -79,41 +80,49 @@ struct pubsub_tcp_admin {
         hash_map_t *map; //key = pubsub message serialization marker svc id (long), pubsub_serialization_handler_t*.
     } serializationHandlers;
 
-    pubsub_tcp_endPointStore_t endpointStore;
+  pubsub_sktHandler_endPointStore_t endpointStore;
 };
 
-typedef struct psa_tcp_protocol_entry {
+typedef struct psa_udp_protocol_entry {
     const char *protType;
     long svcId;
     pubsub_protocol_service_t *svc;
-} psa_tcp_protocol_entry_t;
+} psa_udp_protocol_entry_t;
 
 static celix_status_t
-pubsub_tcpAdmin_connectEndpointToReceiver(pubsub_tcp_admin_t *psa, pubsub_tcp_topic_receiver_t *receiver,
+pubsub_udpAdmin_connectEndpointToReceiver(pubsub_udp_admin_t *psa, pubsub_udp_topic_receiver_t *receiver,
                                           const celix_properties_t *endpoint);
+static celix_status_t
+pubsub_udpAdmin_connectEndpointToSender(pubsub_udp_admin_t *psa, pubsub_udp_topic_sender_t *sender,
+                                        const celix_properties_t *endpoint);
 
 static celix_status_t
-pubsub_tcpAdmin_disconnectEndpointFromReceiver(pubsub_tcp_admin_t *psa, pubsub_tcp_topic_receiver_t *receiver,
+pubsub_udpAdmin_disconnectEndpointFromReceiver(pubsub_udp_admin_t *psa, pubsub_udp_topic_receiver_t *receiver,
                                                const celix_properties_t *endpoint);
 
-static bool pubsub_tcpAdmin_endpointIsPublisher(const celix_properties_t *endpoint) {
+static bool pubsub_udpAdmin_endpointIsPublisher(const celix_properties_t *endpoint) {
     const char *type = celix_properties_get(endpoint, PUBSUB_ENDPOINT_TYPE, NULL);
     return type != NULL && strncmp(PUBSUB_PUBLISHER_ENDPOINT_TYPE, type, strlen(PUBSUB_PUBLISHER_ENDPOINT_TYPE)) == 0;
 }
 
-pubsub_tcp_admin_t *pubsub_tcpAdmin_create(celix_bundle_context_t *ctx, celix_log_helper_t *logHelper) {
-    pubsub_tcp_admin_t *psa = calloc(1, sizeof(*psa));
+static bool pubsub_udpAdmin_endpointIsSubScriber(const celix_properties_t *endpoint) {
+    const char *type = celix_properties_get(endpoint, PUBSUB_ENDPOINT_TYPE, NULL);
+    return type != NULL && strncmp(PUBSUB_SUBSCRIBER_ENDPOINT_TYPE, type, strlen(PUBSUB_SUBSCRIBER_ENDPOINT_TYPE)) == 0;
+}
+
+pubsub_udp_admin_t *pubsub_udpAdmin_create(celix_bundle_context_t *ctx, celix_log_helper_t *logHelper) {
+    pubsub_udp_admin_t *psa = calloc(1, sizeof(*psa));
     psa->ctx = ctx;
     psa->log = logHelper;
-    psa->verbose = celix_bundleContext_getPropertyAsBool(ctx, PUBSUB_TCP_VERBOSE_KEY, PUBSUB_TCP_VERBOSE_DEFAULT);
+    psa->verbose = celix_bundleContext_getPropertyAsBool(ctx, PUBSUB_UDP_VERBOSE_KEY, PUBSUB_UDP_VERBOSE_DEFAULT);
     psa->fwUUID = celix_bundleContext_getProperty(ctx, OSGI_FRAMEWORK_FRAMEWORK_UUID, NULL);
-    long basePort = celix_bundleContext_getPropertyAsLong(ctx, PSA_TCP_BASE_PORT, PSA_TCP_DEFAULT_BASE_PORT);
+    long basePort = celix_bundleContext_getPropertyAsLong(ctx, PSA_UDP_BASE_PORT, PSA_UDP_DEFAULT_BASE_PORT);
     psa->basePort = (unsigned int) basePort;
-    psa->defaultScore = celix_bundleContext_getPropertyAsDouble(ctx, PSA_TCP_DEFAULT_SCORE_KEY, PSA_TCP_DEFAULT_SCORE);
-    psa->qosSampleScore = celix_bundleContext_getPropertyAsDouble(ctx, PSA_TCP_QOS_SAMPLE_SCORE_KEY,
-                                                                  PSA_TCP_DEFAULT_QOS_SAMPLE_SCORE);
-    psa->qosControlScore = celix_bundleContext_getPropertyAsDouble(ctx, PSA_TCP_QOS_CONTROL_SCORE_KEY,
-                                                                   PSA_TCP_DEFAULT_QOS_CONTROL_SCORE);
+    psa->defaultScore = celix_bundleContext_getPropertyAsDouble(ctx, PSA_UDP_DEFAULT_SCORE_KEY, PSA_UDP_DEFAULT_SCORE);
+    psa->qosSampleScore = celix_bundleContext_getPropertyAsDouble(ctx, PSA_UDP_QOS_SAMPLE_SCORE_KEY,
+                                                                  PSA_UDP_DEFAULT_QOS_SAMPLE_SCORE);
+    psa->qosControlScore = celix_bundleContext_getPropertyAsDouble(ctx, PSA_UDP_QOS_CONTROL_SCORE_KEY,
+                                                                   PSA_UDP_DEFAULT_QOS_CONTROL_SCORE);
 
     celixThreadMutex_create(&psa->protocols.mutex, NULL);
     psa->protocols.map = hashMap_create(NULL, NULL, NULL, NULL);
@@ -136,7 +145,7 @@ pubsub_tcp_admin_t *pubsub_tcpAdmin_create(celix_bundle_context_t *ctx, celix_lo
     return psa;
 }
 
-void pubsub_tcpAdmin_destroy(pubsub_tcp_admin_t *psa) {
+void pubsub_udpAdmin_destroy(pubsub_udp_admin_t *psa) {
     if (psa == NULL) {
         return;
     }
@@ -144,24 +153,24 @@ void pubsub_tcpAdmin_destroy(pubsub_tcp_admin_t *psa) {
     celixThreadMutex_lock(&psa->endpointStore.mutex);
     hash_map_iterator_t iter = hashMapIterator_construct(psa->endpointStore.map);
     while (hashMapIterator_hasNext(&iter)) {
-        pubsub_tcpHandler_t *tcpHandler = hashMapIterator_nextValue(&iter);
-        pubsub_tcpHandler_destroy(tcpHandler);
+        pubsub_sktHandler_t *udpHandler = hashMapIterator_nextValue(&iter);
+        pubsub_sktHandler_destroy(udpHandler);
     }
     celixThreadMutex_unlock(&psa->endpointStore.mutex);
 
     celixThreadMutex_lock(&psa->topicSenders.mutex);
     iter = hashMapIterator_construct(psa->topicSenders.map);
     while (hashMapIterator_hasNext(&iter)) {
-        pubsub_tcp_topic_sender_t *sender = hashMapIterator_nextValue(&iter);
-        pubsub_tcpTopicSender_destroy(sender);
+        pubsub_udp_topic_sender_t *sender = hashMapIterator_nextValue(&iter);
+        pubsub_udpTopicSender_destroy(sender);
     }
     celixThreadMutex_unlock(&psa->topicSenders.mutex);
 
     celixThreadMutex_lock(&psa->topicReceivers.mutex);
     iter = hashMapIterator_construct(psa->topicReceivers.map);
     while (hashMapIterator_hasNext(&iter)) {
-        pubsub_tcp_topic_receiver_t *recv = hashMapIterator_nextValue(&iter);
-        pubsub_tcpTopicReceiver_destroy(recv);
+        pubsub_udp_topic_receiver_t *recv = hashMapIterator_nextValue(&iter);
+        pubsub_udpTopicReceiver_destroy(recv);
     }
     celixThreadMutex_unlock(&psa->topicReceivers.mutex);
 
@@ -184,7 +193,7 @@ void pubsub_tcpAdmin_destroy(pubsub_tcp_admin_t *psa) {
     celixThreadMutex_lock(&psa->protocols.mutex);
     iter = hashMapIterator_construct(psa->protocols.map);
     while (hashMapIterator_hasNext(&iter)) {
-        psa_tcp_protocol_entry_t *entry = hashMapIterator_nextValue(&iter);
+        psa_udp_protocol_entry_t *entry = hashMapIterator_nextValue(&iter);
         free(entry);
     }
     celixThreadMutex_unlock(&psa->protocols.mutex);
@@ -212,19 +221,19 @@ void pubsub_tcpAdmin_destroy(pubsub_tcp_admin_t *psa) {
     free(psa);
 }
 
-void pubsub_tcpAdmin_addProtocolSvc(void *handle, void *svc, const celix_properties_t *props) {
-    pubsub_tcp_admin_t *psa = handle;
+void pubsub_udpAdmin_addProtocolSvc(void *handle, void *svc, const celix_properties_t *props) {
+    pubsub_udp_admin_t *psa = handle;
 
     const char *protType = celix_properties_get(props, PUBSUB_PROTOCOL_TYPE_KEY, NULL);
     long svcId = celix_properties_getAsLong(props, OSGI_FRAMEWORK_SERVICE_ID, -1L);
 
     if (protType == NULL) {
-        L_INFO("[PSA_tcp] Ignoring protocol service without %s property", PUBSUB_PROTOCOL_TYPE_KEY);
+        L_INFO("[PSA_UDP] Ignoring protocol service without %s property", PUBSUB_PROTOCOL_TYPE_KEY);
         return;
     }
 
     celixThreadMutex_lock(&psa->protocols.mutex);
-    psa_tcp_protocol_entry_t *entry = hashMap_get(psa->protocols.map, (void *) svcId);
+    psa_udp_protocol_entry_t *entry = hashMap_get(psa->protocols.map, (void *) svcId);
     if (entry == NULL) {
         entry = calloc(1, sizeof(*entry));
         entry->protType = protType;
@@ -235,8 +244,8 @@ void pubsub_tcpAdmin_addProtocolSvc(void *handle, void *svc, const celix_propert
     celixThreadMutex_unlock(&psa->protocols.mutex);
 }
 
-void pubsub_tcpAdmin_removeProtocolSvc(void *handle, void *svc, const celix_properties_t *props) {
-    pubsub_tcp_admin_t *psa = handle;
+void pubsub_udpAdmin_removeProtocolSvc(void *handle, void *svc, const celix_properties_t *props) {
+    pubsub_udp_admin_t *psa = handle;
     long svcId = celix_properties_getAsLong(props, OSGI_FRAMEWORK_SERVICE_ID, -1L);
 
     //remove protocol
@@ -246,7 +255,7 @@ void pubsub_tcpAdmin_removeProtocolSvc(void *handle, void *svc, const celix_prop
     // Note that it is the responsibility of the topology manager to create new topic senders/receivers
 
     celixThreadMutex_lock(&psa->protocols.mutex);
-    psa_tcp_protocol_entry_t *entry = hashMap_remove(psa->protocols.map, (void *) svcId);
+    psa_udp_protocol_entry_t *entry = hashMap_remove(psa->protocols.map, (void *) svcId);
     celixThreadMutex_unlock(&psa->protocols.mutex);
 
     if (entry != NULL) {
@@ -254,11 +263,11 @@ void pubsub_tcpAdmin_removeProtocolSvc(void *handle, void *svc, const celix_prop
         hash_map_iterator_t iter = hashMapIterator_construct(psa->topicSenders.map);
         while (hashMapIterator_hasNext(&iter)) {
             hash_map_entry_t *senderEntry = hashMapIterator_nextEntry(&iter);
-            pubsub_tcp_topic_sender_t *sender = hashMapEntry_getValue(senderEntry);
-            if (sender != NULL && entry->svcId == pubsub_tcpTopicSender_protocolSvcId(sender)) {
+            pubsub_udp_topic_sender_t *sender = hashMapEntry_getValue(senderEntry);
+            if (sender != NULL && entry->svcId == pubsub_udpTopicSender_protocolSvcId(sender)) {
                 char *key = hashMapEntry_getKey(senderEntry);
                 hashMapIterator_remove(&iter);
-                pubsub_tcpTopicSender_destroy(sender);
+                pubsub_udpTopicSender_destroy(sender);
                 free(key);
             }
         }
@@ -268,11 +277,11 @@ void pubsub_tcpAdmin_removeProtocolSvc(void *handle, void *svc, const celix_prop
         iter = hashMapIterator_construct(psa->topicReceivers.map);
         while (hashMapIterator_hasNext(&iter)) {
             hash_map_entry_t *senderEntry = hashMapIterator_nextEntry(&iter);
-            pubsub_tcp_topic_receiver_t *receiver = hashMapEntry_getValue(senderEntry);
-            if (receiver != NULL && entry->svcId == pubsub_tcpTopicReceiver_protocolSvcId(receiver)) {
+            pubsub_udp_topic_receiver_t *receiver = hashMapEntry_getValue(senderEntry);
+            if (receiver != NULL && entry->svcId == pubsub_udpTopicReceiver_protocolSvcId(receiver)) {
                 char *key = hashMapEntry_getKey(senderEntry);
                 hashMapIterator_remove(&iter);
-                pubsub_tcpTopicReceiver_destroy(receiver);
+                pubsub_udpTopicReceiver_destroy(receiver);
                 free(key);
             }
         }
@@ -282,13 +291,13 @@ void pubsub_tcpAdmin_removeProtocolSvc(void *handle, void *svc, const celix_prop
     }
 }
 
-celix_status_t pubsub_tcpAdmin_matchPublisher(void *handle, long svcRequesterBndId, const celix_filter_t *svcFilter,
+celix_status_t pubsub_udpAdmin_matchPublisher(void *handle, long svcRequesterBndId, const celix_filter_t *svcFilter,
                                               celix_properties_t **topicProperties, double *outScore,
                                               long *outSerializerSvcId, long *outProtocolSvcId) {
-    pubsub_tcp_admin_t *psa = handle;
-    L_DEBUG("[PSA_TCP_V2] pubsub_tcpAdmin_matchPublisher");
+    pubsub_udp_admin_t *psa = handle;
+    L_DEBUG("[PSA_UDP_V2] pubsub_udpAdmin_matchPublisher");
     celix_status_t status = CELIX_SUCCESS;
-    double score = pubsub_utils_matchPublisher(psa->ctx, svcRequesterBndId, svcFilter->filterStr, PUBSUB_TCP_ADMIN_TYPE,
+    double score = pubsub_utils_matchPublisher(psa->ctx, svcRequesterBndId, svcFilter->filterStr, PUBSUB_UDP_ADMIN_TYPE,
                                                psa->qosSampleScore, psa->qosControlScore, psa->defaultScore, true, topicProperties, outSerializerSvcId, outProtocolSvcId);
     *outScore = score;
 
@@ -297,13 +306,13 @@ celix_status_t pubsub_tcpAdmin_matchPublisher(void *handle, long svcRequesterBnd
 }
 
 celix_status_t
-pubsub_tcpAdmin_matchSubscriber(void *handle, long svcProviderBndId, const celix_properties_t *svcProperties,
+pubsub_udpAdmin_matchSubscriber(void *handle, long svcProviderBndId, const celix_properties_t *svcProperties,
                                 celix_properties_t **topicProperties, double *outScore, long *outSerializerSvcId,
                                 long *outProtocolSvcId) {
-    pubsub_tcp_admin_t *psa = handle;
-    L_DEBUG("[PSA_TCP_V2] pubsub_tcpAdmin_matchSubscriber");
+    pubsub_udp_admin_t *psa = handle;
+    L_DEBUG("[PSA_UDP_V2] pubsub_udpAdmin_matchSubscriber");
     celix_status_t status = CELIX_SUCCESS;
-    double score = pubsub_utils_matchSubscriber(psa->ctx, svcProviderBndId, svcProperties, PUBSUB_TCP_ADMIN_TYPE,
+    double score = pubsub_utils_matchSubscriber(psa->ctx, svcProviderBndId, svcProperties, PUBSUB_UDP_ADMIN_TYPE,
                                                 psa->qosSampleScore, psa->qosControlScore, psa->defaultScore, true, topicProperties, outSerializerSvcId, outProtocolSvcId);
     if (outScore != NULL) {
         *outScore = score;
@@ -312,18 +321,18 @@ pubsub_tcpAdmin_matchSubscriber(void *handle, long svcProviderBndId, const celix
 }
 
 celix_status_t
-pubsub_tcpAdmin_matchDiscoveredEndpoint(void *handle, const celix_properties_t *endpoint, bool *outMatch) {
-    pubsub_tcp_admin_t *psa = handle;
-    L_DEBUG("[PSA_TCP_V2] pubsub_tcpAdmin_matchEndpoint");
+pubsub_udpAdmin_matchDiscoveredEndpoint(void *handle, const celix_properties_t *endpoint, bool *outMatch) {
+    pubsub_udp_admin_t *psa = handle;
+    L_DEBUG("[PSA_UDP_V2] pubsub_udpAdmin_matchEndpoint");
     celix_status_t status = CELIX_SUCCESS;
-    bool match = pubsub_utils_matchEndpoint(psa->ctx, psa->log, endpoint, PUBSUB_TCP_ADMIN_TYPE, true, NULL, NULL);
+    bool match = pubsub_utils_matchEndpoint(psa->ctx, psa->log, endpoint, PUBSUB_UDP_ADMIN_TYPE, true, NULL, NULL);
     if (outMatch != NULL) {
         *outMatch = match;
     }
     return status;
 }
 
-static pubsub_serializer_handler_t* pubsub_tcpAdmin_getSerializationHandler(pubsub_tcp_admin_t* psa, long msgSerializationMarkerSvcId) {
+static pubsub_serializer_handler_t* pubsub_udpAdmin_getSerializationHandler(pubsub_udp_admin_t* psa, long msgSerializationMarkerSvcId) {
     pubsub_serializer_handler_t* handler = NULL;
     celixThreadMutex_lock(&psa->serializationHandlers.mutex);
     handler = hashMap_get(psa->serializationHandlers.map, (void*)msgSerializationMarkerSvcId);
@@ -337,10 +346,10 @@ static pubsub_serializer_handler_t* pubsub_tcpAdmin_getSerializationHandler(pubs
     return handler;
 }
 
-celix_status_t pubsub_tcpAdmin_setupTopicSender(void *handle, const char *scope, const char *topic,
+celix_status_t pubsub_udpAdmin_setupTopicSender(void *handle, const char *scope, const char *topic,
                                                 const celix_properties_t *topicProperties, long serializerSvcId,
                                                 long protocolSvcId, celix_properties_t **outPublisherEndpoint) {
-    pubsub_tcp_admin_t *psa = handle;
+    pubsub_udp_admin_t *psa = handle;
     celix_status_t status = CELIX_SUCCESS;
 
     //1) Get serialization handler
@@ -349,7 +358,7 @@ celix_status_t pubsub_tcpAdmin_setupTopicSender(void *handle, const char *scope,
     //4) Connect existing endpoints
     //5) set outPublisherEndpoint
 
-    pubsub_serializer_handler_t* handler = pubsub_tcpAdmin_getSerializationHandler(psa, serializerSvcId);
+    pubsub_serializer_handler_t* handler = pubsub_udpAdmin_getSerializationHandler(psa, serializerSvcId);
     if (handler == NULL) {
         L_ERROR("Cannot create topic sender without serialization handler");
         return CELIX_ILLEGAL_STATE;
@@ -360,24 +369,25 @@ celix_status_t pubsub_tcpAdmin_setupTopicSender(void *handle, const char *scope,
     
     celixThreadMutex_lock(&psa->protocols.mutex);
     celixThreadMutex_lock(&psa->topicSenders.mutex);
-    pubsub_tcp_topic_sender_t *sender = hashMap_get(psa->topicSenders.map, key);
+    pubsub_udp_topic_sender_t *sender = hashMap_get(psa->topicSenders.map, key);
     celixThreadMutex_unlock(&psa->topicSenders.mutex);
     if (sender == NULL) {
-        psa_tcp_protocol_entry_t *protEntry = hashMap_get(psa->protocols.map, (void *) protocolSvcId);
+        psa_udp_protocol_entry_t *protEntry = hashMap_get(psa->protocols.map, (void *) protocolSvcId);
         if (protEntry != NULL) {
-            sender = pubsub_tcpTopicSender_create(psa->ctx, psa->log, scope, topic, handler, handle, topicProperties,
+            sender = pubsub_udpTopicSender_create(psa->ctx, psa->log, scope, topic, handler, handle, topicProperties,
                                                   &psa->endpointStore, protocolSvcId,
                                                   protEntry->svc);
         }
         if (sender != NULL) {
-            const char *psaType = PUBSUB_TCP_ADMIN_TYPE;
+            const char *psaType = PUBSUB_UDP_ADMIN_TYPE;
             const char *protType = protEntry->protType;
             newEndpoint = pubsubEndpoint_create(psa->fwUUID, scope, topic, PUBSUB_PUBLISHER_ENDPOINT_TYPE, psaType,
                                                 pubsub_serializerHandler_getSerializationType(handler), protType, NULL);
-            celix_properties_set(newEndpoint, PUBSUB_TCP_URL_KEY, pubsub_tcpTopicSender_url(sender));
+            const char* url = pubsub_udpTopicSender_url(sender);
+            if (url) celix_properties_set(newEndpoint, PUBSUB_UDP_URL_KEY, url);
 
-            celix_properties_setBool(newEndpoint, PUBSUB_TCP_STATIC_CONFIGURED, pubsub_tcpTopicSender_isStatic(sender));
-            if (pubsub_tcpTopicSender_isPassive(sender)) {
+            celix_properties_setBool(newEndpoint, PUBSUB_UDP_STATIC_CONFIGURED, pubsub_udpTopicSender_isStatic(sender));
+            if (pubsub_udpTopicSender_isPassive(sender)) {
                 celix_properties_set(newEndpoint, PUBSUB_ENDPOINT_VISIBILITY, PUBSUB_ENDPOINT_LOCAL_VISIBILITY);
             } else {
                 celix_properties_set(newEndpoint, PUBSUB_ENDPOINT_VISIBILITY, PUBSUB_ENDPOINT_SYSTEM_VISIBILITY);
@@ -390,15 +400,31 @@ celix_status_t pubsub_tcpAdmin_setupTopicSender(void *handle, const char *scope,
             hashMap_put(psa->topicSenders.map, key, sender);
             celixThreadMutex_unlock(&psa->topicSenders.mutex);
         } else {
-            L_ERROR("[PSA_TCP_V2] Error creating a TopicSender");
+            L_ERROR("[PSA_UDP_V2] Error creating a TopicSender");
             free(key);
         }
     } else {
         free(key);
-        L_ERROR("[PSA_TCP_V2] Cannot setup already existing TopicSender for scope/topic %s/%s!", scope, topic);
+        L_ERROR("[PSA_UDP_V2] Cannot setup already existing TopicSender for scope/topic %s/%s!", scope, topic);
     }
     celixThreadMutex_unlock(&psa->protocols.mutex);
 
+    if (sender != NULL && newEndpoint != NULL) {
+        if (pubsub_udpAdmin_endpointIsSubScriber(newEndpoint) && pubsubEndpoint_matchWithTopicAndScope(newEndpoint, topic, scope)) {
+            pubsub_udpAdmin_connectEndpointToSender(psa, sender, newEndpoint);
+        }
+        if (pubsub_udpAdmin_endpointIsPublisher(newEndpoint) && pubsubEndpoint_matchWithTopicAndScope(newEndpoint, topic, scope)) {
+            celixThreadMutex_lock(&psa->topicReceivers.mutex);
+            hash_map_iterator_t senderIter = hashMapIterator_construct(psa->topicReceivers.map);
+            while (hashMapIterator_hasNext(&senderIter)) {
+                pubsub_udp_topic_receiver_t *receiver = hashMapIterator_nextValue(&senderIter);
+                pubsub_udpAdmin_connectEndpointToReceiver(psa, receiver, newEndpoint);
+            }
+            celixThreadMutex_unlock(&psa->topicReceivers.mutex);
+        }
+
+    }
+
     if (newEndpoint != NULL && outPublisherEndpoint != NULL) {
         *outPublisherEndpoint = newEndpoint;
     }
@@ -406,8 +432,8 @@ celix_status_t pubsub_tcpAdmin_setupTopicSender(void *handle, const char *scope,
     return status;
 }
 
-celix_status_t pubsub_tcpAdmin_teardownTopicSender(void *handle, const char *scope, const char *topic) {
-    pubsub_tcp_admin_t *psa = handle;
+celix_status_t pubsub_udpAdmin_teardownTopicSender(void *handle, const char *scope, const char *topic) {
+    pubsub_udp_admin_t *psa = handle;
     celix_status_t status = CELIX_SUCCESS;
 
     //1) Find and remove TopicSender from map
@@ -418,13 +444,13 @@ celix_status_t pubsub_tcpAdmin_teardownTopicSender(void *handle, const char *sco
     hash_map_entry_t *entry = hashMap_getEntry(psa->topicSenders.map, key);
     if (entry != NULL) {
         char *mapKey = hashMapEntry_getKey(entry);
-        pubsub_tcp_topic_sender_t *sender = hashMap_remove(psa->topicSenders.map, key);
+        pubsub_udp_topic_sender_t *sender = hashMap_remove(psa->topicSenders.map, key);
         celixThreadMutex_unlock(&psa->topicSenders.mutex);
         free(mapKey);
-        pubsub_tcpTopicSender_destroy(sender);
+        pubsub_udpTopicSender_destroy(sender);
     } else {
         celixThreadMutex_unlock(&psa->topicSenders.mutex);
-        L_ERROR("[PSA_TCP_V2] Cannot teardown TopicSender with scope/topic %s/%s. Does not exists",
+        L_ERROR("[PSA_UDP_V2] Cannot teardown TopicSender with scope/topic %s/%s. Does not exists",
                 scope == NULL ? "(null)" : scope,
                 topic);
     }
@@ -433,12 +459,12 @@ celix_status_t pubsub_tcpAdmin_teardownTopicSender(void *handle, const char *sco
     return status;
 }
 
-celix_status_t pubsub_tcpAdmin_setupTopicReceiver(void *handle, const char *scope, const char *topic,
+celix_status_t pubsub_udpAdmin_setupTopicReceiver(void *handle, const char *scope, const char *topic,
                                                   const celix_properties_t *topicProperties, long serializerSvcId,
                                                   long protocolSvcId, celix_properties_t **outSubscriberEndpoint) {
-    pubsub_tcp_admin_t *psa = handle;
+    pubsub_udp_admin_t *psa = handle;
 
-    pubsub_serializer_handler_t* handler = pubsub_tcpAdmin_getSerializationHandler(psa, serializerSvcId);
+    pubsub_serializer_handler_t* handler = pubsub_udpAdmin_getSerializationHandler(psa, serializerSvcId);
     if (handler == NULL) {
         L_ERROR("Cannot create topic receiver without serialization handler");
         return CELIX_ILLEGAL_STATE;
@@ -449,22 +475,32 @@ celix_status_t pubsub_tcpAdmin_setupTopicReceiver(void *handle, const char *scop
 
     celixThreadMutex_lock(&psa->protocols.mutex);
     celixThreadMutex_lock(&psa->topicReceivers.mutex);
-    pubsub_tcp_topic_receiver_t *receiver = hashMap_get(psa->topicReceivers.map, key);
+    pubsub_udp_topic_receiver_t *receiver = hashMap_get(psa->topicReceivers.map, key);
     celixThreadMutex_unlock(&psa->topicReceivers.mutex);
     if (receiver == NULL) {
-        psa_tcp_protocol_entry_t *protEntry = hashMap_get(psa->protocols.map, (void *) protocolSvcId);
+        psa_udp_protocol_entry_t *protEntry = hashMap_get(psa->protocols.map, (void *) protocolSvcId);
         if (protEntry != NULL) {
-            receiver = pubsub_tcpTopicReceiver_create(psa->ctx, psa->log, scope, topic,
+            receiver = pubsub_udpTopicReceiver_create(psa->ctx, psa->log, scope, topic,
                                                       handler, handle, topicProperties,
                                                       &psa->endpointStore, protocolSvcId, protEntry->svc);
         } else {
-            L_ERROR("[PSA_TCP_V2] Cannot find serializer or protocol for TopicSender %s/%s", scope == NULL ? "(null)" : scope, topic);
+            L_ERROR("[PSA_UDP_V2] Cannot find serializer or protocol for TopicSender %s/%s", scope == NULL ? "(null)" : scope, topic);
         }
         if (receiver != NULL) {
-            const char *psaType = PUBSUB_TCP_ADMIN_TYPE;
+            const char *psaType = PUBSUB_UDP_ADMIN_TYPE;
             const char *protType = protEntry->protType;
             newEndpoint = pubsubEndpoint_create(psa->fwUUID, scope, topic,
                                                 PUBSUB_SUBSCRIBER_ENDPOINT_TYPE, psaType, pubsub_serializerHandler_getSerializationType(handler), protType, NULL);
+            const char* url = pubsub_udpTopicReceiver_url(receiver);
+            if (url) celix_properties_set(newEndpoint, PUBSUB_UDP_URL_KEY, url);
+
+            celix_properties_setBool(newEndpoint, PUBSUB_UDP_STATIC_CONFIGURED, pubsub_udpTopicReceiver_isStatic(receiver));
+            if (pubsub_udpTopicReceiver_isPassive(receiver)) {
+                celix_properties_set(newEndpoint, PUBSUB_ENDPOINT_VISIBILITY, PUBSUB_ENDPOINT_LOCAL_VISIBILITY);
+            } else {
+                celix_properties_set(newEndpoint, PUBSUB_ENDPOINT_VISIBILITY, PUBSUB_ENDPOINT_SYSTEM_VISIBILITY);
+            }
+
             //if available also set container name
             const char *cn = celix_bundleContext_getProperty(psa->ctx, "CELIX_CONTAINER_NAME", NULL);
             if (cn != NULL) {
@@ -474,27 +510,28 @@ celix_status_t pubsub_tcpAdmin_setupTopicReceiver(void *handle, const char *scop
             hashMap_put(psa->topicReceivers.map, key, receiver);
             celixThreadMutex_unlock(&psa->topicReceivers.mutex);
         } else {
-            L_ERROR("[PSA_TCP_V2] Error creating a TopicReceiver.");
+            L_ERROR("[PSA_UDP_V2] Error creating a TopicReceiver.");
             free(key);
         }
     } else {
         free(key);
-        L_ERROR("[PSA_TCP_V2] Cannot setup already existing TopicReceiver for scope/topic %s/%s!",
+        L_ERROR("[PSA_UDP_V2] Cannot setup already existing TopicReceiver for scope/topic %s/%s!",
                 scope == NULL ? "(null)" : scope,
                 topic);
     }
     celixThreadMutex_unlock(&psa->protocols.mutex);
 
     if (receiver != NULL && newEndpoint != NULL) {
-        celixThreadMutex_lock(&psa->discoveredEndpoints.mutex);
-        hash_map_iterator_t iter = hashMapIterator_construct(psa->discoveredEndpoints.map);
-        while (hashMapIterator_hasNext(&iter)) {
-            celix_properties_t *endpoint = hashMapIterator_nextValue(&iter);
-            if (pubsub_tcpAdmin_endpointIsPublisher(endpoint) && pubsubEndpoint_matchWithTopicAndScope(endpoint, topic, scope)) {
-                pubsub_tcpAdmin_connectEndpointToReceiver(psa, receiver, endpoint);
-            }
+        if (pubsub_udpAdmin_endpointIsPublisher(newEndpoint) && pubsubEndpoint_matchWithTopicAndScope(newEndpoint, topic, scope)) {
+            pubsub_udpAdmin_connectEndpointToReceiver(psa, receiver, newEndpoint);
         }
-        celixThreadMutex_unlock(&psa->discoveredEndpoints.mutex);
+        celixThreadMutex_lock(&psa->topicSenders.mutex);
+        hash_map_iterator_t senderIter = hashMapIterator_construct(psa->topicSenders.map);
+        while (hashMapIterator_hasNext(&senderIter)) {
+            pubsub_udp_topic_sender_t *sender = hashMapIterator_nextValue(&senderIter);
+            pubsub_udpAdmin_connectEndpointToSender(psa, sender, newEndpoint);
+        }
+        celixThreadMutex_unlock(&psa->topicSenders.mutex);
     }
 
     if (newEndpoint != NULL && outSubscriberEndpoint != NULL) {
@@ -505,8 +542,8 @@ celix_status_t pubsub_tcpAdmin_setupTopicReceiver(void *handle, const char *scop
     return status;
 }
 
-celix_status_t pubsub_tcpAdmin_teardownTopicReceiver(void *handle, const char *scope, const char *topic) {
-    pubsub_tcp_admin_t *psa = handle;
+celix_status_t pubsub_udpAdmin_teardownTopicReceiver(void *handle, const char *scope, const char *topic) {
+    pubsub_udp_admin_t *psa = handle;
 
     char *key = pubsubEndpoint_createScopeTopicKey(scope, topic);
     celixThreadMutex_lock(&psa->topicReceivers.mutex);
@@ -514,12 +551,12 @@ celix_status_t pubsub_tcpAdmin_teardownTopicReceiver(void *handle, const char *s
     free(key);
     if (entry != NULL) {
         char *receiverKey = hashMapEntry_getKey(entry);
-        pubsub_tcp_topic_receiver_t *receiver = hashMapEntry_getValue(entry);
+        pubsub_udp_topic_receiver_t *receiver = hashMapEntry_getValue(entry);
         hashMap_remove(psa->topicReceivers.map, receiverKey);
         celixThreadMutex_unlock(&psa->topicReceivers.mutex);
 
         free(receiverKey);
-        pubsub_tcpTopicReceiver_destroy(receiver);
+        pubsub_udpTopicReceiver_destroy(receiver);
     } else {
         celixThreadMutex_unlock(&psa->topicReceivers.mutex);
     }
@@ -529,40 +566,53 @@ celix_status_t pubsub_tcpAdmin_teardownTopicReceiver(void *handle, const char *s
 }
 
 static celix_status_t
-pubsub_tcpAdmin_connectEndpointToReceiver(pubsub_tcp_admin_t *psa, pubsub_tcp_topic_receiver_t *receiver,
+pubsub_udpAdmin_connectEndpointToReceiver(pubsub_udp_admin_t *psa, pubsub_udp_topic_receiver_t *receiver,
                                           const celix_properties_t *endpoint) {
     //note can be called with discoveredEndpoint.mutex lock
     celix_status_t status = CELIX_SUCCESS;
+    const char *url = celix_properties_get(endpoint, PUBSUB_UDP_URL_KEY, NULL);
+    pubsub_udpTopicReceiver_connectTo(receiver, url);
+    return status;
+}
 
-    const char *url = celix_properties_get(endpoint, PUBSUB_TCP_URL_KEY, NULL);
-
-    if (url == NULL) {
-        const char *admin = celix_properties_get(endpoint, PUBSUB_ENDPOINT_ADMIN_TYPE, NULL);
-        const char *type = celix_properties_get(endpoint, PUBSUB_ENDPOINT_TYPE, NULL);
-        L_WARN("[PSA_TCP_V2] Error got endpoint without a tcp url (admin: %s, type: %s)", admin, type);
-        status = CELIX_BUNDLE_EXCEPTION;
-    } else {
-        pubsub_tcpTopicReceiver_connectTo(receiver, url);
-    }
-
+static celix_status_t
+pubsub_udpAdmin_connectEndpointToSender(pubsub_udp_admin_t *psa, pubsub_udp_topic_sender_t *sender,
+                                          const celix_properties_t *endpoint) {
+    //note can be called with discoveredEndpoint.mutex lock
+    celix_status_t status = CELIX_SUCCESS;
+    const char *url = celix_properties_get(endpoint, PUBSUB_UDP_URL_KEY, NULL);
+    pubsub_udpTopicSender_connectTo(sender, url);
     return status;
 }
 
-celix_status_t pubsub_tcpAdmin_addDiscoveredEndpoint(void *handle, const celix_properties_t *endpoint) {
-    pubsub_tcp_admin_t *psa = handle;
 
-    if (pubsub_tcpAdmin_endpointIsPublisher(endpoint)) {
+celix_status_t pubsub_udpAdmin_addDiscoveredEndpoint(void *handle, const celix_properties_t *endpoint) {
+    pubsub_udp_admin_t *psa = handle;
+
+    if (pubsub_udpAdmin_endpointIsPublisher(endpoint)) {
         celixThreadMutex_lock(&psa->topicReceivers.mutex);
         hash_map_iterator_t iter = hashMapIterator_construct(psa->topicReceivers.map);
         while (hashMapIterator_hasNext(&iter)) {
-            pubsub_tcp_topic_receiver_t *receiver = hashMapIterator_nextValue(&iter);
-            if (pubsubEndpoint_matchWithTopicAndScope(endpoint, pubsub_tcpTopicReceiver_topic(receiver), pubsub_tcpTopicReceiver_scope(receiver))) {
-                pubsub_tcpAdmin_connectEndpointToReceiver(psa, receiver, endpoint);
+            pubsub_udp_topic_receiver_t *receiver = hashMapIterator_nextValue(&iter);
+            if (pubsubEndpoint_matchWithTopicAndScope(endpoint, pubsub_udpTopicReceiver_topic(receiver), pubsub_udpTopicReceiver_scope(receiver))) {
+                pubsub_udpAdmin_connectEndpointToReceiver(psa, receiver, endpoint);
             }
         }
         celixThreadMutex_unlock(&psa->topicReceivers.mutex);
     }
 
+    if (pubsub_udpAdmin_endpointIsSubScriber(endpoint)) {
+        celixThreadMutex_lock(&psa->topicSenders.mutex);
+        hash_map_iterator_t iter = hashMapIterator_construct(psa->topicSenders.map);
+        while (hashMapIterator_hasNext(&iter)) {
+            pubsub_udp_topic_sender_t *sender = hashMapIterator_nextValue(&iter);
+            if (pubsubEndpoint_matchWithTopicAndScope(endpoint, pubsub_udpTopicSender_topic(sender), pubsub_udpTopicSender_scope(sender))) {
+                pubsub_udpAdmin_connectEndpointToSender(psa, sender, endpoint);
+            }
+        }
+        celixThreadMutex_unlock(&psa->topicSenders.mutex);
+    }
+
     celix_properties_t *cpy = celix_properties_copy(endpoint);
     const char *uuid = celix_properties_get(cpy, PUBSUB_ENDPOINT_UUID, NULL);
 
@@ -575,36 +625,48 @@ celix_status_t pubsub_tcpAdmin_addDiscoveredEndpoint(void *handle, const celix_p
 }
 
 static celix_status_t
-pubsub_tcpAdmin_disconnectEndpointFromReceiver(pubsub_tcp_admin_t *psa, pubsub_tcp_topic_receiver_t *receiver,
+pubsub_udpAdmin_disconnectEndpointFromReceiver(pubsub_udp_admin_t *psa, pubsub_udp_topic_receiver_t *receiver,
                                                const celix_properties_t *endpoint) {
     //note can be called with discoveredEndpoint.mutex lock
     celix_status_t status = CELIX_SUCCESS;
+    const char *url = celix_properties_get(endpoint, PUBSUB_UDP_URL_KEY, NULL);
+    pubsub_udpTopicReceiver_disconnectFrom(receiver, url);
+    return status;
+}
 
-    const char *url = celix_properties_get(endpoint, PUBSUB_TCP_URL_KEY, NULL);
-
-    if (url == NULL) {
-        L_WARN("[PSA_TCP_V2] Error got endpoint without tcp url");
-        status = CELIX_BUNDLE_EXCEPTION;
-    } else {
-        pubsub_tcpTopicReceiver_disconnectFrom(receiver, url);
-    }
-
+static celix_status_t
+pubsub_udpAdmin_disconnectEndpointFromSender(pubsub_udp_admin_t *psa, pubsub_udp_topic_sender_t *sender,
+                                               const celix_properties_t *endpoint) {
+    //note can be called with discoveredEndpoint.mutex lock
+    celix_status_t status = CELIX_SUCCESS;
+    const char *url = celix_properties_get(endpoint, PUBSUB_UDP_URL_KEY, NULL);
+    pubsub_udpTopicSender_disconnectFrom(sender, url);
     return status;
 }
 
-celix_status_t pubsub_tcpAdmin_removeDiscoveredEndpoint(void *handle, const celix_properties_t *endpoint) {
-    pubsub_tcp_admin_t *psa = handle;
+celix_status_t pubsub_udpAdmin_removeDiscoveredEndpoint(void *handle, const celix_properties_t *endpoint) {
+    pubsub_udp_admin_t *psa = handle;
 
-    if (pubsub_tcpAdmin_endpointIsPublisher(endpoint)) {
+    if (pubsub_udpAdmin_endpointIsPublisher(endpoint)) {
         celixThreadMutex_lock(&psa->topicReceivers.mutex);
         hash_map_iterator_t iter = hashMapIterator_construct(psa->topicReceivers.map);
         while (hashMapIterator_hasNext(&iter)) {
-            pubsub_tcp_topic_receiver_t *receiver = hashMapIterator_nextValue(&iter);
-            pubsub_tcpAdmin_disconnectEndpointFromReceiver(psa, receiver, endpoint);
+            pubsub_udp_topic_receiver_t *receiver = hashMapIterator_nextValue(&iter);
+            pubsub_udpAdmin_disconnectEndpointFromReceiver(psa, receiver, endpoint);
         }
         celixThreadMutex_unlock(&psa->topicReceivers.mutex);
     }
 
+    if (pubsub_udpAdmin_endpointIsSubScriber(endpoint)) {
+        celixThreadMutex_lock(&psa->topicSenders.mutex);
+        hash_map_iterator_t iter = hashMapIterator_construct(psa->topicSenders.map);
+        while (hashMapIterator_hasNext(&iter)) {
+            pubsub_udp_topic_sender_t *sender = hashMapIterator_nextValue(&iter);
+            pubsub_udpAdmin_disconnectEndpointFromSender(psa, sender, endpoint);
+        }
+        celixThreadMutex_unlock(&psa->topicSenders.mutex);
+    }
+
     celixThreadMutex_lock(&psa->discoveredEndpoints.mutex);
     const char *uuid = celix_properties_get(endpoint, PUBSUB_ENDPOINT_UUID, NULL);
     celix_properties_t *found = hashMap_remove(psa->discoveredEndpoints.map, (void *) uuid);
@@ -618,9 +680,9 @@ celix_status_t pubsub_tcpAdmin_removeDiscoveredEndpoint(void *handle, const celi
     return status;
 }
 
-bool pubsub_tcpAdmin_executeCommand(void *handle, const char *commandLine __attribute__((unused)), FILE *out,
+bool pubsub_udpAdmin_executeCommand(void *handle, const char *commandLine __attribute__((unused)), FILE *out,
                                     FILE *errStream __attribute__((unused))) {
-    pubsub_tcp_admin_t *psa = handle;
+    pubsub_udp_admin_t *psa = handle;
     celix_status_t status = CELIX_SUCCESS;
     char *line = celix_utils_strdup(commandLine);
     char *token = line;
@@ -644,20 +706,29 @@ bool pubsub_tcpAdmin_executeCommand(void *handle, const char *commandLine __attr
     celixThreadMutex_lock(&psa->topicSenders.mutex);
     hash_map_iterator_t iter = hashMapIterator_construct(psa->topicSenders.map);
     while (hashMapIterator_hasNext(&iter)) {
-        pubsub_tcp_topic_sender_t *sender = hashMapIterator_nextValue(&iter);
-        long protSvcId = pubsub_tcpTopicSender_protocolSvcId(sender);
-        psa_tcp_protocol_entry_t *protEntry = hashMap_get(psa->protocols.map, (void *) protSvcId);
-        const char *serType = pubsub_tcpTopicSender_serializerType(sender);
+        pubsub_udp_topic_sender_t *sender = hashMapIterator_nextValue(&iter);
+        long protSvcId = pubsub_udpTopicSender_protocolSvcId(sender);
+        psa_udp_protocol_entry_t *protEntry = hashMap_get(psa->protocols.map, (void *) protSvcId);
+        const char *serType = pubsub_udpTopicSender_serializerType(sender);
         const char *protType = protEntry == NULL ? "!Error!" : protEntry->protType;
-        const char *scope = pubsub_tcpTopicSender_scope(sender);
-        const char *topic = pubsub_tcpTopicSender_topic(sender);
-        const char *url = pubsub_tcpTopicSender_url(sender);
-        const char *isPassive = pubsub_tcpTopicSender_isPassive(sender) ? " (passive)" : "";
-        const char *postUrl = pubsub_tcpTopicSender_isStatic(sender) ? " (static)" : "";
+        const char *scope = pubsub_udpTopicSender_scope(sender);
+        const char *topic = pubsub_udpTopicSender_topic(sender);
+        const char *url = pubsub_udpTopicSender_url(sender);
+        const char *isPassive = pubsub_udpTopicSender_isPassive(sender) ? " (passive)" : "";
+        const char *postUrl = pubsub_udpTopicSender_isStatic(sender) ? " (static)" : "";
+        celix_array_list_t *urls = celix_arrayList_create();
+        pubsub_udpTopicSender_listConnections(sender, urls);
+
         fprintf(out, "|- Topic Sender %s/%s\n", scope == NULL ? "(null)" : scope, topic);
         fprintf(out, "   |- serializer type = %s\n", serType);
         fprintf(out, "   |- protocol type = %s\n", protType);
-        fprintf(out, "   |- url            = %s%s%s\n", url, postUrl, isPassive);
+        if (url) fprintf(out, "   |- url            = %s%s%s\n", url, postUrl, isPassive);
+        for (int i = 0; i < celix_arrayList_size(urls); ++i) {
+            char *_url = celix_arrayList_get(urls, i);
+            fprintf(out, "   |- connected url   = %s\n", _url);
+            free(_url);
+        }
+        celix_arrayList_destroy(urls);
     }
     celixThreadMutex_unlock(&psa->topicSenders.mutex);
     celixThreadMutex_unlock(&psa->protocols.mutex);
@@ -668,30 +739,34 @@ bool pubsub_tcpAdmin_executeCommand(void *handle, const char *commandLine __attr
     celixThreadMutex_lock(&psa->topicReceivers.mutex);
     iter = hashMapIterator_construct(psa->topicReceivers.map);
     while (hashMapIterator_hasNext(&iter)) {
-        pubsub_tcp_topic_receiver_t *receiver = hashMapIterator_nextValue(&iter);
-        long protSvcId = pubsub_tcpTopicReceiver_protocolSvcId(receiver);
-        psa_tcp_protocol_entry_t *protEntry = hashMap_get(psa->protocols.map, (void *) protSvcId);
-        const char *serType = pubsub_tcpTopicReceiver_serializerType(receiver);
+        pubsub_udp_topic_receiver_t *receiver = hashMapIterator_nextValue(&iter);
+        long protSvcId = pubsub_udpTopicReceiver_protocolSvcId(receiver);
+        psa_udp_protocol_entry_t *protEntry = hashMap_get(psa->protocols.map, (void *) protSvcId);
+        const char *serType = pubsub_udpTopicReceiver_serializerType(receiver);
         const char *protType = protEntry == NULL ? "!Error!" : protEntry->protType;
-        const char *scope = pubsub_tcpTopicReceiver_scope(receiver);
-        const char *topic = pubsub_tcpTopicReceiver_topic(receiver);
+        const char *scope = pubsub_udpTopicReceiver_scope(receiver);
+        const char *topic = pubsub_udpTopicReceiver_topic(receiver);
+        const char *url = pubsub_udpTopicReceiver_url(receiver);
+        const char *isPassive = pubsub_udpTopicReceiver_isPassive(receiver) ? " (passive)" : "";
+        const char *postUrl = pubsub_udpTopicReceiver_isStatic(receiver) ? " (static)" : "";
 
         celix_array_list_t *connected = celix_arrayList_create();
         celix_array_list_t *unconnected = celix_arrayList_create();
-        pubsub_tcpTopicReceiver_listConnections(receiver, connected, unconnected);
+        pubsub_udpTopicReceiver_listConnections(receiver, connected, unconnected);
 
         fprintf(out, "|- Topic Receiver %s/%s\n", scope == NULL ? "(null)" : scope, topic);
         fprintf(out, "   |- serializer type = %s\n", serType);
         fprintf(out, "   |- protocol type = %s\n", protType);
+        if (url) fprintf(out, "   |- url            = %s%s%s\n", url, postUrl, isPassive);
         for (int i = 0; i < celix_arrayList_size(connected); ++i) {
-            char *url = celix_arrayList_get(connected, i);
-            fprintf(out, "   |- connected url   = %s\n", url);
-            free(url);
+            char *_url = celix_arrayList_get(connected, i);
+            fprintf(out, "   |- connected url   = %s\n", _url);
+            free(_url);
         }
         for (int i = 0; i < celix_arrayList_size(unconnected); ++i) {
-            char *url = celix_arrayList_get(unconnected, i);
-            fprintf(out, "   |- unconnected url = %s\n", url);
-            free(url);
+            char *_url = celix_arrayList_get(unconnected, i);
+            fprintf(out, "   |- unconnected url = %s\n", _url);
+            free(_url);
         }
         celix_arrayList_destroy(connected);
         celix_arrayList_destroy(unconnected);
@@ -704,6 +779,6 @@ bool pubsub_tcpAdmin_executeCommand(void *handle, const char *commandLine __attr
     return status;
 }
 
-pubsub_admin_metrics_t *pubsub_tcpAdmin_metrics(void *handle) {
+pubsub_admin_metrics_t *pubsub_udpAdmin_metrics(void *handle) {
     return NULL;
 }
diff --git a/bundles/pubsub/pubsub_admin_udp/src/pubsub_udp_admin.h b/bundles/pubsub/pubsub_admin_udp/src/pubsub_udp_admin.h
new file mode 100644
index 0000000..fd5ea24
--- /dev/null
+++ b/bundles/pubsub/pubsub_admin_udp/src/pubsub_udp_admin.h
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ */
+
+#ifndef CELIX_PUBSUB_UDP_ADMIN_H
+#define CELIX_PUBSUB_UDP_ADMIN_H
+
+#include <pubsub_admin_metrics.h>
+#include <pubsub_message_serialization_service.h>
+#include <stdint.h>
+#include "celix_api.h"
+#include "celix_log_helper.h"
+#include "pubsub_psa_udp_constants.h"
+
+typedef struct pubsub_udp_admin pubsub_udp_admin_t;
+
+typedef struct psa_udp_serializer_entry {
+    const char *fqn;
+    const char *version;
+    pubsub_message_serialization_service_t *svc;
+} psa_udp_serializer_entry_t;
+
+pubsub_udp_admin_t *pubsub_udpAdmin_create(celix_bundle_context_t *ctx, celix_log_helper_t *logHelper);
+void pubsub_udpAdmin_destroy(pubsub_udp_admin_t *psa);
+
+celix_status_t pubsub_udpAdmin_matchPublisher(void *handle,
+                                              long svcRequesterBndId,
+                                              const celix_filter_t *svcFilter,
+                                              celix_properties_t **topicProperties,
+                                              double *score,
+                                              long *serializerSvcId,
+                                              long *protocolSvcId);
+celix_status_t pubsub_udpAdmin_matchSubscriber(void *handle,
+                                               long svcProviderBndId,
+                                               const celix_properties_t *svcProperties,
+                                               celix_properties_t **topicProperties,
+                                               double *score,
+                                               long *serializerSvcId,
+                                               long *protocolSvcId);
+celix_status_t pubsub_udpAdmin_matchDiscoveredEndpoint(void *handle, const celix_properties_t *endpoint, bool *match);
+
+celix_status_t pubsub_udpAdmin_setupTopicSender(void *handle,
+                                                const char *scope,
+                                                const char *topic,
+                                                const celix_properties_t *topicProperties,
+                                                long serializerSvcId,
+                                                long protocolSvcId,
+                                                celix_properties_t **publisherEndpoint);
+celix_status_t pubsub_udpAdmin_teardownTopicSender(void *handle, const char *scope, const char *topic);
+
+celix_status_t pubsub_udpAdmin_setupTopicReceiver(void *handle,
+                                                  const char *scope,
+                                                  const char *topic,
+                                                  const celix_properties_t *topicProperties,
+                                                  long serializerSvcId,
+                                                  long protocolSvcId,
+                                                  celix_properties_t **subscriberEndpoint);
+celix_status_t pubsub_udpAdmin_teardownTopicReceiver(void *handle, const char *scope, const char *topic);
+
+celix_status_t pubsub_udpAdmin_addDiscoveredEndpoint(void *handle, const celix_properties_t *endpoint);
+celix_status_t pubsub_udpAdmin_removeDiscoveredEndpoint(void *handle, const celix_properties_t *endpoint);
+
+void pubsub_udpAdmin_addSerializerSvc(void *handle, void *svc, const celix_properties_t *props);
+void pubsub_udpAdmin_removeSerializerSvc(void *handle, void *svc, const celix_properties_t *props);
+
+void pubsub_udpAdmin_addProtocolSvc(void *handle, void *svc, const celix_properties_t *props);
+void pubsub_udpAdmin_removeProtocolSvc(void *handle, void *svc, const celix_properties_t *props);
+bool pubsub_udpAdmin_executeCommand(void *handle, const char *commandLine, FILE *outStream, FILE *errStream);
+
+pubsub_admin_metrics_t *pubsub_udpAdmin_metrics(void *handle);
+
+#endif //CELIX_PUBSUB_udp_ADMIN_H
+
diff --git a/bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_topic_receiver.c b/bundles/pubsub/pubsub_admin_udp/src/pubsub_udp_topic_receiver.c
similarity index 70%
copy from bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_topic_receiver.c
copy to bundles/pubsub/pubsub_admin_udp/src/pubsub_udp_topic_receiver.c
index 597e4ff..6e78c9d 100644
--- a/bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_topic_receiver.c
+++ b/bundles/pubsub/pubsub_admin_udp/src/pubsub_udp_topic_receiver.c
@@ -25,11 +25,9 @@
 #include <memory.h>
 #include <arpa/inet.h>
 #include <celix_log_helper.h>
-#include "pubsub_tcp_handler.h"
-#include "pubsub_tcp_topic_receiver.h"
-#include "pubsub_psa_tcp_constants.h"
-#include "pubsub_tcp_common.h"
-#include "pubsub_tcp_admin.h"
+#include "pubsub_skt_handler.h"
+#include "pubsub_udp_topic_receiver.h"
+#include "pubsub_psa_udp_constants.h"
 
 #include <uuid/uuid.h>
 #include <pubsub_utils.h>
@@ -51,19 +49,21 @@
 #define L_ERROR(...) \
     celix_logHelper_log(receiver->logHelper, CELIX_LOG_LEVEL_ERROR, __VA_ARGS__)
 
-struct pubsub_tcp_topic_receiver {
+struct pubsub_udp_topic_receiver {
     celix_bundle_context_t *ctx;
     celix_log_helper_t *logHelper;
     long protocolSvcId;
     pubsub_protocol_service_t *protocol;
     char *scope;
     char *topic;
+    char *url;
     pubsub_serializer_handler_t* serializerHandler;
     void *admin;
     size_t timeout;
     bool isPassive;
-    pubsub_tcpHandler_t *socketHandler;
-    pubsub_tcpHandler_t *sharedSocketHandler;
+    bool isStatic;
+    pubsub_sktHandler_t *socketHandler;
+    pubsub_sktHandler_t *sharedSocketHandler;
     pubsub_interceptors_handler_t *interceptorsHandler;
 
     struct {
@@ -74,50 +74,50 @@ struct pubsub_tcp_topic_receiver {
 
     struct {
         celix_thread_mutex_t mutex;
-        hash_map_t *map; //key = tcp url, value = psa_tcp_requested_connection_entry_t*
+        hash_map_t *map; //key = udp url, value = psa_udp_requested_connection_entry_t*
         bool allConnected; //true if all requestedConnection are connected
     } requestedConnections;
 
     long subscriberTrackerId;
     struct {
         celix_thread_mutex_t mutex;
-        hash_map_t *map; //key = long svc id, value = psa_tcp_subscriber_entry_t
+        hash_map_t *map; //key = long svc id, value = psa_udp_subscriber_entry_t
         bool allInitialized;
     } subscribers;
 };
 
-typedef struct psa_tcp_requested_connection_entry {
-    pubsub_tcp_topic_receiver_t *parent;
+typedef struct psa_udp_requested_connection_entry {
+    pubsub_udp_topic_receiver_t *parent;
     char *url;
     bool connected;
     bool statically; //true if the connection is statically configured through the topic properties.
-} psa_tcp_requested_connection_entry_t;
+} psa_udp_requested_connection_entry_t;
 
-typedef struct psa_tcp_subscriber_entry {
+typedef struct psa_udp_subscriber_entry {
     pubsub_subscriber_t* subscriberSvc;
     bool initialized; //true if the init function is called through the receive thread
-} psa_tcp_subscriber_entry_t;
+} psa_udp_subscriber_entry_t;
 
-static void pubsub_tcpTopicReceiver_addSubscriber(void *handle, void *svc, const celix_properties_t *props);
-static void pubsub_tcpTopicReceiver_removeSubscriber(void *handle, void *svc, const celix_properties_t *props);
-static void *psa_tcp_recvThread(void *data);
-static void psa_tcp_connectToAllRequestedConnections(pubsub_tcp_topic_receiver_t *receiver);
-static void psa_tcp_initializeAllSubscribers(pubsub_tcp_topic_receiver_t *receiver);
+static void pubsub_udpTopicReceiver_addSubscriber(void *handle, void *svc, const celix_properties_t *props);
+static void pubsub_udpTopicReceiver_removeSubscriber(void *handle, void *svc, const celix_properties_t *props);
+static void *psa_udp_recvThread(void *data);
+static void psa_udp_connectToAllRequestedConnections(pubsub_udp_topic_receiver_t *receiver);
+static void psa_udp_initializeAllSubscribers(pubsub_udp_topic_receiver_t *receiver);
 static void processMsg(void *handle, const pubsub_protocol_message_t *message, bool *release, struct timespec *receiveTime);
-static void psa_tcp_connectHandler(void *handle, const char *url, bool lock);
-static void psa_tcp_disConnectHandler(void *handle, const char *url, bool lock);
+static void psa_udp_connectHandler(void *handle, const char *url, bool lock);
+static void psa_udp_disConnectHandler(void *handle, const char *url, bool lock);
 
-pubsub_tcp_topic_receiver_t *pubsub_tcpTopicReceiver_create(celix_bundle_context_t *ctx,
+pubsub_udp_topic_receiver_t *pubsub_udpTopicReceiver_create(celix_bundle_context_t *ctx,
                                                             celix_log_helper_t *logHelper,
                                                             const char *scope,
                                                             const char *topic,
                                                             pubsub_serializer_handler_t* serializerHandler,
                                                             void *admin,
                                                             const celix_properties_t *topicProperties,
-                                                            pubsub_tcp_endPointStore_t *handlerStore,
+                                                            pubsub_sktHandler_endPointStore_t *handlerStore,
                                                             long protocolSvcId,
                                                             pubsub_protocol_service_t *protocol) {
-    pubsub_tcp_topic_receiver_t *receiver = calloc(1, sizeof(*receiver));
+    pubsub_udp_topic_receiver_t *receiver = calloc(1, sizeof(*receiver));
     receiver->ctx = ctx;
     receiver->logHelper = logHelper;
     receiver->serializerHandler = serializerHandler;
@@ -126,38 +126,43 @@ pubsub_tcp_topic_receiver_t *pubsub_tcpTopicReceiver_create(celix_bundle_context
     receiver->protocol = protocol;
     receiver->scope = celix_utils_strdup(scope);
     receiver->topic = celix_utils_strdup(topic);
-    receiver->interceptorsHandler = pubsubInterceptorsHandler_create(ctx, scope, topic, PUBSUB_TCP_ADMIN_TYPE,
+    receiver->interceptorsHandler = pubsubInterceptorsHandler_create(ctx, scope, topic, PUBSUB_UDP_ADMIN_TYPE,
                                                                      pubsub_serializerHandler_getSerializationType(serializerHandler));
-    const char *staticConnectUrls = pubsub_getEnvironmentVariableWithScopeTopic(ctx, PUBSUB_TCP_STATIC_CONNECT_URLS_FOR, topic, scope);
-    const char *isPassive = pubsub_getEnvironmentVariableWithScopeTopic(ctx, PUBSUB_TCP_PASSIVE_ENABLED, topic, scope);
-    const char *passiveKey = pubsub_getEnvironmentVariableWithScopeTopic(ctx, PUBSUB_TCP_PASSIVE_SELECTION_KEY, topic, scope);
+    const char *ip = celix_bundleContext_getProperty(ctx, PUBSUB_UDP_PSA_IP_KEY, NULL);
+    const char *discUrl = pubsub_getEnvironmentVariableWithScopeTopic(ctx, PUBSUB_UDP_STATIC_BIND_URL_FOR, topic, scope);
+    const char *staticConnectUrls = pubsub_getEnvironmentVariableWithScopeTopic(ctx, PUBSUB_UDP_STATIC_CONNECT_URLS_FOR, topic, scope);
+    const char *isPassive = pubsub_getEnvironmentVariableWithScopeTopic(ctx, PUBSUB_UDP_PASSIVE_ENABLED, topic, scope);
+    const char *passiveKey = pubsub_getEnvironmentVariableWithScopeTopic(ctx, PUBSUB_UDP_PASSIVE_SELECTION_KEY, topic, scope);
 
     if (isPassive) {
-        receiver->isPassive = psa_tcp_isPassive(isPassive);
+        receiver->isPassive = pubsub_sktHandler_isPassive(isPassive);
     }
     if (topicProperties != NULL) {
+        if (discUrl == NULL) {
+            discUrl = celix_properties_get(topicProperties, PUBSUB_UDP_STATIC_DISCOVER_URL, NULL);
+        }
         if(staticConnectUrls == NULL) {
-            staticConnectUrls = celix_properties_get(topicProperties, PUBSUB_TCP_STATIC_CONNECT_URLS, NULL);
+            staticConnectUrls = celix_properties_get(topicProperties, PUBSUB_UDP_STATIC_CONNECT_URLS, NULL);
         }
         if (isPassive == NULL) {
-            receiver->isPassive = celix_properties_getAsBool(topicProperties, PUBSUB_TCP_PASSIVE_CONFIGURED, false);
+            receiver->isPassive = celix_properties_getAsBool(topicProperties, PUBSUB_UDP_PASSIVE_CONFIGURED, false);
         }
         if (passiveKey == NULL) {
-            passiveKey = celix_properties_get(topicProperties, PUBSUB_TCP_PASSIVE_KEY, NULL);
+            passiveKey = celix_properties_get(topicProperties, PUBSUB_UDP_PASSIVE_KEY, NULL);
         }
     }
 
     // Set receiver connection thread timeout.
     // property is in ms, timeout value in us. (convert ms to us).
-    receiver->timeout = celix_bundleContext_getPropertyAsLong(ctx, PSA_TCP_SUBSCRIBER_CONNECTION_TIMEOUT,
-                                                              PSA_TCP_SUBSCRIBER_CONNECTION_DEFAULT_TIMEOUT) * 1000;
+    receiver->timeout = celix_bundleContext_getPropertyAsLong(ctx, PSA_UDP_SUBSCRIBER_CONNECTION_TIMEOUT,
+                                                              PSA_UDP_SUBSCRIBER_CONNECTION_DEFAULT_TIMEOUT) * 1000;
     /* When it's an endpoint share the socket with the sender */
     if (passiveKey != NULL) {
         celixThreadMutex_lock(&handlerStore->mutex);
-        pubsub_tcpHandler_t *entry = hashMap_get(handlerStore->map, passiveKey);
+        pubsub_sktHandler_t *entry = hashMap_get(handlerStore->map, passiveKey);
         if (entry == NULL) {
             if (receiver->socketHandler == NULL)
-                receiver->socketHandler = pubsub_tcpHandler_create(receiver->protocol, receiver->logHelper);
+                receiver->socketHandler = pubsub_sktHandler_create(receiver->protocol, receiver->logHelper);
             entry = receiver->socketHandler;
             receiver->sharedSocketHandler = receiver->socketHandler;
             hashMap_put(handlerStore->map, (void *) passiveKey, entry);
@@ -167,28 +172,28 @@ pubsub_tcp_topic_receiver_t *pubsub_tcpTopicReceiver_create(celix_bundle_context
         }
         celixThreadMutex_unlock(&handlerStore->mutex);
     } else {
-        receiver->socketHandler = pubsub_tcpHandler_create(receiver->protocol, receiver->logHelper);
+        receiver->socketHandler = pubsub_sktHandler_create(receiver->protocol, receiver->logHelper);
     }
 
     if (receiver->socketHandler != NULL) {
-        long prio = celix_properties_getAsLong(topicProperties, PUBSUB_TCP_THREAD_REALTIME_PRIO, -1L);
-        const char *sched = celix_properties_get(topicProperties, PUBSUB_TCP_THREAD_REALTIME_SCHED, NULL);
-        long retryCnt = celix_properties_getAsLong(topicProperties, PUBSUB_TCP_SUBSCRIBER_RETRY_CNT_KEY,
-                                                   PUBSUB_TCP_SUBSCRIBER_RETRY_CNT_DEFAULT);
-        double rcvTimeout = celix_properties_getAsDouble(topicProperties, PUBSUB_TCP_SUBSCRIBER_RCVTIMEO_KEY, PUBSUB_TCP_SUBSCRIBER_RCVTIMEO_DEFAULT);
-        long bufferSize = celix_bundleContext_getPropertyAsLong(ctx, PSA_TCP_RECV_BUFFER_SIZE,
-                                                                 PSA_TCP_DEFAULT_RECV_BUFFER_SIZE);
-        long timeout = celix_bundleContext_getPropertyAsLong(ctx, PSA_TCP_TIMEOUT, PSA_TCP_DEFAULT_TIMEOUT);
-
-        pubsub_tcpHandler_setThreadName(receiver->socketHandler, topic, scope);
-        pubsub_tcpHandler_setReceiveBufferSize(receiver->socketHandler, (unsigned int) bufferSize);
-        pubsub_tcpHandler_setTimeout(receiver->socketHandler, (unsigned int) timeout);
-        pubsub_tcpHandler_addMessageHandler(receiver->socketHandler, receiver, processMsg);
-        pubsub_tcpHandler_addReceiverConnectionCallback(receiver->socketHandler, receiver, psa_tcp_connectHandler,
-                                                        psa_tcp_disConnectHandler);
-        pubsub_tcpHandler_setThreadPriority(receiver->socketHandler, prio, sched);
-        pubsub_tcpHandler_setReceiveRetryCnt(receiver->socketHandler, (unsigned int) retryCnt);
-        pubsub_tcpHandler_setReceiveTimeOut(receiver->socketHandler, rcvTimeout);
+        long prio = celix_properties_getAsLong(topicProperties, PUBSUB_UDP_THREAD_REALTIME_PRIO, -1L);
+        const char *sched = celix_properties_get(topicProperties, PUBSUB_UDP_THREAD_REALTIME_SCHED, NULL);
+        long retryCnt = celix_properties_getAsLong(topicProperties, PUBSUB_UDP_SUBSCRIBER_RETRY_CNT_KEY,
+                                                   PUBSUB_UDP_SUBSCRIBER_RETRY_CNT_DEFAULT);
+        double rcvTimeout = celix_properties_getAsDouble(topicProperties, PUBSUB_UDP_SUBSCRIBER_RCVTIMEO_KEY, PUBSUB_UDP_SUBSCRIBER_RCVTIMEO_DEFAULT);
+        long bufferSize = celix_bundleContext_getPropertyAsLong(ctx, PSA_UDP_RECV_BUFFER_SIZE,
+                                                                 PSA_UDP_DEFAULT_RECV_BUFFER_SIZE);
+        long timeout = celix_bundleContext_getPropertyAsLong(ctx, PSA_UDP_TIMEOUT, PSA_UDP_DEFAULT_TIMEOUT);
+
+        pubsub_sktHandler_setThreadName(receiver->socketHandler, topic, scope);
+        pubsub_sktHandler_setReceiveBufferSize(receiver->socketHandler, (unsigned int) bufferSize);
+        pubsub_sktHandler_setTimeout(receiver->socketHandler, (unsigned int) timeout);
+        pubsub_sktHandler_addMessageHandler(receiver->socketHandler, receiver, processMsg);
+        pubsub_sktHandler_addReceiverConnectionCallback(receiver->socketHandler, receiver, psa_udp_connectHandler,
+                                                        psa_udp_disConnectHandler);
+        pubsub_sktHandler_setThreadPriority(receiver->socketHandler, prio, sched);
+        pubsub_sktHandler_setReceiveRetryCnt(receiver->socketHandler, (unsigned int) retryCnt);
+        pubsub_sktHandler_setReceiveTimeOut(receiver->socketHandler, rcvTimeout);
     }
     celixThreadMutex_create(&receiver->subscribers.mutex, NULL);
     celixThreadMutex_create(&receiver->requestedConnections.mutex, NULL);
@@ -202,23 +207,63 @@ pubsub_tcp_topic_receiver_t *pubsub_tcpTopicReceiver_create(celix_bundle_context
         char *url;
         char *save = urlsCopy;
         while ((url = strtok_r(save, " ", &save))) {
-            psa_tcp_requested_connection_entry_t *entry = calloc(1, sizeof(*entry));
-            entry->statically = true;
-            entry->connected = false;
-            entry->url = celix_utils_strdup(url);
-            entry->parent = receiver;
-            hashMap_put(receiver->requestedConnections.map, entry->url, entry);
-            receiver->requestedConnections.allConnected = false;
+            pubsub_utils_url_t *url_info = pubsub_utils_url_parse(url);
+            bool is_multicast = pubsub_utils_url_is_multicast(url_info->hostname);
+            bool is_broadcast = pubsub_utils_url_is_broadcast(url_info->hostname);
+            if (is_multicast || is_broadcast) {
+                psa_udp_requested_connection_entry_t *entry = calloc(1, sizeof(*entry));
+                entry->statically = true;
+                entry->connected = false;
+                entry->url = celix_utils_strdup(url);
+                entry->parent = receiver;
+                hashMap_put(receiver->requestedConnections.map, entry->url, entry);
+                receiver->requestedConnections.allConnected = false;
+            }
+            pubsub_utils_url_free(url_info);
         }
         free(urlsCopy);
     }
 
+    if (!receiver->isPassive) {
+        //setting up tcp socket for UDP TopicReceiver
+        char *urls = NULL;
+        if (discUrl != NULL) {
+            urls = celix_utils_strdup(discUrl);
+        } else if (ip != NULL) {
+            urls = celix_utils_strdup(ip);
+        } else {
+            struct sockaddr_in *sin = pubsub_utils_url_getInAddr(NULL, 0);
+            urls = pubsub_utils_url_get_url(sin, NULL);
+            free(sin);
+        }
+        if (urls) {
+            char *urlsCopy = celix_utils_strdup(urls);
+            char *url;
+            char *save = urlsCopy;
+            while ((url = strtok_r(save, " ", &save))) {
+                pubsub_utils_url_t *url_info = pubsub_utils_url_parse(url);
+                bool is_multicast = pubsub_utils_url_is_multicast(url_info->hostname);
+                bool is_broadcast = pubsub_utils_url_is_broadcast(url_info->hostname);
+                if (!is_multicast && !is_broadcast) {
+                    int rc = pubsub_sktHandler_udp_bind(receiver->socketHandler, url);
+                    if (rc < 0) {
+                        L_WARN("Error for udp listen using dynamic bind url '%s'. %s", url, strerror(errno));
+                    } else {
+                        url = NULL;}
+                }
+                pubsub_utils_url_free(url_info);
+            }
+            receiver->url = pubsub_sktHandler_get_interface_url(receiver->socketHandler);
+            free(urlsCopy);
+        }
+        free(urls);
+    }
     if (receiver->socketHandler != NULL && (!receiver->isPassive)) {
         // Configure Receiver thread
         receiver->thread.running = true;
-        celixThread_create(&receiver->thread.thread, NULL, psa_tcp_recvThread, receiver);
+        celixThread_create(&receiver->thread.thread, NULL, psa_udp_recvThread, receiver);
         char name[64];
-        snprintf(name, 64, "TCP TR %s/%s", scope == NULL ? "(null)" : scope, topic);
+        snprintf(name, 64, "UDP TR %s/%s", scope == NULL ? "(null)" : scope, topic);
         celixThread_setName(&receiver->thread.thread, name);
     }
 
@@ -232,8 +277,8 @@ pubsub_tcp_topic_receiver_t *pubsub_tcpTopicReceiver_create(celix_bundle_context
         opts.filter.serviceName = PUBSUB_SUBSCRIBER_SERVICE_NAME;
         opts.filter.filter = buf;
         opts.callbackHandle = receiver;
-        opts.addWithProperties = pubsub_tcpTopicReceiver_addSubscriber;
-        opts.removeWithProperties = pubsub_tcpTopicReceiver_removeSubscriber;
+        opts.addWithProperties = pubsub_udpTopicReceiver_addSubscriber;
+        opts.removeWithProperties = pubsub_udpTopicReceiver_removeSubscriber;
         receiver->subscriberTrackerId = celix_bundleContext_trackServicesWithOptions(ctx, &opts);
     }
 
@@ -244,12 +289,12 @@ pubsub_tcp_topic_receiver_t *pubsub_tcpTopicReceiver_create(celix_bundle_context
         free(receiver->topic);
         free(receiver);
         receiver = NULL;
-        L_ERROR("[PSA_TCP] Cannot create TopicReceiver for %s/%s", scope == NULL ? "(null)" : scope, topic);
+        L_ERROR("[PSA_udp] Cannot create TopicReceiver for %s/%s", scope == NULL ? "(null)" : scope, topic);
     }
     return receiver;
 }
 
-void pubsub_tcpTopicReceiver_destroy(pubsub_tcp_topic_receiver_t *receiver) {
+void pubsub_udpTopicReceiver_destroy(pubsub_udp_topic_receiver_t *receiver) {
     if (receiver != NULL) {
 
         celixThreadMutex_lock(&receiver->thread.mutex);
@@ -268,7 +313,7 @@ void pubsub_tcpTopicReceiver_destroy(pubsub_tcp_topic_receiver_t *receiver) {
         celixThreadMutex_lock(&receiver->requestedConnections.mutex);
         hash_map_iterator_t iter = hashMapIterator_construct(receiver->requestedConnections.map);
         while (hashMapIterator_hasNext(&iter)) {
-            psa_tcp_requested_connection_entry_t *entry = hashMapIterator_nextValue(&iter);
+            psa_udp_requested_connection_entry_t *entry = hashMapIterator_nextValue(&iter);
             if (entry != NULL) {
                 free(entry->url);
                 free(entry);
@@ -281,10 +326,10 @@ void pubsub_tcpTopicReceiver_destroy(pubsub_tcp_topic_receiver_t *receiver) {
         celixThreadMutex_destroy(&receiver->requestedConnections.mutex);
         celixThreadMutex_destroy(&receiver->thread.mutex);
 
-        pubsub_tcpHandler_addMessageHandler(receiver->socketHandler, NULL, NULL);
-        pubsub_tcpHandler_addReceiverConnectionCallback(receiver->socketHandler, NULL, NULL, NULL);
+        pubsub_sktHandler_addMessageHandler(receiver->socketHandler, NULL, NULL);
+        pubsub_sktHandler_addReceiverConnectionCallback(receiver->socketHandler, NULL, NULL, NULL);
         if ((receiver->socketHandler) && (receiver->sharedSocketHandler == NULL)) {
-            pubsub_tcpHandler_destroy(receiver->socketHandler);
+            pubsub_sktHandler_destroy(receiver->socketHandler);
             receiver->socketHandler = NULL;
         }
         pubsubInterceptorsHandler_destroy(receiver->interceptorsHandler);
@@ -296,27 +341,44 @@ void pubsub_tcpTopicReceiver_destroy(pubsub_tcp_topic_receiver_t *receiver) {
     free(receiver);
 }
 
-const char *pubsub_tcpTopicReceiver_scope(pubsub_tcp_topic_receiver_t *receiver) {
+const char *pubsub_udpTopicReceiver_scope(pubsub_udp_topic_receiver_t *receiver) {
     return receiver->scope;
 }
 
-const char *pubsub_tcpTopicReceiver_topic(pubsub_tcp_topic_receiver_t *receiver) {
+const char *pubsub_udpTopicReceiver_topic(pubsub_udp_topic_receiver_t *receiver) {
     return receiver->topic;
 }
 
-const char *pubsub_tcpTopicReceiver_serializerType(pubsub_tcp_topic_receiver_t *receiver) {
+const char *pubsub_udpTopicReceiver_serializerType(pubsub_udp_topic_receiver_t *receiver) {
     return pubsub_serializerHandler_getSerializationType(receiver->serializerHandler);
 }
 
-long pubsub_tcpTopicReceiver_protocolSvcId(pubsub_tcp_topic_receiver_t *receiver) {
+long pubsub_udpTopicReceiver_protocolSvcId(pubsub_udp_topic_receiver_t *receiver) {
     return receiver->protocolSvcId;
 }
 
-void pubsub_tcpTopicReceiver_listConnections(pubsub_tcp_topic_receiver_t *receiver, celix_array_list_t *connectedUrls,
+bool pubsub_udpTopicReceiver_isStatic(pubsub_udp_topic_receiver_t *receiver) {
+    return receiver->isStatic;
+}
+
+bool pubsub_udpTopicReceiver_isPassive(pubsub_udp_topic_receiver_t *receiver) {
+    return receiver->isPassive;
+}
+
+const char *pubsub_udpTopicReceiver_url(pubsub_udp_topic_receiver_t *receiver) {
+    if (receiver->isPassive) {
+        return pubsub_sktHandler_get_connection_url(receiver->socketHandler);
+    } else {
+        return receiver->url;
+    }
+}
+
+
+void pubsub_udpTopicReceiver_listConnections(pubsub_udp_topic_receiver_t *receiver, celix_array_list_t *connectedUrls,
                                              celix_array_list_t *unconnectedUrls) {
     celixThreadMutex_lock(&receiver->requestedConnections.mutex);
     if (receiver->isPassive) {
-        char* interface_url = pubsub_tcpHandler_get_interface_url(receiver->socketHandler);
+        char* interface_url = pubsub_sktHandler_get_interface_url(receiver->socketHandler);
         char *url = NULL;
         asprintf(&url, "%s (passive)", interface_url ? interface_url : "");
         if (interface_url) {
@@ -328,7 +390,7 @@ void pubsub_tcpTopicReceiver_listConnections(pubsub_tcp_topic_receiver_t *receiv
     } else {
         hash_map_iterator_t iter = hashMapIterator_construct(receiver->requestedConnections.map);
         while (hashMapIterator_hasNext(&iter)) {
-            psa_tcp_requested_connection_entry_t *entry = hashMapIterator_nextValue(&iter);
+            psa_udp_requested_connection_entry_t *entry = hashMapIterator_nextValue(&iter);
             char *url = NULL;
             asprintf(&url, "%s%s", entry->url, entry->statically ? " (static)" : "");
             if (entry->connected) {
@@ -341,46 +403,49 @@ void pubsub_tcpTopicReceiver_listConnections(pubsub_tcp_topic_receiver_t *receiv
     celixThreadMutex_unlock(&receiver->requestedConnections.mutex);
 }
 
-bool pubsub_tcpTopicReceiver_isPassive(pubsub_tcp_topic_receiver_t *receiver) {
-    return receiver->isPassive;
-}
+void pubsub_udpTopicReceiver_connectTo(pubsub_udp_topic_receiver_t *receiver, const char *url) {
+    if (!url) return;
+    char *connectUrl =  celix_utils_strdup(url);
+    pubsub_utils_url_t *urlInfo = pubsub_utils_url_parse(connectUrl);
+    bool is_multicast = pubsub_utils_url_is_multicast(urlInfo->hostname);
+    bool is_broadcast = pubsub_utils_url_is_broadcast(urlInfo->hostname);
+    pubsub_utils_url_free(urlInfo);
 
-void pubsub_tcpTopicReceiver_connectTo(
-    pubsub_tcp_topic_receiver_t *receiver,
-    const char *url) {
-    L_DEBUG("[PSA_TCP] TopicReceiver %s/%s connecting to tcp url %s",
-            receiver->scope == NULL ? "(null)" : receiver->scope,
-            receiver->topic,
-            url);
+    if (is_multicast || is_broadcast) {
+        L_DEBUG("[PSA_udp] TopicReceiver %s/%s connecting to udp url %s",
+                receiver->scope == NULL ? "(null)" : receiver->scope,
+                receiver->topic,
+                url);
 
-    celixThreadMutex_lock(&receiver->requestedConnections.mutex);
-    psa_tcp_requested_connection_entry_t *entry = hashMap_get(receiver->requestedConnections.map, url);
-    if (entry == NULL) {
-        entry = calloc(1, sizeof(*entry));
-        entry->url = celix_utils_strdup(url);
-        entry->connected = false;
-        entry->statically = false;
-        entry->parent = receiver;
-        hashMap_put(receiver->requestedConnections.map, (void *) entry->url, entry);
-        receiver->requestedConnections.allConnected = false;
+        celixThreadMutex_lock(&receiver->requestedConnections.mutex);
+        psa_udp_requested_connection_entry_t *entry = hashMap_get(receiver->requestedConnections.map, url);
+        if (entry == NULL) {
+            entry = calloc(1, sizeof(*entry));
+            entry->url = celix_utils_strdup(url);
+            entry->connected = false;
+            entry->statically = false;
+            entry->parent = receiver;
+            hashMap_put(receiver->requestedConnections.map, (void *) entry->url, entry);
+            receiver->requestedConnections.allConnected = false;
+        }
+        celixThreadMutex_unlock(&receiver->requestedConnections.mutex);
+        psa_udp_connectToAllRequestedConnections(receiver);
     }
-    celixThreadMutex_unlock(&receiver->requestedConnections.mutex);
-
-    psa_tcp_connectToAllRequestedConnections(receiver);
 }
 
-void pubsub_tcpTopicReceiver_disconnectFrom(pubsub_tcp_topic_receiver_t *receiver, const char *url) {
-    L_DEBUG("[PSA TCP] TopicReceiver %s/%s disconnect from tcp url %s",
+void pubsub_udpTopicReceiver_disconnectFrom(pubsub_udp_topic_receiver_t *receiver, const char *url) {
+    if (!url) return;
+    L_DEBUG("[PSA udp] TopicReceiver %s/%s disconnect from udp url %s",
             receiver->scope == NULL ? "(null)" : receiver->scope,
             receiver->topic,
             url);
 
     celixThreadMutex_lock(&receiver->requestedConnections.mutex);
-    psa_tcp_requested_connection_entry_t *entry = hashMap_remove(receiver->requestedConnections.map, url);
+    psa_udp_requested_connection_entry_t *entry = hashMap_remove(receiver->requestedConnections.map, url);
     if (entry != NULL) {
-        int rc = pubsub_tcpHandler_disconnect(receiver->socketHandler, entry->url);
+        int rc = pubsub_sktHandler_disconnect(receiver->socketHandler, entry->url);
         if (rc < 0)
-            L_WARN("[PSA_TCP] Error disconnecting from tcp url %s. (%s)", url, strerror(errno));
+            L_WARN("[PSA_udp] Error disconnecting from udp url %s. (%s)", url, strerror(errno));
     }
     if (entry != NULL) {
         free(entry->url);
@@ -389,8 +454,8 @@ void pubsub_tcpTopicReceiver_disconnectFrom(pubsub_tcp_topic_receiver_t *receive
     celixThreadMutex_unlock(&receiver->requestedConnections.mutex);
 }
 
-static void pubsub_tcpTopicReceiver_addSubscriber(void *handle, void *svc, const celix_properties_t *props) {
-    pubsub_tcp_topic_receiver_t *receiver = handle;
+static void pubsub_udpTopicReceiver_addSubscriber(void *handle, void *svc, const celix_properties_t *props) {
+    pubsub_udp_topic_receiver_t *receiver = handle;
 
     long svcId = celix_properties_getAsLong(props, OSGI_FRAMEWORK_SERVICE_ID, -1);
     const char *subScope = celix_properties_get(props, PUBSUB_SUBSCRIBER_SCOPE, NULL);
@@ -408,7 +473,7 @@ static void pubsub_tcpTopicReceiver_addSubscriber(void *handle, void *svc, const
         return;
     }
 
-    psa_tcp_subscriber_entry_t *entry = calloc(1, sizeof(*entry));
+    psa_udp_subscriber_entry_t *entry = calloc(1, sizeof(*entry));
     entry->subscriberSvc = svc;
     entry->initialized = false;
 
@@ -418,23 +483,23 @@ static void pubsub_tcpTopicReceiver_addSubscriber(void *handle, void *svc, const
     celixThreadMutex_unlock(&receiver->subscribers.mutex);
 }
 
-static void pubsub_tcpTopicReceiver_removeSubscriber(void *handle, void *svc __attribute__((unused)), const celix_properties_t *props) {
-    pubsub_tcp_topic_receiver_t *receiver = handle;
+static void pubsub_udpTopicReceiver_removeSubscriber(void *handle, void *svc __attribute__((unused)), const celix_properties_t *props) {
+    pubsub_udp_topic_receiver_t *receiver = handle;
 
     long svcId = celix_properties_getAsLong(props, OSGI_FRAMEWORK_SERVICE_ID, -1);
 
     celixThreadMutex_lock(&receiver->subscribers.mutex);
-    psa_tcp_subscriber_entry_t *entry = hashMap_remove(receiver->subscribers.map, (void *)svcId);
+    psa_udp_subscriber_entry_t *entry = hashMap_remove(receiver->subscribers.map, (void *)svcId);
     free(entry);
     celixThreadMutex_unlock(&receiver->subscribers.mutex);
 }
 
-static void callReceivers(pubsub_tcp_topic_receiver_t *receiver, const char* msgFqn, const pubsub_protocol_message_t *message, void** msg, bool* release, const celix_properties_t* metadata) {
+static void callReceivers(pubsub_udp_topic_receiver_t *receiver, const char* msgFqn, const pubsub_protocol_message_t *message, void** msg, bool* release, const celix_properties_t* metadata) {
     *release = true;
     celixThreadMutex_lock(&receiver->subscribers.mutex);
     hash_map_iterator_t iter = hashMapIterator_construct(receiver->subscribers.map);
     while (hashMapIterator_hasNext(&iter)) {
-        psa_tcp_subscriber_entry_t* entry = hashMapIterator_nextValue(&iter);
+        psa_udp_subscriber_entry_t* entry = hashMapIterator_nextValue(&iter);
         if (entry != NULL && entry->subscriberSvc->receive != NULL) {
             entry->subscriberSvc->receive(entry->subscriberSvc->handle, msgFqn, message->header.msgId, *msg, metadata, release);
             if (!(*release) && hashMapIterator_hasNext(&iter)) { //receive function has taken ownership, deserialize again for new message
@@ -447,7 +512,7 @@ static void callReceivers(pubsub_tcp_topic_receiver_t *receiver, const char* msg
                                                                              message->header.msgMinorVersion,
                                                                              &deSerializeBuffer, 0, msg);
                 if (status != CELIX_SUCCESS) {
-                    L_WARN("[PSA_TCP_TR] Cannot deserialize msg type %s for scope/topic %s/%s", msgFqn,
+                    L_WARN("[PSA_UDP_TR] Cannot deserialize msg type %s for scope/topic %s/%s", msgFqn,
                            receiver->scope == NULL ? "(null)" : receiver->scope, receiver->topic);
                     break;
                 }
@@ -461,7 +526,7 @@ static void callReceivers(pubsub_tcp_topic_receiver_t *receiver, const char* msg
 }
 
 static inline void processMsg(void* handle, const pubsub_protocol_message_t *message, bool* releaseMsg, struct timespec *receiveTime) {
-    pubsub_tcp_topic_receiver_t *receiver = handle;
+    pubsub_udp_topic_receiver_t *receiver = handle;
 
     const char *msgFqn = pubsub_serializerHandler_getMsgFqn(receiver->serializerHandler, message->header.msgId);
     if (msgFqn == NULL) {
@@ -501,7 +566,7 @@ static inline void processMsg(void* handle, const pubsub_protocol_message_t *mes
                                                                                  message->header.msgMinorVersion,
                                                                                  &deSerializeBuffer, 0, &deSerializedMsg);
                         if (status != CELIX_SUCCESS) {
-                            L_WARN("[PSA_TCP_TR] Cannot deserialize msg type %s for scope/topic %s/%s", msgFqn,
+                            L_WARN("[PSA_UDP_TR] Cannot deserialize msg type %s for scope/topic %s/%s", msgFqn,
                                    receiver->scope == NULL ? "(null)" : receiver->scope, receiver->topic);
                         } else {
                             pubsubInterceptorHandler_invokePostReceive(receiver->interceptorsHandler, msgFqn, message->header.msgId, deSerializedMsg, metadata);
@@ -521,11 +586,11 @@ static inline void processMsg(void* handle, const pubsub_protocol_message_t *mes
                 celix_properties_destroy(metadata);
             }
         } else {
-            L_WARN("[PSA_TCP_TR] Cannot deserialize msg type %s for scope/topic %s/%s", msgFqn,
+            L_WARN("[PSA_UDP_TR] Cannot deserialize msg type %s for scope/topic %s/%s", msgFqn,
                    receiver->scope == NULL ? "(null)" : receiver->scope, receiver->topic);
         }
     } else {
-        L_WARN("[PSA_TCP_TR] Cannot deserialize message '%s' using %s, version mismatch. Version received: %i.%i.x, version local: %i.%i.x",
+        L_WARN("[PSA_UDP_TR] Cannot deserialize message '%s' using %s, version mismatch. Version received: %i.%i.x, version local: %i.%i.x",
                msgFqn,
                pubsub_serializerHandler_getSerializationType(receiver->serializerHandler),
                (int) message->header.msgMajorVersion,
@@ -535,8 +600,8 @@ static inline void processMsg(void* handle, const pubsub_protocol_message_t *mes
     }
 }
 
-static void *psa_tcp_recvThread(void *data) {
-    pubsub_tcp_topic_receiver_t *receiver = data;
+static void *psa_udp_recvThread(void *data) {
+    pubsub_udp_topic_receiver_t *receiver = data;
 
     celixThreadMutex_lock(&receiver->thread.mutex);
     bool running = receiver->thread.running;
@@ -552,10 +617,10 @@ static void *psa_tcp_recvThread(void *data) {
 
     while (running) {
         if (!allConnected) {
-            psa_tcp_connectToAllRequestedConnections(receiver);
+            psa_udp_connectToAllRequestedConnections(receiver);
         }
         if (!allInitialized) {
-            psa_tcp_initializeAllSubscribers(receiver);
+            psa_udp_initializeAllSubscribers(receiver);
         }
         usleep(receiver->timeout);
 
@@ -574,15 +639,15 @@ static void *psa_tcp_recvThread(void *data) {
     return NULL;
 }
 
-static void psa_tcp_connectToAllRequestedConnections(pubsub_tcp_topic_receiver_t *receiver) {
+static void psa_udp_connectToAllRequestedConnections(pubsub_udp_topic_receiver_t *receiver) {
     celixThreadMutex_lock(&receiver->requestedConnections.mutex);
     if (!receiver->requestedConnections.allConnected) {
         bool allConnected = true;
         hash_map_iterator_t iter = hashMapIterator_construct(receiver->requestedConnections.map);
         while (hashMapIterator_hasNext(&iter)) {
-            psa_tcp_requested_connection_entry_t *entry = hashMapIterator_nextValue(&iter);
+            psa_udp_requested_connection_entry_t *entry = hashMapIterator_nextValue(&iter);
             if ((entry) && (!entry->connected) && (!receiver->isPassive)) {
-                int rc = pubsub_tcpHandler_connect(entry->parent->socketHandler, entry->url);
+                int rc = pubsub_sktHandler_udp_connect(entry->parent->socketHandler, entry->url);
                 if (rc < 0) {
                     allConnected = false;
                 }
@@ -593,15 +658,15 @@ static void psa_tcp_connectToAllRequestedConnections(pubsub_tcp_topic_receiver_t
     celixThreadMutex_unlock(&receiver->requestedConnections.mutex);
 }
 
-static void psa_tcp_connectHandler(void *handle, const char *url, bool lock) {
-    pubsub_tcp_topic_receiver_t *receiver = handle;
-    L_DEBUG("[PSA_TCP] TopicReceiver %s/%s connecting to tcp url %s",
+static void psa_udp_connectHandler(void *handle, const char *url, bool lock) {
+    pubsub_udp_topic_receiver_t *receiver = handle;
+    L_DEBUG("[PSA_udp] TopicReceiver %s/%s connecting to udp url %s",
             receiver->scope == NULL ? "(null)" : receiver->scope,
             receiver->topic,
             url);
     if (lock)
         celixThreadMutex_lock(&receiver->requestedConnections.mutex);
-    psa_tcp_requested_connection_entry_t *entry = hashMap_get(receiver->requestedConnections.map, url);
+    psa_udp_requested_connection_entry_t *entry = hashMap_get(receiver->requestedConnections.map, url);
     if (entry == NULL) {
         entry = calloc(1, sizeof(*entry));
         entry->parent = receiver;
@@ -615,15 +680,15 @@ static void psa_tcp_connectHandler(void *handle, const char *url, bool lock) {
         celixThreadMutex_unlock(&receiver->requestedConnections.mutex);
 }
 
-static void psa_tcp_disConnectHandler(void *handle, const char *url, bool lock) {
-    pubsub_tcp_topic_receiver_t *receiver = handle;
-    L_DEBUG("[PSA TCP] TopicReceiver %s/%s disconnect from tcp url %s",
+static void psa_udp_disConnectHandler(void *handle, const char *url, bool lock) {
+    pubsub_udp_topic_receiver_t *receiver = handle;
+    L_DEBUG("[PSA udp] TopicReceiver %s/%s disconnect from udp url %s",
             receiver->scope == NULL ? "(null)" : receiver->scope,
             receiver->topic,
             url);
     if (lock)
         celixThreadMutex_lock(&receiver->requestedConnections.mutex);
-    psa_tcp_requested_connection_entry_t *entry = hashMap_get(receiver->requestedConnections.map, url);
+    psa_udp_requested_connection_entry_t *entry = hashMap_get(receiver->requestedConnections.map, url);
     if (entry != NULL) {
         entry->connected = false;
         receiver->requestedConnections.allConnected = false;
@@ -632,13 +697,13 @@ static void psa_tcp_disConnectHandler(void *handle, const char *url, bool lock)
         celixThreadMutex_unlock(&receiver->requestedConnections.mutex);
 }
 
-static void psa_tcp_initializeAllSubscribers(pubsub_tcp_topic_receiver_t *receiver) {
+static void psa_udp_initializeAllSubscribers(pubsub_udp_topic_receiver_t *receiver) {
     celixThreadMutex_lock(&receiver->subscribers.mutex);
     if (!receiver->subscribers.allInitialized) {
         bool allInitialized = true;
         hash_map_iterator_t iter = hashMapIterator_construct(receiver->subscribers.map);
         while (hashMapIterator_hasNext(&iter)) {
-            psa_tcp_subscriber_entry_t *entry = hashMapIterator_nextValue(&iter);
+            psa_udp_subscriber_entry_t *entry = hashMapIterator_nextValue(&iter);
             if (!entry->initialized) {
                 int rc = 0;
                 if (entry->subscriberSvc->init != NULL) {
diff --git a/bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_topic_receiver.h b/bundles/pubsub/pubsub_admin_udp/src/pubsub_udp_topic_receiver.h
similarity index 66%
copy from bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_topic_receiver.h
copy to bundles/pubsub/pubsub_admin_udp/src/pubsub_udp_topic_receiver.h
index 35c14c6..40a18c4 100644
--- a/bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_topic_receiver.h
+++ b/bundles/pubsub/pubsub_admin_udp/src/pubsub_udp_topic_receiver.h
@@ -17,40 +17,40 @@
  * under the License.
  */
 
-#ifndef CELIX_PUBSUB_TCP_TOPIC_RECEIVER_H
-#define CELIX_PUBSUB_TCP_TOPIC_RECEIVER_H
+#ifndef CELIX_PUBSUB_UDP_TOPIC_RECEIVER_H
+#define CELIX_PUBSUB_UDP_TOPIC_RECEIVER_H
 
 #include "pubsub_admin_metrics.h"
 #include "celix_bundle_context.h"
 #include "pubsub_protocol.h"
-#include "pubsub_tcp_common.h"
 #include "pubsub_serializer_handler.h"
 
-typedef struct pubsub_tcp_topic_receiver pubsub_tcp_topic_receiver_t;
+typedef struct pubsub_udp_topic_receiver pubsub_udp_topic_receiver_t;
 
-pubsub_tcp_topic_receiver_t *pubsub_tcpTopicReceiver_create(celix_bundle_context_t *ctx,
+pubsub_udp_topic_receiver_t *pubsub_udpTopicReceiver_create(celix_bundle_context_t *ctx,
                                                             celix_log_helper_t *logHelper,
                                                             const char *scope,
                                                             const char *topic,
                                                             pubsub_serializer_handler_t* serializerHandler,
                                                             void *admin,
                                                             const celix_properties_t *topicProperties,
-                                                            pubsub_tcp_endPointStore_t *handlerStore,
+                                                            pubsub_sktHandler_endPointStore_t *handlerStore,
                                                             long protocolSvcId,
                                                             pubsub_protocol_service_t *protocol);
-void pubsub_tcpTopicReceiver_destroy(pubsub_tcp_topic_receiver_t *receiver);
+void pubsub_udpTopicReceiver_destroy(pubsub_udp_topic_receiver_t *receiver);
 
-const char *pubsub_tcpTopicReceiver_scope(pubsub_tcp_topic_receiver_t *receiver);
-const char *pubsub_tcpTopicReceiver_topic(pubsub_tcp_topic_receiver_t *receiver);
-const char *pubsub_tcpTopicReceiver_serializerType(pubsub_tcp_topic_receiver_t *sender);
+const char *pubsub_udpTopicReceiver_scope(pubsub_udp_topic_receiver_t *receiver);
+const char *pubsub_udpTopicReceiver_topic(pubsub_udp_topic_receiver_t *receiver);
+const char *pubsub_udpTopicReceiver_serializerType(pubsub_udp_topic_receiver_t *sender);
 
-long pubsub_tcpTopicReceiver_protocolSvcId(pubsub_tcp_topic_receiver_t *receiver);
-void pubsub_tcpTopicReceiver_listConnections(pubsub_tcp_topic_receiver_t *receiver,
+long pubsub_udpTopicReceiver_protocolSvcId(pubsub_udp_topic_receiver_t *receiver);
+void pubsub_udpTopicReceiver_listConnections(pubsub_udp_topic_receiver_t *receiver,
                                              celix_array_list_t *connectedUrls,
                                              celix_array_list_t *unconnectedUrls);
-bool pubsub_tcpTopicReceiver_isPassive(pubsub_tcp_topic_receiver_t *sender);
+bool pubsub_udpTopicReceiver_isPassive(pubsub_udp_topic_receiver_t *receiver);
+const char *pubsub_udpTopicReceiver_url(pubsub_udp_topic_receiver_t *receiver);
+bool pubsub_udpTopicReceiver_isStatic(pubsub_udp_topic_receiver_t *receiver);
+void pubsub_udpTopicReceiver_connectTo(pubsub_udp_topic_receiver_t *receiver, const char *url);
+void pubsub_udpTopicReceiver_disconnectFrom(pubsub_udp_topic_receiver_t *receiver, const char *url);
 
-void pubsub_tcpTopicReceiver_connectTo(pubsub_tcp_topic_receiver_t *receiver, const char *url);
-void pubsub_tcpTopicReceiver_disconnectFrom(pubsub_tcp_topic_receiver_t *receiver, const char *url);
-
-#endif //CELIX_PUBSUB_TCP_TOPIC_RECEIVER_H
+#endif //CELIX_PUBSUB_UDP_TOPIC_RECEIVER_H
diff --git a/bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_topic_sender.c b/bundles/pubsub/pubsub_admin_udp/src/pubsub_udp_topic_sender.c
similarity index 62%
copy from bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_topic_sender.c
copy to bundles/pubsub/pubsub_admin_udp/src/pubsub_udp_topic_sender.c
index e318829..71efebd 100644
--- a/bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_topic_sender.c
+++ b/bundles/pubsub/pubsub_admin_udp/src/pubsub_udp_topic_sender.c
@@ -27,17 +27,17 @@
 #include <zconf.h>
 #include <arpa/inet.h>
 #include <celix_log_helper.h>
-#include "pubsub_psa_tcp_constants.h"
-#include "pubsub_tcp_topic_sender.h"
-#include "pubsub_tcp_handler.h"
-#include "pubsub_tcp_common.h"
+#include "pubsub_psa_udp_constants.h"
+#include "pubsub_udp_topic_sender.h"
+#include "pubsub_skt_handler.h"
 #include <uuid/uuid.h>
 #include "celix_constants.h"
 #include <pubsub_utils.h>
 #include "pubsub_interceptors_handler.h"
-#include "pubsub_tcp_admin.h"
 
-#define TCP_BIND_MAX_RETRY                      10
+#define UDP_BIND_MAX_RETRY                      10
+// Max message size is 64k - 8byte UDP header - 20byte IP header
+#define UDP_MAX_MSG_SIZE (((64 * 1024) - 1) - 28)
 
 #define L_DEBUG(...) \
     celix_logHelper_log(sender->logHelper, CELIX_LOG_LEVEL_DEBUG, __VA_ARGS__)
@@ -48,14 +48,14 @@
 #define L_ERROR(...) \
     celix_logHelper_log(sender->logHelper, CELIX_LOG_LEVEL_ERROR, __VA_ARGS__)
 
-struct pubsub_tcp_topic_sender {
+struct pubsub_udp_topic_sender {
     celix_bundle_context_t *ctx;
     celix_log_helper_t *logHelper;
     long protocolSvcId;
     pubsub_protocol_service_t *protocol;
     uuid_t fwUUID;
-    pubsub_tcpHandler_t *socketHandler;
-    pubsub_tcpHandler_t *sharedSocketHandler;
+    pubsub_sktHandler_t *socketHandler;
+    pubsub_sktHandler_t *sharedSocketHandler;
     pubsub_interceptors_handler_t *interceptorsHandler;
     pubsub_serializer_handler_t* serializerHandler;
 
@@ -76,31 +76,31 @@ struct pubsub_tcp_topic_sender {
 
     struct {
         celix_thread_mutex_t mutex;
-        hash_map_t *map;  //key = bndId, value = psa_tcp_bounded_service_entry_t
+        hash_map_t *map;  //key = bndId, value = psa_udp_bounded_service_entry_t
     } boundedServices;
 };
 
-typedef struct psa_tcp_bounded_service_entry {
-    pubsub_tcp_topic_sender_t *parent;
+typedef struct psa_udp_bounded_service_entry {
+    pubsub_udp_topic_sender_t *parent;
     pubsub_publisher_t service;
     long bndId;
     int getCount;
-} psa_tcp_bounded_service_entry_t;
+} psa_udp_bounded_service_entry_t;
 
-static int psa_tcp_localMsgTypeIdForMsgType(void *handle, const char *msgType, unsigned int *msgTypeId);
+static int psa_udp_localMsgTypeIdForMsgType(void *handle, const char *msgType, unsigned int *msgTypeId);
 
-static void *psa_tcp_getPublisherService(void *handle, const celix_bundle_t *requestingBundle,
+static void *psa_udp_getPublisherService(void *handle, const celix_bundle_t *requestingBundle,
                                          const celix_properties_t *svcProperties);
 
-static void psa_tcp_ungetPublisherService(void *handle, const celix_bundle_t *requestingBundle,
+static void psa_udp_ungetPublisherService(void *handle, const celix_bundle_t *requestingBundle,
                                           const celix_properties_t *svcProperties);
 
-static void delay_first_send_for_late_joiners(pubsub_tcp_topic_sender_t *sender);
+static void delay_first_send_for_late_joiners(pubsub_udp_topic_sender_t *sender);
 
 static int
-psa_tcp_topicPublicationSend(void *handle, unsigned int msgTypeId, const void *msg, celix_properties_t *metadata);
+psa_udp_topicPublicationSend(void *handle, unsigned int msgTypeId, const void *msg, celix_properties_t *metadata);
 
-pubsub_tcp_topic_sender_t *pubsub_tcpTopicSender_create(
+pubsub_udp_topic_sender_t *pubsub_udpTopicSender_create(
     celix_bundle_context_t *ctx,
     celix_log_helper_t *logHelper,
     const char *scope,
@@ -108,10 +108,10 @@ pubsub_tcp_topic_sender_t *pubsub_tcpTopicSender_create(
     pubsub_serializer_handler_t* serializerHandler,
     void *admin,
     const celix_properties_t *topicProperties,
-    pubsub_tcp_endPointStore_t *handlerStore,
+    pubsub_sktHandler_endPointStore_t *handlerStore,
     long protocolSvcId,
     pubsub_protocol_service_t *protocol) {
-    pubsub_tcp_topic_sender_t *sender = calloc(1, sizeof(*sender));
+    pubsub_udp_topic_sender_t *sender = calloc(1, sizeof(*sender));
     sender->ctx = ctx;
     sender->logHelper = logHelper;
     sender->serializerHandler = serializerHandler;
@@ -122,36 +122,40 @@ pubsub_tcp_topic_sender_t *pubsub_tcpTopicSender_create(
     if (uuid != NULL) {
         uuid_parse(uuid, sender->fwUUID);
     }
-    sender->interceptorsHandler = pubsubInterceptorsHandler_create(ctx, scope, topic, PUBSUB_TCP_ADMIN_TYPE,
+    sender->interceptorsHandler = pubsubInterceptorsHandler_create(ctx, scope, topic, PUBSUB_UDP_ADMIN_TYPE,
                                                                    pubsub_serializerHandler_getSerializationType(serializerHandler));
     sender->isPassive = false;
     char *urls = NULL;
-    const char *ip = celix_bundleContext_getProperty(ctx, PUBSUB_TCP_PSA_IP_KEY, NULL);
-    const char *discUrl = pubsub_getEnvironmentVariableWithScopeTopic(ctx, PUBSUB_TCP_STATIC_BIND_URL_FOR, topic, scope);
-    const char *isPassive = pubsub_getEnvironmentVariableWithScopeTopic(ctx, PUBSUB_TCP_PASSIVE_ENABLED, topic, scope);
-    const char *passiveKey = pubsub_getEnvironmentVariableWithScopeTopic(ctx, PUBSUB_TCP_PASSIVE_SELECTION_KEY, topic, scope);
+    const char *ip = celix_bundleContext_getProperty(ctx, PUBSUB_UDP_PSA_IP_KEY, NULL);
+    const char *discUrl = pubsub_getEnvironmentVariableWithScopeTopic(ctx, PUBSUB_UDP_STATIC_BIND_URL_FOR, topic, scope);
+    const char *isPassive = pubsub_getEnvironmentVariableWithScopeTopic(ctx, PUBSUB_UDP_PASSIVE_ENABLED, topic, scope);
+    const char *passiveKey = pubsub_getEnvironmentVariableWithScopeTopic(ctx, PUBSUB_UDP_PASSIVE_SELECTION_KEY, topic, scope);
+    const char *staticConnectUrls = pubsub_getEnvironmentVariableWithScopeTopic(ctx, PUBSUB_UDP_STATIC_CONNECT_URLS_FOR, topic, scope);
 
     if (isPassive) {
-        sender->isPassive = psa_tcp_isPassive(isPassive);
+        sender->isPassive = pubsub_sktHandler_isPassive(isPassive);
     }
     if (topicProperties != NULL) {
         if (discUrl == NULL) {
-            discUrl = celix_properties_get(topicProperties, PUBSUB_TCP_STATIC_DISCOVER_URL, NULL);
+            discUrl = celix_properties_get(topicProperties, PUBSUB_UDP_STATIC_DISCOVER_URL, NULL);
         }
         if (isPassive == NULL) {
-            sender->isPassive = celix_properties_getAsBool(topicProperties, PUBSUB_TCP_PASSIVE_CONFIGURED, false);
+            sender->isPassive = celix_properties_getAsBool(topicProperties, PUBSUB_UDP_PASSIVE_CONFIGURED, false);
         }
         if (passiveKey == NULL) {
-            passiveKey = celix_properties_get(topicProperties, PUBSUB_TCP_PASSIVE_KEY, NULL);
+            passiveKey = celix_properties_get(topicProperties, PUBSUB_UDP_PASSIVE_KEY, NULL);
+        }
+        if(staticConnectUrls == NULL) {
+            staticConnectUrls = celix_properties_get(topicProperties, PUBSUB_UDP_STATIC_CONNECT_URLS, NULL);
         }
     }
     /* When it's an endpoint share the socket with the receiver */
     if (passiveKey != NULL) {
         celixThreadMutex_lock(&handlerStore->mutex);
-        pubsub_tcpHandler_t *entry = hashMap_get(handlerStore->map, passiveKey);
+        pubsub_sktHandler_t *entry = hashMap_get(handlerStore->map, passiveKey);
         if (entry == NULL) {
             if (sender->socketHandler == NULL)
-                sender->socketHandler = pubsub_tcpHandler_create(sender->protocol, sender->logHelper);
+                sender->socketHandler = pubsub_sktHandler_create(sender->protocol, sender->logHelper);
             entry = sender->socketHandler;
             sender->sharedSocketHandler = sender->socketHandler;
             hashMap_put(handlerStore->map, (void *) passiveKey, entry);
@@ -161,66 +165,91 @@ pubsub_tcp_topic_sender_t *pubsub_tcpTopicSender_create(
         }
         celixThreadMutex_unlock(&handlerStore->mutex);
     } else {
-        sender->socketHandler = pubsub_tcpHandler_create(sender->protocol, sender->logHelper);
+        sender->socketHandler = pubsub_sktHandler_create(sender->protocol, sender->logHelper);
     }
 
     if ((sender->socketHandler != NULL) && (topicProperties != NULL)) {
-        long prio = celix_properties_getAsLong(topicProperties, PUBSUB_TCP_THREAD_REALTIME_PRIO, -1L);
-        const char *sched = celix_properties_get(topicProperties, PUBSUB_TCP_THREAD_REALTIME_SCHED, NULL);
-        long retryCnt = celix_properties_getAsLong(topicProperties, PUBSUB_TCP_PUBLISHER_RETRY_CNT_KEY, PUBSUB_TCP_PUBLISHER_RETRY_CNT_DEFAULT);
-        double sendTimeout = celix_properties_getAsDouble(topicProperties, PUBSUB_TCP_PUBLISHER_SNDTIMEO_KEY, PUBSUB_TCP_PUBLISHER_SNDTIMEO_DEFAULT);
-        long maxMsgSize = celix_properties_getAsLong(topicProperties, PSA_TCP_MAX_MESSAGE_SIZE, PSA_TCP_DEFAULT_MAX_MESSAGE_SIZE);
-        long timeout = celix_bundleContext_getPropertyAsLong(ctx, PSA_TCP_TIMEOUT, PSA_TCP_DEFAULT_TIMEOUT);
+        long prio = celix_properties_getAsLong(topicProperties, PUBSUB_UDP_THREAD_REALTIME_PRIO, -1L);
+        const char *sched = celix_properties_get(topicProperties, PUBSUB_UDP_THREAD_REALTIME_SCHED, NULL);
+        long retryCnt = celix_properties_getAsLong(topicProperties, PUBSUB_UDP_PUBLISHER_RETRY_CNT_KEY, PUBSUB_UDP_PUBLISHER_RETRY_CNT_DEFAULT);
+        double sendTimeout = celix_properties_getAsDouble(topicProperties, PUBSUB_UDP_PUBLISHER_SNDTIMEO_KEY, PUBSUB_UDP_PUBLISHER_SNDTIMEO_DEFAULT);
+        long maxMsgSize = celix_properties_getAsLong(topicProperties, PSA_UDP_MAX_MESSAGE_SIZE, PSA_UDP_DEFAULT_MAX_MESSAGE_SIZE);
+        long timeout = celix_bundleContext_getPropertyAsLong(ctx, PSA_UDP_TIMEOUT, PSA_UDP_DEFAULT_TIMEOUT);
         sender->send_delay = celix_bundleContext_getPropertyAsLong(ctx,  PUBSUB_UTILS_PSA_SEND_DELAY, PUBSUB_UTILS_PSA_DEFAULT_SEND_DELAY);
-        pubsub_tcpHandler_setThreadName(sender->socketHandler, topic, scope);
-        pubsub_tcpHandler_setThreadPriority(sender->socketHandler, prio, sched);
-        pubsub_tcpHandler_setSendRetryCnt(sender->socketHandler, (unsigned int) retryCnt);
-        pubsub_tcpHandler_setSendTimeOut(sender->socketHandler, sendTimeout);
-        pubsub_tcpHandler_setMaxMsgSize(sender->socketHandler, (unsigned int) maxMsgSize);
+        maxMsgSize = MIN(UDP_MAX_MSG_SIZE, maxMsgSize);
+        pubsub_sktHandler_setThreadName(sender->socketHandler, topic, scope);
+        pubsub_sktHandler_setThreadPriority(sender->socketHandler, prio, sched);
+        pubsub_sktHandler_setSendRetryCnt(sender->socketHandler, (unsigned int) retryCnt);
+        pubsub_sktHandler_setSendTimeOut(sender->socketHandler, sendTimeout);
+        pubsub_sktHandler_setMaxMsgSize(sender->socketHandler, (unsigned int) maxMsgSize);
         // When passiveKey is specified, enable receive event for full-duplex connection using key.
         // Because the topic receiver is already started, enable the receive event.
-        pubsub_tcpHandler_enableReceiveEvent(sender->socketHandler, (passiveKey) ? true : false);
-        pubsub_tcpHandler_setTimeout(sender->socketHandler, (unsigned int) timeout);
+        pubsub_sktHandler_enableReceiveEvent(sender->socketHandler, (passiveKey) ? true : false);
+        pubsub_sktHandler_setTimeout(sender->socketHandler, (unsigned int) timeout);
     }
 
     if (!sender->isPassive) {
-        //setting up tcp socket for TCP TopicSender
+        //setting up tcp socket for UDP TopicSender
         if (discUrl != NULL) {
-            urls = strndup(discUrl, 1024 * 1024);
+            urls = celix_utils_strdup(discUrl);
             sender->isStatic = true;
         } else if (ip != NULL) {
-            urls = strndup(ip, 1024 * 1024);
+            urls = celix_utils_strdup(ip);
         } else {
             struct sockaddr_in *sin = pubsub_utils_url_getInAddr(NULL, 0);
             urls = pubsub_utils_url_get_url(sin, NULL);
             free(sin);
         }
-        if (!sender->url) {
-            char *urlsCopy = strndup(urls, 1024 * 1024);
+        if (!sender->url && urls) {
+            char *urlsCopy = celix_utils_strdup(urls);
             char *url;
             char *save = urlsCopy;
             while ((url = strtok_r(save, " ", &save))) {
                 int retry = 0;
-                while (url && retry < TCP_BIND_MAX_RETRY) {
-                    pubsub_utils_url_t *urlInfo = pubsub_utils_url_parse(url);
-                    int rc = pubsub_tcpHandler_listen(sender->socketHandler, urlInfo->url);
+                pubsub_utils_url_t *urlInfo = pubsub_utils_url_parse(url);
+                bool is_multicast = pubsub_utils_url_is_multicast(urlInfo->hostname);
+                bool is_broadcast = pubsub_utils_url_is_broadcast(urlInfo->hostname);
+                pubsub_utils_url_free(urlInfo);
+                while ((is_multicast || is_broadcast) && url && retry < UDP_BIND_MAX_RETRY) {
+                    int rc = pubsub_sktHandler_udp_bind(sender->socketHandler, url);
                     if (rc < 0) {
-                        L_WARN("Error for tcp_bind using dynamic bind url '%s'. %s", urlInfo->url, strerror(errno));
+                        L_WARN("Error for udp bind using dynamic bind url '%s'. %s", url, strerror(errno));
                     } else {
                         url = NULL;
                     }
-                    pubsub_utils_url_free(urlInfo);
                     retry++;
                 }
             }
             free(urlsCopy);
-            sender->url = pubsub_tcpHandler_get_interface_url(sender->socketHandler);
+            sender->url = pubsub_sktHandler_get_interface_url(sender->socketHandler);
         }
         free(urls);
+        if (staticConnectUrls){
+            char *urlsCopy = celix_utils_strdup(staticConnectUrls);
+            char *url;
+            char *save = urlsCopy;
+            while ((url = strtok_r(save, " ", &save))) {
+                if (url) {
+                    int rc = 0;
+                    pubsub_utils_url_t *urlInfo = pubsub_utils_url_parse(url);
+                    bool is_multicast = pubsub_utils_url_is_multicast(urlInfo->hostname);
+                    bool is_broadcast = pubsub_utils_url_is_broadcast(urlInfo->hostname);
+                    if (!is_multicast && !is_broadcast) {
+                        L_INFO("Udp static connect '%s'", url);
+                        rc = pubsub_sktHandler_udp_connect(sender->socketHandler, url);
+                    }
+                    if (rc < 0) {
+                        L_WARN("Error for udp static connect '%s'. %s", url, strerror(errno));
+                    }
+                    pubsub_utils_url_free(urlInfo);
+                }
+            }
+            free(urlsCopy);
+        }
     }
 
     //register publisher services using a service factory
-    if ((sender->url != NULL) ||  (sender->isPassive)) {
+    {
         sender->scope = scope == NULL ? NULL : strndup(scope, 1024 * 1024);
         sender->topic = strndup(topic, 1024 * 1024);
 
@@ -228,8 +257,8 @@ pubsub_tcp_topic_sender_t *pubsub_tcpTopicSender_create(
         sender->boundedServices.map = hashMap_create(NULL, NULL, NULL, NULL);
 
         sender->publisher.factory.handle = sender;
-        sender->publisher.factory.getService = psa_tcp_getPublisherService;
-        sender->publisher.factory.ungetService = psa_tcp_ungetPublisherService;
+        sender->publisher.factory.getService = psa_udp_getPublisherService;
+        sender->publisher.factory.ungetService = psa_udp_ungetPublisherService;
 
         celix_properties_t *props = celix_properties_create();
         celix_properties_set(props, PUBSUB_PUBLISHER_TOPIC, sender->topic);
@@ -244,15 +273,11 @@ pubsub_tcp_topic_sender_t *pubsub_tcpTopicSender_create(
         opts.properties = props;
 
         sender->publisher.svcId = celix_bundleContext_registerServiceWithOptions(ctx, &opts);
-    } else {
-        free(sender);
-        sender = NULL;
     }
-
     return sender;
 }
 
-void pubsub_tcpTopicSender_destroy(pubsub_tcp_topic_sender_t *sender) {
+void pubsub_udpTopicSender_destroy(pubsub_udp_topic_sender_t *sender) {
     if (sender != NULL) {
 
         celix_bundleContext_unregisterService(sender->ctx, sender->publisher.svcId);
@@ -260,7 +285,7 @@ void pubsub_tcpTopicSender_destroy(pubsub_tcp_topic_sender_t *sender) {
         celixThreadMutex_lock(&sender->boundedServices.mutex);
         hash_map_iterator_t iter = hashMapIterator_construct(sender->boundedServices.map);
         while (hashMapIterator_hasNext(&iter)) {
-            psa_tcp_bounded_service_entry_t *entry = hashMapIterator_nextValue(&iter);
+            psa_udp_bounded_service_entry_t *entry = hashMapIterator_nextValue(&iter);
             free(entry);
         }
         hashMap_destroy(sender->boundedServices.map, false, false);
@@ -269,7 +294,7 @@ void pubsub_tcpTopicSender_destroy(pubsub_tcp_topic_sender_t *sender) {
 
         pubsubInterceptorsHandler_destroy(sender->interceptorsHandler);
         if ((sender->socketHandler) && (sender->sharedSocketHandler == NULL)) {
-            pubsub_tcpHandler_destroy(sender->socketHandler);
+            pubsub_sktHandler_destroy(sender->socketHandler);
             sender->socketHandler = NULL;
         }
 
@@ -282,44 +307,83 @@ void pubsub_tcpTopicSender_destroy(pubsub_tcp_topic_sender_t *sender) {
     }
 }
 
-long pubsub_tcpTopicSender_protocolSvcId(pubsub_tcp_topic_sender_t *sender) {
+long pubsub_udpTopicSender_protocolSvcId(pubsub_udp_topic_sender_t *sender) {
     return sender->protocolSvcId;
 }
 
-const char *pubsub_tcpTopicSender_scope(pubsub_tcp_topic_sender_t *sender) {
+const char *pubsub_udpTopicSender_scope(pubsub_udp_topic_sender_t *sender) {
     return sender->scope;
 }
 
-const char *pubsub_tcpTopicSender_topic(pubsub_tcp_topic_sender_t *sender) {
+const char *pubsub_udpTopicSender_topic(pubsub_udp_topic_sender_t *sender) {
     return sender->topic;
 }
 
-const char* pubsub_tcpTopicSender_serializerType(pubsub_tcp_topic_sender_t *sender) {
+const char* pubsub_udpTopicSender_serializerType(pubsub_udp_topic_sender_t *sender) {
     return pubsub_serializerHandler_getSerializationType(sender->serializerHandler);
 }
 
-const char *pubsub_tcpTopicSender_url(pubsub_tcp_topic_sender_t *sender) {
+const char *pubsub_udpTopicSender_url(pubsub_udp_topic_sender_t *sender) {
     if (sender->isPassive) {
-        return pubsub_tcpHandler_get_connection_url(sender->socketHandler);
+        return pubsub_sktHandler_get_connection_url(sender->socketHandler);
     } else {
         return sender->url;
     }
 }
-bool pubsub_tcpTopicSender_isStatic(pubsub_tcp_topic_sender_t *sender) {
+
+void pubsub_udpTopicSender_listConnections(pubsub_udp_topic_sender_t *sender, celix_array_list_t *urls) {
+    pubsub_sktHandler_get_connection_urls(sender->socketHandler, urls);
+}
+
+bool pubsub_udpTopicSender_isStatic(pubsub_udp_topic_sender_t *sender) {
     return sender->isStatic;
 }
 
-bool pubsub_tcpTopicSender_isPassive(pubsub_tcp_topic_sender_t *sender) {
+bool pubsub_udpTopicSender_isPassive(pubsub_udp_topic_sender_t *sender) {
     return sender->isPassive;
 }
 
-static void *psa_tcp_getPublisherService(void *handle, const celix_bundle_t *requestingBundle,
+void pubsub_udpTopicSender_connectTo(pubsub_udp_topic_sender_t *sender, const char *url) {
+    if (!url) return;
+    char *connectUrl =  celix_utils_strdup(url);
+    pubsub_utils_url_t *urlInfo = pubsub_utils_url_parse(connectUrl);
+    bool is_multicast = pubsub_utils_url_is_multicast(urlInfo->hostname);
+    bool is_broadcast = pubsub_utils_url_is_broadcast(urlInfo->hostname);
+    pubsub_utils_url_free(urlInfo);
+
+    if (!is_multicast && !is_broadcast) {
+        L_DEBUG("[PSA_udp] TopicSender %s/%s connecting to udp url %s",
+                sender->scope == NULL ? "(null)" : sender->scope,
+                sender->topic,
+                url);
+        pubsub_sktHandler_udp_connect(sender->socketHandler, connectUrl);
+    }
+    free(connectUrl);
+}
+
+void pubsub_udpTopicSender_disconnectFrom(pubsub_udp_topic_sender_t *sender, const char *url) {
+    if (!url) return;
+    char *connectUrl =  celix_utils_strdup(url);
+    pubsub_utils_url_t *urlInfo = pubsub_utils_url_parse(connectUrl);
+    bool is_multicast = pubsub_utils_url_is_multicast(urlInfo->hostname);
+    bool is_broadcast = pubsub_utils_url_is_broadcast(urlInfo->hostname);
+    pubsub_utils_url_free(urlInfo);
+    if (!is_multicast && !is_broadcast) {
+        L_DEBUG("[PSA udp] TopicSender %s/%s disconnect from udp url %s",
+                sender->scope == NULL ? "(null)" : sender->scope,
+                sender->topic,
+                url);
+        pubsub_sktHandler_disconnect(sender->socketHandler, connectUrl);
+    }
+}
+
+static void *psa_udp_getPublisherService(void *handle, const celix_bundle_t *requestingBundle,
                                          const celix_properties_t *svcProperties __attribute__((unused))) {
-    pubsub_tcp_topic_sender_t *sender = handle;
+    pubsub_udp_topic_sender_t *sender = handle;
     long bndId = celix_bundle_getId(requestingBundle);
 
     celixThreadMutex_lock(&sender->boundedServices.mutex);
-    psa_tcp_bounded_service_entry_t *entry = hashMap_get(sender->boundedServices.map, (void *) bndId);
+    psa_udp_bounded_service_entry_t *entry = hashMap_get(sender->boundedServices.map, (void *) bndId);
     if (entry != NULL) {
         entry->getCount += 1;
     } else {
@@ -328,8 +392,8 @@ static void *psa_tcp_getPublisherService(void *handle, const celix_bundle_t *req
         entry->parent = sender;
         entry->bndId = bndId;
         entry->service.handle = entry;
-        entry->service.localMsgTypeIdForMsgType = psa_tcp_localMsgTypeIdForMsgType;
-        entry->service.send = psa_tcp_topicPublicationSend;
+        entry->service.localMsgTypeIdForMsgType = psa_udp_localMsgTypeIdForMsgType;
+        entry->service.send = psa_udp_topicPublicationSend;
         hashMap_put(sender->boundedServices.map, (void *) bndId, entry);
     }
     celixThreadMutex_unlock(&sender->boundedServices.mutex);
@@ -337,13 +401,13 @@ static void *psa_tcp_getPublisherService(void *handle, const celix_bundle_t *req
     return &entry->service;
 }
 
-static void psa_tcp_ungetPublisherService(void *handle, const celix_bundle_t *requestingBundle,
+static void psa_udp_ungetPublisherService(void *handle, const celix_bundle_t *requestingBundle,
                                           const celix_properties_t *svcProperties __attribute__((unused))) {
-    pubsub_tcp_topic_sender_t *sender = handle;
+    pubsub_udp_topic_sender_t *sender = handle;
     long bndId = celix_bundle_getId(requestingBundle);
 
     celixThreadMutex_lock(&sender->boundedServices.mutex);
-    psa_tcp_bounded_service_entry_t *entry = hashMap_get(sender->boundedServices.map, (void *) bndId);
+    psa_udp_bounded_service_entry_t *entry = hashMap_get(sender->boundedServices.map, (void *) bndId);
     if (entry != NULL) {
         entry->getCount -= 1;
     }
@@ -357,9 +421,9 @@ static void psa_tcp_ungetPublisherService(void *handle, const celix_bundle_t *re
 }
 
 static int
-psa_tcp_topicPublicationSend(void *handle, unsigned int msgTypeId, const void *inMsg, celix_properties_t *metadata) {
-    psa_tcp_bounded_service_entry_t *bound = handle;
-    pubsub_tcp_topic_sender_t *sender = bound->parent;
+psa_udp_topicPublicationSend(void *handle, unsigned int msgTypeId, const void *inMsg, celix_properties_t *metadata) {
+    psa_udp_bounded_service_entry_t *bound = handle;
+    pubsub_udp_topic_sender_t *sender = bound->parent;
     const char* msgFqn;
     int majorVersion;
     int minorVersion;
@@ -382,7 +446,7 @@ psa_tcp_topicPublicationSend(void *handle, unsigned int msgTypeId, const void *i
     struct iovec *serializedIoVecOutput = NULL;
     status = pubsub_serializerHandler_serialize(sender->serializerHandler, msgTypeId, inMsg, &serializedIoVecOutput, &serializedIoVecOutputLen);
     if (status != CELIX_SUCCESS) {
-        L_WARN("[PSA_TCP_V2_TS] Error serialize message of type %s for scope/topic %s/%s", msgFqn,
+        L_WARN("[PSA_UDP_V2_TS] Error serialize message of type %s for scope/topic %s/%s", msgFqn,
                sender->scope == NULL ? "(null)" : sender->scope, sender->topic);
         celix_properties_destroy(metadata);
         return status;
@@ -411,7 +475,7 @@ psa_tcp_topicPublicationSend(void *handle, unsigned int msgTypeId, const void *i
     }
     bool sendOk = true;
     {
-        int rc = pubsub_tcpHandler_write(sender->socketHandler, &message, serializedIoVecOutput, serializedIoVecOutputLen, 0);
+        int rc = pubsub_sktHandler_write(sender->socketHandler, &message, serializedIoVecOutput, serializedIoVecOutputLen, 0);
         if (rc < 0) {
             status = -1;
             sendOk = false;
@@ -424,28 +488,28 @@ psa_tcp_topicPublicationSend(void *handle, unsigned int msgTypeId, const void *i
     }
 
     if (!sendOk) {
-        L_WARN("[PSA_TCP_V2_TS] Error sending msg. %s", strerror(errno));
+        L_WARN("[PSA_UDP_V2_TS] Error sending msg. %s", strerror(errno));
     }
 
     celix_properties_destroy(metadata);
     return status;
 }
 
-static void delay_first_send_for_late_joiners(pubsub_tcp_topic_sender_t *sender) {
+static void delay_first_send_for_late_joiners(pubsub_udp_topic_sender_t *sender) {
 
     static bool firstSend = true;
 
     if (firstSend) {
         if (sender->send_delay ) {
-            L_INFO("PSA_TCP_TP: Delaying first send for late joiners...\n");
+            L_INFO("PSA_UDP_TP: Delaying first send for late joiners...\n");
         }
         usleep(sender->send_delay * 1000);
         firstSend = false;
     }
 }
 
-static int psa_tcp_localMsgTypeIdForMsgType(void *handle, const char *msgType, unsigned int *msgTypeId) {
-    psa_tcp_bounded_service_entry_t* entry = handle;
+static int psa_udp_localMsgTypeIdForMsgType(void *handle, const char *msgType, unsigned int *msgTypeId) {
+    psa_udp_bounded_service_entry_t* entry = handle;
     uint32_t msgId = pubsub_serializerHandler_getMsgId(entry->parent->serializerHandler, msgType);
     *msgTypeId = (unsigned int)msgId;
     return 0;
diff --git a/bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_topic_sender.h b/bundles/pubsub/pubsub_admin_udp/src/pubsub_udp_topic_sender.h
similarity index 54%
copy from bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_topic_sender.h
copy to bundles/pubsub/pubsub_admin_udp/src/pubsub_udp_topic_sender.h
index 57b13a6..8b142e1 100644
--- a/bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_topic_sender.h
+++ b/bundles/pubsub/pubsub_admin_udp/src/pubsub_udp_topic_sender.h
@@ -17,18 +17,18 @@
  * under the License.
  */
 
-#ifndef CELIX_PUBSUB_TCP_TOPIC_SENDER_H
-#define CELIX_PUBSUB_TCP_TOPIC_SENDER_H
+#ifndef CELIX_PUBSUB_UDP_TOPIC_SENDER_H
+#define CELIX_PUBSUB_UDP_TOPIC_SENDER_H
 
 #include "celix_bundle_context.h"
 #include "pubsub_admin_metrics.h"
 #include "pubsub_protocol.h"
-#include "pubsub_tcp_common.h"
+#include "pubsub_skt_handler.h"
 #include "pubsub_serializer_handler.h"
 
-typedef struct pubsub_tcp_topic_sender pubsub_tcp_topic_sender_t;
+typedef struct pubsub_udp_topic_sender pubsub_udp_topic_sender_t;
 
-pubsub_tcp_topic_sender_t *pubsub_tcpTopicSender_create(
+pubsub_udp_topic_sender_t *pubsub_udpTopicSender_create(
     celix_bundle_context_t *ctx,
     celix_log_helper_t *logHelper,
     const char *scope,
@@ -36,17 +36,20 @@ pubsub_tcp_topic_sender_t *pubsub_tcpTopicSender_create(
     pubsub_serializer_handler_t* serializerHandler,
     void *admin,
     const celix_properties_t *topicProperties,
-    pubsub_tcp_endPointStore_t *handlerStore,
+    pubsub_sktHandler_endPointStore_t *handlerStore,
     long protocolSvcId,
     pubsub_protocol_service_t *prot);
 
-void pubsub_tcpTopicSender_destroy(pubsub_tcp_topic_sender_t *sender);
-const char *pubsub_tcpTopicSender_scope(pubsub_tcp_topic_sender_t *sender);
-const char *pubsub_tcpTopicSender_topic(pubsub_tcp_topic_sender_t *sender);
-const char *pubsub_tcpTopicSender_url(pubsub_tcp_topic_sender_t *sender);
-const char* pubsub_tcpTopicSender_serializerType(pubsub_tcp_topic_sender_t *sender);
-bool pubsub_tcpTopicSender_isStatic(pubsub_tcp_topic_sender_t *sender);
-bool pubsub_tcpTopicSender_isPassive(pubsub_tcp_topic_sender_t *sender);
-long pubsub_tcpTopicSender_protocolSvcId(pubsub_tcp_topic_sender_t *sender);
+void pubsub_udpTopicSender_destroy(pubsub_udp_topic_sender_t *sender);
+const char *pubsub_udpTopicSender_scope(pubsub_udp_topic_sender_t *sender);
+const char *pubsub_udpTopicSender_topic(pubsub_udp_topic_sender_t *sender);
+const char *pubsub_udpTopicSender_url(pubsub_udp_topic_sender_t *sender);
+const char* pubsub_udpTopicSender_serializerType(pubsub_udp_topic_sender_t *sender);
+bool pubsub_udpTopicSender_isStatic(pubsub_udp_topic_sender_t *sender);
+bool pubsub_udpTopicSender_isPassive(pubsub_udp_topic_sender_t *sender);
+long pubsub_udpTopicSender_protocolSvcId(pubsub_udp_topic_sender_t *sender);
+void pubsub_udpTopicSender_connectTo(pubsub_udp_topic_sender_t *receiver, const char *url);
+void pubsub_udpTopicSender_disconnectFrom(pubsub_udp_topic_sender_t *receiver, const char *url);
+void pubsub_udpTopicSender_listConnections(pubsub_udp_topic_sender_t *sender, celix_array_list_t *urls);
 
-#endif //CELIX_PUBSUB_TCP_TOPIC_SENDER_H
+#endif //CELIX_PUBSUB_udp_TOPIC_SENDER_H
diff --git a/bundles/pubsub/pubsub_utils/CMakeLists.txt b/bundles/pubsub/pubsub_utils/CMakeLists.txt
index 0c285aa..967cc52 100644
--- a/bundles/pubsub/pubsub_utils/CMakeLists.txt
+++ b/bundles/pubsub/pubsub_utils/CMakeLists.txt
@@ -19,6 +19,7 @@ add_library(pubsub_utils STATIC
         src/pubsub_utils.c
         src/pubsub_utils_url.c
         src/pubsub_serializer_handler.c
+        src/pubsub_skt_handler.c
         src/pubsub_serialization_provider.c
         src/pubsub_matching.c
 )
diff --git a/bundles/pubsub/pubsub_utils/include/pubsub_skt_handler.h b/bundles/pubsub/pubsub_utils/include/pubsub_skt_handler.h
new file mode 100644
index 0000000..bfd52ca
--- /dev/null
+++ b/bundles/pubsub/pubsub_utils/include/pubsub_skt_handler.h
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ */
+/*
+ * pubsub_skt_handler.h
+ *
+ *  \date       July 18, 2016
+ *  \author     <a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright  Apache License, Version 2.0
+ */
+
+#ifndef _PUBSUB_SKT_BUFFER_HANDLER_H_
+#define _PUBSUB_SKT_BUFFER_HANDLER_H_
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <celix_log_helper.h>
+#include "celix_threads.h"
+#include "pubsub_utils_url.h"
+#include <pubsub_protocol.h>
+
+#ifndef MIN
+#define MIN(a, b) ((a<b) ? (a) : (b))
+#endif
+
+#ifndef MAX
+#define MAX(a, b) ((a>b) ? (a) : (b))
+#endif
+
+typedef struct  pubsub_sktHandler_endPointStore {
+  celix_thread_mutex_t mutex;
+  hash_map_t *map;
+}  pubsub_sktHandler_endPointStore_t;
+
+typedef struct pubsub_sktHandler pubsub_sktHandler_t;
+typedef void(*pubsub_sktHandler_processMessage_callback_t)
+    (void *payload, const pubsub_protocol_message_t *header, bool *release, struct timespec *receiveTime);
+typedef void (*pubsub_sktHandler_receiverConnectMessage_callback_t)(void *payload, const char *url, bool lock);
+typedef void (*pubsub_sktHandler_acceptConnectMessage_callback_t)(void *payload, const char *url);
+
+pubsub_sktHandler_t *pubsub_sktHandler_create(pubsub_protocol_service_t *protocol, celix_log_helper_t *logHelper);
+void pubsub_sktHandler_destroy(pubsub_sktHandler_t *handle);
+int pubsub_sktHandler_open(pubsub_sktHandler_t *handle, int socket_type, char *url);
+int pubsub_sktHandler_bind(pubsub_sktHandler_t *handle, int fd,char *url, unsigned int port_nr);
+int pubsub_sktHandler_close(pubsub_sktHandler_t *handle, int fd);
+int pubsub_sktHandler_tcp_connect(pubsub_sktHandler_t *handle, char *url);
+int pubsub_sktHandler_disconnect(pubsub_sktHandler_t *handle, char *url);
+int pubsub_sktHandler_udp_connect(pubsub_sktHandler_t *handle, char *url);
+int pubsub_sktHandler_udp_bind(pubsub_sktHandler_t *handle, char *url);
+int pubsub_sktHandler_udp_listen(pubsub_sktHandler_t *handle, char *url);
+int pubsub_sktHandler_tcp_listen(pubsub_sktHandler_t *handle, char *url);
+int pubsub_sktHandler_setReceiveBufferSize(pubsub_sktHandler_t *handle, unsigned int size);
+int pubsub_sktHandler_setMaxMsgSize(pubsub_sktHandler_t *handle, unsigned int size);
+void pubsub_sktHandler_setTimeout(pubsub_sktHandler_t *handle, unsigned int timeout);
+void pubsub_sktHandler_setSendRetryCnt(pubsub_sktHandler_t *handle, unsigned int count);
+void pubsub_sktHandler_setReceiveRetryCnt(pubsub_sktHandler_t *handle, unsigned int count);
+void pubsub_sktHandler_setSendTimeOut(pubsub_sktHandler_t *handle, double timeout);
+void pubsub_sktHandler_setReceiveTimeOut(pubsub_sktHandler_t *handle, double timeout);
+void pubsub_sktHandler_enableReceiveEvent(pubsub_sktHandler_t *handle, bool enable);
+
+int pubsub_sktHandler_read(pubsub_sktHandler_t *handle, int fd);
+int pubsub_sktHandler_write(pubsub_sktHandler_t *handle,
+                            pubsub_protocol_message_t *message,
+                            struct iovec *msg_iovec,
+                            size_t msg_iov_len,
+                            int flags);
+int pubsub_sktHandler_addMessageHandler(pubsub_sktHandler_t *handle,
+                                        void *payload,
+                                        pubsub_sktHandler_processMessage_callback_t processMessageCallback);
+int pubsub_sktHandler_addReceiverConnectionCallback(pubsub_sktHandler_t *handle,
+                                                    void *payload,
+                                                    pubsub_sktHandler_receiverConnectMessage_callback_t connectMessageCallback,
+                                                    pubsub_sktHandler_receiverConnectMessage_callback_t disconnectMessageCallback);
+int pubsub_sktHandler_addAcceptConnectionCallback(pubsub_sktHandler_t *handle,
+                                                  void *payload,
+                                                  pubsub_sktHandler_acceptConnectMessage_callback_t connectMessageCallback,
+                                                  pubsub_sktHandler_acceptConnectMessage_callback_t disconnectMessageCallback);
+char *pubsub_sktHandler_get_interface_url(pubsub_sktHandler_t *handle);
+char *pubsub_sktHandler_get_connection_url(pubsub_sktHandler_t *handle);
+void pubsub_sktHandler_get_connection_urls(pubsub_sktHandler_t *handle, celix_array_list_t *urls);
+bool pubsub_sktHandler_isPassive(const char* buffer);
+void pubsub_sktHandler_setThreadPriority(pubsub_sktHandler_t *handle, long prio, const char *sched);
+void pubsub_sktHandler_setThreadName(pubsub_sktHandler_t *handle, const char *topic, const char *scope);
+
+#endif /* _PUBSUB_SKT_BUFFER_HANDLER_H_ */
diff --git a/bundles/pubsub/pubsub_utils/include/pubsub_utils_url.h b/bundles/pubsub/pubsub_utils/include/pubsub_utils_url.h
index b10863c..efea1c8 100644
--- a/bundles/pubsub/pubsub_utils/include/pubsub_utils_url.h
+++ b/bundles/pubsub/pubsub_utils/include/pubsub_utils_url.h
@@ -40,8 +40,9 @@ struct sockaddr_in *pubsub_utils_url_getInAddr(const char *hostname, unsigned in
 char *pubsub_utils_url_generate_url(char *hostname, unsigned int port_nr, char *protocol);
 char *pubsub_utils_url_get_url(struct sockaddr_in *inp, char *protocol);
 bool pubsub_utils_url_is_multicast(char *hostname);
-char *pubsub_utils_url_get_multicast_ip(char *hostname);
-char *pubsub_utils_url_get_ip(char *hostname);
+bool pubsub_utils_url_is_broadcast(char *hostname);
+char *pubsub_utils_url_get_multicast_ip(char *hostname, in_addr_t* intf_addr);
+char *pubsub_utils_url_get_ip(char *hostname, in_addr_t* intf_addr);
 void pubsub_utils_url_parse_url(char *_url, pubsub_utils_url_t *url_info);
 pubsub_utils_url_t *pubsub_utils_url_parse(char *url);
 void pubsub_utils_url_free(pubsub_utils_url_t *url_info);
diff --git a/bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_handler.c b/bundles/pubsub/pubsub_utils/src/pubsub_skt_handler.c
similarity index 56%
rename from bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_handler.c
rename to bundles/pubsub/pubsub_utils/src/pubsub_skt_handler.c
index eb02f79..fbc96b8 100644
--- a/bundles/pubsub/pubsub_admin_tcp/src/pubsub_tcp_handler.c
+++ b/bundles/pubsub/pubsub_utils/src/pubsub_skt_handler.c
@@ -17,7 +17,7 @@
  * under the License.
  */
 /*
- * pubsub_tcp_handler.c
+ * pubsub_skt_handler.c
  *
  *  \date       July 18, 2019
  *  \author     <a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
@@ -42,9 +42,10 @@
 #include <fcntl.h>
 #include <arpa/inet.h>
 #include <netinet/tcp.h>
+//#include <netinet/udp.h>
 #include "hash_map.h"
 #include "utils.h"
-#include "pubsub_tcp_handler.h"
+#include "pubsub_skt_handler.h"
 
 #define MAX_EVENTS   64
 #define MAX_DEFAULT_BUFFER_SIZE 4u
@@ -67,11 +68,15 @@
 //
 // Entry administration
 //
-typedef struct psa_tcp_connection_entry {
+typedef struct psa_skt_connection_entry {
     char *interface_url;
     char *url;
     int fd;
+    int socket_domain;
+    int socket_type;
+    char* protocol;
     struct sockaddr_in addr;
+    struct sockaddr_in dst_addr;
     socklen_t len;
     bool connected;
     bool headerError;
@@ -96,12 +101,13 @@ typedef struct psa_tcp_connection_entry {
     unsigned int retryCount;
     celix_thread_mutex_t writeMutex;
     struct msghdr readMsg;
-} psa_tcp_connection_entry_t;
+    struct sockaddr_in readMsgAddr;
+} psa_skt_connection_entry_t;
 
 //
 // Handle administration
 //
-struct pubsub_tcpHandler {
+struct pubsub_sktHandler {
     celix_thread_rwlock_t dbLock;
     unsigned int timeout;
     hash_map_t *connection_url_map;
@@ -109,13 +115,14 @@ struct pubsub_tcpHandler {
     hash_map_t *interface_url_map;
     hash_map_t *interface_fd_map;
     int efd;
-    pubsub_tcpHandler_receiverConnectMessage_callback_t receiverConnectMessageCallback;
-    pubsub_tcpHandler_receiverConnectMessage_callback_t receiverDisconnectMessageCallback;
+    int fd;
+    pubsub_sktHandler_receiverConnectMessage_callback_t receiverConnectMessageCallback;
+    pubsub_sktHandler_receiverConnectMessage_callback_t receiverDisconnectMessageCallback;
     void *receiverConnectPayload;
-    pubsub_tcpHandler_acceptConnectMessage_callback_t acceptConnectMessageCallback;
-    pubsub_tcpHandler_acceptConnectMessage_callback_t acceptDisconnectMessageCallback;
+    pubsub_sktHandler_acceptConnectMessage_callback_t acceptConnectMessageCallback;
+    pubsub_sktHandler_acceptConnectMessage_callback_t acceptDisconnectMessageCallback;
     void *acceptConnectPayload;
-    pubsub_tcpHandler_processMessage_callback_t processMessageCallback;
+    pubsub_sktHandler_processMessage_callback_t processMessageCallback;
     void *processMessagePayload;
     celix_log_helper_t *logHelper;
     pubsub_protocol_service_t *protocol;
@@ -130,34 +137,36 @@ struct pubsub_tcpHandler {
     bool enableReceiveEvent;
 };
 
-static inline int pubsub_tcpHandler_closeConnectionEntry(pubsub_tcpHandler_t *handle, psa_tcp_connection_entry_t *entry, bool lock);
-static inline int pubsub_tcpHandler_closeInterfaceEntry(pubsub_tcpHandler_t *handle, psa_tcp_connection_entry_t *entry);
-static inline int pubsub_tcpHandler_makeNonBlocking(pubsub_tcpHandler_t *handle, int fd);
-static inline psa_tcp_connection_entry_t* pubsub_tcpHandler_createEntry(pubsub_tcpHandler_t *handle, int fd, char *url, char *interface_url, struct sockaddr_in *addr);
-static inline void pubsub_tcpHandler_freeEntry(psa_tcp_connection_entry_t *entry);
-static inline void pubsub_tcpHandler_releaseEntryBuffer(pubsub_tcpHandler_t *handle, int fd, unsigned int index);
-static inline long int pubsub_tcpHandler_getMsgSize(psa_tcp_connection_entry_t *entry);
-static inline void pubsub_tcpHandler_ensureReadBufferCapacity(pubsub_tcpHandler_t *handle, psa_tcp_connection_entry_t *entry);
-static inline bool pubsub_tcpHandler_readHeader(pubsub_tcpHandler_t *handle, int fd, psa_tcp_connection_entry_t *entry, long int* msgSize);
-static inline void pubsub_tcpHandler_decodePayload(pubsub_tcpHandler_t *handle, psa_tcp_connection_entry_t *entry);
-static inline long int pubsub_tcpHandler_readPayload(pubsub_tcpHandler_t *handle, int fd, psa_tcp_connection_entry_t *entry);
-static inline void pubsub_tcpHandler_connectionHandler(pubsub_tcpHandler_t *handle, int fd);
-static inline void pubsub_tcpHandler_handler(pubsub_tcpHandler_t *handle);
-static void *pubsub_tcpHandler_thread(void *data);
+static inline int pubsub_sktHandler_closeConnectionEntry(pubsub_sktHandler_t *handle, psa_skt_connection_entry_t *entry, bool lock);
+static inline int pubsub_sktHandler_closeInterfaceEntry(pubsub_sktHandler_t *handle, psa_skt_connection_entry_t *entry);
+static inline int pubsub_sktHandler_makeNonBlocking(pubsub_sktHandler_t *handle, int fd);
+static inline struct sockaddr_in pubsub_sktHandler_getMultiCastAddr(psa_skt_connection_entry_t *entry, struct sockaddr_in* sin, struct sockaddr_in* intf_addr );
+static inline psa_skt_connection_entry_t* pubsub_sktHandler_createEntry(pubsub_sktHandler_t *handle, int fd, char *url, char *interface_url, struct sockaddr_in *addr);
+static inline void pubsub_sktHandler_freeEntry(psa_skt_connection_entry_t *entry);
+static inline void pubsub_sktHandler_releaseEntryBuffer(pubsub_sktHandler_t *handle, int fd, unsigned int index);
+static inline long int pubsub_sktHandler_getMsgSize(psa_skt_connection_entry_t *entry);
+static inline void pubsub_sktHandler_ensureReadBufferCapacity(pubsub_sktHandler_t *handle, psa_skt_connection_entry_t *entry);
+static inline bool pubsub_sktHandler_readHeader(pubsub_sktHandler_t *handle, int fd, psa_skt_connection_entry_t *entry, long int* msgSize);
+static inline void pubsub_sktHandler_decodePayload(pubsub_sktHandler_t *handle, psa_skt_connection_entry_t *entry);
+static inline long int pubsub_sktHandler_readPayload(pubsub_sktHandler_t *handle, int fd, psa_skt_connection_entry_t *entry);
+static inline void pubsub_sktHandler_connectionHandler(pubsub_sktHandler_t *handle, int fd);
+static inline void pubsub_sktHandler_handler(pubsub_sktHandler_t *handle);
+static void *pubsub_sktHandler_thread(void *data);
 
 
 
 //
 // Create a handle
 //
-pubsub_tcpHandler_t *pubsub_tcpHandler_create(pubsub_protocol_service_t *protocol, celix_log_helper_t *logHelper) {
-    pubsub_tcpHandler_t *handle = calloc(sizeof(*handle), 1);
+pubsub_sktHandler_t *pubsub_sktHandler_create(pubsub_protocol_service_t *protocol, celix_log_helper_t *logHelper) {
+    pubsub_sktHandler_t *handle = calloc(sizeof(*handle), 1);
     if (handle != NULL) {
 #if defined(__APPLE__)
         handle->efd = kqueue();
 #else
         handle->efd = epoll_create1(0);
 #endif
+        handle->fd = -1;
         handle->connection_url_map = hashMap_create(utils_stringHash, NULL, utils_stringEquals, NULL);
         handle->connection_fd_map = hashMap_create(NULL, NULL, NULL, NULL);
         handle->interface_url_map = hashMap_create(utils_stringHash, NULL, utils_stringEquals, NULL);
@@ -168,7 +177,7 @@ pubsub_tcpHandler_t *pubsub_tcpHandler_create(pubsub_protocol_service_t *protoco
         handle->bufferSize = MAX_DEFAULT_BUFFER_SIZE;
         celixThreadRwlock_create(&handle->dbLock, 0);
         handle->running = true;
-        celixThread_create(&handle->thread, NULL, pubsub_tcpHandler_thread, handle);
+        celixThread_create(&handle->thread, NULL, pubsub_sktHandler_thread, handle);
         // signal(SIGPIPE, SIG_IGN);
     }
     return handle;
@@ -177,7 +186,7 @@ pubsub_tcpHandler_t *pubsub_tcpHandler_create(pubsub_protocol_service_t *protoco
 //
 // Destroys the handle
 //
-void pubsub_tcpHandler_destroy(pubsub_tcpHandler_t *handle) {
+void pubsub_sktHandler_destroy(pubsub_sktHandler_t *handle) {
     if (handle != NULL) {
         celixThreadRwlock_readLock(&handle->dbLock);
         bool running = handle->running;
@@ -189,19 +198,18 @@ void pubsub_tcpHandler_destroy(pubsub_tcpHandler_t *handle) {
             celixThread_join(handle->thread, NULL);
         }
         celixThreadRwlock_writeLock(&handle->dbLock);
-        hash_map_iterator_t interface_iter = hashMapIterator_construct(handle->interface_url_map);
-        while (hashMapIterator_hasNext(&interface_iter)) {
-            psa_tcp_connection_entry_t *entry = hashMapIterator_nextValue(&interface_iter);
+        hash_map_iterator_t connection_iter = hashMapIterator_construct(handle->connection_url_map);
+        while (hashMapIterator_hasNext(&connection_iter)) {
+            psa_skt_connection_entry_t *entry = hashMapIterator_nextValue(&connection_iter);
             if (entry != NULL) {
-                pubsub_tcpHandler_closeInterfaceEntry(handle, entry);
+                pubsub_sktHandler_closeConnectionEntry(handle, entry, true);
             }
         }
-
-        hash_map_iterator_t connection_iter = hashMapIterator_construct(handle->connection_url_map);
-        while (hashMapIterator_hasNext(&connection_iter)) {
-            psa_tcp_connection_entry_t *entry = hashMapIterator_nextValue(&connection_iter);
+        hash_map_iterator_t interface_iter = hashMapIterator_construct(handle->interface_url_map);
+        while (hashMapIterator_hasNext(&interface_iter)) {
+            psa_skt_connection_entry_t *entry = hashMapIterator_nextValue(&interface_iter);
             if (entry != NULL) {
-                pubsub_tcpHandler_closeConnectionEntry(handle, entry, true);
+                pubsub_sktHandler_closeInterfaceEntry(handle, entry);
             }
         }
         if (handle->efd >= 0) close(handle->efd);
@@ -215,31 +223,45 @@ void pubsub_tcpHandler_destroy(pubsub_tcpHandler_t *handle) {
     }
 }
 
+
+
 //
 // Open the socket using an url
 //
-int pubsub_tcpHandler_open(pubsub_tcpHandler_t *handle, char *url) {
+int pubsub_sktHandler_open(pubsub_sktHandler_t *handle, int socket_type, char *url) {
     int rc = 0;
     celixThreadRwlock_readLock(&handle->dbLock);
     pubsub_utils_url_t *url_info = pubsub_utils_url_parse(url);
-    int fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
-    if (rc >= 0) {
+    int socket_domain = AF_INET;
+    //int socket_type   = SOCK_STREAM(tcp); SOCK_DGRAM(udp);
+    if (url_info->protocol) {
+        // IPC is not supported !!!
+        //socket_domain = (!strcmp("ipc", url_info->protocol)) ? AF_LOCAL : AF_INET;
+        int url_socket_type = (!strcmp("udp", url_info->protocol)) ? SOCK_DGRAM : SOCK_STREAM;
+        if (url_socket_type != socket_type) {
+            L_ERROR("[SKT Socket] unexpected url socket type %s != %s \n", url, socket_type==SOCK_STREAM ? "tcp" : "udp");
+            return -1;
+        }
+    }
+   // bool useBind = (socket_type == SOCK_DGRAM) ? false : true;
+    int fd = socket(socket_domain , socket_type,  socket_type == SOCK_STREAM ? IPPROTO_TCP : IPPROTO_UDP);
+    if (fd >= 0) {
         int setting = 1;
-        if (rc == 0) {
-            rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &setting, sizeof(setting));
-            if (rc != 0) {
-                close(fd);
-                L_ERROR("[TCP Socket] Error setsockopt(SO_REUSEADDR): %s\n", strerror(errno));
-            }
+        rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &setting, sizeof(setting));
+        if (rc != 0) {
+            close(fd);
+            L_ERROR("[SKT Handler] Error setsockopt(SO_REUSEADDR): %s\n", strerror(errno));
         }
-        if (rc == 0) {
-            rc = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &setting, sizeof(setting));
-            if (rc != 0) {
-                close(fd);
-                L_ERROR("[TCP Socket] Error setsockopt(TCP_NODELAY): %s\n", strerror(errno));
+        if (socket_type == SOCK_STREAM) {
+            if (rc == 0) {
+                rc = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &setting, sizeof(setting));
+                if (rc != 0) {
+                    close(fd);
+                    L_ERROR("[TCP SKT Handler] Error setsockopt(SKT_NODELAY): %s\n", strerror(errno));
+                }
+            } else {
+                L_ERROR("[TCP SKT Handler] Error creating socket: %s\n", strerror(errno));
             }
-        } else {
-            L_ERROR("[TCP Socket] Error creating socket: %s\n", strerror(errno));
         }
         if (rc == 0 && handle->sendTimeout != 0.0) {
             struct timeval tv;
@@ -247,7 +269,7 @@ int pubsub_tcpHandler_open(pubsub_tcpHandler_t *handle, char *url) {
             tv.tv_usec = (long int) ((handle->sendTimeout - tv.tv_sec) * 1000000.0);
             rc = setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
             if (rc != 0) {
-                L_ERROR("[TCP Socket] Error setsockopt (SO_SNDTIMEO) to set send timeout: %s", strerror(errno));
+                L_ERROR("[SKT Handler] Error setsockopt (SO_SNDTIMEO) to set send timeout: %s", strerror(errno));
             }
         }
         if (rc == 0 && handle->rcvTimeout != 0.0) {
@@ -256,18 +278,11 @@ int pubsub_tcpHandler_open(pubsub_tcpHandler_t *handle, char *url) {
             tv.tv_usec = (long int) ((handle->rcvTimeout - tv.tv_sec) * 1000000.0);
             rc = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
             if (rc != 0) {
-                L_ERROR("[TCP Socket] Error setsockopt (SO_RCVTIMEO) to set send timeout: %s", strerror(errno));
+                L_ERROR("[SKT Handler] Error setsockopt (SO_RCVTIMEO) to set send timeout: %s", strerror(errno));
             }
         }
-        struct sockaddr_in *addr = pubsub_utils_url_getInAddr(url_info->hostname, url_info->port_nr);
-        if (addr) {
-            rc = bind(fd, (struct sockaddr *) addr, sizeof(struct sockaddr));
-            if (rc != 0) {
-                close(fd);
-                L_ERROR("[TCP Socket] Error bind: %s\n", strerror(errno));
-            }
-            free(addr);
-        }
+    } else {
+        L_ERROR("[SKT Handler] Error creating socket: %s\n", strerror(errno));
     }
     pubsub_utils_url_free(url_info);
     celixThreadRwlock_unlock(&handle->dbLock);
@@ -275,23 +290,60 @@ int pubsub_tcpHandler_open(pubsub_tcpHandler_t *handle, char *url) {
 }
 
 //
+// Open the socket using an url
+//
+int pubsub_sktHandler_bind(pubsub_sktHandler_t *handle, int fd, char *url, unsigned int port_nr) {
+    int rc = 0;
+    celixThreadRwlock_readLock(&handle->dbLock);
+    struct sockaddr_in *addr = NULL;
+    socklen_t length = sizeof(int);
+    int socket_domain;
+    rc = getsockopt(fd, SOL_SOCKET, SO_DOMAIN, &socket_domain, &length);
+
+    if (url) {
+        pubsub_utils_url_t *url_info = pubsub_utils_url_parse(url);
+        if (url_info->interface) {
+            addr = pubsub_utils_url_getInAddr(url_info->interface, (!port_nr) ? url_info->interface_port_nr : port_nr);
+        } else {
+            addr = pubsub_utils_url_getInAddr(url_info->hostname,  (!port_nr) ? url_info->port_nr : port_nr);
+        }
+        pubsub_utils_url_free(url_info);
+    } else {
+        addr = pubsub_utils_url_getInAddr(NULL, port_nr);
+    }
+    if (addr) {
+        addr->sin_family = socket_domain;
+        rc = bind(fd, (struct sockaddr *) addr, sizeof(struct sockaddr));
+        if (rc != 0) {
+            close(fd);
+            L_ERROR("[SKT Handler] Error bind: %s\n", strerror(errno));
+            fd = -1;
+        }
+        free(addr);
+    }
+    celixThreadRwlock_unlock(&handle->dbLock);
+    return (!rc) ? fd : rc;
+}
+
+
+//
 // Closes the discriptor with it's connection/interfaces (receiver/sender)
 //
-int pubsub_tcpHandler_close(pubsub_tcpHandler_t *handle, int fd) {
+int pubsub_sktHandler_close(pubsub_sktHandler_t *handle, int fd) {
     int rc = 0;
     if (handle != NULL) {
-        psa_tcp_connection_entry_t *entry = NULL;
+        psa_skt_connection_entry_t *entry = NULL;
         celixThreadRwlock_writeLock(&handle->dbLock);
         entry = hashMap_get(handle->interface_fd_map, (void *) (intptr_t) fd);
         if (entry) {
             entry = hashMap_remove(handle->interface_url_map, (void *) (intptr_t) entry->url);
-            rc = pubsub_tcpHandler_closeInterfaceEntry(handle, entry);
+            rc = pubsub_sktHandler_closeInterfaceEntry(handle, entry);
             entry = NULL;
         }
         entry = hashMap_get(handle->connection_fd_map, (void *) (intptr_t) fd);
         if (entry) {
             entry = hashMap_remove(handle->connection_url_map, (void *) (intptr_t) entry->url);
-            rc = pubsub_tcpHandler_closeConnectionEntry(handle, entry, false);
+            rc = pubsub_sktHandler_closeConnectionEntry(handle, entry, false);
             entry = NULL;
         }
         celixThreadRwlock_unlock(&handle->dbLock);
@@ -302,12 +354,11 @@ int pubsub_tcpHandler_close(pubsub_tcpHandler_t *handle, int fd) {
 //
 // Create connection/interface entry
 //
-static inline psa_tcp_connection_entry_t *
-pubsub_tcpHandler_createEntry(pubsub_tcpHandler_t *handle, int fd, char *url, char *interface_url,
-                              struct sockaddr_in *addr) {
-    psa_tcp_connection_entry_t *entry = NULL;
+static inline psa_skt_connection_entry_t *
+pubsub_sktHandler_createEntry(pubsub_sktHandler_t *handle, int fd, char *url, char *interface_url, struct sockaddr_in *addr) {
+    psa_skt_connection_entry_t *entry = NULL;
     if (fd >= 0) {
-        entry = calloc(sizeof(psa_tcp_connection_entry_t), 1);
+        entry = calloc(sizeof(psa_skt_connection_entry_t), 1);
         entry->fd = fd;
         celixThreadMutex_create(&entry->writeMutex, NULL);
         if (url) {
@@ -315,17 +366,18 @@ pubsub_tcpHandler_createEntry(pubsub_tcpHandler_t *handle, int fd, char *url, ch
         }
         if (interface_url) {
             entry->interface_url = strndup(interface_url, 1024 * 1024);
-        } else {
-            if (url) {
-                entry->interface_url = strndup(url, 1024 * 1024);
-            }
-        }
-        if (addr) {
-            entry->addr = *addr;
         }
         entry->len = sizeof(struct sockaddr_in);
         size_t headerSize = 0;
         size_t footerSize = 0;
+        socklen_t length = sizeof(int);
+        getsockopt(fd, SOL_SOCKET, SO_DOMAIN, &entry->socket_domain, &length);
+        getsockopt(fd, SOL_SOCKET, SO_TYPE, &entry->socket_type, &length);
+        if (addr) {
+            entry->addr = *addr;
+            entry->addr.sin_family = entry->socket_domain;
+        }
+        entry->protocol = strndup((entry->socket_type == SOCK_STREAM) ? "tcp" : "udp",10);
         handle->protocol->getHeaderSize(handle->protocol->handle, &headerSize);
         handle->protocol->getFooterSize(handle->protocol->handle, &footerSize);
         entry->readHeaderBufferSize = headerSize;
@@ -337,13 +389,13 @@ pubsub_tcpHandler_createEntry(pubsub_tcpHandler_t *handle, int fd, char *url, ch
         entry->connected = false;
         unsigned minimalMsgSize = entry->writeHeaderBufferSize + entry->writeFooterBufferSize;
         if ((minimalMsgSize > handle->maxMsgSize) && (handle->maxMsgSize)) {
-            L_ERROR("[TCP Socket] maxMsgSize (%d) < headerSize + FooterSize (%d): %s\n", handle->maxMsgSize, minimalMsgSize);
+            L_ERROR("[SKT Handler] maxMsgSize (%d) < headerSize + FooterSize (%d): %s\n", handle->maxMsgSize, minimalMsgSize);
         } else {
             entry->maxMsgSize = (handle->maxMsgSize) ? handle->maxMsgSize : LONG_MAX;
         }
         entry->readHeaderBuffer = calloc(sizeof(char), headerSize);
         entry->writeHeaderBuffer = calloc(sizeof(char), headerSize);
-        if (entry->readFooterBufferSize ) entry->readFooterBuffer = calloc(sizeof(char), entry->readFooterBufferSize );
+        if (entry->readFooterBufferSize ) entry->readFooterBuffer = calloc(sizeof(char), entry->readFooterBufferSize);
         if (entry->writeFooterBufferSize) entry->writeFooterBuffer = calloc(sizeof(char), entry->writeFooterBufferSize);
         if (entry->bufferSize) entry->buffer = calloc(sizeof(char), entry->bufferSize);
         memset(&entry->readMsg, 0x00, sizeof(struct msghdr));
@@ -356,12 +408,12 @@ pubsub_tcpHandler_createEntry(pubsub_tcpHandler_t *handle, int fd, char *url, ch
 // Free connection/interface entry
 //
 static inline void
-pubsub_tcpHandler_freeEntry(psa_tcp_connection_entry_t *entry) {
+pubsub_sktHandler_freeEntry(psa_skt_connection_entry_t *entry) {
     if (entry) {
         free(entry->url);
         free(entry->interface_url);
-        if (entry->fd >= 0) close(entry->fd);
         free(entry->buffer);
+        free(entry->protocol);
         free(entry->readHeaderBuffer);
         free(entry->writeHeaderBuffer);
         free(entry->readFooterBuffer);
@@ -378,23 +430,94 @@ pubsub_tcpHandler_freeEntry(psa_tcp_connection_entry_t *entry) {
 // Releases the Buffer
 //
 static inline void
-pubsub_tcpHandler_releaseEntryBuffer(pubsub_tcpHandler_t *handle, int fd, unsigned int index __attribute__((unused))) {
-    psa_tcp_connection_entry_t *entry = hashMap_get(handle->connection_fd_map, (void *) (intptr_t) fd);
+pubsub_sktHandler_releaseEntryBuffer(pubsub_sktHandler_t *handle, int fd, unsigned int index __attribute__((unused))) {
+    psa_skt_connection_entry_t *entry = hashMap_get(handle->connection_fd_map, (void *) (intptr_t) fd);
     if (entry != NULL) {
         entry->buffer = NULL;
         entry->bufferSize = 0;
     }
 }
 
+static
+int pubsub_sktHandler_add_fd_event(pubsub_sktHandler_t *handle, psa_skt_connection_entry_t *entry, bool useInputEvent)
+{
+    int rc = 0;
+    if ((handle->efd >= 0) && entry) {
+#if defined(__APPLE__)
+        struct kevent ev;
+        EV_SET (&ev, fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0); // EVFILT_READ | EVFILT_WRITE
+        rc = kevent(handle->efd, &ev, 1, NULL, 0, NULL);
+#else
+        struct epoll_event event;
+        bzero(&event, sizeof(event)); // zero the struct
+        event.events = EPOLLRDHUP | EPOLLERR;
+        if (useInputEvent) {
+            event.events |= EPOLLIN;
+        }
+        event.data.fd = entry->fd;
+        rc = epoll_ctl(handle->efd, EPOLL_CTL_ADD, entry->fd, &event);
+#endif
+
+        if (rc < 0) {
+            L_ERROR("[ %s SKT Handler] Cannot create poll: %s\n", entry->protocol, strerror(errno));
+            errno = 0;
+        }
+    }
+    return rc;
+};
+
+
+
+
+//
+// Connect to url (receiver)
+//
+static
+int pubsub_sktHandler_config_udp_connect(pubsub_sktHandler_t *handle, psa_skt_connection_entry_t *entry, pubsub_utils_url_t *url_info) {
+    int rc = 0;
+    struct sockaddr_in *addr = pubsub_utils_url_getInAddr(url_info->hostname, url_info->port_nr);
+    if (!addr) return -1;
+    bool is_multicast = pubsub_utils_url_is_multicast(url_info->hostname);
+    bool is_broadcast = pubsub_utils_url_is_broadcast(url_info->hostname);
+    if (is_multicast) {
+        struct ip_mreq mc_addr;
+        bzero(&mc_addr, sizeof(struct ip_mreq));
+        mc_addr.imr_multiaddr.s_addr = addr->sin_addr.s_addr;
+        mc_addr.imr_interface.s_addr = entry->addr.sin_addr.s_addr;
+        if (rc == 0) {
+            rc = setsockopt(entry->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mc_addr, sizeof(mc_addr));
+        }
+        if (rc != 0) {
+            L_ERROR("[UDP SKT Handler] Error setsockopt (IP_ADD_MEMBERSHIP): %s", strerror(errno));
+        }
+    } else if (is_broadcast) {
+        int setting = 1;
+        rc = setsockopt(entry->fd, SOL_SOCKET, SO_BROADCAST, &setting, sizeof(setting));
+        if (rc != 0) {
+            L_ERROR("[UDP SKT Handler] Error setsockopt(SO_BROADCAST): %s", strerror(errno));
+        }
+    } else {
+        entry->dst_addr = *addr;
+    }
+
+    if (rc != 0) {
+        L_ERROR("[UDP SKT Handler] Cannot connect %s\n", strerror(errno));
+    }
+
+    free(addr);
+    return rc;
+}
+
 //
 // Connect to url (receiver)
 //
-int pubsub_tcpHandler_connect(pubsub_tcpHandler_t *handle, char *url) {
+int pubsub_sktHandler_tcp_connect(pubsub_sktHandler_t *handle, char *url) {
     int rc = 0;
-    psa_tcp_connection_entry_t *entry = hashMap_get(handle->connection_url_map, (void *) (intptr_t) url);
+    psa_skt_connection_entry_t *entry = hashMap_get(handle->connection_url_map, (void *) (intptr_t) url);
     if (entry == NULL) {
         pubsub_utils_url_t *url_info = pubsub_utils_url_parse(url);
-        int fd = pubsub_tcpHandler_open(handle, url_info->interface_url);
+        int fd = pubsub_sktHandler_open(handle, SOCK_STREAM, url_info->interface_url);
+        fd     = pubsub_sktHandler_bind(handle, fd, url_info->interface_url, 0);
         rc = fd;
         // Connect to sender
         struct sockaddr_in sin;
@@ -405,41 +528,98 @@ int pubsub_tcpHandler_connect(pubsub_tcpHandler_t *handle, char *url) {
         if ((rc >= 0) && addr) {
             rc = connect(fd, (struct sockaddr *) addr, sizeof(struct sockaddr));
             if (rc < 0 && errno != EINPROGRESS) {
-                L_ERROR("[TCP Socket] Cannot connect to %s:%d: using %s err(%d): %s\n", url_info->hostname, url_info->port_nr, interface_url, errno, strerror(errno));
+                L_ERROR("[TCP SKT Handler] Cannot connect to %s:%d: using %s err(%d): %s\n", url_info->hostname, url_info->port_nr, interface_url, errno, strerror(errno));
                 close(fd);
             } else {
-                entry = pubsub_tcpHandler_createEntry(handle, fd, url, interface_url, &sin);
+                entry = pubsub_sktHandler_createEntry(handle, fd, url, interface_url, &sin);
             }
             free(addr);
         }
         free(interface_url);
-        // Subscribe File Descriptor to epoll
+        if (rc >= 0) {
+            rc = pubsub_sktHandler_add_fd_event(handle, entry, true);
+        }
+
+        if (rc < 0) {
+            pubsub_sktHandler_freeEntry(entry);
+            entry = NULL;
+        }
+
         if ((rc >= 0) && (entry)) {
-#if defined(__APPLE__)
-            struct kevent ev;
-            EV_SET (&ev, entry->fd, EVFILT_READ | EVFILT_WRITE, EV_ADD | EV_ENABLE, 0, 0, 0);
-            rc = kevent (handle->efd, &ev, 1, NULL, 0, NULL);
-#else
-            struct epoll_event event;
-            bzero(&event,  sizeof(struct epoll_event)); // zero the struct
-            event.events = EPOLLIN | EPOLLRDHUP | EPOLLERR;
-            event.data.fd = entry->fd;
-            rc = epoll_ctl(handle->efd, EPOLL_CTL_ADD, entry->fd, &event);
-#endif
-            if (rc < 0) {
-                pubsub_tcpHandler_freeEntry(entry);
-                L_ERROR("[TCP Socket] Cannot create poll event %s\n", strerror(errno));
-                entry = NULL;
+            celixThreadRwlock_writeLock(&handle->dbLock);
+            hashMap_put(handle->connection_url_map, entry->url, entry);
+            hashMap_put(handle->connection_fd_map, (void *) (intptr_t) entry->fd, entry);
+            celixThreadRwlock_unlock(&handle->dbLock);
+            pubsub_sktHandler_connectionHandler(handle, fd);
+            if (entry->interface_url) {
+                L_INFO("[TCP SKT Handler] Connect to %s using: %s\n", entry->url, entry->interface_url);
+            } else {
+                L_INFO("[TCP SKT Handler] Connect to %s\n", entry->url);
             }
         }
-        if ((rc >= 0) && (entry)) {
+        pubsub_utils_url_free(url_info);
+    }
+    return rc;
+}
+
+//
+// Connect to url (receiver)
+//
+int pubsub_sktHandler_udp_connect(pubsub_sktHandler_t *handle, char *url) {
+    int rc = 0;
+    psa_skt_connection_entry_t *entry = hashMap_get(handle->connection_url_map, (void *) (intptr_t) url);
+    if (entry == NULL) {
+        pubsub_utils_url_t *url_info = pubsub_utils_url_parse(url);
+        bool is_multicast = pubsub_utils_url_is_multicast(url_info->hostname);
+        bool is_broadcast = pubsub_utils_url_is_broadcast(url_info->hostname);
+        int fd = pubsub_sktHandler_open(handle, SOCK_DGRAM, url_info->interface_url);
+        if (is_multicast || is_broadcast) {
+            fd = pubsub_sktHandler_bind(handle, fd, NULL, url_info->port_nr);
+        } else {
+            fd = pubsub_sktHandler_bind(handle, fd, url_info->interface_url, 0);
+        }
+        rc = fd;
+        char *pUrl = NULL;
+        struct sockaddr_in *sin = NULL;
+        sin = pubsub_utils_url_from_fd(fd);
+        // check if socket is bind
+        if (sin->sin_port) {
+            pUrl = pubsub_utils_url_get_url(sin, "udp");
+        }
+        // Make handler fd entry
+        if (fd >= 0) {
+            entry = pubsub_sktHandler_createEntry(handle, fd, url_info->url, pUrl, sin);
+            rc = pubsub_sktHandler_config_udp_connect(handle, entry, url_info);
+        }
+
+        if (rc >= 0) {
+            rc = pubsub_sktHandler_add_fd_event(handle, entry, true);
+        }
+
+        if (rc < 0) {
+            pubsub_sktHandler_freeEntry(entry);
+            entry = NULL;
+        }
+
+        if ((rc>=0) && entry) {
+            L_INFO("[%s SKT Handler] Using %s for service annunciation", entry->protocol, entry->url);
             celixThreadRwlock_writeLock(&handle->dbLock);
             hashMap_put(handle->connection_url_map, entry->url, entry);
             hashMap_put(handle->connection_fd_map, (void *) (intptr_t) entry->fd, entry);
+            psa_skt_connection_entry_t *interface_entry  = pubsub_sktHandler_createEntry(handle, entry->fd, entry->url, entry->interface_url, &entry->addr);
+            hashMap_put(handle->interface_fd_map, (void *) (intptr_t) interface_entry->fd, interface_entry);
+            hashMap_put(handle->interface_url_map, entry->interface_url ? interface_entry->interface_url : interface_entry->url, interface_entry);
             celixThreadRwlock_unlock(&handle->dbLock);
-            pubsub_tcpHandler_connectionHandler(handle, fd);
-            L_INFO("[TCP Socket] Connect to %s using: %s\n", entry->url, entry->interface_url);
+            pubsub_sktHandler_connectionHandler(handle, entry->fd);
+            __atomic_store_n(&interface_entry->connected, true, __ATOMIC_RELEASE);
+            __atomic_store_n(&entry->connected, true, __ATOMIC_RELEASE);
+            if (!entry->interface_url) {
+                L_INFO("[%s SKT Handler] Connect to %s", entry->protocol, entry->url);
+            } else {
+                L_INFO("[%s SKT Handler] Connect to %s using: %s", entry->protocol, entry->url, entry->interface_url);
+            }
         }
+        free(sin);
         pubsub_utils_url_free(url_info);
     }
     return rc;
@@ -448,14 +628,14 @@ int pubsub_tcpHandler_connect(pubsub_tcpHandler_t *handle, char *url) {
 //
 // Disconnect from url
 //
-int pubsub_tcpHandler_disconnect(pubsub_tcpHandler_t *handle, char *url) {
+int pubsub_sktHandler_disconnect(pubsub_sktHandler_t *handle, char *url) {
     int rc = 0;
     if (handle != NULL) {
         celixThreadRwlock_writeLock(&handle->dbLock);
-        psa_tcp_connection_entry_t *entry = NULL;
+        psa_skt_connection_entry_t *entry = NULL;
         entry = hashMap_remove(handle->connection_url_map, url);
         if (entry) {
-            pubsub_tcpHandler_closeConnectionEntry(handle, entry, false);
+            pubsub_sktHandler_closeConnectionEntry(handle, entry, false);
         }
         celixThreadRwlock_unlock(&handle->dbLock);
     }
@@ -464,24 +644,27 @@ int pubsub_tcpHandler_disconnect(pubsub_tcpHandler_t *handle, char *url) {
 
 // loses the connection entry (of receiver)
 //
-static inline int pubsub_tcpHandler_closeConnectionEntry(
-    pubsub_tcpHandler_t *handle, psa_tcp_connection_entry_t *entry, bool lock) {
+static inline int pubsub_sktHandler_closeConnectionEntry(
+    pubsub_sktHandler_t *handle, psa_skt_connection_entry_t *entry, bool lock) {
     int rc = 0;
     if (handle != NULL && entry != NULL) {
-        fprintf(stdout, "[TCP Socket] Close connection to url: %s: \n", entry->url);
+        L_INFO("[%s SKT Handler] Close connection to url: %s: ", entry->protocol, entry->url);
         hashMap_remove(handle->connection_fd_map, (void *) (intptr_t) entry->fd);
         if ((handle->efd >= 0)) {
+            // For TCP remove the connection socket
+            if (entry->socket_type == SOCK_STREAM) {
 #if defined(__APPLE__)
-          struct kevent ev;
-          EV_SET (&ev, entry->fd, EVFILT_READ, EV_DELETE , 0, 0, 0);
-          rc = kevent (handle->efd, &ev, 1, NULL, 0, NULL);
+                struct kevent ev;
+                EV_SET (&ev, entry->fd, EVFILT_READ, EV_DELETE , 0, 0, 0);
+                rc = kevent (handle->efd, &ev, 1, NULL, 0, NULL);
 #else
-            struct epoll_event event;
-            bzero(&event, sizeof(struct epoll_event)); // zero the struct
-            rc = epoll_ctl(handle->efd, EPOLL_CTL_DEL, entry->fd, &event);
+                struct epoll_event event;
+                bzero(&event, sizeof(struct epoll_event)); // zero the struct
+                rc = epoll_ctl(handle->efd, EPOLL_CTL_DEL, entry->fd, &event);
 #endif
-            if (rc < 0) {
-                L_ERROR("[PSA TCP] Error disconnecting %s\n", strerror(errno));
+                if (rc < 0) {
+                    L_ERROR("[SKT Handler] Error disconnecting %s", strerror(errno));
+                }
             }
         }
         if (entry->fd >= 0) {
@@ -489,7 +672,10 @@ static inline int pubsub_tcpHandler_closeConnectionEntry(
                 handle->receiverDisconnectMessageCallback(handle->receiverConnectPayload, entry->url, lock);
             if (handle->acceptConnectMessageCallback)
                 handle->acceptConnectMessageCallback(handle->acceptConnectPayload, entry->url);
-            pubsub_tcpHandler_freeEntry(entry);
+            if (entry->socket_type == SOCK_STREAM) {
+                close(entry->fd);
+            }
+            pubsub_sktHandler_freeEntry(entry);
             entry = NULL;
         }
     }
@@ -500,11 +686,11 @@ static inline int pubsub_tcpHandler_closeConnectionEntry(
 // Closes the interface entry (of sender)
 //
 static inline int
-pubsub_tcpHandler_closeInterfaceEntry(pubsub_tcpHandler_t *handle,
-                                      psa_tcp_connection_entry_t *entry) {
+pubsub_sktHandler_closeInterfaceEntry(pubsub_sktHandler_t *handle,
+                                      psa_skt_connection_entry_t *entry) {
     int rc = 0;
     if (handle != NULL && entry != NULL) {
-        L_INFO("[TCP Socket] Close interface url: %s: \n", entry->url);
+        L_INFO("[%s SKT Handler] Close interface url: %s: ", entry->protocol ,entry->interface_url ? entry->interface_url : entry->url);
         hashMap_remove(handle->interface_fd_map, (void *) (intptr_t) entry->fd);
         if ((handle->efd >= 0)) {
 #if defined(__APPLE__)
@@ -517,20 +703,37 @@ pubsub_tcpHandler_closeInterfaceEntry(pubsub_tcpHandler_t *handle,
             rc = epoll_ctl(handle->efd, EPOLL_CTL_DEL, entry->fd, &event);
 #endif
             if (rc < 0) {
-                L_ERROR("[PSA TCP] Error disconnecting %s\n", strerror(errno));
+                L_ERROR("[SKT Handler] Error disconnecting %s", strerror(errno));
             }
         }
         if (entry->fd >= 0) {
-            pubsub_tcpHandler_freeEntry(entry);
+            close(entry->fd);
+            pubsub_sktHandler_freeEntry(entry);
         }
     }
     return rc;
 }
 
+static inline
+struct sockaddr_in pubsub_sktHandler_getMultiCastAddr(psa_skt_connection_entry_t *entry, struct sockaddr_in* sin, struct sockaddr_in* intf_addr ) {
+    pubsub_utils_url_t* multiCastUrl = calloc(1, sizeof(pubsub_utils_url_t));
+    pubsub_utils_url_parse_url(entry->url, multiCastUrl);
+    char* hostname = NULL;
+    if (multiCastUrl->hostname) hostname = strchr(multiCastUrl->hostname, '/');
+    if (intf_addr->sin_addr.s_addr && hostname) {
+        in_addr_t listDigit = inet_lnaof(sin->sin_addr);
+        in_addr_t listDigitIntf = inet_lnaof(intf_addr->sin_addr);
+        uint32_t s_addr = ntohl(sin->sin_addr.s_addr);
+        sin->sin_addr.s_addr = htonl(s_addr - listDigit + listDigitIntf);
+    }
+    pubsub_utils_url_free(multiCastUrl);
+    return *sin;
+}
+
 //
 // Make accept file descriptor non blocking
 //
-static inline int pubsub_tcpHandler_makeNonBlocking(pubsub_tcpHandler_t *handle, int fd) {
+static inline int pubsub_sktHandler_makeNonBlocking(pubsub_sktHandler_t *handle, int fd) {
     int rc = 0;
     int flags = fcntl(fd, F_GETFL, 0);
     if (flags == -1)
@@ -538,7 +741,7 @@ static inline int pubsub_tcpHandler_makeNonBlocking(pubsub_tcpHandler_t *handle,
     else {
         rc = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
         if (rc < 0) {
-            L_ERROR("[TCP Socket] Cannot set to NON_BLOCKING: %s\n", strerror(errno));
+            L_ERROR("[SKT Handler] Cannot set to NON_BLOCKING: %s\n", strerror(errno));
         }
     }
     return rc;
@@ -547,20 +750,20 @@ static inline int pubsub_tcpHandler_makeNonBlocking(pubsub_tcpHandler_t *handle,
 //
 // setup listening to interface (sender) using an url
 //
-int pubsub_tcpHandler_listen(pubsub_tcpHandler_t *handle, char *url) {
+int pubsub_sktHandler_tcp_listen(pubsub_sktHandler_t *handle, char *url) {
     int rc = 0;
     celixThreadRwlock_readLock(&handle->dbLock);
-    psa_tcp_connection_entry_t *entry =
+    psa_skt_connection_entry_t *entry =
         hashMap_get(handle->connection_url_map, (void *) (intptr_t) url);
     celixThreadRwlock_unlock(&handle->dbLock);
     if (entry == NULL) {
-        char protocol[] = "tcp";
-        int fd = pubsub_tcpHandler_open(handle, url);
+        int fd = pubsub_sktHandler_open(handle, SOCK_STREAM, url);
+        fd = pubsub_sktHandler_bind(handle, fd, url, 0);
         rc = fd;
         struct sockaddr_in *sin = pubsub_utils_url_from_fd(fd);
         // Make handler fd entry
-        char *pUrl = pubsub_utils_url_get_url(sin, protocol);
-        entry = pubsub_tcpHandler_createEntry(handle, fd, pUrl, NULL, sin);
+        char *pUrl = pubsub_utils_url_get_url(sin, "tcp");
+        entry = pubsub_sktHandler_createEntry(handle, fd, pUrl, NULL, sin);
         if (entry != NULL) {
             __atomic_store_n(&entry->connected, true, __ATOMIC_RELEASE);
             free(pUrl);
@@ -569,46 +772,190 @@ int pubsub_tcpHandler_listen(pubsub_tcpHandler_t *handle, char *url) {
             if (rc >= 0) {
                 rc = listen(fd, SOMAXCONN);
                 if (rc != 0) {
-                    L_ERROR("[TCP Socket] Error listen: %s\n", strerror(errno));
-                    pubsub_tcpHandler_freeEntry(entry);
+                    L_ERROR("[TCP SKT Handler] Error listen: %s\n", strerror(errno));
+                    pubsub_sktHandler_freeEntry(entry);
                     entry = NULL;
                 }
             }
             if (rc >= 0) {
-                rc = pubsub_tcpHandler_makeNonBlocking(handle, fd);
+                rc = pubsub_sktHandler_makeNonBlocking(handle, fd);
                 if (rc < 0) {
-                    pubsub_tcpHandler_freeEntry(entry);
+                    pubsub_sktHandler_freeEntry(entry);
                     entry = NULL;
                 }
             }
-            if ((rc >= 0) && (handle->efd >= 0)) {
-#if defined(__APPLE__)
-                struct kevent ev;
-                EV_SET (&ev, fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0);
-                rc = kevent(handle->efd, &ev, 1, NULL, 0, NULL);
-#else
-                struct epoll_event event;
-                bzero(&event, sizeof(event)); // zero the struct
-                event.events = EPOLLIN | EPOLLRDHUP | EPOLLERR;
-                event.data.fd = fd;
-                rc = epoll_ctl(handle->efd, EPOLL_CTL_ADD, fd, &event);
-#endif
-                if (rc < 0) {
-                    L_ERROR("[TCP Socket] Cannot create poll: %s\n", strerror(errno));
-                    errno = 0;
-                    pubsub_tcpHandler_freeEntry(entry);
-                    entry = NULL;
-                }
-                if (entry) {
-                    L_INFO("[TCP Socket] Using %s for service annunciation", entry->url);
-                    hashMap_put(handle->interface_fd_map, (void *) (intptr_t) entry->fd, entry);
-                    hashMap_put(handle->interface_url_map, entry->url, entry);
+            if (rc >= 0) {
+                rc = pubsub_sktHandler_add_fd_event(handle, entry, true);
+            }
+
+            if (rc < 0) {
+                pubsub_sktHandler_freeEntry(entry);
+                entry = NULL;
+            }
+
+            if ((rc>=0) && entry) {
+                if (entry->interface_url) {
+                    L_INFO("[TCP SKT Handler] Using %s:%s for service annunciation", entry->protocol, entry->url, entry->interface_url);
+                } else {
+                    L_INFO("[TCP SKT Handler] Using %s for service annunciation", entry->protocol, entry->url);
                 }
+                hashMap_put(handle->interface_fd_map, (void *) (intptr_t) entry->fd, entry);
+                hashMap_put(handle->interface_url_map, entry->url, entry);
             }
             celixThreadRwlock_unlock(&handle->dbLock);
         } else {
-            L_ERROR("[TCP Socket] Error listen socket cannot bind to %s: %s\n", url ? url : "", strerror(errno));
+            L_ERROR("[TCP SKT Handler] Error listen socket cannot bind to %s: %s\n", url ? url : "", strerror(errno));
+        }
+    }
+    return rc;
+}
+
+//
+// setup listening to interface (sender) using an url
+//
+static
+int pubsub_sktHandler_config_udp_bind(pubsub_sktHandler_t *handle, psa_skt_connection_entry_t *entry, pubsub_utils_url_t *url_info) {
+    /** Check UDP type*/
+    int rc = 0;
+    bool is_multicast = pubsub_utils_url_is_multicast(url_info->hostname);
+    bool is_broadcast = pubsub_utils_url_is_broadcast(url_info->hostname);
+    if (is_multicast) {
+        char loop = 1;
+        char ttl  = 1;
+        struct sockaddr_in *intf_addr = pubsub_utils_url_getInAddr(url_info->interface, url_info->interface_port_nr);
+        if (!intf_addr) return -1;
+        rc = setsockopt(entry->fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop));
+        if (rc != 0) {
+            L_ERROR("[UDP SKT Handler] Error setsockopt (IP_MULTICAST_LOOP): %s", strerror(errno));
+            pubsub_sktHandler_freeEntry(entry);
+            entry = NULL;
+        }
+        rc = setsockopt(entry->fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl));
+        if (rc != 0) {
+            L_ERROR("[UDP SKT Handler] Error setsockopt (IP_MULTICAST_LOOP): %s", strerror(errno));
+            pubsub_sktHandler_freeEntry(entry);
+            entry = NULL;
+        }
+        if (!rc) {
+            rc = setsockopt(entry->fd, IPPROTO_IP, IP_MULTICAST_IF, &intf_addr->sin_addr, sizeof(struct in_addr));
+            if (rc != 0) {
+                L_ERROR("[UDP SKT Handler] Error setsockopt(IP_MULTICAST_IF): %s", strerror(errno));
+                pubsub_sktHandler_freeEntry(entry);
+                entry = NULL;
+            }
+        }
+        // bind multi cast address
+        struct sockaddr_in *addr = pubsub_utils_url_getInAddr(url_info->hostname, url_info->port_nr);
+        if (!rc && addr) {
+            rc = bind(entry->fd, (struct sockaddr *) addr, sizeof(*addr));
+            if (rc != 0) {
+                L_ERROR("[UDP SKT Handler] Cannot bind to multicast %s:%d:  err(%d): %s\n", url_info->url, url_info->port_nr, errno, strerror(errno));
+                pubsub_sktHandler_freeEntry(entry);
+                entry = NULL;
+            } else {
+               struct sockaddr_in *sin = pubsub_utils_url_from_fd(entry->fd);
+               entry->dst_addr = pubsub_sktHandler_getMultiCastAddr(entry, sin, &entry->addr);
+               free(sin);
+            }
+        }
+        free(addr);
+        free(intf_addr);
+    } else if (is_broadcast) {
+        int setting = 1;
+        if (!rc) {
+            rc = setsockopt(entry->fd, SOL_SOCKET, SO_BROADCAST, &setting, sizeof(setting));
+        }
+        if (!entry->dst_addr.sin_port) entry->dst_addr.sin_port = entry->addr.sin_port;
+        if (rc != 0) {
+            L_ERROR("[UDP SKT Handler] Error setsockopt(SO_BROADCAST): %s", strerror(errno));
+            pubsub_sktHandler_freeEntry(entry);
+            entry = NULL;
+        }
+    }
+
+    // Store connection);
+    if (!rc && entry) {
+        if (is_multicast || is_broadcast) {
+            free(entry->url);
+            free(entry->interface_url);
+            entry->url = pubsub_utils_url_get_url(&entry->dst_addr, url_info->protocol ? url_info->protocol : entry->protocol);
+            entry->interface_url = pubsub_utils_url_get_url(&entry->addr, url_info->protocol ? url_info->protocol : entry->protocol);
+        }
+        psa_skt_connection_entry_t *connection_entry = pubsub_sktHandler_createEntry(handle, entry->fd, entry->url, entry->interface_url, &entry->addr);
+        connection_entry->dst_addr = entry->dst_addr;
+        __atomic_store_n(&entry->connected, true, __ATOMIC_RELEASE);
+        __atomic_store_n(&connection_entry->connected, true, __ATOMIC_RELEASE);
+        hashMap_put(handle->connection_fd_map, (void *) (intptr_t) connection_entry->fd, connection_entry);
+        hashMap_put(handle->connection_url_map, connection_entry->url, connection_entry);
+    }
+
+    // Remove not connected interface
+    if (!entry->connected) {
+        pubsub_sktHandler_freeEntry(entry);
+        entry = NULL;
+    }
+    if (!rc && entry) {
+        rc = pubsub_sktHandler_add_fd_event(handle, entry, (!is_multicast && !is_broadcast));
+    }
+    if (rc < 0) {
+        pubsub_sktHandler_freeEntry(entry);
+        entry = NULL;
+    }
+
+    if ((rc>=0) && entry) {
+        if (entry->interface_url) {
+            L_INFO("[UDP SKT Handler] Using %s:%s for service annunciation", entry->protocol, entry->url, entry->interface_url);
+        } else {
+            L_INFO("[UDP SKT Handler] Using %s for service annunciation", entry->protocol, entry->url);
         }
+        hashMap_put(handle->interface_fd_map, (void *) (intptr_t) entry->fd, entry);
+        hashMap_put(handle->interface_url_map, entry->url, entry);
+    }
+    return rc;
+}
+
+//
+// setup listening to interface (sender) using an url
+//
+int pubsub_sktHandler_udp_bind(pubsub_sktHandler_t *handle, char *url) {
+    int rc = 0;
+    celixThreadRwlock_readLock(&handle->dbLock);
+    psa_skt_connection_entry_t *entry = hashMap_get(handle->interface_url_map, (void *) (intptr_t) url);
+    celixThreadRwlock_unlock(&handle->dbLock);
+    if (entry == NULL) {
+        pubsub_utils_url_t *url_info = pubsub_utils_url_parse(url);
+        bool is_multicast = pubsub_utils_url_is_multicast(url_info->hostname);
+        bool is_broadcast = pubsub_utils_url_is_broadcast(url_info->hostname);
+        int fd = pubsub_sktHandler_open(handle, SOCK_DGRAM, url);
+        char *pUrl = NULL;
+        struct sockaddr_in *sin = NULL;
+        if (!is_multicast) {
+            // Make handler fd entry
+            if (is_broadcast) {
+                fd = pubsub_sktHandler_bind(handle, fd, url_info->interface_url ? url_info->interface_url : NULL, url_info->port_nr);
+            } else {
+                fd = pubsub_sktHandler_bind(handle, fd, url, 0);
+            }
+            sin = pubsub_utils_url_from_fd(fd);
+            pUrl = pubsub_utils_url_get_url(sin, "udp");
+        }
+        rc = fd;
+        if (is_multicast || is_broadcast) {
+            // Create entry for multicast / broadcast
+            entry = pubsub_sktHandler_createEntry(handle, fd, url_info->url, pUrl, sin);
+        } else {
+            // Create entry for unicast
+            entry = pubsub_sktHandler_createEntry(handle, fd, pUrl, NULL, sin);
+        }
+        if (entry != NULL) {
+            celixThreadRwlock_writeLock(&handle->dbLock);
+            rc = pubsub_sktHandler_config_udp_bind(handle, entry, url_info);
+            celixThreadRwlock_unlock(&handle->dbLock);
+        } else {
+            L_ERROR("[UDP SKT Socket] Error publish socket cannot bind to %s: %s\n", url ? url : "", strerror(errno));
+        }
+        free(sin);
+        pubsub_utils_url_free(url_info);
     }
     return rc;
 }
@@ -618,7 +965,7 @@ int pubsub_tcpHandler_listen(pubsub_tcpHandler_t *handle, char *url) {
 // This size is used to allocated the initial read buffer, to avoid receive buffer reallocting.
 // The default receive buffer is allocated in the createEntry when the connection is establised
 //
-int pubsub_tcpHandler_setReceiveBufferSize(pubsub_tcpHandler_t *handle, unsigned int size) {
+int pubsub_sktHandler_setReceiveBufferSize(pubsub_sktHandler_t *handle, unsigned int size) {
     if (handle != NULL) {
         celixThreadRwlock_writeLock(&handle->dbLock);
         handle->bufferSize = size;
@@ -630,7 +977,7 @@ int pubsub_tcpHandler_setReceiveBufferSize(pubsub_tcpHandler_t *handle, unsigned
 //
 // Set Maximum message size
 //
-int pubsub_tcpHandler_setMaxMsgSize(pubsub_tcpHandler_t *handle, unsigned int size) {
+int pubsub_sktHandler_setMaxMsgSize(pubsub_sktHandler_t *handle, unsigned int size) {
     if (handle != NULL) {
         celixThreadRwlock_writeLock(&handle->dbLock);
         handle->maxMsgSize = size;
@@ -642,7 +989,7 @@ int pubsub_tcpHandler_setMaxMsgSize(pubsub_tcpHandler_t *handle, unsigned int si
 //
 // Setup thread timeout
 //
-void pubsub_tcpHandler_setTimeout(pubsub_tcpHandler_t *handle,
+void pubsub_sktHandler_setTimeout(pubsub_sktHandler_t *handle,
                                   unsigned int timeout) {
     if (handle != NULL) {
         celixThreadRwlock_writeLock(&handle->dbLock);
@@ -654,14 +1001,14 @@ void pubsub_tcpHandler_setTimeout(pubsub_tcpHandler_t *handle,
 //
 // Setup thread name
 //
-void pubsub_tcpHandler_setThreadName(pubsub_tcpHandler_t *handle,
+void pubsub_sktHandler_setThreadName(pubsub_sktHandler_t *handle,
                                      const char *topic, const char *scope) {
     if ((handle != NULL) && (topic)) {
         char *thread_name = NULL;
         if ((scope) && (topic))
-            asprintf(&thread_name, "TCP TS %s/%s", scope, topic);
+            asprintf(&thread_name, "SKT TS %s/%s", scope, topic);
         else
-            asprintf(&thread_name, "TCP TS %s", topic);
+            asprintf(&thread_name, "SKT TS %s", topic);
         celixThreadRwlock_writeLock(&handle->dbLock);
         celixThread_setName(&handle->thread, thread_name);
         celixThreadRwlock_unlock(&handle->dbLock);
@@ -672,18 +1019,11 @@ void pubsub_tcpHandler_setThreadName(pubsub_tcpHandler_t *handle,
 //
 // Setup thread priorities
 //
-void pubsub_tcpHandler_setThreadPriority(pubsub_tcpHandler_t *handle, long prio,
+void pubsub_sktHandler_setThreadPriority(pubsub_sktHandler_t *handle, long prio,
                                          const char *sched) {
     if (handle == NULL)
         return;
-    // NOTE. Function will abort when performing a sched_setscheduler without
-    // permission. As result permission has to be checked first.
-    // TODO update this to use cap_get_pid and cap-get_flag instead of check user
-    // is root (note adds dep to -lcap)
-    bool gotPermission = false;
-    if (getuid() == 0) {
-        gotPermission = true;
-    }
+
     if (sched != NULL) {
         int policy = SCHED_OTHER;
         if (strncmp("SCHED_OTHER", sched, 16) == 0) {
@@ -699,24 +1039,23 @@ void pubsub_tcpHandler_setThreadPriority(pubsub_tcpHandler_t *handle, long prio,
         } else if (strncmp("SCHED_RR", sched, 16) == 0) {
             policy = SCHED_RR;
         }
-        if (gotPermission) {
-            celixThreadRwlock_writeLock(&handle->dbLock);
-            if (prio > 0 && prio < 100) {
-                struct sched_param sch;
-                bzero(&sch, sizeof(struct sched_param));
-                sch.sched_priority = (int)prio;
-                pthread_setschedparam(handle->thread.thread, policy, &sch);
-            } else {
-                L_INFO("Skipping configuration of thread prio to %i and thread "
-                       "scheduling to %s. No permission\n",
-                       (int) prio, sched);
-            }
-            celixThreadRwlock_unlock(&handle->dbLock);
+
+        celixThreadRwlock_writeLock(&handle->dbLock);
+        if (prio > 0 && prio < 100) {
+            struct sched_param sch;
+            bzero(&sch, sizeof(struct sched_param));
+            sch.sched_priority = (int)prio;
+            pthread_setschedparam(handle->thread.thread, policy, &sch);
+        } else {
+            L_INFO("Skipping configuration of thread prio to %i and thread "
+                   "scheduling to %s. No permission\n",
+                   (int) prio, sched);
         }
+        celixThreadRwlock_unlock(&handle->dbLock);
     }
 }
 
-void pubsub_tcpHandler_setSendRetryCnt(pubsub_tcpHandler_t *handle, unsigned int count) {
+void pubsub_sktHandler_setSendRetryCnt(pubsub_sktHandler_t *handle, unsigned int count) {
     if (handle != NULL) {
         celixThreadRwlock_writeLock(&handle->dbLock);
         handle->maxSendRetryCount = count;
@@ -724,7 +1063,7 @@ void pubsub_tcpHandler_setSendRetryCnt(pubsub_tcpHandler_t *handle, unsigned int
     }
 }
 
-void pubsub_tcpHandler_setReceiveRetryCnt(pubsub_tcpHandler_t *handle, unsigned int count) {
+void pubsub_sktHandler_setReceiveRetryCnt(pubsub_sktHandler_t *handle, unsigned int count) {
     if (handle != NULL) {
         celixThreadRwlock_writeLock(&handle->dbLock);
         handle->maxRcvRetryCount = count;
@@ -732,7 +1071,7 @@ void pubsub_tcpHandler_setReceiveRetryCnt(pubsub_tcpHandler_t *handle, unsigned
     }
 }
 
-void pubsub_tcpHandler_setSendTimeOut(pubsub_tcpHandler_t *handle, double timeout) {
+void pubsub_sktHandler_setSendTimeOut(pubsub_sktHandler_t *handle, double timeout) {
     if (handle != NULL) {
         celixThreadRwlock_writeLock(&handle->dbLock);
         handle->sendTimeout = timeout;
@@ -740,7 +1079,7 @@ void pubsub_tcpHandler_setSendTimeOut(pubsub_tcpHandler_t *handle, double timeou
     }
 }
 
-void pubsub_tcpHandler_setReceiveTimeOut(pubsub_tcpHandler_t *handle, double timeout) {
+void pubsub_sktHandler_setReceiveTimeOut(pubsub_sktHandler_t *handle, double timeout) {
     if (handle != NULL) {
         celixThreadRwlock_writeLock(&handle->dbLock);
         handle->rcvTimeout = timeout;
@@ -748,7 +1087,7 @@ void pubsub_tcpHandler_setReceiveTimeOut(pubsub_tcpHandler_t *handle, double tim
     }
 }
 
-void pubsub_tcpHandler_enableReceiveEvent(pubsub_tcpHandler_t *handle,bool enable) {
+void pubsub_sktHandler_enableReceiveEvent(pubsub_sktHandler_t *handle,bool enable) {
     if (handle != NULL) {
         celixThreadRwlock_writeLock(&handle->dbLock);
         handle->enableReceiveEvent = enable;
@@ -756,13 +1095,31 @@ void pubsub_tcpHandler_enableReceiveEvent(pubsub_tcpHandler_t *handle,bool enabl
     }
 }
 
-static inline long int pubsub_tcpHandler_getMsgSize(psa_tcp_connection_entry_t *entry) {
+
+bool pubsub_sktHandler_isPassive(const char* buffer) {
+    bool isPassive = false;
+    // Parse Properties
+    if (buffer != NULL) {
+        char buf[32];
+        snprintf(buf, 32, "%s", buffer);
+        char *trimmed = utils_stringTrim(buf);
+        if (strncasecmp("true", trimmed, strlen("true")) == 0) {
+            isPassive = true;
+        } else if (strncasecmp("false", trimmed, strlen("false")) == 0) {
+            isPassive = false;
+        }
+    }
+    return isPassive;
+}
+
+
+static inline long int pubsub_sktHandler_getMsgSize(psa_skt_connection_entry_t *entry) {
     // Note header message is already read
     return (long int)entry->header.header.payloadPartSize + (long int)entry->header.header.metadataSize + (long int)entry->readFooterSize;
 }
 
 static inline 
-bool pubsub_tcpHandler_readHeader(pubsub_tcpHandler_t *handle, int fd, psa_tcp_connection_entry_t *entry, long int* msgSize) {
+bool pubsub_sktHandler_readHeader(pubsub_sktHandler_t *handle, int fd, psa_skt_connection_entry_t *entry, long int* msgSize) {
     bool result = false;
     size_t syncSize = 0;
     size_t protocolHeaderBufferSize = 0;
@@ -774,8 +1131,10 @@ bool pubsub_tcpHandler_readHeader(pubsub_tcpHandler_t *handle, int fd, psa_tcp_c
     handle->protocol->getHeaderBufferSize(handle->protocol->handle, &protocolHeaderBufferSize);
 
     // Ensure capacity in header buffer
-    pubsub_tcpHandler_ensureReadBufferCapacity(handle, entry);
+    pubsub_sktHandler_ensureReadBufferCapacity(handle, entry);
 
+    entry->readMsg.msg_name = &entry->readMsgAddr;
+    entry->readMsg.msg_namelen = entry->len;
     entry->readMsg.msg_iovlen = 0;
     entry->readMsg.msg_iov[entry->readMsg.msg_iovlen].iov_base = entry->readHeaderBuffer;
     entry->readMsg.msg_iov[entry->readMsg.msg_iovlen].iov_len  = entry->readHeaderBufferSize;
@@ -784,7 +1143,8 @@ bool pubsub_tcpHandler_readHeader(pubsub_tcpHandler_t *handle, int fd, psa_tcp_c
     // Read the message
     long int nbytes = 0;
     // Use peek flag to find sync word or when header is part of the payload
-    unsigned int flag = (entry->headerError || (!protocolHeaderBufferSize)) ? MSG_PEEK : 0;
+    bool isUdp =  (entry->socket_type == SOCK_DGRAM) ? true : false;
+    unsigned int flag = (entry->headerError || (!protocolHeaderBufferSize) || isUdp) ? MSG_PEEK : 0;
     if (entry->readHeaderSize) nbytes = recvmsg(fd, &(entry->readMsg), MSG_NOSIGNAL | MSG_WAITALL | flag);
     if (nbytes >= entry->readHeaderSize) {
         if (handle->protocol->decodeHeader(handle->protocol->handle,
@@ -799,7 +1159,7 @@ bool pubsub_tcpHandler_readHeader(pubsub_tcpHandler_t *handle, int fd, psa_tcp_c
             // Did not receive correct header
             // skip sync word and try to read next header
             if (!entry->headerError) {
-                L_WARN("[TCP Socket] Failed to decode message header (fd: %d) (url: %s)", entry->fd, entry->url);
+                L_WARN("[SKT Handler] Failed to decode message header (fd: %d) (url: %s)", entry->fd, entry->url);
             }
             entry->headerError = true;
             entry->readMsg.msg_iovlen = 0;
@@ -814,7 +1174,7 @@ bool pubsub_tcpHandler_readHeader(pubsub_tcpHandler_t *handle, int fd, psa_tcp_c
 }
 
 
-static inline void pubsub_tcpHandler_ensureReadBufferCapacity(pubsub_tcpHandler_t *handle, psa_tcp_connection_entry_t *entry) {
+static inline void pubsub_sktHandler_ensureReadBufferCapacity(pubsub_sktHandler_t *handle, psa_skt_connection_entry_t *entry) {
     if (entry->readHeaderSize > entry->readHeaderBufferSize) {
         free(entry->readHeaderBuffer);
         entry->readHeaderBuffer = malloc((size_t) entry->readHeaderSize);
@@ -841,7 +1201,7 @@ static inline void pubsub_tcpHandler_ensureReadBufferCapacity(pubsub_tcpHandler_
 }
 
 static inline
-void pubsub_tcpHandler_decodePayload(pubsub_tcpHandler_t *handle, psa_tcp_connection_entry_t *entry) {
+void pubsub_sktHandler_decodePayload(pubsub_sktHandler_t *handle, psa_skt_connection_entry_t *entry) {
 
   if (entry->header.header.payloadSize > 0) {
       handle->protocol->decodePayload(handle->protocol->handle, entry->buffer, entry->header.header.payloadSize, &entry->header);
@@ -856,7 +1216,7 @@ void pubsub_tcpHandler_decodePayload(pubsub_tcpHandler_t *handle, psa_tcp_connec
     bool releaseEntryBuffer = false;
     handle->processMessageCallback(handle->processMessagePayload, &entry->header, &releaseEntryBuffer, &receiveTime);
     if (releaseEntryBuffer) {
-      pubsub_tcpHandler_releaseEntryBuffer(handle, entry->fd, 0);
+      pubsub_sktHandler_releaseEntryBuffer(handle, entry->fd, 0);
     }
   }
   celix_properties_destroy(entry->header.metadata.metadata);
@@ -864,13 +1224,19 @@ void pubsub_tcpHandler_decodePayload(pubsub_tcpHandler_t *handle, psa_tcp_connec
 }
 
 static inline
-long int pubsub_tcpHandler_readPayload(pubsub_tcpHandler_t *handle, int fd, psa_tcp_connection_entry_t *entry) {
+long int pubsub_sktHandler_readPayload(pubsub_sktHandler_t *handle, int fd, psa_skt_connection_entry_t *entry) {
     entry->readMsg.msg_iovlen = 0;
     handle->protocol->getFooterSize(handle->protocol->handle, &entry->readFooterSize);
 
     // from the header can be determined how large buffers should be. Even before receiving all data these buffers can be allocated
-    pubsub_tcpHandler_ensureReadBufferCapacity(handle, entry);
+    pubsub_sktHandler_ensureReadBufferCapacity(handle, entry);
 
+    // Read UDP packet in one message
+    if (entry->readHeaderSize && (entry->socket_type == SOCK_DGRAM)) {
+        entry->readMsg.msg_iov[entry->readMsg.msg_iovlen].iov_base = entry->readHeaderBuffer;
+        entry->readMsg.msg_iov[entry->readMsg.msg_iovlen].iov_len = entry->readHeaderBufferSize;
+        entry->readMsg.msg_iovlen++;
+    }
     if (entry->header.header.payloadPartSize) {
         char* buffer = entry->buffer;
         entry->readMsg.msg_iov[entry->readMsg.msg_iovlen].iov_base = &buffer[entry->header.header.payloadOffset];
@@ -890,12 +1256,12 @@ long int pubsub_tcpHandler_readPayload(pubsub_tcpHandler_t *handle, int fd, psa_
     }
 
     long int nbytes = recvmsg(fd, &(entry->readMsg), MSG_NOSIGNAL | MSG_WAITALL);
-    if (nbytes >= pubsub_tcpHandler_getMsgSize(entry)) {
+    if (nbytes >= pubsub_sktHandler_getMsgSize(entry)) {
         bool valid = true;
         if (entry->readFooterSize) {
             if (handle->protocol->decodeFooter(handle->protocol->handle, entry->readFooterBuffer, entry->readFooterBufferSize, &entry->header) != CELIX_SUCCESS) {
                 // Did not receive correct footer
-                L_ERROR("[TCP Socket] Failed to decode message footer seq %d (received corrupt message, transmit buffer full?) (fd: %d) (url: %s)", entry->header.header.seqNr, entry->fd, entry->url);
+                L_ERROR("[SKT Handler] Failed to decode message footer seq %d (received corrupt message, transmit buffer full?) (fd: %d) (url: %s)", entry->header.header.seqNr, entry->fd, entry->url);
                 valid = false;
             }
         }
@@ -904,9 +1270,17 @@ long int pubsub_tcpHandler_readPayload(pubsub_tcpHandler_t *handle, int fd, psa_
             valid = false;
         }
 
+        if (entry->socket_type == SOCK_DGRAM && entry->readMsg.msg_name && !entry->dst_addr.sin_port) {
+            entry->dst_addr = entry->readMsgAddr;
+            psa_skt_connection_entry_t *connection_entry = hashMap_get(handle->connection_fd_map, (void *) (intptr_t) fd);
+            if (connection_entry != NULL) {
+                connection_entry->dst_addr = entry->readMsgAddr;;
+            }
+        }
+
         if (valid) {
             // Complete message is received
-            pubsub_tcpHandler_decodePayload(handle, entry);
+            pubsub_sktHandler_decodePayload(handle, entry);
         }
     }
     return nbytes;
@@ -916,9 +1290,9 @@ long int pubsub_tcpHandler_readPayload(pubsub_tcpHandler_t *handle, int fd, psa_
 // Reads data from the filedescriptor which has date (determined by epoll()) and stores it in the internal structure
 // If the message is completely reassembled true is returned and the index and size have valid values
 //
-int pubsub_tcpHandler_read(pubsub_tcpHandler_t *handle, int fd) {
+int pubsub_sktHandler_read(pubsub_sktHandler_t *handle, int fd) {
     celixThreadRwlock_readLock(&handle->dbLock);
-    psa_tcp_connection_entry_t *entry = hashMap_get(handle->interface_fd_map, (void *) (intptr_t) fd);
+    psa_skt_connection_entry_t *entry = hashMap_get(handle->interface_fd_map, (void *) (intptr_t) fd);
     if (entry == NULL) {
         entry = hashMap_get(handle->connection_fd_map, (void *) (intptr_t) fd);
     }
@@ -934,8 +1308,8 @@ int pubsub_tcpHandler_read(pubsub_tcpHandler_t *handle, int fd) {
     }
     long int nbytes = 0;
     // if not yet enough bytes are received the header can not be read
-    if (pubsub_tcpHandler_readHeader(handle, fd, entry, &nbytes)) {
-        nbytes = pubsub_tcpHandler_readPayload(handle, fd, entry);
+    if (pubsub_sktHandler_readHeader(handle, fd, entry, &nbytes)) {
+        nbytes = pubsub_sktHandler_readPayload(handle, fd, entry);
     }
     if (nbytes > 0) {
         entry->retryCount = 0;
@@ -946,10 +1320,10 @@ int pubsub_tcpHandler_read(pubsub_tcpHandler_t *handle, int fd) {
         } else if (entry->retryCount < handle->maxRcvRetryCount) {
             entry->retryCount++;
             L_WARN(
-                    "[TCP Socket] Failed to receive message (fd: %d), try again. error(%d): %s, Retry count %u of %u.",
+                    "[SKT Handler] Failed to receive message (fd: %d), try again. error(%d): %s, Retry count %u of %u.",
                     entry->fd, errno, strerror(errno), entry->retryCount, handle->maxSendRetryCount);
         } else {
-            L_ERROR("[TCP Socket] Failed to receive message (fd: %d) after %u retries! Closing connection... Error: %s",
+            L_ERROR("[SKT Handler] Failed to receive message (fd: %d) after %u retries! Closing connection... Error: %s",
                     entry->fd, handle->maxRcvRetryCount, strerror(errno));
             nbytes = 0; //Return 0 as indicator to close the connection
         }
@@ -958,8 +1332,8 @@ int pubsub_tcpHandler_read(pubsub_tcpHandler_t *handle, int fd) {
     return (int)nbytes;
 }
 
-int pubsub_tcpHandler_addMessageHandler(pubsub_tcpHandler_t *handle, void *payload,
-                                        pubsub_tcpHandler_processMessage_callback_t processMessageCallback) {
+int pubsub_sktHandler_addMessageHandler(pubsub_sktHandler_t *handle, void *payload,
+                                        pubsub_sktHandler_processMessage_callback_t processMessageCallback) {
     int result = 0;
     celixThreadRwlock_writeLock(&handle->dbLock);
     handle->processMessageCallback = processMessageCallback;
@@ -968,9 +1342,9 @@ int pubsub_tcpHandler_addMessageHandler(pubsub_tcpHandler_t *handle, void *paylo
     return result;
 }
 
-int pubsub_tcpHandler_addReceiverConnectionCallback(pubsub_tcpHandler_t *handle, void *payload,
-                                                    pubsub_tcpHandler_receiverConnectMessage_callback_t connectMessageCallback,
-                                                    pubsub_tcpHandler_receiverConnectMessage_callback_t disconnectMessageCallback) {
+int pubsub_sktHandler_addReceiverConnectionCallback(pubsub_sktHandler_t *handle, void *payload,
+                                                    pubsub_sktHandler_receiverConnectMessage_callback_t connectMessageCallback,
+                                                    pubsub_sktHandler_receiverConnectMessage_callback_t disconnectMessageCallback) {
     int result = 0;
     celixThreadRwlock_writeLock(&handle->dbLock);
     handle->receiverConnectMessageCallback = connectMessageCallback;
@@ -981,9 +1355,9 @@ int pubsub_tcpHandler_addReceiverConnectionCallback(pubsub_tcpHandler_t *handle,
 }
 
 //
-// Write large data to TCP. .
+// Write large data to socket .
 //
-int pubsub_tcpHandler_write(pubsub_tcpHandler_t *handle, pubsub_protocol_message_t *message, struct iovec *msgIoVec,
+int pubsub_sktHandler_write(pubsub_sktHandler_t *handle, pubsub_protocol_message_t *message, struct iovec *msgIoVec,
                             size_t msg_iov_len, int flags) {
     int result = 0;
     if (handle == NULL) {
@@ -994,9 +1368,8 @@ int pubsub_tcpHandler_write(pubsub_tcpHandler_t *handle, pubsub_protocol_message
     if (handle) {
         celixThreadRwlock_readLock(&handle->dbLock);
         hash_map_iterator_t iter = hashMapIterator_construct(handle->connection_fd_map);
-        size_t max_msg_iov_len = IOV_MAX - 2; // header , footer, padding
         while (hashMapIterator_hasNext(&iter)) {
-            psa_tcp_connection_entry_t *entry = hashMapIterator_nextValue(&iter);
+            psa_skt_connection_entry_t *entry = hashMapIterator_nextValue(&iter);
             if (!__atomic_load_n(&entry->connected, __ATOMIC_ACQUIRE)) {
                 continue;
             }
@@ -1016,11 +1389,21 @@ int pubsub_tcpHandler_write(pubsub_tcpHandler_t *handle, pubsub_protocol_message
                 }
             }
 
+            size_t protocolHeaderBufferSize = 0;
+            // Get HeaderBufferSize of the Protocol Header, when headerBufferSize == 0, the protocol header is included in the payload (needed for endpoints)
+            handle->protocol->getHeaderBufferSize(handle->protocol->handle, &protocolHeaderBufferSize);
+            size_t footerSize = 0;
+            // Get size of the Protocol Footer
+            handle->protocol->getFooterSize(handle->protocol->handle, &footerSize);
+            size_t max_msg_iov_len = IOV_MAX; // header , footer, padding
+            max_msg_iov_len -= (protocolHeaderBufferSize) ? 1 : 0;
+            max_msg_iov_len -= (footerSize) ? 1 : 0;
+
             // check if message is not too large
             bool isMessageSegmentationSupported = false;
             handle->protocol->isMessageSegmentationSupported(handle->protocol->handle, &isMessageSegmentationSupported);
             if (!isMessageSegmentationSupported && (msg_iov_len > max_msg_iov_len || payloadSize > entry->maxMsgSize)) {
-                L_WARN("[TCP Socket] Failed to send message (fd: %d), Message segmentation is not supported\n", entry->fd);
+                L_WARN("[SKT Handler] Failed to send message (fd: %d), Message segmentation is not supported\n", entry->fd);
                 celixThreadMutex_unlock(&entry->writeMutex);
                 continue;
             }
@@ -1034,15 +1417,14 @@ int pubsub_tcpHandler_write(pubsub_tcpHandler_t *handle, pubsub_protocol_message
             void *metadataData = NULL;
             size_t metadataSize = 0;
             if (message->metadata.metadata) {
-                metadataSize = entry->writeMetaBufferSize;
                 metadataData = entry->writeMetaBuffer;
-                // When maxMsgSize is smaller then meta data is disabled
+                metadataSize = entry->writeMetaBufferSize;
+                // When maxMsgSize is smaller than meta data is disabled
                 if (metadataSize > entry->maxMsgSize) {
                     metadataSize = 0;
                 }
                 handle->protocol->encodeMetadata(handle->protocol->handle, message, &metadataData, &metadataSize);
             }
-
             message->header.metadataSize = metadataSize;
             size_t totalMsgSize = payloadSize + metadataSize;
 
@@ -1055,7 +1437,7 @@ int pubsub_tcpHandler_write(pubsub_tcpHandler_t *handle, pubsub_protocol_message
                 struct msghdr msg;
                 struct iovec msg_iov[IOV_MAX];
                 memset(&msg, 0x00, sizeof(struct msghdr));
-                msg.msg_name = &entry->addr;
+                msg.msg_name = &entry->dst_addr;
                 msg.msg_namelen = entry->len;
                 msg.msg_flags = flags;
                 msg.msg_iov = msg_iov;
@@ -1065,13 +1447,6 @@ int pubsub_tcpHandler_write(pubsub_tcpHandler_t *handle, pubsub_protocol_message
                 message->header.payloadOffset = 0;
                 message->header.metadataSize = 0;
                 message->header.isLastSegment = 0;
-
-                size_t protocolHeaderBufferSize = 0;
-                // Get HeaderBufferSize of the Protocol Header, when headerBufferSize == 0, the protocol header is included in the payload (needed for endpoints)
-                handle->protocol->getHeaderBufferSize(handle->protocol->handle, &protocolHeaderBufferSize);
-                size_t footerSize = 0;
-                // Get size of the Protocol Footer
-                handle->protocol->getFooterSize(handle->protocol->handle, &footerSize);
                 size_t maxMsgSize = entry->maxMsgSize - protocolHeaderBufferSize - footerSize;
 
                 // reserve space for the header if required, header is added later when size of message is known (message can split in parts)
@@ -1094,6 +1469,10 @@ int pubsub_tcpHandler_write(pubsub_tcpHandler_t *handle, pubsub_protocol_message
                             if ((msgPartSize + msgIoVec[i].iov_len) > maxMsgSize) {
                                 break;
                             }
+                            // When iov_len is zero, skip item and send next item
+                            if (!msgIoVec[i].iov_len) {
+                                msgIovOffset = ++i;
+                            }
                             msg.msg_iov[msg.msg_iovlen].iov_base = msgIoVec[i].iov_base;
                             msg.msg_iov[msg.msg_iovlen].iov_len = msgIoVec[i].iov_len;
                             msgPartSize += msg.msg_iov[msg.msg_iovlen].iov_len;
@@ -1102,7 +1481,7 @@ int pubsub_tcpHandler_write(pubsub_tcpHandler_t *handle, pubsub_protocol_message
                         // if no entry could be added
                         if (i == msgIovOffset) {
                             // TODO element can be split in parts?
-                            L_ERROR("[TCP Socket] vector io element is larger than max msg size");
+                            L_ERROR("[SKT Handler] vector io element is larger than max msg size");
                             break;
                         }
                         msgIovOffset = i;
@@ -1150,7 +1529,7 @@ int pubsub_tcpHandler_write(pubsub_tcpHandler_t *handle, pubsub_protocol_message
                         msg.msg_iov[0].iov_len = headerSize;
                         msgPartSize += msg.msg_iov[0].iov_len;
                     } else {
-                        L_ERROR("[TCP Socket] No header buffer is generated");
+                        L_ERROR("[SKT Handler] No header buffer is generated");
                         break;
                     }
                 }
@@ -1181,27 +1560,24 @@ int pubsub_tcpHandler_write(pubsub_tcpHandler_t *handle, pubsub_protocol_message
                     if (entry->retryCount < handle->maxSendRetryCount) {
                         entry->retryCount++;
                         L_ERROR(
-                            "[TCP Socket] Failed to send message (fd: %d), try again. Retry count %u of %u, error(%d): %s.",
+                            "[SKT Handler] Failed to send message (fd: %d), try again. Retry count %u of %u, error(%d): %s.",
                             entry->fd, entry->retryCount, handle->maxSendRetryCount, errno, strerror(errno));
                     } else {
                         L_ERROR(
-                            "[TCP Socket] Failed to send message (fd: %d) after %u retries! Closing connection... Error: %s", entry->fd, handle->maxSendRetryCount, strerror(errno));
+                            "[SKT Handler] Failed to send message (fd: %d) after %u retries! Closing connection... Error: %s", entry->fd, handle->maxSendRetryCount, strerror(errno));
                         connFdCloseQueue[nofConnToClose++] = entry->fd;
                     }
                     result = -1; //At least one connection failed sending
                 } else if (msgPartSize) {
                     entry->retryCount = 0;
                     if (nbytes != msgPartSize) {
-                        L_ERROR("[TCP Socket] seq: %d MsgSize not correct: %d != %d (%s)\n", message->header.seqNr, msgPartSize, nbytes, strerror(errno));
+                        L_ERROR("[SKT Handler] seq: %d MsgSize not correct: %d != %d (%s)\n", message->header.seqNr, msgPartSize, nbytes, strerror(errno));
                     }
                 }
                 // Note: serialized Payload is deleted by serializer
                 if (payloadData && (payloadData != message->payload.payload)) {
                     free(payloadData);
                 }
-                if (metadataData && metadataSize > 0) {
-                    free(metadataData);
-                }
             }
             celixThreadMutex_unlock(&entry->writeMutex);
         }
@@ -1209,7 +1585,7 @@ int pubsub_tcpHandler_write(pubsub_tcpHandler_t *handle, pubsub_protocol_message
     }
     //Force close all connections that are queued in a list, done outside of locking handle->dbLock to prevent deadlock
     for (int i = 0; i < nofConnToClose; i++) {
-        pubsub_tcpHandler_close(handle, connFdCloseQueue[i]);
+        pubsub_sktHandler_close(handle, connFdCloseQueue[i]);
     }
     return result;
 }
@@ -1217,12 +1593,12 @@ int pubsub_tcpHandler_write(pubsub_tcpHandler_t *handle, pubsub_protocol_message
 //
 // get interface URL
 //
-char *pubsub_tcpHandler_get_interface_url(pubsub_tcpHandler_t *handle) {
+char *pubsub_sktHandler_get_interface_url(pubsub_sktHandler_t *handle) {
     hash_map_iterator_t iter =
         hashMapIterator_construct(handle->interface_url_map);
     char *url = NULL;
     while (hashMapIterator_hasNext(&iter)) {
-        psa_tcp_connection_entry_t *entry =
+        psa_skt_connection_entry_t *entry =
             hashMapIterator_nextValue(&iter);
         if (entry && entry->url) {
             if (!url) {
@@ -1236,16 +1612,17 @@ char *pubsub_tcpHandler_get_interface_url(pubsub_tcpHandler_t *handle) {
     }
     return url;
 }
+
 //
 // get interface URL
 //
-char *pubsub_tcpHandler_get_connection_url(pubsub_tcpHandler_t *handle) {
+char *pubsub_sktHandler_get_connection_url(pubsub_sktHandler_t *handle) {
     celixThreadRwlock_writeLock(&handle->dbLock);
     hash_map_iterator_t iter =
             hashMapIterator_construct(handle->connection_url_map);
     char *url = NULL;
     while (hashMapIterator_hasNext(&iter)) {
-        psa_tcp_connection_entry_t *entry =
+        psa_skt_connection_entry_t *entry =
                 hashMapIterator_nextValue(&iter);
         if (entry && entry->url) {
             if (!url) {
@@ -1266,10 +1643,33 @@ char *pubsub_tcpHandler_get_connection_url(pubsub_tcpHandler_t *handle) {
 }
 
 //
+// get interface URL
+//
+void pubsub_sktHandler_get_connection_urls(pubsub_sktHandler_t *handle, celix_array_list_t *urls) {
+    celixThreadRwlock_writeLock(&handle->dbLock);
+    hash_map_iterator_t iter =
+        hashMapIterator_construct(handle->connection_url_map);
+    char *url = NULL;
+    while (hashMapIterator_hasNext(&iter)) {
+        psa_skt_connection_entry_t *entry =
+            hashMapIterator_nextValue(&iter);
+        if (entry && entry->url) {
+            asprintf(&url, "%s", entry->url);
+            celix_arrayList_add(urls, url);
+            free(url);
+            url = NULL;
+        }
+    }
+    celixThreadRwlock_unlock(&handle->dbLock);
+}
+
+
+
+//
 // Handle non-blocking accept (sender)
 //
 static inline
-int pubsub_tcpHandler_acceptHandler(pubsub_tcpHandler_t *handle, psa_tcp_connection_entry_t *pendingConnectionEntry) {
+int pubsub_sktHandler_acceptHandler(pubsub_sktHandler_t *handle, psa_skt_connection_entry_t *pendingConnectionEntry) {
     celixThreadRwlock_writeLock(&handle->dbLock);
     // new connection available
     struct sockaddr_in their_addr;
@@ -1277,7 +1677,7 @@ int pubsub_tcpHandler_acceptHandler(pubsub_tcpHandler_t *handle, psa_tcp_connect
     int fd = accept(pendingConnectionEntry->fd, (struct sockaddr*)&their_addr, &len);
     int rc = fd;
     if (rc == -1) {
-        L_ERROR("[TCP Socket] accept failed: %s\n", strerror(errno));
+        L_ERROR("[TCP SKT Handler] accept failed: %s\n", strerror(errno));
     }
     if (rc >= 0) {
         // handle new connection:
@@ -1285,7 +1685,7 @@ int pubsub_tcpHandler_acceptHandler(pubsub_tcpHandler_t *handle, psa_tcp_connect
         getsockname(pendingConnectionEntry->fd, (struct sockaddr *) &sin, &len);
         char *interface_url = pubsub_utils_url_get_url(&sin, NULL);
         char *url = pubsub_utils_url_get_url(&their_addr, NULL);
-        psa_tcp_connection_entry_t *entry = pubsub_tcpHandler_createEntry(handle, fd, url, interface_url, &their_addr);
+        psa_skt_connection_entry_t *entry = pubsub_sktHandler_createEntry(handle, fd, url, interface_url, &their_addr);
 #if defined(__APPLE__)
         struct kevent ev;
         EV_SET (&ev, entry->fd, EVFILT_READ, EV_ADD | EV_ENABLE , 0, 0, 0);
@@ -1300,16 +1700,16 @@ int pubsub_tcpHandler_acceptHandler(pubsub_tcpHandler_t *handle, psa_tcp_connect
         rc = epoll_ctl(handle->efd, EPOLL_CTL_ADD, entry->fd, &event);
 #endif
         if (rc < 0) {
-            pubsub_tcpHandler_freeEntry(entry);
+            pubsub_sktHandler_freeEntry(entry);
             free(entry);
-            L_ERROR("[TCP Socket] Cannot create epoll\n");
+            L_ERROR("[TCP SKT Handler] Cannot create epoll\n");
         } else {
             // Call Accept Connection callback
             if (handle->acceptConnectMessageCallback)
                 handle->acceptConnectMessageCallback(handle->acceptConnectPayload, url);
             hashMap_put(handle->connection_fd_map, (void *) (intptr_t) entry->fd, entry);
             hashMap_put(handle->connection_url_map, entry->url, entry);
-            L_INFO("[TCP Socket] New connection to url: %s: \n", url);
+            L_INFO("[TCP SKT Handler] New connection to url: %s: \n", url);
         }
         free(url);
         free(interface_url);
@@ -1322,9 +1722,9 @@ int pubsub_tcpHandler_acceptHandler(pubsub_tcpHandler_t *handle, psa_tcp_connect
 // Handle sockets connection (sender)
 //
 static inline
-void pubsub_tcpHandler_connectionHandler(pubsub_tcpHandler_t *handle, int fd) {
+void pubsub_sktHandler_connectionHandler(pubsub_sktHandler_t *handle, int fd) {
     celixThreadRwlock_readLock(&handle->dbLock);
-    psa_tcp_connection_entry_t *entry = hashMap_get(handle->connection_fd_map, (void *) (intptr_t) fd);
+    psa_skt_connection_entry_t *entry = hashMap_get(handle->connection_fd_map, (void *) (intptr_t) fd);
     if (entry)
         if (!__atomic_exchange_n(&entry->connected, true, __ATOMIC_ACQ_REL)) {
             // tell sender that an receiver is connected
@@ -1339,7 +1739,7 @@ void pubsub_tcpHandler_connectionHandler(pubsub_tcpHandler_t *handle, int fd) {
 // The main socket event loop
 //
 static inline
-void pubsub_tcpHandler_handler(pubsub_tcpHandler_t *handle) {
+void pubsub_sktHandler_handler(pubsub_sktHandler_t *handle) {
   int rc = 0;
   if (handle->efd >= 0) {
     int nof_events = 0;
@@ -1350,34 +1750,34 @@ void pubsub_tcpHandler_handler(pubsub_tcpHandler_t *handle) {
     if (nof_events < 0) {
       if ((errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)) {
       } else
-        L_ERROR("[TCP Socket] Cannot create poll wait (%d) %s\n", nof_events, strerror(errno));
+        L_ERROR("[SKT Handler] Cannot create poll wait (%d) %s\n", nof_events, strerror(errno));
     }
     for (int i = 0; i < nof_events; i++) {
       hash_map_iterator_t iter = hashMapIterator_construct(handle->interface_fd_map);
-      psa_tcp_connection_entry_t *pendingConnectionEntry = NULL;
+      psa_skt_connection_entry_t *pendingConnectionEntry = NULL;
       while (hashMapIterator_hasNext(&iter)) {
-        psa_tcp_connection_entry_t *entry = hashMapIterator_nextValue(&iter);
+        psa_skt_connection_entry_t *entry = hashMapIterator_nextValue(&iter);
         if (events[i].ident == entry->fd)
           pendingConnectionEntry = entry;
       }
       if (pendingConnectionEntry) {
-        int fd = pubsub_tcpHandler_acceptHandler(handle, pendingConnectionEntry);
-        pubsub_tcpHandler_connectionHandler(handle, fd);
+        int fd = pubsub_sktHandler_acceptHandler(handle, pendingConnectionEntry);
+        pubsub_sktHandler_connectionHandler(handle, fd);
       } else if (events[i].filter & EVFILT_READ) {
-        int rc = pubsub_tcpHandler_read(handle, events[i].ident);
-        if (rc == 0) pubsub_tcpHandler_close(handle, events[i].ident);
+        int rc = pubsub_sktHandler_read(handle, events[i].ident);
+        if (rc == 0) pubsub_sktHandler_close(handle, events[i].ident);
       } else if (events[i].flags & EV_EOF) {
         int err = 0;
         socklen_t len = sizeof(int);
         rc = getsockopt(events[i].ident, SOL_SOCKET, SO_ERROR, &err, &len);
         if (rc != 0) {
-          L_ERROR("[TCP Socket]:EPOLLRDHUP ERROR read from socket %s\n", strerror(errno));
+          L_ERROR("[SKT Handler]:EPOLLRDHUP ERROR read from socket %s\n", strerror(errno));
           continue;
         }
-        pubsub_tcpHandler_close(handle, events[i].ident);
+        pubsub_sktHandler_close(handle, events[i].ident);
       } else if (events[i].flags & EV_ERROR) {
-        L_ERROR("[TCP Socket]:EPOLLERR  ERROR read from socket %s\n", strerror(errno));
-        pubsub_tcpHandler_close(handle, events[i].ident);
+        L_ERROR("[SKT Handler]:EPOLLERR  ERROR read from socket %s\n", strerror(errno));
+        pubsub_sktHandler_close(handle, events[i].ident);
         continue;
       }
     }
@@ -1391,43 +1791,34 @@ void pubsub_tcpHandler_handler(pubsub_tcpHandler_t *handle) {
 // The main socket event loop
 //
 static inline
-void pubsub_tcpHandler_handler(pubsub_tcpHandler_t *handle) {
+void pubsub_sktHandler_handler(pubsub_sktHandler_t *handle) {
     int rc = 0;
     if (handle->efd >= 0) {
         int nof_events = 0;
         struct epoll_event events[MAX_EVENTS];
         nof_events = epoll_wait(handle->efd, events, MAX_EVENTS, (int)handle->timeout);
-        if (nof_events < 0) {
-            if ((errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)) {
-            } else
-                L_ERROR("[TCP Socket] Cannot create epoll wait (%d) %s\n", nof_events, strerror(errno));
-        }
+        if  ((nof_events < 0) && (!((errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR))))
+            L_ERROR("[SKT Socket] Cannot create epoll wait (%d) %s\n", nof_events, strerror(errno));
         for (int i = 0; i < nof_events; i++) {
-            hash_map_iterator_t iter = hashMapIterator_construct(handle->interface_fd_map);
-            psa_tcp_connection_entry_t *pendingConnectionEntry = NULL;
-            while (hashMapIterator_hasNext(&iter)) {
-                psa_tcp_connection_entry_t *entry = hashMapIterator_nextValue(&iter);
-                if (events[i].data.fd == entry->fd)
-                    pendingConnectionEntry = entry;
-            }
-            if (pendingConnectionEntry) {
-               int fd = pubsub_tcpHandler_acceptHandler(handle, pendingConnectionEntry);
-               pubsub_tcpHandler_connectionHandler(handle, fd);
+            psa_skt_connection_entry_t *entry = hashMap_get(handle->interface_fd_map, (void *) (intptr_t) events[i].data.fd );
+            if (entry && (entry->socket_type == SOCK_STREAM)) {
+               int fd = pubsub_sktHandler_acceptHandler(handle, entry);
+               pubsub_sktHandler_connectionHandler(handle, fd);
             } else if (events[i].events & EPOLLIN) {
-                rc = pubsub_tcpHandler_read(handle, events[i].data.fd);
-                if (rc == 0) pubsub_tcpHandler_close(handle, events[i].data.fd);
+                rc = pubsub_sktHandler_read(handle, events[i].data.fd);
+                if (rc == 0) pubsub_sktHandler_close(handle, events[i].data.fd);
             } else if (events[i].events & EPOLLRDHUP) {
                 int err = 0;
                 socklen_t len = sizeof(int);
                 rc = getsockopt(events[i].data.fd, SOL_SOCKET, SO_ERROR, &err, &len);
                 if (rc != 0) {
-                    L_ERROR("[TCP Socket]:EPOLLRDHUP ERROR read from socket %s\n", strerror(errno));
+                    L_ERROR("[SKT Handler]:EPOLLRDHUP ERROR read from socket %s\n", strerror(errno));
                     continue;
                 }
-                pubsub_tcpHandler_close(handle, events[i].data.fd);
+                pubsub_sktHandler_close(handle, events[i].data.fd);
             } else if (events[i].events & EPOLLERR) {
-                L_ERROR("[TCP Socket]:EPOLLERR  ERROR read from socket %s\n", strerror(errno));
-                pubsub_tcpHandler_close(handle, events[i].data.fd);
+                L_ERROR("[SKT Handler]:EPOLLERR  ERROR read from socket %s\n", strerror(errno));
+                pubsub_sktHandler_close(handle, events[i].data.fd);
                 continue;
             }
         }
@@ -1438,14 +1829,14 @@ void pubsub_tcpHandler_handler(pubsub_tcpHandler_t *handle) {
 //
 // The socket thread
 //
-static void *pubsub_tcpHandler_thread(void *data) {
-    pubsub_tcpHandler_t *handle = data;
+static void *pubsub_sktHandler_thread(void *data) {
+    pubsub_sktHandler_t *handle = data;
     celixThreadRwlock_readLock(&handle->dbLock);
     bool running = handle->running;
     celixThreadRwlock_unlock(&handle->dbLock);
 
     while (running) {
-        pubsub_tcpHandler_handler(handle);
+        pubsub_sktHandler_handler(handle);
         celixThreadRwlock_readLock(&handle->dbLock);
         running = handle->running;
         celixThreadRwlock_unlock(&handle->dbLock);
diff --git a/bundles/pubsub/pubsub_utils/src/pubsub_utils_url.c b/bundles/pubsub/pubsub_utils/src/pubsub_utils_url.c
index 65a1ff2..c4cec1a 100644
--- a/bundles/pubsub/pubsub_utils/src/pubsub_utils_url.c
+++ b/bundles/pubsub/pubsub_utils/src/pubsub_utils_url.c
@@ -115,14 +115,19 @@ bool pubsub_utils_url_is_multicast(char *hostname) {
     return (ntohl(inet_addr(hostname)) >= ntohl(inet_addr("224.0.0.0"))) ? true : false;
 }
 
+bool pubsub_utils_url_is_broadcast(char *hostname) {
+    return (((inet_addr("0.0.0.255") & inet_addr(hostname)) == inet_addr("0.0.0.255"))) ? true : false;
+}
+
 /** Finds an IP of the available network interfaces of the machine by specifying an CIDR subnet.
  *
- * @param ipWithPrefix  IP with prefix, e.g. 192.168.1.0/24
+ * @param hostname      IP with prefix, e.g. 200.100.0.0/24
+ * @param intf_addr     interface addr
  * @return ip           In case a matching interface could be found, an allocated string containing the IP of the
- *                      interface will be returned, e.g. 192.168.1.16. Memory for the new string can be freed with free().
+ *                      interface will be returned, e.g. 200.100.0.16. Memory for the new string can be freed with free().
  *                      When no matching interface is found NULL will be returned.
  */
-char *pubsub_utils_url_get_multicast_ip(char *hostname) {
+char* pubsub_utils_url_get_multicast_ip(char *hostname, in_addr_t* intf_addr) {
     char *ip = NULL;
     if (hostname) {
         char *subNet = strchr(hostname, '/');
@@ -144,8 +149,14 @@ char *pubsub_utils_url_get_multicast_ip(char *hostname) {
             unsigned int ipAsUint = ntohl(address.sin_addr.s_addr);
             unsigned int bitmask = ipUtils_prefixToBitmask(inputPrefix);
             unsigned int ipRangeStart = ipAsUint & bitmask;
-            unsigned int ipRangeStop = ipAsUint | ~bitmask;
-            unsigned int addr = pubsub_utils_url_rand_range(ipRangeStart, ipRangeStop);
+            unsigned int addr = 0;
+            if (intf_addr && *intf_addr) {
+                unsigned int intfIpAsUint = ntohl(*intf_addr);
+                addr = ipRangeStart + (intfIpAsUint & ~bitmask);
+            } else {
+                unsigned int ipRangeStop = ipAsUint | ~bitmask;
+                addr = pubsub_utils_url_rand_range(ipRangeStart, ipRangeStop);
+            }
             address.sin_addr.s_addr = htonl(addr);
             ip = pubsub_utils_url_get_url(&address, NULL);
         }
@@ -153,7 +164,7 @@ char *pubsub_utils_url_get_multicast_ip(char *hostname) {
     return ip;
 }
 
-char *pubsub_utils_url_get_ip(char *_hostname) {
+char *pubsub_utils_url_get_ip(char *_hostname, in_addr_t* intf_addr) {
     char *ip = NULL;
     if (_hostname) {
         char *subNet = strstr(_hostname, "/");
@@ -163,7 +174,7 @@ char *pubsub_utils_url_get_ip(char *_hostname) {
             if ((length > 1) && isdigit(subNet[1])) {
                 bool is_multicast = pubsub_utils_url_is_multicast(hostname);
                 if (is_multicast)
-                    ip = pubsub_utils_url_get_multicast_ip(_hostname);
+                    ip = pubsub_utils_url_get_multicast_ip(_hostname, intf_addr);
                 else
                     ip = ipUtils_findIpBySubnet(_hostname);
                 if (ip == NULL)
@@ -284,7 +295,7 @@ pubsub_utils_url_t *pubsub_utils_url_parse(char *url) {
     if (url_info->interface) {
         pubsub_utils_url_t interface_url_info;
         bzero(&interface_url_info, sizeof(pubsub_utils_url_t));
-        char *ip = pubsub_utils_url_get_ip(url_info->interface);
+        char *ip = pubsub_utils_url_get_ip(url_info->interface, NULL);
         if (ip != NULL) {
             free(url_info->interface);
             url_info->interface = ip;
@@ -299,9 +310,10 @@ pubsub_utils_url_t *pubsub_utils_url_parse(char *url) {
     }
 
     if (url_info->hostname) {
-        if (url_info->url)
-            free(url_info->url);
-        char *ip = pubsub_utils_url_get_ip(url_info->hostname);
+        if (url_info->url) free(url_info->url);
+        struct sockaddr_in *m_sin = pubsub_utils_url_getInAddr(url_info->interface, url_info->interface_port_nr);
+        char *ip = pubsub_utils_url_get_ip(url_info->hostname, &m_sin->sin_addr.s_addr);
+        free(m_sin);
         if (ip != NULL) {
             free(url_info->hostname);
             url_info->hostname = ip;