-/******************************************************************\r
-*\r
-* Copyright 2014 Samsung Electronics All Rights Reserved.\r
-*\r
-*\r
-*\r
-* Licensed under the Apache License, Version 2.0 (the "License");\r
-* you may not use this file except in compliance with the License.\r
-* You may obtain a copy of the License at\r
-*\r
-* http://www.apache.org/licenses/LICENSE-2.0\r
-*\r
-* Unless required by applicable law or agreed to in writing, software\r
-* distributed under the License is distributed on an "AS IS" BASIS,\r
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-* See the License for the specific language governing permissions and\r
-* limitations under the License.\r
-*\r
-******************************************************************/\r
-#include "cawifiinterface.h"\r
-\r
-#include <sys/types.h>\r
-#include <sys/socket.h>\r
-#include <unistd.h>\r
-#include <fcntl.h>\r
-#include <sys/select.h>\r
-#include <arpa/inet.h>\r
-#include <netinet/in.h>\r
-#include <errno.h>\r
-\r
-#include "pdu.h"\r
-#include "caadapterutils.h"\r
-#ifdef __WITH_DTLS__\r
-#include "caadapternetdtls.h"\r
-#endif\r
-#include "umutex.h"\r
-\r
-/**\r
- * @def WIFI_SERVER_TAG\r
- * @brief Logging tag for module name\r
- */\r
-#define WIFI_SERVER_TAG "WIFI_SERVER"\r
-\r
-/**\r
- * @def CA_UDP_BIND_RETRY_COUNT\r
- * @brief Retry count in case of socket bind failure.\r
- */\r
-#define CA_UDP_BIND_RETRY_COUNT 10\r
-\r
-/**\r
- * @def IPNAMESIZE\r
- * @brief max length for ip\r
- */\r
-#define IPNAMESIZE 16\r
-\r
-/**\r
- * @var gUnicastServerSocketFD\r
- * @brief Unicast server socket descriptor\r
- */\r
-static int32_t gUnicastServerSocketFD = -1;\r
-\r
-/**\r
- * @var gMutexUnicastServer\r
- * @brief Mutex to synchronize unicast server\r
- */\r
-static u_mutex gMutexUnicastServer = NULL;\r
-\r
-/**\r
- * @var gStopUnicast\r
- * @brief Flag to control the Receive Unicast Data Thread\r
- */\r
-static bool gStopUnicast = false;\r
-\r
-/**\r
- * @var gMulticastServerSocketFD\r
- * @brief socket descriptor for multicast server\r
- */\r
-static int32_t gMulticastServerSocketFD = -1;\r
-\r
-/**\r
- * @var gMutexMulticastServer\r
- * @brief Mutex to synchronize secure multicast server\r
- */\r
-static u_mutex gMutexMulticastServer = NULL;\r
-\r
-/**\r
- * @var gStopMulticast\r
- * @brief Flag to control the Receive Multicast Data Thread\r
- */\r
-static bool gStopMulticast = false;\r
-\r
-#ifdef __WITH_DTLS__\r
-/**\r
- * @var gSecureUnicastServerSocketFD\r
- * @brief Secure unicast server socket descriptor\r
- */\r
-static int32_t gSecureUnicastServerSocketFD = -1;\r
-\r
-/**\r
- * @var gMutexSecureUnicastServer\r
- * @brief Mutex to synchronize secure unicast server\r
- */\r
-static u_mutex gMutexSecureUnicastServer = NULL;\r
-\r
-/**\r
- * @var gStopSecureUnicast\r
- * @brief Flag to control the unicast secure data receive thread\r
- */\r
-static bool gStopSecureUnicast = false;\r
-#endif\r
-\r
-/**\r
- * @var gThreadPool\r
- * @brief ThreadPool for storing u_thread_pool_t handle passed from adapter\r
- */\r
-static u_thread_pool_t gThreadPool = NULL;\r
-\r
-/**\r
- * @var gMulticastServerInterface\r
- * @brief Local interface on which multicast server is running\r
- */\r
-static char gMulticastServerInterface[IPNAMESIZE];\r
-\r
-/**\r
- * @var gMulticastMemberReq\r
- * @brief ip_mreq structure passed to join a multicast group\r
- */\r
-static struct ip_mreq gMulticastMemberReq;\r
-\r
-/**\r
- * @var gPacketReceivedCallback\r
- * @brief Callback for notifying the upper layer on receival data from remote OIC device\r
- */\r
-static CAWiFiPacketReceivedCallback gPacketReceivedCallback = NULL;\r
-\r
-/**\r
- * @var gExceptionCallback\r
- * @brief Callback for notifying the upper layer when unicast/multicast server encounters exception\r
- */\r
-static CAWiFiExceptionCallback gExceptionCallback = NULL;\r
-\r
-/**\r
- @brief Thread context information for unicast, multicast and secured unicast server\r
- */\r
-typedef struct\r
-{\r
- bool *stopFlag;\r
- int32_t socket_fd;\r
- CAAdapterServerType_t type;\r
-} CAAdapterReceiveThreadContext_t;\r
-\r
-static void CAReceiveHandler(void *data)\r
-{\r
- OIC_LOG(DEBUG, WIFI_SERVER_TAG, "IN");\r
- // Input validation\r
- VERIFY_NON_NULL_VOID(data, WIFI_SERVER_TAG, "Invalid thread context");\r
-\r
- CAAdapterReceiveThreadContext_t *ctx = (CAAdapterReceiveThreadContext_t *)data;\r
- fd_set reads;\r
- struct timeval timeout;\r
- char recvBuffer[COAP_MAX_PDU_SIZE] = {0};\r
-\r
- while (true != *(ctx->stopFlag))\r
- {\r
- timeout.tv_sec = 1;\r
- timeout.tv_usec = 0;\r
-\r
- FD_ZERO(&reads);\r
- FD_SET(ctx->socket_fd, &reads);\r
-\r
- int32_t ret = select(ctx->socket_fd + 1, &reads, NULL, NULL, &timeout);\r
- if (*(ctx->stopFlag) == true)\r
- {\r
- OIC_LOG_V(DEBUG, WIFI_SERVER_TAG, "Stop request received for [%d] server", ctx->type);\r
- break;\r
- }\r
- if (ret < 0)\r
- {\r
- OIC_LOG_V(FATAL, WIFI_SERVER_TAG, "select returned error %s", strerror(errno));\r
- continue;\r
- }\r
- if (!FD_ISSET(ctx->socket_fd, &reads))\r
- {\r
- continue;\r
- }\r
-\r
- memset(recvBuffer, 0, sizeof(recvBuffer));\r
-\r
- // Read data from socket\r
- struct sockaddr_in srcSockAddress;\r
- int32_t recvLen;\r
- socklen_t srcAddressLen = sizeof(srcSockAddress);\r
- if (-1 == (recvLen = recvfrom(ctx->socket_fd, recvBuffer,\r
- sizeof(recvBuffer), 0, (struct sockaddr *) &srcSockAddress,\r
- &srcAddressLen)))\r
- {\r
- OIC_LOG_V(DEBUG, WIFI_SERVER_TAG, "%s", strerror(errno));\r
- continue;\r
- }\r
- else if (0 == recvLen)\r
- {\r
- OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Server socket shutdown [%d]!", ctx->type);\r
-\r
- // Notify upper layer this exception\r
- if (gExceptionCallback)\r
- {\r
- gExceptionCallback(ctx->type);\r
- }\r
- OICFree(ctx);\r
- return;\r
- }\r
-\r
- const char *srcIPAddress = NULL;\r
- int32_t srcPort = -1;\r
-\r
- srcIPAddress = inet_ntoa(srcSockAddress.sin_addr);\r
- srcPort = ntohs(srcSockAddress.sin_port);\r
-\r
- OIC_LOG_V(DEBUG, WIFI_SERVER_TAG, "Received packet from %s:%d\n",\r
- srcIPAddress, srcPort);\r
- OIC_LOG_V(DEBUG, WIFI_SERVER_TAG, "Data: %s\t, DataLength: %d\n",\r
- recvBuffer, recvLen);\r
-\r
- char *netMask = NULL;\r
- if (CA_STATUS_OK != CAWiFiGetInterfaceSubnetMask(&netMask))\r
- {\r
- OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Failed to get ethernet subnet");\r
- continue;\r
- }\r
-\r
- if (!CAAdapterIsSameSubnet(gMulticastServerInterface, srcIPAddress, netMask))\r
- {\r
- OIC_LOG(DEBUG, WIFI_SERVER_TAG, "Packet received from different subnet, Ignore!");\r
- if (NULL != netMask)\r
- {\r
- OICFree(netMask);\r
- }\r
- netMask = NULL;\r
- continue;\r
- }\r
-\r
- OICFree(netMask);\r
- switch (ctx->type)\r
- {\r
- case CA_UNICAST_SERVER:\r
- case CA_MULTICAST_SERVER:\r
- // Notify data to upper layer\r
- if (gPacketReceivedCallback)\r
- {\r
- gPacketReceivedCallback(srcIPAddress, srcPort, recvBuffer, recvLen, false);\r
- }\r
- break;\r
-#ifdef __WITH_DTLS__\r
- case CA_SECURED_UNICAST_SERVER:\r
- {\r
- CAResult_t ret = CAAdapterNetDtlsDecrypt(srcIPAddress,\r
- srcPort,\r
- (uint8_t *)recvBuffer,\r
- recvLen, DTLS_WIFI);\r
- OIC_LOG_V(DEBUG, WIFI_SERVER_TAG, "CAAdapterNetDtlsDecrypt returns [%d]", ret);\r
- }\r
- break;\r
-#endif //__WITH_DTLS__\r default:\r // Should never occur\r
- OIC_LOG_V(DEBUG, WIFI_SERVER_TAG, "Invalid server type");\r
- OICFree(ctx);\r
- return;\r
- }\r
- }\r
-\r
- // free context\r
- OICFree(ctx);\r
-\r
- OIC_LOG(DEBUG, WIFI_SERVER_TAG, "OUT");\r
-}\r
-\r
-static CAResult_t CAWiFiCreateSocket(int32_t *socketFD, const char *localIp, int16_t *port,\r
- const bool forceStart)\r
-{\r
- int32_t sock = -1;\r
- // Create a UDP socket\r
- if (-1 == (sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)))\r
- {\r
- OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Failed to create Socket, Error code: %s",\r
- strerror(errno));\r
- return CA_STATUS_FAILED;\r
- }\r
-\r
- // Make the socket non-blocking\r
- if (-1 == fcntl(sock, F_SETFL, O_NONBLOCK))\r
- {\r
- OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Failed to set non-block mode, Error code: %s",\r
- strerror(errno));\r
-\r
- close(sock);\r
- return CA_STATUS_FAILED;\r
- }\r
-\r
- if (true == forceStart)\r
- {\r
- int32_t setOptionOn = 1;\r
- if (-1 == setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,\r
- (char *) &setOptionOn,\r
- sizeof(setOptionOn)))\r
- {\r
- OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Failed to set SO_REUSEADDR! Error code: %s",\r
- strerror(errno));\r
-\r
- close(sock);\r
- return CA_STATUS_FAILED;\r
- }\r
- }\r
-\r
- struct sockaddr_in sockAddr;\r
- bool isBound = false;\r
- int16_t serverPort = *port;\r
-\r
- memset((char *) &sockAddr, 0, sizeof(sockAddr));\r
- sockAddr.sin_family = AF_INET;\r
- sockAddr.sin_port = htons(serverPort);\r
- if (localIp)\r
- {\r
- sockAddr.sin_addr.s_addr = inet_addr(localIp);\r
- }\r
- else\r
- {\r
- sockAddr.sin_addr.s_addr = htonl(INADDR_ANY);\r
- }\r
-\r
- int16_t i;\r
- for (i = 0; i < CA_UDP_BIND_RETRY_COUNT; i++)\r
- {\r
- if (-1 == bind(sock, (struct sockaddr *) &sockAddr,\r
- sizeof(sockAddr)))\r
- {\r
- if (false == forceStart)\r
- {\r
- OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Failed to bind socket[%s]. Trying again..",\r
- strerror(errno));\r
-\r
- //Set the port to next one\r
- serverPort += 1;\r
- sockAddr.sin_port = htons(serverPort);\r
- continue;\r
- }\r
- else\r
- {\r
- OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Failed to bind socket[%s]!",\r
- strerror(errno));\r
- break;\r
- }\r
- }\r
-\r
- isBound = true;\r
- break;\r
- }\r
-\r
- if (false == isBound)\r
- {\r
- close(sock);\r
- return CA_STATUS_FAILED;\r
- }\r
-\r
- *port = serverPort;\r
- *socketFD = sock;\r
- return CA_STATUS_OK;\r
-}\r
-\r
-static CAResult_t CAWiFiCloseSocket(int32_t *socketFD)\r
-{\r
- if (-1 == *socketFD)\r
- {\r
- OIC_LOG(INFO, WIFI_SERVER_TAG, "Server not running");\r
- return CA_SERVER_NOT_STARTED;\r
- }\r
-\r
- // close the socket\r
- if (-1 == close(*socketFD))\r
- {\r
- OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Failed to close the socket, Error code: %s\n",\r
- strerror(errno));\r
- return CA_STATUS_FAILED;\r
- }\r
-\r
- *socketFD = -1;\r
- return CA_STATUS_OK;\r
-}\r
-\r
-static CAResult_t CAStartUnicastServer(const char *localAddress, int16_t *port,\r
- const bool forceStart, bool isSecured, int32_t *serverFD)\r
-{\r
- OIC_LOG(DEBUG, WIFI_SERVER_TAG, "IN");\r
-\r
- CAResult_t ret = CAWiFiCreateSocket(serverFD, localAddress, port, forceStart);\r
- if (CA_STATUS_OK != ret)\r
- {\r
- OIC_LOG(ERROR, WIFI_SERVER_TAG, "Failed to create unicast socket");\r
- return ret;\r
- }\r
-\r
- /**\r
- * The task to listen for data from unicast socket is added to the thread pool.\r
- * This is a blocking call is made where we try to receive some data..\r
- * We will keep waiting until some data is received.\r
- * This task will be terminated when thread pool is freed on stopping the adapters.\r
- * Thread context will be freed by thread on exit.\r
- */\r
- CAAdapterReceiveThreadContext_t *ctx = (CAAdapterReceiveThreadContext_t *)\r
- OICMalloc(sizeof(CAAdapterReceiveThreadContext_t));\r
- if (!ctx)\r
- {\r
- OIC_LOG(ERROR, WIFI_SERVER_TAG, "Out of memory!");\r
- close(*serverFD);\r
- return CA_MEMORY_ALLOC_FAILED;\r
- }\r
-\r
- ctx->stopFlag = &gStopUnicast;\r
- ctx->socket_fd = *serverFD;\r
- ctx->type = isSecured ? CA_SECURED_UNICAST_SERVER : CA_UNICAST_SERVER;\r
- if (CA_STATUS_OK != u_thread_pool_add_task(gThreadPool, CAReceiveHandler, (void *)ctx))\r
- {\r
- OIC_LOG(ERROR, WIFI_SERVER_TAG, "Failed to create read thread!");\r
- OICFree((void *)ctx);\r
- close(*serverFD);\r
- return CA_STATUS_FAILED;\r
- }\r
-\r
- OIC_LOG(DEBUG, WIFI_SERVER_TAG, "OUT");\r
- return CA_STATUS_OK;\r
-}\r
-\r
-static void CAWiFiServerDestroyMutex(void)\r
-{\r
- OIC_LOG(DEBUG, WIFI_SERVER_TAG, "IN");\r
-\r
- if (gMutexUnicastServer)\r
- {\r
- u_mutex_free(gMutexUnicastServer);\r
- gMutexUnicastServer = NULL;\r
- }\r
-\r
-#ifdef __WITH_DTLS__\r
- if (gMutexSecureUnicastServer)\r
- {\r
- u_mutex_free(gMutexSecureUnicastServer);\r
- gMutexSecureUnicastServer = NULL;\r
- }\r
-#endif\r
-\r
- if (gMutexMulticastServer)\r
- {\r
- u_mutex_free(gMutexMulticastServer);\r
- gMutexMulticastServer = NULL;\r
- }\r
-\r
- OIC_LOG(DEBUG, WIFI_SERVER_TAG, "OUT");\r
-}\r
-\r
-static CAResult_t CAWiFiServerCreateMutex(void)\r
-{\r
- OIC_LOG(DEBUG, WIFI_SERVER_TAG, "IN");\r
-\r
- gMutexUnicastServer = u_mutex_new();\r
- if (!gMutexUnicastServer)\r
- {\r
- OIC_LOG(ERROR, WIFI_SERVER_TAG, "Failed to created mutex!");\r
- return CA_STATUS_FAILED;\r
- }\r
-\r
-#ifdef __WITH_DTLS__\r
- gMutexSecureUnicastServer = u_mutex_new();\r
- if (!gMutexSecureUnicastServer)\r
- {\r
- OIC_LOG(ERROR, WIFI_SERVER_TAG, "Failed to created mutex!");\r
-\r
- CAWiFiServerDestroyMutex();\r
- return CA_STATUS_FAILED;\r
- }\r
-#endif\r
-\r
- gMutexMulticastServer = u_mutex_new();\r
- if (!gMutexMulticastServer)\r
- {\r
- OIC_LOG(ERROR, WIFI_SERVER_TAG, "Failed to created mutex!");\r
-\r
- CAWiFiServerDestroyMutex();\r
- return CA_STATUS_FAILED;\r
- }\r
-\r
- OIC_LOG(DEBUG, WIFI_SERVER_TAG, "OUT");\r
- return CA_STATUS_OK;\r
-}\r
-\r
-CAResult_t CAWiFiInitializeServer(const u_thread_pool_t threadPool)\r
-{\r
- OIC_LOG(DEBUG, WIFI_SERVER_TAG, "IN");\r
-\r
- // Input validation\r
- VERIFY_NON_NULL(threadPool, WIFI_SERVER_TAG, "Thread pool handle is NULL");\r
-\r
- // Initialize mutex\r
- if (CA_STATUS_OK != CAWiFiServerCreateMutex())\r
- {\r
- OIC_LOG(ERROR, WIFI_SERVER_TAG, "Failed to create mutex!");\r
- return CA_STATUS_FAILED;\r
- }\r
-\r
- gThreadPool = threadPool;\r
-\r
- OIC_LOG(DEBUG, WIFI_SERVER_TAG, "OUT");\r
- return CA_STATUS_OK;\r
-}\r
-\r
-void CAWiFiTerminateServer(void)\r
-{\r
- OIC_LOG(DEBUG, WIFI_SERVER_TAG, "IN");\r
-\r
- gThreadPool = NULL;\r
-\r
- // Destroy mutex\r
- CAWiFiServerDestroyMutex();\r
-\r
- OIC_LOG(DEBUG, WIFI_SERVER_TAG, "OUT");\r
-}\r
-\r
-CAResult_t CAWiFiStartUnicastServer(const char *localAddress, int16_t *port,\r
- const bool forceStart, const CABool_t isSecured,\r
- int32_t *serverFD)\r
-{\r
- OIC_LOG(DEBUG, WIFI_SERVER_TAG, "IN");\r
-\r
- // Input validation\r
- VERIFY_NON_NULL(localAddress, WIFI_SERVER_TAG, "localAddress");\r
- VERIFY_NON_NULL(port, WIFI_SERVER_TAG, "port");\r
- VERIFY_NON_NULL(serverFD, WIFI_SERVER_TAG, "server socket FD");\r
-\r
- if (0 >= *port)\r
- {\r
- OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Invalid input: port is invalid!");\r
- return CA_STATUS_INVALID_PARAM;\r
- }\r
-\r
- *serverFD = -1;\r
- if (CA_FALSE == isSecured)\r
- {\r
- u_mutex_lock(gMutexUnicastServer);\r
- if (-1 != gUnicastServerSocketFD)\r
- {\r
- OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Unicast Server is Started Already!",\r
- CA_SERVER_STARTED_ALREADY);\r
-\r
- *serverFD = gUnicastServerSocketFD;\r
- u_mutex_unlock(gMutexUnicastServer);\r
- return CA_SERVER_STARTED_ALREADY;\r
- }\r
-\r
- gStopUnicast = false;\r
- if (CA_STATUS_OK != CAStartUnicastServer(localAddress, port, forceStart, isSecured,\r
- &gUnicastServerSocketFD))\r
- {\r
- OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Failed to start unicast server!");\r
- gUnicastServerSocketFD = -1;\r
- u_mutex_unlock(gMutexUnicastServer);\r
- return CA_STATUS_FAILED;\r
- }\r
-\r
- *serverFD = gUnicastServerSocketFD;\r
- u_mutex_unlock(gMutexUnicastServer);\r
- }\r
-#ifdef __WITH_DTLS__\r
- else // Start unicast server for secured communication\r
- {\r
- u_mutex_lock(gMutexSecureUnicastServer);\r
- if (-1 != gSecureUnicastServerSocketFD)\r
- {\r
- OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Unicast Server is Started Already!",\r
- CA_SERVER_STARTED_ALREADY);\r
-\r
- *serverFD = gSecureUnicastServerSocketFD;\r
- u_mutex_unlock(gMutexSecureUnicastServer);\r
- return CA_SERVER_STARTED_ALREADY;\r
- }\r
-\r
- gStopSecureUnicast = false;\r
- if (CA_STATUS_OK != CAStartUnicastServer(localAddress, port, forceStart, isSecured,\r
- &gSecureUnicastServerSocketFD))\r
- {\r
- OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Failed to start unicast server!");\r
- gSecureUnicastServerSocketFD = -1;\r
- u_mutex_unlock(gMutexSecureUnicastServer);\r
- return CA_STATUS_FAILED;\r
- }\r
-\r
- *serverFD = gSecureUnicastServerSocketFD;\r
- u_mutex_unlock(gMutexSecureUnicastServer);\r
- }\r
-#endif\r
- OIC_LOG(DEBUG, WIFI_SERVER_TAG, "OUT");\r
- return CA_STATUS_OK;\r
-}\r
-\r
-CAResult_t CAWiFiStartMulticastServer(const char *localAddress, const char *multicastAddress,\r
- const int16_t multicastPort, int32_t *serverFD)\r
-{\r
- OIC_LOG(DEBUG, WIFI_SERVER_TAG, "IN");\r
-\r
- // Input validation\r
- VERIFY_NON_NULL(localAddress, WIFI_SERVER_TAG, "localAddress");\r
- VERIFY_NON_NULL(multicastAddress, WIFI_SERVER_TAG, "port");\r
- VERIFY_NON_NULL(serverFD, WIFI_SERVER_TAG, "server socket FD");\r
-\r
- int16_t port = multicastPort;\r
- if (0 >= port)\r
- {\r
- OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Invalid input: Multicast port is invalid!");\r
- return CA_STATUS_INVALID_PARAM;\r
- }\r
-\r
- u_mutex_lock(gMutexMulticastServer);\r
-\r
- if (gMulticastServerSocketFD != -1)\r
- {\r
- OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Multicast Server is already running!");\r
- u_mutex_unlock(gMutexMulticastServer);\r
- return CA_SERVER_STARTED_ALREADY;\r
- }\r
-\r
- CAResult_t ret = CAWiFiCreateSocket(&gMulticastServerSocketFD, multicastAddress, &port, true);\r
- if (ret != CA_STATUS_OK)\r
- {\r
- OIC_LOG(ERROR, WIFI_SERVER_TAG, "Failed to create multicast socket");\r
- u_mutex_unlock(gMutexMulticastServer);\r
- return ret;\r
- }\r
-\r
- // Add membership to receiving socket (join group)\r
- memset(&gMulticastMemberReq, 0, sizeof(struct ip_mreq));\r
- gMulticastMemberReq.imr_interface.s_addr = inet_addr(localAddress);\r
- inet_aton(multicastAddress, &gMulticastMemberReq.imr_multiaddr);\r
-\r
- if (-1 == setsockopt(gMulticastServerSocketFD, IPPROTO_IP, IP_ADD_MEMBERSHIP,\r
- (char *) &gMulticastMemberReq,\r
- sizeof(struct ip_mreq)))\r
- {\r
- OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Failed to add to multicast group, Error code: %s\n",\r
- strerror(errno));\r
- close(gMulticastServerSocketFD);\r
- gMulticastServerSocketFD = -1;\r
- u_mutex_unlock(gMutexMulticastServer);\r
- return CA_STATUS_FAILED;\r
- }\r
-\r
- /**\r
- * The task to listen to data from multicastcast socket is added to the thread pool.\r
- * This is a blocking call is made where we try to receive some data.\r
- * We will keep waiting until some data is received.\r
- * This task will be terminated when thread pool is freed on stopping the adapters.\r
- * Thread context will be freed by thread on exit.\r
- */\r
- CAAdapterReceiveThreadContext_t *ctx = (CAAdapterReceiveThreadContext_t *)\r
- OICMalloc(sizeof(CAAdapterReceiveThreadContext_t));\r
- if (!ctx)\r
- {\r
- OIC_LOG(ERROR, WIFI_SERVER_TAG, "Out of memory!");\r
- close(gMulticastServerSocketFD);\r
- gMulticastServerSocketFD = -1;\r
- return CA_MEMORY_ALLOC_FAILED;\r
- }\r
-\r
- ctx->stopFlag = &gStopMulticast;\r
- ctx->socket_fd = gMulticastServerSocketFD;\r
- ctx->type = CA_MULTICAST_SERVER;\r
-\r
- gStopMulticast = false;\r
- if (CA_STATUS_OK != u_thread_pool_add_task(gThreadPool, CAReceiveHandler, (void *)ctx))\r
- {\r
- OIC_LOG(ERROR, WIFI_SERVER_TAG, "thread_pool_add_task failed!");\r
-\r
- close(gMulticastServerSocketFD);\r
- gMulticastServerSocketFD = -1;\r
- gStopMulticast = true;\r
- u_mutex_unlock(gMutexMulticastServer);\r
- return CA_STATUS_FAILED;\r
- }\r
-\r
- *serverFD = gMulticastServerSocketFD;\r
- strncpy(gMulticastServerInterface, localAddress, IPNAMESIZE);\r
- u_mutex_unlock(gMutexMulticastServer);\r
-\r
- OIC_LOG(DEBUG, WIFI_SERVER_TAG, "OUT");\r
- return CA_STATUS_OK;\r
-}\r
-\r
-CAResult_t CAWiFiStopUnicastServer()\r
-{\r
- OIC_LOG(DEBUG, WIFI_SERVER_TAG, "IN");\r
-\r
- u_mutex_lock(gMutexUnicastServer);\r
- gStopUnicast = true;\r
- CAResult_t ret = CAWiFiCloseSocket(&gUnicastServerSocketFD);\r
- u_mutex_unlock(gMutexUnicastServer);\r
-\r
- OIC_LOG_V(INFO, WIFI_SERVER_TAG, "Unicast server stopped [%d]", ret);\r
- return ret;\r
-}\r
-\r
-#ifdef __WITH_DTLS__\r
-CAResult_t CAWiFiStopSecureUnicastServer()\r
-{\r
- OIC_LOG(DEBUG, WIFI_SERVER_TAG, "IN");\r
-\r
- u_mutex_lock(gMutexSecureUnicastServer);\r
- gStopSecureUnicast = true;\r
- CAResult_t ret = CAWiFiCloseSocket(&gSecureUnicastServerSocketFD);\r
- u_mutex_unlock(gMutexSecureUnicastServer);\r
-\r
- OIC_LOG_V(INFO, WIFI_SERVER_TAG, "Secured unicast server stopped [%d]", ret);\r
- return ret;\r
-}\r
-#endif\r
-\r
-CAResult_t CAWiFiStopMulticastServer(void)\r
-{\r
- OIC_LOG(DEBUG, WIFI_SERVER_TAG, "IN");\r
-\r
- u_mutex_lock(gMutexMulticastServer);\r
-\r
- if (gMulticastServerSocketFD == -1)\r
- {\r
- OIC_LOG(INFO, WIFI_SERVER_TAG, "Multicast server is not yet started");\r
- u_mutex_unlock(gMutexMulticastServer);\r
- return CA_SERVER_NOT_STARTED;\r
- }\r
-\r
- gStopMulticast = true;\r
-\r
- // leave the group after you are done\r
- if (-1 == setsockopt(gMulticastServerSocketFD, IPPROTO_IP, IP_DROP_MEMBERSHIP,\r
- (char *)&gMulticastMemberReq,\r
- sizeof(struct ip_mreq)))\r
- {\r
- OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Failed to leave multicast group, Error code: %s\n",\r
- strerror(errno));\r
- }\r
-\r
- CAResult_t ret = CAWiFiCloseSocket(&gMulticastServerSocketFD);\r
- u_mutex_unlock(gMutexMulticastServer);\r
-\r
- OIC_LOG_V(INFO, WIFI_SERVER_TAG, "Multicast server stopped [%d]", ret);\r
- return ret;\r
-}\r
-\r
-CAResult_t CAWiFiGetUnicastServerInfo(const CABool_t isSecured, char **ipAddress,\r
- int16_t *port, int32_t *serverFD)\r
-{\r
- OIC_LOG(DEBUG, WIFI_SERVER_TAG, "IN");\r
-\r
- // Input validation\r
- VERIFY_NON_NULL(ipAddress, WIFI_SERVER_TAG, "IP address");\r
- VERIFY_NON_NULL(port, WIFI_SERVER_TAG, "Port");\r
- VERIFY_NON_NULL(serverFD, WIFI_SERVER_TAG, "Server ID");\r
-\r
- struct sockaddr_in sockAddr;\r
- socklen_t len = sizeof(struct sockaddr_in);\r
- if (-1 == getsockname(gUnicastServerSocketFD, (struct sockaddr *)&sockAddr, &len))\r
- {\r
- OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Failed in getsockname [%s]!", strerror(errno));\r
- return CA_STATUS_FAILED;\r
- }\r
-\r
-\r
- const char *serverAddress = inet_ntoa(sockAddr.sin_addr);\r
- *ipAddress = (serverAddress) ? strndup(serverAddress, strlen(serverAddress)) : NULL;\r
- *port = ntohs(sockAddr.sin_port);\r
-#ifdef __WITH_DTLS__\r
- *serverFD = (CA_TRUE == isSecured) ? gSecureUnicastServerSocketFD : gUnicastServerSocketFD;\r
-#else\r
- *serverFD = gUnicastServerSocketFD;\r
-#endif\r
- OIC_LOG(DEBUG, WIFI_SERVER_TAG, "OUT");\r
- return CA_STATUS_OK;\r
-}\r
-\r
-void CAWiFiSetPacketReceiveCallback(CAWiFiPacketReceivedCallback callback)\r
-{\r
- OIC_LOG(DEBUG, WIFI_SERVER_TAG, "IN");\r
-\r
- gPacketReceivedCallback = callback;\r
-}\r
-\r
-void CAWiFiSetExceptionCallback(CAWiFiExceptionCallback callback)\r
-{\r
- OIC_LOG(DEBUG, WIFI_SERVER_TAG, "IN");\r
-\r
- gExceptionCallback = callback;\r
-}\r
-\r
-\r
+/******************************************************************
+*
+* Copyright 2014 Samsung Electronics All Rights Reserved.
+*
+*
+*
+* Licensed 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 "cawifiinterface.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/select.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <errno.h>
+
+#include "pdu.h"
+#include "caadapterutils.h"
+#ifdef __WITH_DTLS__
+#include "caadapternetdtls.h"
+#endif
+#include "umutex.h"
+
+/**
+ * @def WIFI_SERVER_TAG
+ * @brief Logging tag for module name
+ */
+#define WIFI_SERVER_TAG "WIFI_SERVER"
+
+/**
+ * @def CA_UDP_BIND_RETRY_COUNT
+ * @brief Retry count in case of socket bind failure.
+ */
+#define CA_UDP_BIND_RETRY_COUNT 10
+
+/**
+ * @def IPNAMESIZE
+ * @brief max length for ip
+ */
+#define IPNAMESIZE 16
+
+/**
+ * @var gUnicastServerSocketFD
+ * @brief Unicast server socket descriptor
+ */
+static int32_t gUnicastServerSocketFD = -1;
+
+/**
+ * @var gMutexUnicastServer
+ * @brief Mutex to synchronize unicast server
+ */
+static u_mutex gMutexUnicastServer = NULL;
+
+/**
+ * @var gStopUnicast
+ * @brief Flag to control the Receive Unicast Data Thread
+ */
+static bool gStopUnicast = false;
+
+/**
+ * @var gMulticastServerSocketFD
+ * @brief socket descriptor for multicast server
+ */
+static int32_t gMulticastServerSocketFD = -1;
+
+/**
+ * @var gMutexMulticastServer
+ * @brief Mutex to synchronize secure multicast server
+ */
+static u_mutex gMutexMulticastServer = NULL;
+
+/**
+ * @var gStopMulticast
+ * @brief Flag to control the Receive Multicast Data Thread
+ */
+static bool gStopMulticast = false;
+
+#ifdef __WITH_DTLS__
+/**
+ * @var gSecureUnicastServerSocketFD
+ * @brief Secure unicast server socket descriptor
+ */
+static int32_t gSecureUnicastServerSocketFD = -1;
+
+/**
+ * @var gMutexSecureUnicastServer
+ * @brief Mutex to synchronize secure unicast server
+ */
+static u_mutex gMutexSecureUnicastServer = NULL;
+
+/**
+ * @var gStopSecureUnicast
+ * @brief Flag to control the unicast secure data receive thread
+ */
+static bool gStopSecureUnicast = false;
+#endif
+
+/**
+ * @var gThreadPool
+ * @brief ThreadPool for storing u_thread_pool_t handle passed from adapter
+ */
+static u_thread_pool_t gThreadPool = NULL;
+
+/**
+ * @var gMulticastServerInterface
+ * @brief Local interface on which multicast server is running
+ */
+static char gMulticastServerInterface[IPNAMESIZE];
+
+/**
+ * @var gMulticastMemberReq
+ * @brief ip_mreq structure passed to join a multicast group
+ */
+static struct ip_mreq gMulticastMemberReq;
+
+/**
+ * @var gPacketReceivedCallback
+ * @brief Callback for notifying the upper layer on receival data from remote OIC device
+ */
+static CAWiFiPacketReceivedCallback gPacketReceivedCallback = NULL;
+
+/**
+ * @var gExceptionCallback
+ * @brief Callback for notifying the upper layer when unicast/multicast server encounters exception
+ */
+static CAWiFiExceptionCallback gExceptionCallback = NULL;
+
+/**
+ @brief Thread context information for unicast, multicast and secured unicast server
+ */
+typedef struct
+{
+ bool *stopFlag;
+ int32_t socket_fd;
+ CAAdapterServerType_t type;
+} CAAdapterReceiveThreadContext_t;
+
+static void CAReceiveHandler(void *data)
+{
+ OIC_LOG(DEBUG, WIFI_SERVER_TAG, "IN");
+ // Input validation
+ VERIFY_NON_NULL_VOID(data, WIFI_SERVER_TAG, "Invalid thread context");
+
+ CAAdapterReceiveThreadContext_t *ctx = (CAAdapterReceiveThreadContext_t *)data;
+ fd_set reads;
+ struct timeval timeout;
+ char recvBuffer[COAP_MAX_PDU_SIZE] = {0};
+
+ while (true != *(ctx->stopFlag))
+ {
+ timeout.tv_sec = 1;
+ timeout.tv_usec = 0;
+
+ FD_ZERO(&reads);
+ FD_SET(ctx->socket_fd, &reads);
+
+ int32_t ret = select(ctx->socket_fd + 1, &reads, NULL, NULL, &timeout);
+ if (*(ctx->stopFlag) == true)
+ {
+ OIC_LOG_V(DEBUG, WIFI_SERVER_TAG, "Stop request received for [%d] server", ctx->type);
+ break;
+ }
+ if (ret < 0)
+ {
+ OIC_LOG_V(FATAL, WIFI_SERVER_TAG, "select returned error %s", strerror(errno));
+ continue;
+ }
+ if (!FD_ISSET(ctx->socket_fd, &reads))
+ {
+ continue;
+ }
+
+ memset(recvBuffer, 0, sizeof(recvBuffer));
+
+ // Read data from socket
+ struct sockaddr_in srcSockAddress;
+ int32_t recvLen;
+ socklen_t srcAddressLen = sizeof(srcSockAddress);
+ if (-1 == (recvLen = recvfrom(ctx->socket_fd, recvBuffer,
+ sizeof(recvBuffer), 0, (struct sockaddr *) &srcSockAddress,
+ &srcAddressLen)))
+ {
+ OIC_LOG_V(DEBUG, WIFI_SERVER_TAG, "%s", strerror(errno));
+ continue;
+ }
+ else if (0 == recvLen)
+ {
+ OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Server socket shutdown [%d]!", ctx->type);
+
+ // Notify upper layer this exception
+ if (gExceptionCallback)
+ {
+ gExceptionCallback(ctx->type);
+ }
+ OICFree(ctx);
+ return;
+ }
+
+ const char *srcIPAddress = NULL;
+ int32_t srcPort = -1;
+
+ srcIPAddress = inet_ntoa(srcSockAddress.sin_addr);
+ srcPort = ntohs(srcSockAddress.sin_port);
+
+ OIC_LOG_V(DEBUG, WIFI_SERVER_TAG, "Received packet from %s:%d\n",
+ srcIPAddress, srcPort);
+ OIC_LOG_V(DEBUG, WIFI_SERVER_TAG, "Data: %s\t, DataLength: %d\n",
+ recvBuffer, recvLen);
+
+ char *netMask = NULL;
+ if (CA_STATUS_OK != CAWiFiGetInterfaceSubnetMask(&netMask))
+ {
+ OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Failed to get ethernet subnet");
+ continue;
+ }
+
+ if (!CAAdapterIsSameSubnet(gMulticastServerInterface, srcIPAddress, netMask))
+ {
+ OIC_LOG(DEBUG, WIFI_SERVER_TAG, "Packet received from different subnet, Ignore!");
+ if (NULL != netMask)
+ {
+ OICFree(netMask);
+ }
+ netMask = NULL;
+ continue;
+ }
+
+ OICFree(netMask);
+ switch (ctx->type)
+ {
+ case CA_UNICAST_SERVER:
+ case CA_MULTICAST_SERVER:
+ // Notify data to upper layer
+ if (gPacketReceivedCallback)
+ {
+ gPacketReceivedCallback(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_WIFI);
+ OIC_LOG_V(DEBUG, WIFI_SERVER_TAG, "CAAdapterNetDtlsDecrypt returns [%d]", ret);
+ }
+ break;
+#endif //__WITH_DTLS__
+ default:
+ // Should never occur
+ OIC_LOG_V(DEBUG, WIFI_SERVER_TAG, "Invalid server type");
+ OICFree(ctx);
+ return;
+ }
+ }
+
+ // free context
+ OICFree(ctx);
+
+ OIC_LOG(DEBUG, WIFI_SERVER_TAG, "OUT");
+}
+
+static CAResult_t CAWiFiCreateSocket(int32_t *socketFD, const char *localIp, int16_t *port,
+ const bool forceStart)
+{
+ int32_t sock = -1;
+ // Create a UDP socket
+ if (-1 == (sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)))
+ {
+ OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Failed to create Socket, Error code: %s",
+ strerror(errno));
+ return CA_STATUS_FAILED;
+ }
+
+ // Make the socket non-blocking
+ if (-1 == fcntl(sock, F_SETFL, O_NONBLOCK))
+ {
+ OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Failed to set non-block mode, Error code: %s",
+ strerror(errno));
+
+ close(sock);
+ return CA_STATUS_FAILED;
+ }
+
+ if (true == forceStart)
+ {
+ int32_t setOptionOn = 1;
+ if (-1 == setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
+ (char *) &setOptionOn,
+ sizeof(setOptionOn)))
+ {
+ OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Failed to set SO_REUSEADDR! Error code: %s",
+ strerror(errno));
+
+ close(sock);
+ return CA_STATUS_FAILED;
+ }
+ }
+
+ struct sockaddr_in sockAddr;
+ bool isBound = false;
+ int16_t serverPort = *port;
+
+ memset((char *) &sockAddr, 0, sizeof(sockAddr));
+ sockAddr.sin_family = AF_INET;
+ sockAddr.sin_port = htons(serverPort);
+ if (localIp)
+ {
+ sockAddr.sin_addr.s_addr = inet_addr(localIp);
+ }
+ else
+ {
+ sockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
+ }
+
+ int16_t i;
+ for (i = 0; i < CA_UDP_BIND_RETRY_COUNT; i++)
+ {
+ if (-1 == bind(sock, (struct sockaddr *) &sockAddr,
+ sizeof(sockAddr)))
+ {
+ if (false == forceStart)
+ {
+ OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Failed to bind socket[%s]. Trying again..",
+ strerror(errno));
+
+ //Set the port to next one
+ serverPort += 1;
+ sockAddr.sin_port = htons(serverPort);
+ continue;
+ }
+ else
+ {
+ OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Failed to bind socket[%s]!",
+ strerror(errno));
+ break;
+ }
+ }
+
+ isBound = true;
+ break;
+ }
+
+ if (false == isBound)
+ {
+ close(sock);
+ return CA_STATUS_FAILED;
+ }
+
+ *port = serverPort;
+ *socketFD = sock;
+ return CA_STATUS_OK;
+}
+
+static CAResult_t CAWiFiCloseSocket(int32_t *socketFD)
+{
+ if (-1 == *socketFD)
+ {
+ OIC_LOG(INFO, WIFI_SERVER_TAG, "Server not running");
+ return CA_SERVER_NOT_STARTED;
+ }
+
+ // close the socket
+ if (-1 == close(*socketFD))
+ {
+ OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Failed to close the socket, Error code: %s\n",
+ strerror(errno));
+ return CA_STATUS_FAILED;
+ }
+
+ *socketFD = -1;
+ return CA_STATUS_OK;
+}
+
+static CAResult_t CAStartUnicastServer(const char *localAddress, int16_t *port,
+ const bool forceStart, bool isSecured, int32_t *serverFD)
+{
+ OIC_LOG(DEBUG, WIFI_SERVER_TAG, "IN");
+
+ CAResult_t ret = CAWiFiCreateSocket(serverFD, localAddress, port, forceStart);
+ if (CA_STATUS_OK != ret)
+ {
+ OIC_LOG(ERROR, WIFI_SERVER_TAG, "Failed to create unicast socket");
+ return ret;
+ }
+
+ /**
+ * 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, WIFI_SERVER_TAG, "Out of memory!");
+ close(*serverFD);
+ return CA_MEMORY_ALLOC_FAILED;
+ }
+
+ ctx->stopFlag = &gStopUnicast;
+ ctx->socket_fd = *serverFD;
+ ctx->type = isSecured ? CA_SECURED_UNICAST_SERVER : CA_UNICAST_SERVER;
+ if (CA_STATUS_OK != u_thread_pool_add_task(gThreadPool, CAReceiveHandler, (void *)ctx))
+ {
+ OIC_LOG(ERROR, WIFI_SERVER_TAG, "Failed to create read thread!");
+ OICFree((void *)ctx);
+ close(*serverFD);
+ return CA_STATUS_FAILED;
+ }
+
+ OIC_LOG(DEBUG, WIFI_SERVER_TAG, "OUT");
+ return CA_STATUS_OK;
+}
+
+static void CAWiFiServerDestroyMutex(void)
+{
+ OIC_LOG(DEBUG, WIFI_SERVER_TAG, "IN");
+
+ if (gMutexUnicastServer)
+ {
+ u_mutex_free(gMutexUnicastServer);
+ gMutexUnicastServer = NULL;
+ }
+
+#ifdef __WITH_DTLS__
+ if (gMutexSecureUnicastServer)
+ {
+ u_mutex_free(gMutexSecureUnicastServer);
+ gMutexSecureUnicastServer = NULL;
+ }
+#endif
+
+ if (gMutexMulticastServer)
+ {
+ u_mutex_free(gMutexMulticastServer);
+ gMutexMulticastServer = NULL;
+ }
+
+ OIC_LOG(DEBUG, WIFI_SERVER_TAG, "OUT");
+}
+
+static CAResult_t CAWiFiServerCreateMutex(void)
+{
+ OIC_LOG(DEBUG, WIFI_SERVER_TAG, "IN");
+
+ gMutexUnicastServer = u_mutex_new();
+ if (!gMutexUnicastServer)
+ {
+ OIC_LOG(ERROR, WIFI_SERVER_TAG, "Failed to created mutex!");
+ return CA_STATUS_FAILED;
+ }
+
+#ifdef __WITH_DTLS__
+ gMutexSecureUnicastServer = u_mutex_new();
+ if (!gMutexSecureUnicastServer)
+ {
+ OIC_LOG(ERROR, WIFI_SERVER_TAG, "Failed to created mutex!");
+
+ CAWiFiServerDestroyMutex();
+ return CA_STATUS_FAILED;
+ }
+#endif
+
+ gMutexMulticastServer = u_mutex_new();
+ if (!gMutexMulticastServer)
+ {
+ OIC_LOG(ERROR, WIFI_SERVER_TAG, "Failed to created mutex!");
+
+ CAWiFiServerDestroyMutex();
+ return CA_STATUS_FAILED;
+ }
+
+ OIC_LOG(DEBUG, WIFI_SERVER_TAG, "OUT");
+ return CA_STATUS_OK;
+}
+
+CAResult_t CAWiFiInitializeServer(const u_thread_pool_t threadPool)
+{
+ OIC_LOG(DEBUG, WIFI_SERVER_TAG, "IN");
+
+ // Input validation
+ VERIFY_NON_NULL(threadPool, WIFI_SERVER_TAG, "Thread pool handle is NULL");
+
+ // Initialize mutex
+ if (CA_STATUS_OK != CAWiFiServerCreateMutex())
+ {
+ OIC_LOG(ERROR, WIFI_SERVER_TAG, "Failed to create mutex!");
+ return CA_STATUS_FAILED;
+ }
+
+ gThreadPool = threadPool;
+
+ OIC_LOG(DEBUG, WIFI_SERVER_TAG, "OUT");
+ return CA_STATUS_OK;
+}
+
+void CAWiFiTerminateServer(void)
+{
+ OIC_LOG(DEBUG, WIFI_SERVER_TAG, "IN");
+
+ gThreadPool = NULL;
+
+ // Destroy mutex
+ CAWiFiServerDestroyMutex();
+
+ OIC_LOG(DEBUG, WIFI_SERVER_TAG, "OUT");
+}
+
+CAResult_t CAWiFiStartUnicastServer(const char *localAddress, int16_t *port,
+ const bool forceStart, const CABool_t isSecured,
+ int32_t *serverFD)
+{
+ OIC_LOG(DEBUG, WIFI_SERVER_TAG, "IN");
+
+ // Input validation
+ VERIFY_NON_NULL(localAddress, WIFI_SERVER_TAG, "localAddress");
+ VERIFY_NON_NULL(port, WIFI_SERVER_TAG, "port");
+ VERIFY_NON_NULL(serverFD, WIFI_SERVER_TAG, "server socket FD");
+
+ if (0 >= *port)
+ {
+ OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Invalid input: port is invalid!");
+ return CA_STATUS_INVALID_PARAM;
+ }
+
+ *serverFD = -1;
+ if (CA_FALSE == isSecured)
+ {
+ u_mutex_lock(gMutexUnicastServer);
+ if (-1 != gUnicastServerSocketFD)
+ {
+ OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Unicast Server is Started Already!",
+ CA_SERVER_STARTED_ALREADY);
+
+ *serverFD = gUnicastServerSocketFD;
+ u_mutex_unlock(gMutexUnicastServer);
+ return CA_SERVER_STARTED_ALREADY;
+ }
+
+ gStopUnicast = false;
+ if (CA_STATUS_OK != CAStartUnicastServer(localAddress, port, forceStart, isSecured,
+ &gUnicastServerSocketFD))
+ {
+ OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Failed to start unicast server!");
+ gUnicastServerSocketFD = -1;
+ u_mutex_unlock(gMutexUnicastServer);
+ return CA_STATUS_FAILED;
+ }
+
+ *serverFD = gUnicastServerSocketFD;
+ u_mutex_unlock(gMutexUnicastServer);
+ }
+#ifdef __WITH_DTLS__
+ else // Start unicast server for secured communication
+ {
+ u_mutex_lock(gMutexSecureUnicastServer);
+ if (-1 != gSecureUnicastServerSocketFD)
+ {
+ OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Unicast Server is Started Already!",
+ CA_SERVER_STARTED_ALREADY);
+
+ *serverFD = gSecureUnicastServerSocketFD;
+ u_mutex_unlock(gMutexSecureUnicastServer);
+ return CA_SERVER_STARTED_ALREADY;
+ }
+
+ gStopSecureUnicast = false;
+ if (CA_STATUS_OK != CAStartUnicastServer(localAddress, port, forceStart, isSecured,
+ &gSecureUnicastServerSocketFD))
+ {
+ OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Failed to start unicast server!");
+ gSecureUnicastServerSocketFD = -1;
+ u_mutex_unlock(gMutexSecureUnicastServer);
+ return CA_STATUS_FAILED;
+ }
+
+ *serverFD = gSecureUnicastServerSocketFD;
+ u_mutex_unlock(gMutexSecureUnicastServer);
+ }
+#endif
+ OIC_LOG(DEBUG, WIFI_SERVER_TAG, "OUT");
+ return CA_STATUS_OK;
+}
+
+CAResult_t CAWiFiStartMulticastServer(const char *localAddress, const char *multicastAddress,
+ const int16_t multicastPort, int32_t *serverFD)
+{
+ OIC_LOG(DEBUG, WIFI_SERVER_TAG, "IN");
+
+ // Input validation
+ VERIFY_NON_NULL(localAddress, WIFI_SERVER_TAG, "localAddress");
+ VERIFY_NON_NULL(multicastAddress, WIFI_SERVER_TAG, "port");
+ VERIFY_NON_NULL(serverFD, WIFI_SERVER_TAG, "server socket FD");
+
+ int16_t port = multicastPort;
+ if (0 >= port)
+ {
+ OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Invalid input: Multicast port is invalid!");
+ return CA_STATUS_INVALID_PARAM;
+ }
+
+ u_mutex_lock(gMutexMulticastServer);
+
+ if (gMulticastServerSocketFD != -1)
+ {
+ OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Multicast Server is already running!");
+ u_mutex_unlock(gMutexMulticastServer);
+ return CA_SERVER_STARTED_ALREADY;
+ }
+
+ CAResult_t ret = CAWiFiCreateSocket(&gMulticastServerSocketFD, multicastAddress, &port, true);
+ if (ret != CA_STATUS_OK)
+ {
+ OIC_LOG(ERROR, WIFI_SERVER_TAG, "Failed to create multicast socket");
+ u_mutex_unlock(gMutexMulticastServer);
+ return ret;
+ }
+
+ // Add membership to receiving socket (join group)
+ memset(&gMulticastMemberReq, 0, sizeof(struct ip_mreq));
+ gMulticastMemberReq.imr_interface.s_addr = inet_addr(localAddress);
+ inet_aton(multicastAddress, &gMulticastMemberReq.imr_multiaddr);
+
+ if (-1 == setsockopt(gMulticastServerSocketFD, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+ (char *) &gMulticastMemberReq,
+ sizeof(struct ip_mreq)))
+ {
+ OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Failed to add to multicast group, Error code: %s\n",
+ strerror(errno));
+ close(gMulticastServerSocketFD);
+ gMulticastServerSocketFD = -1;
+ u_mutex_unlock(gMutexMulticastServer);
+ 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, WIFI_SERVER_TAG, "Out of memory!");
+ close(gMulticastServerSocketFD);
+ gMulticastServerSocketFD = -1;
+ return CA_MEMORY_ALLOC_FAILED;
+ }
+
+ ctx->stopFlag = &gStopMulticast;
+ ctx->socket_fd = gMulticastServerSocketFD;
+ ctx->type = CA_MULTICAST_SERVER;
+
+ gStopMulticast = false;
+ if (CA_STATUS_OK != u_thread_pool_add_task(gThreadPool, CAReceiveHandler, (void *)ctx))
+ {
+ OIC_LOG(ERROR, WIFI_SERVER_TAG, "thread_pool_add_task failed!");
+
+ close(gMulticastServerSocketFD);
+ gMulticastServerSocketFD = -1;
+ gStopMulticast = true;
+ u_mutex_unlock(gMutexMulticastServer);
+ return CA_STATUS_FAILED;
+ }
+
+ *serverFD = gMulticastServerSocketFD;
+ strncpy(gMulticastServerInterface, localAddress, IPNAMESIZE);
+ u_mutex_unlock(gMutexMulticastServer);
+
+ OIC_LOG(DEBUG, WIFI_SERVER_TAG, "OUT");
+ return CA_STATUS_OK;
+}
+
+CAResult_t CAWiFiStopUnicastServer()
+{
+ OIC_LOG(DEBUG, WIFI_SERVER_TAG, "IN");
+
+ u_mutex_lock(gMutexUnicastServer);
+ gStopUnicast = true;
+ CAResult_t ret = CAWiFiCloseSocket(&gUnicastServerSocketFD);
+ u_mutex_unlock(gMutexUnicastServer);
+
+ OIC_LOG_V(INFO, WIFI_SERVER_TAG, "Unicast server stopped [%d]", ret);
+ return ret;
+}
+
+#ifdef __WITH_DTLS__
+CAResult_t CAWiFiStopSecureUnicastServer()
+{
+ OIC_LOG(DEBUG, WIFI_SERVER_TAG, "IN");
+
+ u_mutex_lock(gMutexSecureUnicastServer);
+ gStopSecureUnicast = true;
+ CAResult_t ret = CAWiFiCloseSocket(&gSecureUnicastServerSocketFD);
+ u_mutex_unlock(gMutexSecureUnicastServer);
+
+ OIC_LOG_V(INFO, WIFI_SERVER_TAG, "Secured unicast server stopped [%d]", ret);
+ return ret;
+}
+#endif
+
+CAResult_t CAWiFiStopMulticastServer(void)
+{
+ OIC_LOG(DEBUG, WIFI_SERVER_TAG, "IN");
+
+ u_mutex_lock(gMutexMulticastServer);
+
+ if (gMulticastServerSocketFD == -1)
+ {
+ OIC_LOG(INFO, WIFI_SERVER_TAG, "Multicast server is not yet started");
+ u_mutex_unlock(gMutexMulticastServer);
+ return CA_SERVER_NOT_STARTED;
+ }
+
+ gStopMulticast = true;
+
+ // leave the group after you are done
+ if (-1 == setsockopt(gMulticastServerSocketFD, IPPROTO_IP, IP_DROP_MEMBERSHIP,
+ (char *)&gMulticastMemberReq,
+ sizeof(struct ip_mreq)))
+ {
+ OIC_LOG_V(ERROR, WIFI_SERVER_TAG, "Failed to leave multicast group, Error code: %s\n",
+ strerror(errno));
+ }
+
+ CAResult_t ret = CAWiFiCloseSocket(&gMulticastServerSocketFD);
+ u_mutex_unlock(gMutexMulticastServer);
+
+ OIC_LOG_V(INFO, WIFI_SERVER_TAG, "Multicast server stopped [%d]", ret);
+ return ret;
+}
+
+CAResult_t CAWiFiGetUnicastServerInfo(const CABool_t isSecured, char **ipAddress,
+ int16_t *port, int32_t *serverFD)
+{
+ OIC_LOG(DEBUG, WIFI_SERVER_TAG, "IN");
+
+ // Input validation
+ VERIFY_NON_NULL(ipAddress, WIFI_SERVER_TAG, "IP address");
+ VERIFY_NON_NULL(port, WIFI_SERVER_TAG, "Port");
+ VERIFY_NON_NULL(serverFD, WIFI_SERVER_TAG, "Server ID");
+
+ struct sockaddr_in sockAddr;
+ socklen_t len = sizeof(struct sockaddr_in);
+ if (-1 == getsockname(gUnicastServerSocketFD, (struct sockaddr *)&sockAddr, &len))
+ {
+ OIC_LOG_V(ERROR, WIFI_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 = (CA_TRUE == isSecured) ? gSecureUnicastServerSocketFD : gUnicastServerSocketFD;
+#else
+ *serverFD = gUnicastServerSocketFD;
+#endif
+ OIC_LOG(DEBUG, WIFI_SERVER_TAG, "OUT");
+ return CA_STATUS_OK;
+}
+
+void CAWiFiSetPacketReceiveCallback(CAWiFiPacketReceivedCallback callback)
+{
+ OIC_LOG(DEBUG, WIFI_SERVER_TAG, "IN");
+
+ gPacketReceivedCallback = callback;
+}
+
+void CAWiFiSetExceptionCallback(CAWiFiExceptionCallback callback)
+{
+ OIC_LOG(DEBUG, WIFI_SERVER_TAG, "IN");
+
+ gExceptionCallback = callback;
+}
+
+