Code portability cleanup.
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / ethernet_adapter / linux / caethernetserver.c
index 94afc43..0b248f2 100644 (file)
 * limitations under the License.
 *
 ******************************************************************/
+
+// Defining _POSIX_C_SOURCE macro with 200809L (or greater) as value
+// causes header files to expose definitions
+// corresponding to the POSIX.1-2008 base
+// specification (excluding the XSI extension).
+// For POSIX.1-2008 base specification,
+// Refer http://pubs.opengroup.org/stage7tc1/
+//
+// For this specific file, see use of strndup,
+// Refer http://man7.org/linux/man-pages/man3/strdup.3.html
+#ifndef _POSIX_C_SOURCE
+#define _POSIX_C_SOURCE 200809L
+#endif
+
+// Defining _BSD_SOURCE or _DEFAULT_SOURCE causes header files to expose
+// definitions that may otherwise be skipped. Skipping can cause implicit
+// declaration warnings and/or bugs and subtle problems in code execution.
+// For glibc information on feature test macros,
+// Refer http://www.gnu.org/software/libc/manual/html_node/Feature-Test-Macros.html
+//
+// This file requires #define use due to struct ip_mreq
+#define _DEFAULT_SOURCE
+#define _BSD_SOURCE
+#include <netinet/in.h>
+
 #include "caethernetinterface.h"
 
 #include <sys/types.h>
 #include <fcntl.h>
 #include <sys/select.h>
 #include <arpa/inet.h>
-#include <netinet/in.h>
+#include <string.h>
+
 #include <errno.h>
 
 #include "pdu.h"
 #include "caadapterutils.h"
+#ifdef __WITH_DTLS__
+#include "caadapternetdtls.h"
+#endif
 #include "umutex.h"
+#include "oic_malloc.h"
 
 /**
  * @def ETHERNET_SERVER_TAG
 #define CA_UDP_BIND_RETRY_COUNT 10
 
 /**
- * @var gUnicastServerSocketDescriptor
- * @brief socket descriptor for unicast server
+ * @def IPNAMESIZE
+ * @brief max length for ip
  */
-static int32_t gUnicastServerSocketDescriptor = -1;
+#define IPNAMESIZE 16
 
 /**
- * @var gUnicastServerSocketDescriptor
- * @brief socket descriptor for unicast server
+ * @var g_unicastServerSocketFD
+ * @brief Unicast server socket descriptor
  */
-static char *gUnicastServerAddress = NULL;
+static int32_t g_unicastServerSocketFD = -1;
 
 /**
- * @var gUnicastServerSocketDescriptor
- * @brief socket descriptor for unicast server
+ * @var g_mutexUnicastServer
+ * @brief Mutex to synchronize unicast server
  */
-static int16_t gUnicastServerPort = -1;
+static u_mutex g_mutexUnicastServer = NULL;
 
 /**
- * @var gMutexUnicastServerSocketDescriptor
- * @brief Mutex for socket descriptor for unicast server
- */
-static u_mutex gMutexUnicastServerSocketDescriptor = NULL;
-/**
- * @var gMulticastServerSocketDescriptor
- * @brief socket descriptor for multicast server
- */
-static int32_t gMulticastServerSocketDescriptor = -1;
-
-/**
- * @var gMutexMulticastServerSocketDescriptor
- * @brief Mutex for socket descriptor for Multicast server
- */
-static u_mutex gMutexMulticastServerSocketDescriptor = NULL;
-
-/**
- * @var gThreadPool
- * @brief ThreadPool for storing u_thread_pool_t handle passed from adapter
- */
-static u_thread_pool_t gThreadPool = NULL;
-
-/**
- * @var gMReq
- * @brief ip_mreq structure passed to join a multicast group
+ * @var g_stopUnicast
+ * @brief Flag to control the Receive Unicast Data Thread
  */
-static struct ip_mreq gMReq;
+static bool g_stopUnicast = false;
 
 /**
- * @var gStopUnicast
- * @brief Flag to control the Receive Unicast Data Thread
+ * @var g_multicastServerSocketFD
+ * @brief socket descriptor for multicast server
  */
-static bool gStopUnicast = false;
+static int32_t g_multicastServerSocketFD = -1;
 
 /**
- * @var gMutexStopUnicast
- * @brief Mutex for gStopUnicast
+ * @var g_mutexMulticastServer
+ * @brief Mutex to synchronize secure multicast server
  */
-static u_mutex gMutexStopUnicast = NULL;
+static u_mutex g_mutexMulticastServer = NULL;
 
 /**
- * @var gStopMulticast
+ * @var g_stopMulticast
  * @brief Flag to control the Receive Multicast Data Thread
  */
-static bool gStopMulticast = false;
+static bool g_stopMulticast = false;
 
+#ifdef __WITH_DTLS__
 /**
- * @var gMutexStopMulticast
- * @brief Mutex for gStopMulticast
+ * @var g_secureUnicastServerSocketFD
+ * @brief Secure unicast server socket descriptor
  */
-static u_mutex gMutexStopMulticast = NULL;
+static int32_t g_secureUnicastServerSocketFD = -1;
 
 /**
- * @var gPacketReceivedCallback
- * @brief Callback for notifying the upper layer on receival data from remote OIC device
+ * @var g_mutexSecureUnicastServer
+ * @brief Mutex to synchronize secure unicast server
  */
-static CAEthernetPacketReceivedCallback gPacketReceivedCallback = NULL;
+static u_mutex g_mutexSecureUnicastServer = NULL;
 
 /**
- * @var gExceptionCallback
- * @brief Callback for notifying the upper layer when unicast/multicast server encounters exception
+ * @var g_stopSecureUnicast
+ * @brief Flag to control the unicast secure data receive thread
  */
-static CAEthernetExceptionCallback gExceptionCallback = NULL;
+static bool g_stopSecureUnicast = false;
+#endif
 
 /**
- * @var gUnicastRecvBuffer
- * @brief Character buffer used for receiving unicast data from network
+ * @var g_threadPool
+ * @brief ThreadPool for storing u_thread_pool_t handle passed from adapter
  */
-static char gUnicastRecvBuffer[COAP_MAX_PDU_SIZE] = {0};
+static u_thread_pool_t g_threadPool = NULL;
 
 /**
- * @var gMulticastRecvBuffer
- * @brief Character buffer used for receiving multicast data from network
+ * @var g_multicastServerInterface
+ * @brief Local interface on which multicast server is running
  */
-static char gMulticastRecvBuffer[COAP_MAX_PDU_SIZE] = {0};
+static char g_multicastServerInterface[IPNAMESIZE];
 
 /**
- * @fn CAEthernetServerCreateMutex
- * @brief Creates and initializes mutex
+ * @var g_multicastMemberReq
+ * @brief ip_mreq structure passed to join a multicast group
  */
-static CAResult_t CAEthernetServerCreateMutex(void);
+static struct ip_mreq g_multicastMemberReq;
 
 /**
- * @fn CAEthernetServerDestroyMutex
- * @brief Releases all created mutex
+ * @var g_packetReceivedCallback
+ * @brief Callback for notifying the upper layer on receival data from remote OIC device
  */
-static void CAEthernetServerDestroyMutex(void);
+static CAEthernetPacketReceivedCallback g_packetReceivedCallback = NULL;
 
 /**
- * @fn CAReceiveThreadForMulticast
- * @brief Handler thread for receiving data on multicast server
+ * @var g_exceptionCallback
+ * @brief Callback for notifying the upper layer when unicast/multicast server encounters exception
  */
-static void *CAReceiveThreadForMulticast(void *data);
+static CAEthernetExceptionCallback g_exceptionCallback = NULL;
 
 /**
- * @fn CAEthernetReceiveThreadForUnicast
- * @brief Handler thread for receiving data on unicast server
+ @brief Thread context information for unicast, multicast and secured unicast server
  */
-static void *CAEthernetReceiveThreadForUnicast(void *data);
-
-CAResult_t CAEthernetInitializeServer(const u_thread_pool_t threadPool)
+typedef struct
 {
-    OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
-
-    //Input validation
-    VERIFY_NON_NULL(threadPool, ETHERNET_SERVER_TAG, "Thread pool handle is NULL");
-
-    //Initialize mutex
-    if (CA_STATUS_OK != CAEthernetServerCreateMutex())
-    {
-        OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Failed to create mutex!");
-        return CA_STATUS_FAILED;
-    }
-
-    gThreadPool = threadPool;
-
-    OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
-    return CA_STATUS_OK;
-}
-
-void CAEthernetTerminateServer(void)
-{
-    OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
-
-    gThreadPool = NULL;
-
-    //Destroy mutex
-    CAEthernetServerDestroyMutex();
-
-    OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
-}
+    bool *stopFlag;
+    int32_t socket_fd;
+    CAAdapterServerType_t type;
+} CAAdapterReceiveThreadContext_t;
 
-CAResult_t CAEthernetStartMulticastServer(const char *localAddress, const char *multicastAddress,
-                                      const int16_t multicastPort, int32_t *serverFD)
+static void CAReceiveHandler(void *data)
 {
     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
 
-    if (gMulticastServerSocketDescriptor != -1)
-    {
-        OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Multicast Server is already running!");
-        return CA_SERVER_STARTED_ALREADY;
-    }
+    // Input validation
+    VERIFY_NON_NULL_VOID(data, ETHERNET_SERVER_TAG, "Invalid thread context");
 
-    VERIFY_NON_NULL(localAddress, ETHERNET_SERVER_TAG, "Local address is NULL");
-    VERIFY_NON_NULL(multicastAddress, ETHERNET_SERVER_TAG, "Multicast address is NULL");
+    CAAdapterReceiveThreadContext_t *ctx = (CAAdapterReceiveThreadContext_t *)data;
+    fd_set reads;
+    struct timeval timeout;
+    char recvBuffer[COAP_MAX_PDU_SIZE] = {0};
 
-    if (0 >= multicastPort)
+    while (true != *(ctx->stopFlag))
     {
-        OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Invalid input: Multicast port is invalid!");
-        return CA_STATUS_INVALID_PARAM;
-    }
+        timeout.tv_sec = 1;
+        timeout.tv_usec = 0;
 
-    // Create a datagram socket on which to recv/send.
-    u_mutex_lock(gMutexStopMulticast);
-    gStopMulticast = false;
-    u_mutex_unlock(gMutexStopMulticast);
+        FD_ZERO(&reads);
+        FD_SET(ctx->socket_fd, &reads);
 
-    u_mutex_lock(gMutexMulticastServerSocketDescriptor);
+        int32_t ret = select(ctx->socket_fd + 1, &reads, NULL, NULL, &timeout);
+        if (*(ctx->stopFlag) == true)
+        {
+            OIC_LOG_V(DEBUG, ETHERNET_SERVER_TAG,
+                "Stop request received for [%d] server", ctx->type);
+            break;
+        }
 
-    // create a UDP socket
-    if ((gMulticastServerSocketDescriptor = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
-    {
-        OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to Create Socket, Error code: %s",
-                  strerror(errno));
-        u_mutex_unlock(gMutexMulticastServerSocketDescriptor);
-        return CA_SOCKET_OPERATION_FAILED;
-    }
+        if (ret < 0)
+        {
+            OIC_LOG_V(FATAL, ETHERNET_SERVER_TAG, "select returned error %s", strerror(errno));
+            continue;
+        }
 
-    // Make the socket non-blocking
-    if (-1 == fcntl(gMulticastServerSocketDescriptor, F_SETFL, O_NONBLOCK))
-    {
-        OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to set non-block mode, Error code: %s",
-                  strerror(errno));
-        close(gMulticastServerSocketDescriptor);
-        gMulticastServerSocketDescriptor = -1;
-        u_mutex_unlock(gMutexMulticastServerSocketDescriptor);
-        return CA_STATUS_FAILED;
-    }
+        if (!FD_ISSET(ctx->socket_fd, &reads))
+        {
+            continue;
+        }
 
-    OIC_LOG(INFO, ETHERNET_SERVER_TAG, "socket creation success");
+        memset(recvBuffer, 0, sizeof(recvBuffer));
 
-    int32_t setOptionOn = 1;
-    if (-1 == setsockopt(gMulticastServerSocketDescriptor, SOL_SOCKET, SO_REUSEADDR,
-                         (char *) &setOptionOn,
-                         sizeof(setOptionOn)))
-    {
-        OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to setsockopt for SO_REUSEADDR, Error code: %s",
-                  strerror(errno));
-        close(gMulticastServerSocketDescriptor);
-        gMulticastServerSocketDescriptor = -1;
-        u_mutex_unlock(gMutexMulticastServerSocketDescriptor);
-        return CA_SOCKET_OPERATION_FAILED;
-    }
+        // Read data from socket
+        struct sockaddr_in srcSockAddress;
+        int32_t recvLen;
+        socklen_t srcAddressLen = sizeof(srcSockAddress);
 
-    struct sockaddr_in sockAddr;
-    memset((char *) &sockAddr, 0, sizeof(sockAddr));
+        recvLen = recvfrom(ctx->socket_fd, recvBuffer,
+                                      sizeof(recvBuffer), 0, (struct sockaddr *) &srcSockAddress,
+                                      &srcAddressLen);
 
-    sockAddr.sin_family = AF_INET;
-    sockAddr.sin_port = htons(multicastPort);
-    sockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
+        if (-1 == recvLen)
+        {
+            OIC_LOG_V(DEBUG, ETHERNET_SERVER_TAG, "%s", strerror(errno));
+            continue;
+        }
+        else if (0 == recvLen)
+        {
+            OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Server socket shutdown [%d]!", ctx->type);
 
-    //bind socket to multicast port
-    if (-1 == bind(gMulticastServerSocketDescriptor, (struct sockaddr *) &sockAddr,
-                   sizeof(sockAddr)))
-    {
-        OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to Bind Socket! Return Code[%d]",
-                  CA_SOCKET_OPERATION_FAILED);
-        close(gMulticastServerSocketDescriptor);
-        gMulticastServerSocketDescriptor = -1;
-        u_mutex_unlock(gMutexMulticastServerSocketDescriptor);
-        return CA_SOCKET_OPERATION_FAILED;
-    }
+            // Notify upper layer this exception
+            if (g_exceptionCallback)
+            {
+                g_exceptionCallback(ctx->type);
+            }
+            OICFree(ctx);
+            ctx = NULL;
+            return;
+        }
 
-    OIC_LOG(INFO, ETHERNET_SERVER_TAG, "socket bind success");
+        char srcIPAddress[CA_IPADDR_SIZE] = {0};
+        inet_ntop(AF_INET, &srcSockAddress.sin_addr.s_addr, srcIPAddress, sizeof(srcIPAddress));
+        uint16_t srcPort = 0;
+        srcPort = ntohs(srcSockAddress.sin_port);
 
-    //Add membership to receiving socket (join group)
-    memset(&gMReq, 0, sizeof(struct ip_mreq));
-    gMReq.imr_interface.s_addr = htonl(INADDR_ANY);
-    inet_aton(multicastAddress, &gMReq.imr_multiaddr);
+        OIC_LOG_V(DEBUG, ETHERNET_SERVER_TAG, "Received packet from %s:%d\n",
+                  srcIPAddress, srcPort);
+        OIC_LOG_V(DEBUG, ETHERNET_SERVER_TAG, "Data: %s\t, DataLength: %d\n",
+                  recvBuffer, recvLen);
 
-    if (-1 == setsockopt(gMulticastServerSocketDescriptor, IPPROTO_IP, IP_ADD_MEMBERSHIP,
-                         (char *) &gMReq,
-                         sizeof(struct ip_mreq)))
-    {
-        OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to add to multicast group, Error code: %s\n",
-                  strerror(errno));
-        close(gMulticastServerSocketDescriptor);
-        gMulticastServerSocketDescriptor = -1;
-        u_mutex_unlock(gMutexMulticastServerSocketDescriptor);
-        return CA_SOCKET_OPERATION_FAILED;
-    }
+        char *netMask = NULL;
+        if (CA_STATUS_OK != CAEthernetGetInterfaceSubnetMask(&netMask))
+        {
+            OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to get ethernet subnet");
+            continue;
+        }
 
-    /**
-      * The task to listen to data from multicastcast socket is added to the thread pool.
-      * This is a blocking call is made where we try to receive some data.. We will keep waiting until some data is received.
-      * This task will be terminated when thread pool is freed on stopping the adapters.
-      */
-    if (CA_STATUS_OK != u_thread_pool_add_task(gThreadPool, (void *) CAReceiveThreadForMulticast,
-            (void *)NULL))
-    {
-        OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "[testThreadPool] thread_pool_add_task failed!");
+        if (!CAAdapterIsSameSubnet(g_multicastServerInterface, srcIPAddress, netMask))
+        {
+            OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "Packet received from different subnet, Ignore!");
+            if (NULL != netMask)
+            {
+                OICFree(netMask);
+            }
+            netMask = NULL;
+            continue;
+        }
 
-        close(gMulticastServerSocketDescriptor);
-        gMulticastServerSocketDescriptor = -1;
-        u_mutex_unlock(gMutexMulticastServerSocketDescriptor);
-        return CA_STATUS_FAILED;
+        OICFree(netMask);
+        switch (ctx->type)
+        {
+            case CA_UNICAST_SERVER:
+            case CA_MULTICAST_SERVER:
+                // Notify data to upper layer
+                if (g_packetReceivedCallback)
+                {
+                    g_packetReceivedCallback(srcIPAddress, srcPort, recvBuffer, recvLen, false);
+                }
+                break;
+#ifdef __WITH_DTLS__
+            case CA_SECURED_UNICAST_SERVER:
+                {
+                    CAResult_t ret = CAAdapterNetDtlsDecrypt(srcIPAddress,
+                                     srcPort,
+                                     (uint8_t *)recvBuffer,
+                                     recvLen, DTLS_ETHERNET);
+                    OIC_LOG_V(DEBUG, ETHERNET_SERVER_TAG,
+                        "CAAdapterNetDtlsDecrypt returns [%d]", ret);
+                }
+                break;
+#endif //__WITH_DTLS__
+            default:
+                // Should never occur
+                OIC_LOG_V(DEBUG, ETHERNET_SERVER_TAG, "Invalid server type");
+                OICFree(ctx);
+                ctx = NULL;
+                return;
+        }
     }
+    OICFree(ctx);
+    ctx = NULL;
 
-    *serverFD = gMulticastServerSocketDescriptor;
-    u_mutex_unlock(gMutexMulticastServerSocketDescriptor);
-
-    OIC_LOG(INFO, ETHERNET_SERVER_TAG, "thread_pool_add_task done");
-    OIC_LOG(INFO, ETHERNET_SERVER_TAG, "Multicast Server Started Successfully");
 
     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
-    return CA_STATUS_OK;
-
 }
 
-CAResult_t CAEthernetStartUnicastServer(const char *localAddress, int16_t *port,
-                                    const bool forceStart, int32_t *serverFD)
+static CAResult_t CACreateSocket(int32_t *socketFD, const char *localIp, uint16_t *port,
+                                 bool forceStart)
 {
-    OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
-
-    if (gUnicastServerSocketDescriptor != -1)
-    {
-        OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Unicast Server is Started Already! Return Code[%d]",
-                  CA_SERVER_STARTED_ALREADY);
-        return CA_SERVER_STARTED_ALREADY;
-    }
-
-    VERIFY_NON_NULL(localAddress, ETHERNET_SERVER_TAG, "Invalid argument : localAddress is NULL");
-    VERIFY_NON_NULL(port, ETHERNET_SERVER_TAG, "Invalid argument : port is NULL");
-
-    if (*port < 0)
-    {
-        OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Invalid input: port is invalid!");
-        return CA_STATUS_INVALID_PARAM;
-    }
-
-    u_mutex_lock(gMutexStopUnicast);
-    gStopUnicast = false;
-    u_mutex_unlock(gMutexStopUnicast);
-
-    u_mutex_lock(gMutexUnicastServerSocketDescriptor);
+    int32_t sock = -1;
     // Create a UDP socket
-    if ((gUnicastServerSocketDescriptor = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
+    sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+    if (-1 == sock)
     {
-        OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to Create Socket, Error code: %s",
+        OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to create Socket, Error code: %s",
                   strerror(errno));
-        u_mutex_unlock(gMutexUnicastServerSocketDescriptor);
-        return CA_SOCKET_OPERATION_FAILED;
+        return CA_STATUS_FAILED;
     }
 
     // Make the socket non-blocking
-    if (-1 == fcntl(gUnicastServerSocketDescriptor, F_SETFL, O_NONBLOCK))
+    if (-1 == fcntl(sock, F_SETFL, O_NONBLOCK))
     {
         OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to set non-block mode, Error code: %s",
                   strerror(errno));
-        close(gUnicastServerSocketDescriptor);
-        gUnicastServerSocketDescriptor = -1;
-        u_mutex_unlock(gMutexUnicastServerSocketDescriptor);
+
+        close(sock);
         return CA_STATUS_FAILED;
     }
 
-    OIC_LOG(INFO, ETHERNET_SERVER_TAG, "socket creation success");
-
     if (true == forceStart)
     {
         int32_t setOptionOn = 1;
-        if (-1 == setsockopt(gUnicastServerSocketDescriptor, SOL_SOCKET, SO_REUSEADDR,
+        if (-1 == setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
                              (char *) &setOptionOn,
                              sizeof(setOptionOn)))
         {
             OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to set SO_REUSEADDR! Error code: %s",
                       strerror(errno));
-            close(gUnicastServerSocketDescriptor);
-            gUnicastServerSocketDescriptor = -1;
-            u_mutex_unlock(gMutexUnicastServerSocketDescriptor);
-            return CA_SOCKET_OPERATION_FAILED;
+
+            close(sock);
+            return CA_STATUS_FAILED;
         }
     }
 
     struct sockaddr_in sockAddr;
     bool isBound = false;
-    int16_t serverPort = *port;
+    uint16_t serverPort = *port;
 
-    memset((char *) &sockAddr, 0, sizeof(sockAddr));
+    memset(&sockAddr, 0, sizeof(sockAddr));
     sockAddr.sin_family = AF_INET;
     sockAddr.sin_port = htons(serverPort);
-    sockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
+    if (localIp)
+    {
+        sockAddr.sin_addr.s_addr = inet_addr(localIp);
+    }
+    else
+    {
+        sockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
+    }
 
-    //Trying for bind in a loop
     int16_t i;
     for (i = 0; i < CA_UDP_BIND_RETRY_COUNT; i++)
     {
-        if (-1 == bind(gUnicastServerSocketDescriptor, (struct sockaddr *) &sockAddr,
+        if (-1 == bind(sock, (struct sockaddr *) &sockAddr,
                        sizeof(sockAddr)))
         {
             if (false == forceStart)
             {
-                OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to bind socket[%s]. Trying again..",
+                OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to bind socket[%s]. Trying again..",
                           strerror(errno));
 
                 //Set the port to next one
@@ -426,197 +395,147 @@ CAResult_t CAEthernetStartUnicastServer(const char *localAddress, int16_t *port,
 
     if (false == isBound)
     {
-        OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to bind Socket! Return code[%d]",
-                  CA_SOCKET_OPERATION_FAILED);
-        close(gUnicastServerSocketDescriptor);
-        gUnicastServerSocketDescriptor = -1;
-        u_mutex_unlock(gMutexUnicastServerSocketDescriptor);
-        return CA_SOCKET_OPERATION_FAILED;
-    }
-
-    OIC_LOG(INFO, ETHERNET_SERVER_TAG, "socket bind success");
-
-    socklen_t len = 0;
-    char *serverAddress = NULL;
-    if (-1 != getsockname(gUnicastServerSocketDescriptor, (struct sockaddr *)&sockAddr, &len))
-    {
-        serverPort = ntohs(sockAddr.sin_port);
-        serverAddress = inet_ntoa(sockAddr.sin_addr);
-    }
-
-    /**
-      * The task to listen for data from unicast socket is added to the thread pool.
-      * This is a blocking call is made where we try to receive some data..
-      * We will keep waiting until some data is received.
-      * This task will be terminated when thread pool is freed on stopping the adapters.
-      */
-    if (CA_STATUS_OK != u_thread_pool_add_task(gThreadPool, (void *) CAEthernetReceiveThreadForUnicast,
-            (void *) NULL))
-    {
-        OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "[testThreadPool] thread_pool_add_task failed!");
-
-        close(gUnicastServerSocketDescriptor);
-        gUnicastServerSocketDescriptor = -1;
-        u_mutex_unlock(gMutexUnicastServerSocketDescriptor);
+        close(sock);
         return CA_STATUS_FAILED;
     }
 
-    //Free the server address previously stored
-    OICFree(gUnicastServerAddress);
-    gUnicastServerAddress = NULL;
-    gUnicastServerPort = serverPort;
-    gUnicastServerAddress = (serverAddress) ? strndup(serverAddress, strlen(serverAddress)) :
-                            NULL;
     *port = serverPort;
-    *serverFD = gUnicastServerSocketDescriptor;
-    u_mutex_unlock(gMutexUnicastServerSocketDescriptor);
-
-    OIC_LOG(INFO, ETHERNET_SERVER_TAG, "Unicast Server Started Successfully");
+    *socketFD = sock;
     return CA_STATUS_OK;
 }
 
-CAResult_t CAEthernetStopMulticastServer(void)
+static CAResult_t CACloseSocket(int32_t *socketFD)
 {
-    OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
-
-    u_mutex_lock(gMutexMulticastServerSocketDescriptor);
-
-    if (gMulticastServerSocketDescriptor == -1)
+    if (socketFD == NULL)
     {
-        OIC_LOG(INFO, ETHERNET_SERVER_TAG, "Multicast Server is not yet Started");
-        u_mutex_unlock(gMutexMulticastServerSocketDescriptor);
-        return CA_SERVER_NOT_STARTED;
+        return CA_STATUS_INVALID_PARAM;
     }
 
-    u_mutex_lock(gMutexStopMulticast);
-    gStopMulticast = true;
-
-    // leave the group after you are done
-    if (-1 == setsockopt(gMulticastServerSocketDescriptor, IPPROTO_IP, IP_DROP_MEMBERSHIP,
-                         (char *)&gMReq,
-                         sizeof(struct ip_mreq)))
+    if (-1 == *socketFD)
     {
-        OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "cannot leave multicast group, Error code: %s\n",
-                  strerror(errno));
+        OIC_LOG(INFO, ETHERNET_SERVER_TAG, "Server not running");
+        return CA_SERVER_NOT_STARTED;
     }
 
     // close the socket
-    if (-1 == close(gMulticastServerSocketDescriptor))
+    if (-1 == close(*socketFD))
     {
-        OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Multicast Server socket close failed, Error code: %s\n",
+        OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to close the socket, Error code: %s\n",
                   strerror(errno));
-        u_mutex_unlock(gMutexMulticastServerSocketDescriptor);
-        u_mutex_unlock(gMutexStopMulticast);
-        return CA_SOCKET_OPERATION_FAILED;
+        return CA_STATUS_FAILED;
     }
 
-    u_mutex_unlock(gMutexStopMulticast);
-
-    gMulticastServerSocketDescriptor = -1;
-    u_mutex_unlock(gMutexMulticastServerSocketDescriptor);
-
-    OIC_LOG(INFO, ETHERNET_SERVER_TAG, "Multicast Server Stopped Successfully");
-
-    OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
+    *socketFD = -1;
     return CA_STATUS_OK;
-
 }
 
-CAResult_t CAEthernetStopUnicastServer()
+static CAResult_t CAStartUnicastServer(const char *localAddress, uint16_t *port,
+                                       const bool forceStart, bool isSecured, int32_t *serverFD)
 {
     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
-    u_mutex_lock(gMutexUnicastServerSocketDescriptor);
 
-    if (gUnicastServerSocketDescriptor == -1)
+    if (serverFD == NULL)
     {
-        OIC_LOG(INFO, ETHERNET_SERVER_TAG, "Unicast Server is not yet Started");
-        u_mutex_unlock(gMutexUnicastServerSocketDescriptor);
-        return CA_SERVER_NOT_STARTED;
+        return CA_STATUS_INVALID_PARAM;
     }
-    u_mutex_lock(gMutexStopUnicast);
-    gStopUnicast = true;
 
-    // close the socket
-    if (-1 == close(gUnicastServerSocketDescriptor))
+    CAResult_t ret = CACreateSocket(serverFD, localAddress, port, forceStart);
+    if (CA_STATUS_OK != ret)
     {
-        OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Unicast Server socket close failed, Error code: %s\n",
-                  strerror(errno));
-        u_mutex_unlock(gMutexUnicastServerSocketDescriptor);
-        u_mutex_unlock(gMutexStopUnicast);
-        return CA_SOCKET_OPERATION_FAILED;
+        OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Failed to create unicast socket");
+        return ret;
     }
 
-    u_mutex_unlock(gMutexStopUnicast);
-    gUnicastServerSocketDescriptor = -1;
+    /**
+      * The task to listen for data from unicast socket is added to the thread pool.
+      * This is a blocking call is made where we try to receive some data..
+      * We will keep waiting until some data is received.
+      * This task will be terminated when thread pool is freed on stopping the adapters.
+      * Thread context will be freed by thread on exit.
+      */
+    CAAdapterReceiveThreadContext_t *ctx = (CAAdapterReceiveThreadContext_t *)
+                                           OICMalloc(sizeof(CAAdapterReceiveThreadContext_t));
+    if (!ctx)
+    {
+        OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Out of memory!");
+        close(*serverFD);
+        return CA_MEMORY_ALLOC_FAILED;
+    }
 
-    u_mutex_unlock(gMutexUnicastServerSocketDescriptor);
+    ctx->stopFlag = &g_stopUnicast;
+    ctx->socket_fd = *serverFD;
+    ctx->type = isSecured ? CA_SECURED_UNICAST_SERVER : CA_UNICAST_SERVER;
+    if (CA_STATUS_OK != u_thread_pool_add_task(g_threadPool, CAReceiveHandler, (void *)ctx))
+    {
+        OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Failed to create read thread!");
+        OICFree(ctx);
+        close(*serverFD);
+        *serverFD = -1;
+        return CA_STATUS_FAILED;
+    }
 
-    OIC_LOG(INFO, ETHERNET_SERVER_TAG, "Unicast Server Stopped Successfully");
+    OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
     return CA_STATUS_OK;
 }
 
-CAResult_t CAEthernetGetUnicastServerInfo(char **ipAddress, int16_t *port, int32_t *serverFD)
+static void CAEthernetServerDestroyMutex(void)
 {
     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
 
-    //Input validation
-    VERIFY_NON_NULL(ipAddress, ETHERNET_SERVER_TAG, "ipAddress holder is NULL");
-    VERIFY_NON_NULL(port, ETHERNET_SERVER_TAG, "port holder is NULL");
-    VERIFY_NON_NULL(serverFD, ETHERNET_SERVER_TAG, "serverID holder is NULL");
-
-    *ipAddress = gUnicastServerAddress;
-    *port = gUnicastServerPort;
-    *serverFD = gUnicastServerSocketDescriptor;
+    if (g_mutexUnicastServer)
+    {
+        u_mutex_free(g_mutexUnicastServer);
+        g_mutexUnicastServer = NULL;
+    }
 
-    OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
-    return CA_STATUS_OK;
-}
+#ifdef __WITH_DTLS__
+    if (g_mutexSecureUnicastServer)
+    {
+        u_mutex_free(g_mutexSecureUnicastServer);
+        g_mutexSecureUnicastServer = NULL;
+    }
+#endif
 
-void CAEthernetSetPacketReceiveCallback(CAEthernetPacketReceivedCallback callback)
-{
-    OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
+    if (g_mutexMulticastServer)
+    {
+        u_mutex_free(g_mutexMulticastServer);
+        g_mutexMulticastServer = NULL;
+    }
 
-    gPacketReceivedCallback = callback;
+    OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
 }
 
-void CAEthernetSetExceptionCallback(CAEthernetExceptionCallback callback)
+static CAResult_t CAEthernetServerCreateMutex(void)
 {
     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
 
-    gExceptionCallback = callback;
-}
-
-CAResult_t CAEthernetServerCreateMutex(void)
-{
-    OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
+    if(g_mutexUnicastServer) {
+        OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "mutex is already created!");
 
-    gMutexUnicastServerSocketDescriptor = u_mutex_new();
-    if (!gMutexUnicastServerSocketDescriptor)
-    {
-        OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Failed to created mutex!");
+        OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
         return CA_STATUS_FAILED;
     }
 
-    gMutexMulticastServerSocketDescriptor = u_mutex_new();
-    if (!gMutexMulticastServerSocketDescriptor)
+    g_mutexUnicastServer = u_mutex_new();
+    if (!g_mutexUnicastServer)
     {
         OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Failed to created mutex!");
-
-        CAEthernetServerDestroyMutex();
         return CA_STATUS_FAILED;
     }
 
-    gMutexStopUnicast = u_mutex_new();
-    if (!gMutexStopUnicast)
+#ifdef __WITH_DTLS__
+    g_mutexSecureUnicastServer = u_mutex_new();
+    if (!g_mutexSecureUnicastServer)
     {
         OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Failed to created mutex!");
 
         CAEthernetServerDestroyMutex();
         return CA_STATUS_FAILED;
     }
+#endif
 
-    gMutexStopMulticast = u_mutex_new();
-    if (!gMutexStopMulticast)
+    g_mutexMulticastServer = u_mutex_new();
+    if (!g_mutexMulticastServer)
     {
         OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Failed to created mutex!");
 
@@ -628,198 +547,307 @@ CAResult_t CAEthernetServerCreateMutex(void)
     return CA_STATUS_OK;
 }
 
-void CAEthernetServerDestroyMutex(void)
+CAResult_t CAEthernetInitializeServer(const u_thread_pool_t threadPool)
 {
     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
 
-    if (gMutexUnicastServerSocketDescriptor)
-    {
-        u_mutex_free(gMutexUnicastServerSocketDescriptor);
-        gMutexUnicastServerSocketDescriptor = NULL;
-    }
+    // Input validation
+    VERIFY_NON_NULL(threadPool, ETHERNET_SERVER_TAG, "Thread pool handle is NULL");
 
-    if (gMutexMulticastServerSocketDescriptor)
+    // Initialize mutex
+    if (CA_STATUS_OK != CAEthernetServerCreateMutex())
     {
-        u_mutex_free(gMutexMulticastServerSocketDescriptor);
-        gMutexMulticastServerSocketDescriptor = NULL;
+        OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Failed to create mutex!");
+        return CA_STATUS_FAILED;
     }
 
-    if (gMutexStopUnicast)
-    {
-        u_mutex_free(gMutexStopUnicast);
-        gMutexStopUnicast = NULL;
-    }
+    g_threadPool = threadPool;
 
-    if (gMutexStopMulticast)
-    {
-        u_mutex_free(gMutexStopMulticast);
-        gMutexStopMulticast = NULL;
-    }
+    OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
+    return CA_STATUS_OK;
+}
+
+void CAEthernetTerminateServer(void)
+{
+    OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
+
+    g_threadPool = NULL;
+
+    // Destroy mutex
+    CAEthernetServerDestroyMutex();
 
     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
 }
 
-void *CAEthernetReceiveThreadForUnicast(void *data)
+CAResult_t CAEthernetStartUnicastServer(const char *localAddress, uint16_t *port,
+                                        bool forceStart, bool isSecured, int32_t *serverFD)
 {
     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
 
-    fd_set reads;
-    struct timeval timeout;
+    // Input validation
+    VERIFY_NON_NULL(localAddress, ETHERNET_SERVER_TAG, "localAddress");
+    VERIFY_NON_NULL(port, ETHERNET_SERVER_TAG, "port");
+    VERIFY_NON_NULL(serverFD, ETHERNET_SERVER_TAG, "server socket FD");
 
-    //keep listening for data
-    while (!gStopUnicast)
+    if (0 >= *port)
     {
-        //OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "Waiting for data..");
+        OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Invalid input: port is invalid!");
+        return CA_STATUS_INVALID_PARAM;
+    }
 
-        timeout.tv_sec = 1;
-        timeout.tv_usec = 0;
+    *serverFD = -1;
+    if (false == isSecured)
+    {
+        u_mutex_lock(g_mutexUnicastServer);
+        if (-1 != g_unicastServerSocketFD)
+        {
+            OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Unicast Server is Started Already!",
+                      CA_SERVER_STARTED_ALREADY);
 
-        FD_ZERO(&reads);
-        FD_SET(gUnicastServerSocketDescriptor, &reads);
+            *serverFD = g_unicastServerSocketFD;
+            u_mutex_unlock(g_mutexUnicastServer);
+            return CA_SERVER_STARTED_ALREADY;
+        }
 
-        int32_t ret = select(gUnicastServerSocketDescriptor + 1, &reads, NULL, NULL, &timeout);
-        if (gStopUnicast)
+        g_stopUnicast = false;
+        if (CA_STATUS_OK != CAStartUnicastServer(localAddress, port, forceStart, isSecured,
+                &g_unicastServerSocketFD))
         {
-            OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "Stop Unicast is called");
-            break;
+            OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to start unicast server!");
+            g_unicastServerSocketFD = -1;
+            u_mutex_unlock(g_mutexUnicastServer);
+            return CA_STATUS_FAILED;
         }
-        if (ret < 0)
+
+        *serverFD = g_unicastServerSocketFD;
+        u_mutex_unlock(g_mutexUnicastServer);
+    }
+#ifdef __WITH_DTLS__
+    else // Start unicast server for secured communication
+    {
+        u_mutex_lock(g_mutexSecureUnicastServer);
+        if (-1 != g_secureUnicastServerSocketFD)
         {
-            OIC_LOG_V(FATAL, ETHERNET_SERVER_TAG, "select returned error %s", strerror(errno));
-            continue;
+            OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Unicast Server is Started Already!",
+                      CA_SERVER_STARTED_ALREADY);
+
+            *serverFD = g_secureUnicastServerSocketFD;
+            u_mutex_unlock(g_mutexSecureUnicastServer);
+            return CA_SERVER_STARTED_ALREADY;
         }
-        if (!FD_ISSET(gUnicastServerSocketDescriptor, &reads))
+
+        g_stopSecureUnicast = false;
+        if (CA_STATUS_OK != CAStartUnicastServer(localAddress, port, forceStart, isSecured,
+                &g_secureUnicastServerSocketFD))
         {
-            //OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "No data to read");
-            continue;
+            OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to start unicast server!");
+            g_secureUnicastServerSocketFD = -1;
+            u_mutex_unlock(g_mutexSecureUnicastServer);
+            return CA_STATUS_FAILED;
         }
 
-        memset(gUnicastRecvBuffer, 0, sizeof(char)*COAP_MAX_PDU_SIZE);
+        *serverFD = g_secureUnicastServerSocketFD;
+        u_mutex_unlock(g_mutexSecureUnicastServer);
+    }
+#endif
+    OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
+    return CA_STATUS_OK;
+}
 
-        //Read data from socket
-        struct sockaddr_in srcSockAddress;
-        int32_t recvLen;
-        socklen_t srcAddressLen = sizeof(srcSockAddress);
-        if (-1 == (recvLen = recvfrom(gUnicastServerSocketDescriptor, gUnicastRecvBuffer,
-                                      COAP_MAX_PDU_SIZE, 0, (struct sockaddr *) &srcSockAddress,
-                                      &srcAddressLen)))
-        {
-            OIC_LOG_V(DEBUG, ETHERNET_SERVER_TAG, "%s", strerror(errno));
-            continue;
-        }
-        else if (0 == recvLen)
-        {
-            OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Unicast server socket is shutdown !");
+CAResult_t CAEthernetStartMulticastServer(const char *localAddress,
+    const char *multicastAddress, const uint16_t multicastPort, int32_t *serverFD)
+{
+    OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
 
-            //Notify upper layer this exception
-            if (gExceptionCallback)
-            {
-                gExceptionCallback(CA_UNICAST_SERVER);
-            }
-            return NULL;
-        }
+    // Input validation
+    VERIFY_NON_NULL(localAddress, ETHERNET_SERVER_TAG, "localAddress");
+    VERIFY_NON_NULL(multicastAddress, ETHERNET_SERVER_TAG, "port");
+    VERIFY_NON_NULL(serverFD, ETHERNET_SERVER_TAG, "server socket FD");
 
-        const char *srcIPAddress = NULL;
-        int32_t srcPort = -1;
+    uint16_t port = multicastPort;
+    if (0 >= port)
+    {
+        OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Invalid input: Multicast port is invalid!");
+        return CA_STATUS_INVALID_PARAM;
+    }
 
-        srcIPAddress = inet_ntoa(srcSockAddress.sin_addr);
-        srcPort = ntohs(srcSockAddress.sin_port);
+    u_mutex_lock(g_mutexMulticastServer);
 
-        OIC_LOG_V(DEBUG, ETHERNET_SERVER_TAG, "Received packet from %s:%d\n",
-                  srcIPAddress, srcPort);
-        OIC_LOG_V(DEBUG, ETHERNET_SERVER_TAG, "Data: %s\t, DataLength: %d\n",
-                  gUnicastRecvBuffer, recvLen);
+    if (g_multicastServerSocketFD != -1)
+    {
+        OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Multicast Server is already running!");
+        u_mutex_unlock(g_mutexMulticastServer);
+        return CA_SERVER_STARTED_ALREADY;
+    }
 
-        //Notify data to upper layer
-        if (gPacketReceivedCallback)
-        {
-            gPacketReceivedCallback(srcIPAddress, srcPort, gUnicastRecvBuffer, recvLen);
-        }
+    CAResult_t ret = CACreateSocket(&g_multicastServerSocketFD, multicastAddress, &port, true);
+    if (ret != CA_STATUS_OK)
+    {
+        OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Failed to create multicast socket");
+        u_mutex_unlock(g_mutexMulticastServer);
+        return ret;
+    }
+
+    // Add membership to receiving socket (join group)
+    memset(&g_multicastMemberReq, 0, sizeof(struct ip_mreq));
+    g_multicastMemberReq.imr_interface.s_addr = inet_addr(localAddress);
+    inet_aton(multicastAddress, &g_multicastMemberReq.imr_multiaddr);
+
+    if (-1 == setsockopt(g_multicastServerSocketFD, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+                         (char *) &g_multicastMemberReq,
+                         sizeof(struct ip_mreq)))
+    {
+        OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to add to multicast group, Error code: %s\n",
+                  strerror(errno));
+        close(g_multicastServerSocketFD);
+        g_multicastServerSocketFD = -1;
+        u_mutex_unlock(g_mutexMulticastServer);
+        return CA_STATUS_FAILED;
+    }
+
+    /**
+      * The task to listen to data from multicastcast socket is added to the thread pool.
+      * This is a blocking call is made where we try to receive some data.
+      * We will keep waiting until some data is received.
+      * This task will be terminated when thread pool is freed on stopping the adapters.
+      * Thread context will be freed by thread on exit.
+      */
+    CAAdapterReceiveThreadContext_t *ctx = (CAAdapterReceiveThreadContext_t *)
+                                           OICMalloc(sizeof(CAAdapterReceiveThreadContext_t));
+    if (!ctx)
+    {
+        OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "Out of memory!");
+        close(g_multicastServerSocketFD);
+        g_multicastServerSocketFD = -1;
+        return CA_MEMORY_ALLOC_FAILED;
+    }
+
+    ctx->stopFlag = &g_stopMulticast;
+    ctx->socket_fd = g_multicastServerSocketFD;
+    ctx->type = CA_MULTICAST_SERVER;
+
+    g_stopMulticast = false;
+    if (CA_STATUS_OK != u_thread_pool_add_task(g_threadPool, CAReceiveHandler, (void *)ctx))
+    {
+        OIC_LOG(ERROR, ETHERNET_SERVER_TAG, "thread_pool_add_task failed!");
+
+        close(g_multicastServerSocketFD);
+        g_multicastServerSocketFD = -1;
+        g_stopMulticast = true;
+        u_mutex_unlock(g_mutexMulticastServer);
+        return CA_STATUS_FAILED;
     }
 
+    *serverFD = g_multicastServerSocketFD;
+    strncpy(g_multicastServerInterface, localAddress, IPNAMESIZE);
+    u_mutex_unlock(g_mutexMulticastServer);
+
     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
-    return NULL;
+    return CA_STATUS_OK;
 }
 
-void *CAReceiveThreadForMulticast(void *data)
+CAResult_t CAEthernetStopUnicastServer()
 {
     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
 
-    fd_set reads;
-    struct timeval timeout;
+    u_mutex_lock(g_mutexUnicastServer);
+    g_stopUnicast = true;
+    CAResult_t ret = CACloseSocket(&g_unicastServerSocketFD);
+    u_mutex_unlock(g_mutexUnicastServer);
 
-    //keep listening for data
-    while (!gStopMulticast)
-    {
-        timeout.tv_sec = 1;
-        timeout.tv_usec = 0;
+    OIC_LOG_V(INFO, ETHERNET_SERVER_TAG, "Unicast server stopped [%d]", ret);
+    return ret;
+}
 
-        FD_ZERO(&reads);
-        FD_SET(gMulticastServerSocketDescriptor, &reads);
+#ifdef __WITH_DTLS__
+CAResult_t CAEthernetStopSecureUnicastServer()
+{
+    OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
 
-        int32_t ret = select(gMulticastServerSocketDescriptor + 1, &reads, NULL, NULL, &timeout);
-        if (gStopMulticast)
-        {
-            OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "Stop Multicast is called");
-            break;
-        }
-        if ( ret < 0)
-        {
-            OIC_LOG_V(FATAL, ETHERNET_SERVER_TAG, "select returned error %s", strerror(errno));
-            continue;
-        }
-        if (!FD_ISSET(gMulticastServerSocketDescriptor, &reads))
-        {
-            continue;
-        }
+    u_mutex_lock(g_mutexSecureUnicastServer);
+    g_stopSecureUnicast = true;
+    CAResult_t ret = CACloseSocket(&g_secureUnicastServerSocketFD);
+    u_mutex_unlock(g_mutexSecureUnicastServer);
 
-        memset(gMulticastRecvBuffer, 0, sizeof(char)*COAP_MAX_PDU_SIZE);
+    OIC_LOG_V(INFO, ETHERNET_SERVER_TAG, "Secured unicast server stopped [%d]", ret);
+    return ret;
+}
+#endif
 
-        //Read data from socket
-        struct sockaddr_in srcSockAddress;
-        int32_t recvLen;
-        socklen_t srcAddressLen = sizeof(srcSockAddress);
-        if (-1 == (recvLen = recvfrom(gMulticastServerSocketDescriptor, gMulticastRecvBuffer,
-                                      COAP_MAX_PDU_SIZE, 0, (struct sockaddr *) &srcSockAddress,
-                                      &srcAddressLen)))
-        {
-            OIC_LOG_V(DEBUG, ETHERNET_SERVER_TAG, "%s", strerror(errno));
-            continue;
-        }
-        else if (0 == recvLen)
-        {
-            OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Multicast socket is shutdown, returning from \
-                thread\n");
+CAResult_t CAEthernetStopMulticastServer(void)
+{
+    OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
 
-            //Notify upper layer this exception
-            if (gExceptionCallback)
-            {
-                gExceptionCallback(CA_MULTICAST_SERVER);
-            }
-            return NULL;
-        }
+    u_mutex_lock(g_mutexMulticastServer);
 
-        const char *srcIPAddress = NULL;
-        int32_t srcPort = -1;
+    if (g_multicastServerSocketFD == -1)
+    {
+        OIC_LOG(INFO, ETHERNET_SERVER_TAG, "Multicast server is not yet started");
+        u_mutex_unlock(g_mutexMulticastServer);
+        return CA_SERVER_NOT_STARTED;
+    }
 
-        srcIPAddress = inet_ntoa(srcSockAddress.sin_addr);
-        srcPort = ntohs(srcSockAddress.sin_port);
+    g_stopMulticast = true;
 
-        OIC_LOG_V(DEBUG, ETHERNET_SERVER_TAG, "Received packet from %s:%d\n",
-                  srcIPAddress, srcPort);
-        OIC_LOG_V(DEBUG, ETHERNET_SERVER_TAG, "Data: %s\t, DataLength: %d\n",
-                  gMulticastRecvBuffer, recvLen);
+    // leave the group after you are done
+    if (-1 == setsockopt(g_multicastServerSocketFD, IPPROTO_IP, IP_DROP_MEMBERSHIP,
+                         (char *)&g_multicastMemberReq,
+                         sizeof(struct ip_mreq)))
+    {
+        OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed to leave multicast group, Error code: %s\n",
+                  strerror(errno));
+    }
 
+    CAResult_t ret = CACloseSocket(&g_multicastServerSocketFD);
+    u_mutex_unlock(g_mutexMulticastServer);
 
-        //Notify data to upper layer
-        if (gPacketReceivedCallback)
-        {
-            gPacketReceivedCallback(srcIPAddress, srcPort, gMulticastRecvBuffer, recvLen);
-        }
+    OIC_LOG_V(INFO, ETHERNET_SERVER_TAG, "Multicast server stopped [%d]", ret);
+    return ret;
+}
+
+CAResult_t CAEthernetGetUnicastServerInfo(bool isSecured,
+    char **ipAddress, uint16_t *port, int32_t *serverFD)
+{
+    OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
+
+    // Input validation
+    VERIFY_NON_NULL(ipAddress, ETHERNET_SERVER_TAG, "IP address");
+    VERIFY_NON_NULL(port, ETHERNET_SERVER_TAG, "Port");
+    VERIFY_NON_NULL(serverFD, ETHERNET_SERVER_TAG, "Server ID");
+
+    struct sockaddr_in sockAddr;
+    socklen_t len = sizeof(struct sockaddr_in);
+    if (-1 == getsockname(g_unicastServerSocketFD, (struct sockaddr *)&sockAddr, &len))
+    {
+        OIC_LOG_V(ERROR, ETHERNET_SERVER_TAG, "Failed in getsockname [%s]!", strerror(errno));
+        return CA_STATUS_FAILED;
     }
 
+
+    const char *serverAddress = inet_ntoa(sockAddr.sin_addr);
+    *ipAddress = (serverAddress) ? strndup(serverAddress, strlen(serverAddress)) : NULL;
+    *port = ntohs(sockAddr.sin_port);
+#ifdef __WITH_DTLS__
+    *serverFD = (true == isSecured) ? g_secureUnicastServerSocketFD : g_unicastServerSocketFD;
+#else
+    *serverFD = g_unicastServerSocketFD;
+#endif
+
+    OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
+    return CA_STATUS_OK;
+}
+
+void CAEthernetSetPacketReceiveCallback(CAEthernetPacketReceivedCallback callback)
+{
+    OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
+    g_packetReceivedCallback = callback;
     OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
-    return NULL;
 }
 
+void CAEthernetSetExceptionCallback(CAEthernetExceptionCallback callback)
+{
+    OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "IN");
+    g_exceptionCallback = callback;
+    OIC_LOG(DEBUG, ETHERNET_SERVER_TAG, "OUT");
+}