Commit 9afc07c5 authored by Dave Thaler's avatar Dave Thaler Committed by Dan Mihai

Port TCP adapter to Windows

Port the tcp_adapter directory using similar code as was done in
ip_adapter

Enable building the relevant directories for Windows as target

Change-Id: Ibae7a30cf353a6088bfa133c27edb1ac2449efaa
Signed-off-by: default avatarDave Thaler <dthaler@microsoft.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/10241Tested-by: default avatarjenkins-iotivity <jenkins-iotivity@opendaylight.org>
Reviewed-by: default avatarDan Mihai <Daniel.Mihai@microsoft.com>
parent 1470a2c7
......@@ -116,7 +116,7 @@ if target_os == 'msys_nt':
libcoap_env.AppendUnique(CPPDEFINES = ['_DEFAULT_SOURCE'])
libcoap_env.AppendUnique(CFLAGS = ['-std=c99'])
if target_os in ['linux', 'tizen', 'android', 'ios', 'arduino']:
if target_os in ['linux', 'tizen', 'android', 'ios', 'arduino', 'windows']:
if with_tcp == True:
libcoap_env.AppendUnique(CPPDEFINES = ['WITH_TCP'])
......
......@@ -89,10 +89,11 @@ else:
mbedtls_env = env.Clone()
mbedtls_env.PrependUnique(CPPPATH = [mbedtls_dir])
mbedtls_env.AppendUnique(CPPPATH = [mbedtls_dir+'include/'])
mbedtls_env.AppendUnique(CFLAGS = ['-Wall'])
if 'g++' in mbedtls_env.get('CXX'):
mbedtls_env.AppendUnique(CFLAGS = ['-Wall'])
if mbedtls_env['CC'] != 'cl':
mbedtls_env.AppendUnique(CFLAGS = ['-fPIC'])
if mbedtls_env['CC'] != 'cl':
mbedtls_env.AppendUnique(CFLAGS = ['-fPIC'])
######################################################################
# Source files and Target(s)
......
......@@ -72,6 +72,9 @@ cxx_headers = ['arpa/inet.h',
'stdlib.h',
'string.h',
'strings.h',
'sys/ioctl.h',
'sys/poll.h',
'sys/select.h',
'sys/socket.h',
'sys/stat.h',
'sys/time.h',
......
......@@ -73,18 +73,22 @@
# endif
# define ssize_t SSIZE_T
# define F_OK 0
# define SHUT_RDWR SD_BOTH
# define sleep(SECS) Sleep(1000*(SECS))
# ifdef __cplusplus
# define SUPPORTS_DEFAULT_CTOR
# endif
# include "windows/include/memmem.h"
# include "windows/include/win_sleep.h"
# include "windows/include/pthread_create.h"
#endif
#ifdef HAVE_WINSOCK2_H
# define OPTVAL_T(t) (const char*)(t)
# define OC_CLOSE_SOCKET(s) closesocket(s)
#else
# define OPTVAL_T(t) (t)
# define OC_CLOSE_SOCKET(s) close(s)
#endif
#endif
......@@ -15,6 +15,7 @@ common_env.AppendUnique(CPPPATH = [header])
src_dir = Dir('src').abspath
helper_src = [
os.path.join(src_dir, 'getopt.c'),
os.path.join(src_dir, 'memmem.c'),
os.path.join(src_dir, 'win_sleep.c'),
os.path.join(src_dir, 'snprintf.c'),
os.path.join(src_dir, 'pthread_create.c')
......@@ -27,6 +28,7 @@ static_libwinhelper = win_helper_env.StaticLibrary('win_helper', helper_src)
win_helper_env.InstallTarget(static_libwinhelper, 'win_helper')
win_helper_env.UserInstallTargetLib(static_libwinhelper, 'win_helper')
win_helper_env.UserInstallTargetHeader('include/memmem.h', 'c_common/windows/include', 'memmem.h')
win_helper_env.UserInstallTargetHeader('include/win_sleep.h', 'c_common/windows/include', 'win_sleep.h')
win_helper_env.UserInstallTargetHeader('include/pthread_create.h', 'c_common/windows/include', 'pthread_create.h')
win_helper_env.UserInstallTargetHeader('include/vs12_snprintf.h', 'c_common/windows/include', 'vs12_snprintf.h')
......
/* *****************************************************************
*
* Copyright 2017 Microsoft
*
*
* 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.
*
******************************************************************/
#ifndef MEMMEM_H__
#define MEMMEM_H__
#ifdef __cplusplus
extern "C" {
#endif
void *memmem(const void *haystack, size_t haystackLen, const void *needle, size_t needleLen);
#ifdef __cplusplus
}
#endif
#endif
/* *****************************************************************
*
* Copyright 2016 Microsoft
*
*
* 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 <stddef.h>
#include <memory.h>
void *memmem(const void *haystack, size_t haystackLen, const void *needle, size_t needleLen)
{
if (needleLen == 0)
{
return (void *) haystack;
}
if (haystackLen >= needleLen)
{
for (size_t i = 0; i <= haystackLen - needleLen; i++)
{
if (memcmp(needle, ((char *) haystack) + i, needleLen) == 0)
{
return ((char *) haystack) + i;
}
}
}
return NULL;
}
......@@ -66,7 +66,7 @@ else:
env.AppendUnique(CPPDEFINES = ['NO_IP_ADAPTER'])
if with_tcp == True:
if target_os in ['linux', 'tizen', 'android', 'arduino']:
if target_os in ['linux', 'tizen', 'android', 'arduino', 'windows']:
env.AppendUnique(CPPDEFINES = ['TCP_ADAPTER', 'WITH_TCP'])
print "CA Transport is TCP"
else:
......
......@@ -28,12 +28,6 @@
#include "iotivity_config.h"
#ifndef WITH_ARDUINO
#ifdef TCP_ADAPTER
#define HAVE_SYS_POLL_H
#endif
#endif
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
......@@ -573,9 +567,9 @@ typedef struct
#else
int netlinkFd; /**< netlink */
int shutdownFds[2]; /**< fds used to signal threads to stop */
int maxfd; /**< highest fd (for select) */
#endif
int selectTimeout; /**< in seconds */
int maxfd; /**< highest fd (for select) */
bool started; /**< the IP adapter has started */
bool terminate; /**< the IP adapter needs to stop */
bool ipv6enabled; /**< IPv6 enabled by OCInit flags */
......@@ -612,9 +606,13 @@ typedef struct
void *svrlist; /**< unicast IPv4 TCP server information*/
int selectTimeout; /**< in seconds */
int listenBacklog; /**< backlog counts*/
#if defined(_WIN32)
WSAEVENT shutdownEvent; /**< Event used to signal threads to stop */
#else
int shutdownFds[2]; /**< shutdown pipe */
int connectionFds[2]; /**< connection pipe */
int maxfd; /**< highest fd (for select) */
#endif
bool started; /**< the TCP adapter has started */
bool terminate; /**< the TCP adapter needs to stop */
bool ipv4tcpenabled; /**< IPv4 TCP enabled by OCInit flags */
......
......@@ -206,17 +206,19 @@ void CAClearServerInfoList(u_arraylist_t *serverInfoList);
* @param[in] sockAddrLen size of sockAddr.
* @param[out] host address string (must be CA_IPADDR_SIZE).
* @param[out] port host order port number.
* @return CA_STATUS_OK on success, or an appropriate error code on failure.
*/
void CAConvertAddrToName(const struct sockaddr_storage *sockAddr, socklen_t sockAddrLen,
char *host, uint16_t *port);
CAResult_t CAConvertAddrToName(const struct sockaddr_storage *sockAddr, socklen_t sockAddrLen,
char *host, uint16_t *port);
/**
* Convert address from string to binary.
* @param[in] host address string.
* @param[in] port host order port number.
* @param[out] ipaddr IP address info.
* @return CA_STATUS_OK on success, or an appropriate error code on failure.
*/
void CAConvertNameToAddr(const char *host, uint16_t port, struct sockaddr_storage *sockaddr);
CAResult_t CAConvertNameToAddr(const char *host, uint16_t port, struct sockaddr_storage *sockaddr);
#endif /* WITH_ARDUINO */
#ifdef __JAVA__
......
......@@ -206,13 +206,13 @@ CATCPSessionInfo_t *CAGetTCPSessionInfoFromEndpoint(const CAEndpoint_t *endpoint
size_t CAGetTotalLengthFromHeader(const unsigned char *recvBuffer);
/**
* Get session information from file descriptor index.
* Get session information from socket file descriptor.
*
* @param[in] fd file descriptor.
* @param[in] fd socket file descriptor.
* @param[out] index index of array list
* @return TCP Server Information structure.
*/
CATCPSessionInfo_t *CAGetSessionInfoFromFD(int fd, size_t *index);
CATCPSessionInfo_t *CAGetSessionInfoFromFD(CASocketFd_t fd, size_t *index);
/**
* Get socket file descriptor from remote device information.
......
......@@ -177,7 +177,7 @@ if 'BLE' in ca_transport:
if 'NFC' in ca_transport:
env.SConscript(os.path.join(ca_path, 'nfc_adapter/SConscript'))
if ca_os in ['linux', 'tizen', 'android']:
if ca_os in ['linux', 'tizen', 'android', 'windows']:
if with_tcp == True:
env.SConscript(os.path.join(ca_path, 'tcp_adapter/SConscript'))
env.AppendUnique(CPPDEFINES = ['WITH_TCP'])
......
......@@ -18,6 +18,7 @@
*
******************************************************************/
#include "iotivity_config.h"
#define _GNU_SOURCE
#include <stddef.h>
......@@ -49,10 +50,16 @@
#include "mbedtls/version.h"
#endif
#ifdef __unix__
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
......@@ -317,43 +324,6 @@ static void DebugSsl(void *ctx, int level, const char *file, int line, const cha
}
#endif
#if defined(_WIN32)
/*
* Finds the first occurrence of the byte string s in byte string l.
*/
static void * memmem(const void *l, size_t lLen, const void *s, size_t sLen)
{
char *cur;
char *last;
const char *cl = (const char *)l;
const char *cs = (const char *)s;
if (lLen == 0 || sLen == 0)
{
return NULL;
}
if (lLen < sLen)
{
return NULL;
}
if (sLen == 1)
{
return (void *)memchr(l, (int)*cs, lLen);
}
last = (char *)cl + lLen - sLen;
for (cur = (char *)cl; cur <= last; cur++)
{
if (cur[0] == cs[0] && memcmp(cur, cs, sLen) == 0)
{
return cur;
}
}
return NULL;
}
#endif
/**
* structure to holds the information of cache message and address info.
*/
......
......@@ -131,16 +131,13 @@ CAResult_t CAParseIPv4AddressInternal(const char *ipAddrStr, uint8_t *ipAddr,
}
#else // not with_arduino
/*
* These two conversion functions return void because errors can't happen
* (because of NI_NUMERIC), and there's nothing to do if they do happen.
*/
void CAConvertAddrToName(const struct sockaddr_storage *sockAddr, socklen_t sockAddrLen,
char *host, uint16_t *port)
CAResult_t CAConvertAddrToName(const struct sockaddr_storage *sockAddr, socklen_t sockAddrLen,
char *host, uint16_t *port)
{
VERIFY_NON_NULL_VOID(sockAddr, CA_ADAPTER_UTILS_TAG, "sockAddr is null");
VERIFY_NON_NULL_VOID(host, CA_ADAPTER_UTILS_TAG, "host is null");
VERIFY_NON_NULL_VOID(port, CA_ADAPTER_UTILS_TAG, "port is null");
VERIFY_NON_NULL_RET(sockAddr, CA_ADAPTER_UTILS_TAG, "sockAddr is null",
CA_STATUS_INVALID_PARAM);
VERIFY_NON_NULL_RET(host, CA_ADAPTER_UTILS_TAG, "host is null", CA_STATUS_INVALID_PARAM);
VERIFY_NON_NULL_RET(port, CA_ADAPTER_UTILS_TAG, "port is null", CA_STATUS_INVALID_PARAM);
int r = getnameinfo((struct sockaddr *)sockAddr,
sockAddrLen,
......@@ -167,19 +164,20 @@ void CAConvertAddrToName(const struct sockaddr_storage *sockAddr, socklen_t sock
OIC_LOG_V(ERROR, CA_ADAPTER_UTILS_TAG,
"getnameinfo failed: %s", gai_strerror(r));
#endif
return;
return CA_STATUS_FAILED;
}
*port = ntohs(((struct sockaddr_in *)sockAddr)->sin_port); // IPv4 and IPv6
return CA_STATUS_OK;
}
void CAConvertNameToAddr(const char *host, uint16_t port, struct sockaddr_storage *sockaddr)
CAResult_t CAConvertNameToAddr(const char *host, uint16_t port, struct sockaddr_storage *sockaddr)
{
VERIFY_NON_NULL_VOID(host, CA_ADAPTER_UTILS_TAG, "host is null");
VERIFY_NON_NULL_VOID(sockaddr, CA_ADAPTER_UTILS_TAG, "sockaddr is null");
VERIFY_NON_NULL_RET(host, CA_ADAPTER_UTILS_TAG, "host is null", CA_STATUS_INVALID_PARAM);
VERIFY_NON_NULL_RET(sockaddr, CA_ADAPTER_UTILS_TAG, "sockaddr is null",
CA_STATUS_INVALID_PARAM);
struct addrinfo *addrs = NULL;
struct addrinfo hints = { .ai_family = AF_UNSPEC,
.ai_socktype = SOCK_DGRAM,
.ai_flags = AI_NUMERICHOST };
int r = getaddrinfo(host, NULL, &hints, &addrs);
......@@ -203,7 +201,7 @@ void CAConvertNameToAddr(const char *host, uint16_t port, struct sockaddr_storag
OIC_LOG_V(ERROR, CA_ADAPTER_UTILS_TAG,
"getaddrinfo failed: %s", gai_strerror(r));
#endif
return;
return CA_STATUS_FAILED;
}
// assumption: in this case, getaddrinfo will only return one addrinfo
// or first is the one we want.
......@@ -218,6 +216,7 @@ void CAConvertNameToAddr(const char *host, uint16_t port, struct sockaddr_storag
((struct sockaddr_in *)sockaddr)->sin_port = htons(port);
}
freeaddrinfo(addrs);
return CA_STATUS_OK;
}
#endif // WITH_ARDUINO
......
......@@ -161,15 +161,15 @@ static void CAReceiveHandler(void *data)
}
}
#if !defined(WSA_WAIT_EVENT_0)
#define CLOSE_SOCKET(TYPE) \
if (caglobals.ip.TYPE.fd != OC_INVALID_SOCKET) \
{ \
close(caglobals.ip.TYPE.fd); \
OC_CLOSE_SOCKET(caglobals.ip.TYPE.fd); \
caglobals.ip.TYPE.fd = OC_INVALID_SOCKET; \
}
#if !defined(WSA_WAIT_EVENT_0)
#define SET(TYPE, FDS) \
if (caglobals.ip.TYPE.fd != OC_INVALID_SOCKET) \
{ \
......@@ -291,13 +291,6 @@ static void CASelectReturned(fd_set *readFds, int ret)
#else // if defined(WSA_WAIT_EVENT_0)
#define CLOSE_SOCKET(TYPE) \
if (caglobals.ip.TYPE.fd != OC_INVALID_SOCKET) \
{ \
closesocket(caglobals.ip.TYPE.fd); \
caglobals.ip.TYPE.fd = OC_INVALID_SOCKET; \
}
#define PUSH_HANDLE(HANDLE, ARRAY, INDEX) \
{ \
ARRAY[INDEX] = HANDLE; \
......@@ -772,11 +765,7 @@ static CASocketFd_t CACreateSocket(int family, uint16_t *port, bool isMulticast)
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, OPTVAL_T(&on), sizeof (on)))
{
OIC_LOG_V(ERROR, TAG, "SO_REUSEADDR failed: %s", CAIPS_GET_ERROR);
#ifdef _WIN32
closesocket(fd);
#else
close(fd);
#endif
OC_CLOSE_SOCKET(fd);
return OC_INVALID_SOCKET;
}
}
......@@ -784,11 +773,7 @@ static CASocketFd_t CACreateSocket(int family, uint16_t *port, bool isMulticast)
if (OC_SOCKET_ERROR == bind(fd, (struct sockaddr *)&sa, socklen))
{
OIC_LOG_V(ERROR, TAG, "bind socket failed: %s", CAIPS_GET_ERROR);
#ifdef _WIN32
closesocket(fd);
#else
close(fd);
#endif
OC_CLOSE_SOCKET(fd);
return OC_INVALID_SOCKET;
}
......@@ -797,11 +782,7 @@ static CASocketFd_t CACreateSocket(int family, uint16_t *port, bool isMulticast)
if (OC_SOCKET_ERROR == getsockname(fd, (struct sockaddr *)&sa, &socklen))
{
OIC_LOG_V(ERROR, TAG, "getsockname failed: %s", CAIPS_GET_ERROR);
#ifdef _WIN32
closesocket(fd);
#else
close(fd);
#endif
OC_CLOSE_SOCKET(fd);
return OC_INVALID_SOCKET;
}
*port = ntohs(family == AF_INET6 ?
......@@ -812,9 +793,14 @@ static CASocketFd_t CACreateSocket(int family, uint16_t *port, bool isMulticast)
return fd;
}
#ifdef _WIN32
#define CHECKFD(FD)
#else
#define CHECKFD(FD) \
if (FD > caglobals.ip.maxfd) \
caglobals.ip.maxfd = FD;
#endif
#define NEWSOCKET(FAMILY, NAME, MULTICAST) \
caglobals.ip.NAME.fd = CACreateSocket(FAMILY, &caglobals.ip.NAME.port, MULTICAST); \
if (caglobals.ip.NAME.fd == OC_INVALID_SOCKET) \
......
......@@ -416,6 +416,13 @@ BOOL RegisterForIpAddressChange()
CAResult_t CAIPStartNetworkMonitor(CAIPAdapterStateChangeCallback callback,
CATransportAdapter_t adapter)
{
if (g_CAIPNetworkMonitorNotificationHandle != NULL)
{
// The monitor has already been started. This can happen when using both the
// IP and TCP transport adapters.
return CA_STATUS_OK;
}
CAResult_t res = CAIPInitializeNetworkMonitorList();
if (res != CA_STATUS_OK)
{
......@@ -425,26 +432,28 @@ CAResult_t CAIPStartNetworkMonitor(CAIPAdapterStateChangeCallback callback,
res = CAIPSetNetworkMonitorCallback(callback, adapter);
if (res != CA_STATUS_OK)
{
CAIPDestroyNetworkMonitorList();
return res;
}
if (g_CAIPNetworkMonitorNotificationHandle == NULL)
{
#ifdef USE_SOCKET_ADDRESS_CHANGE_EVENT
if (!RegisterForIpAddressChange())
{
return CA_STATUS_FAILED;
}
if (!RegisterForIpAddressChange())
{
CAIPDestroyNetworkMonitorList();
CAIPUnSetNetworkMonitorCallback(adapter);
return CA_STATUS_FAILED;
}
#else
int err = NotifyUnicastIpAddressChange(AF_UNSPEC, IpAddressChangeCallback, NULL,
true,
&g_CAIPNetworkMonitorNotificationHandle);
if (err != NO_ERROR)
{
return CA_STATUS_FAILED;
}
#endif
int err = NotifyUnicastIpAddressChange(AF_UNSPEC, IpAddressChangeCallback, NULL,
true,
&g_CAIPNetworkMonitorNotificationHandle);
if (err != NO_ERROR)
{
CAIPDestroyNetworkMonitorList();
CAIPUnSetNetworkMonitorCallback(adapter);
return CA_STATUS_FAILED;
}
#endif
return CA_STATUS_OK;
}
......
......@@ -15,7 +15,7 @@ src_dir = './tcp_adapter/'
# Source files to build common for all platforms
common_files = None
if target_os in ['linux', 'tizen', 'android']:
if target_os in ['linux', 'tizen', 'android', 'windows']:
common_files = [
os.path.join(src_dir, 'catcpadapter.c'),
os.path.join(src_dir, 'catcpserver.c') ]
......@@ -46,4 +46,4 @@ target_files = [ os.path.join(src_dir, target_os, f) for f in target_files ]
# The list of TCP adapter source files is a combination of both the
# common and target-specific source file lists.
env.AppendUnique(CA_SRC = common_files + target_files)
\ No newline at end of file
env.AppendUnique(CA_SRC = common_files + target_files)
......@@ -18,6 +18,7 @@
*
******************************************************************/
#include "iotivity_config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
......
......@@ -18,22 +18,42 @@
*
******************************************************************/
#include "iotivity_config.h"
#include "iotivity_debug.h"
#include <sys/types.h>
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef HAVE_WS2TCPIP_H
#include <ws2tcpip.h>
#endif
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
#ifdef HAVE_SYS_POLL_H
#include <sys/poll.h>
#endif
#include <stdio.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <fcntl.h>
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifdef HAVE_NET_IF_H
#include <net/if.h>
#endif
#include <errno.h>
#include <assert.h>
#ifndef WITH_ARDUINO
#include <sys/socket.h>
#include <netinet/in.h>
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
......@@ -97,19 +117,27 @@ static void CATCPDestroyCond();
static CASocketFd_t CACreateAcceptSocket(int family, CASocket_t *sock);
static void CAAcceptConnection(CATransportFlags_t flag, CASocket_t *sock);
static void CAFindReadyMessage();
#if !defined(WSA_WAIT_EVENT_0)
static void CASelectReturned(fd_set *readFds);
static void CAReceiveMessage(int fd);
#else
static void CASocketEventReturned(CASocketFd_t socket);
#endif
static void CAReceiveMessage(CASocketFd_t fd);
static void CAReceiveHandler(void *data);
static CAResult_t CATCPCreateSocket(int family, CATCPSessionInfo_t *svritem);
#if defined(WSA_WAIT_EVENT_0)
#define CHECKFD(FD)
#else
#define CHECKFD(FD) \
if (FD > caglobals.tcp.maxfd) \
caglobals.tcp.maxfd = FD;
#endif
#define CLOSE_SOCKET(TYPE) \
if (caglobals.tcp.TYPE.fd != OC_INVALID_SOCKET) \
{ \
close(caglobals.tcp.TYPE.fd); \
OC_CLOSE_SOCKET(caglobals.tcp.TYPE.fd); \
caglobals.tcp.TYPE.fd = OC_INVALID_SOCKET; \