-/******************************************************************
-*
-* 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!");
- 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;
- }
- }
-
- 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, "Local address is NULL");
- VERIFY_NON_NULL(multicastAddress, WIFI_SERVER_TAG, "Multicast address is NULL");
-
- 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, sizeof(gMulticastServerInterface));
- 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;
-}
-
-
+/******************************************************************\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
+ 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
+ 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, "Local address is NULL");\r
+ VERIFY_NON_NULL(multicastAddress, WIFI_SERVER_TAG, "Multicast address is NULL");\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, sizeof(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