Files
handleaiuinew/env/LMI/include/kApi/Io/kSocket.cpp
T
2024-05-18 23:53:26 +08:00

1609 lines
41 KiB
C++

/**
* @file kSocket.cpp
*
* @internal
* Copyright (C) 2004-2021 by LMI Technologies Inc.
* Licensed under the MIT License.
* Redistributed files must retain the above copyright notice.
*/
#define K_PLATFORM
#include <kApi/Io/kSocket.h>
/*
* kSocketType
*/
kBeginEnumEx(k, kSocketType)
kAddEnumerator(kSocketType, kSOCKET_TYPE_TCP)
kAddEnumerator(kSocketType, kSOCKET_TYPE_UDP)
kEndEnumEx()
/*
* kSocketWait
*/
kBeginEnumEx(k, kSocketEvent)
kAddEnumerator(kSocketEvent, kSOCKET_EVENT_READ)
kAddEnumerator(kSocketEvent, kSOCKET_EVENT_WRITE)
kAddEnumerator(kSocketEvent, kSOCKET_EVENT_EXCEPT)
kEndEnumEx()
/*
* kSocket
*/
kBeginClassEx(k, kSocket)
kAddPrivateVMethod(kSocket, kObject, VRelease)
kEndClassEx()
kFx(kStatus) kSocket_WaitAny(const kSocket* sockts, kSize count, k64u timeout)
{
struct timeval tv;
fd_set readSet, writeSet, exceptSet;
xkSocketHandle highest = 0;
int result;
kSize i;
kCheckArgs(count <= FD_SETSIZE);
FD_ZERO(&readSet);
FD_ZERO(&writeSet);
FD_ZERO(&exceptSet);
for (i = 0; i < count; i++)
{
kObj(kSocket, sockts[i]);
if (obj->handle > highest)
{
highest = obj->handle;
}
if (obj->eventTypes & kSOCKET_EVENT_READ) FD_SET(obj->handle, &readSet);
if (obj->eventTypes & kSOCKET_EVENT_WRITE) FD_SET(obj->handle, &writeSet);
if (obj->eventTypes & kSOCKET_EVENT_EXCEPT) FD_SET(obj->handle, &exceptSet);
obj->eventStatus = 0;
}
result = xkSocket_Select((int) (highest) + 1, &readSet, &writeSet, &exceptSet, xkSocket_FormatTimeVal(&tv, timeout));
if (result == 0)
{
return kERROR_TIMEOUT;
}
else if (result < 0)
{
return kERROR_STREAM;
}
for (i = 0; i < count; i++)
{
kObj(kSocket, sockts[i]);
if ((obj->eventTypes & kSOCKET_EVENT_READ) && FD_ISSET(obj->handle, &readSet)) obj->eventStatus |= kSOCKET_EVENT_READ;
if ((obj->eventTypes & kSOCKET_EVENT_WRITE) && FD_ISSET(obj->handle, &writeSet)) obj->eventStatus |= kSOCKET_EVENT_WRITE;
if ((obj->eventTypes & kSOCKET_EVENT_EXCEPT) && FD_ISSET(obj->handle, &exceptSet)) obj->eventStatus |= kSOCKET_EVENT_EXCEPT;
}
return kOK;
}
kFx(struct timeval*) xkSocket_FormatTimeVal(struct timeval* tv, k64u timeout)
{
if (timeout == kINFINITE)
{
return kNULL;
}
tv->tv_sec = (long) timeout / 1000000;
tv->tv_usec = (int) (timeout % 1000000);
return tv;
}
kFx(kStatus) kSocket_Construct(kSocket* sockt, kIpVersion ipVersion, kSocketType socketType, kAlloc allocator)
{
kAlloc alloc = kAlloc_Fallback(allocator);
kType type = kTypeOf(kSocket);
kStatus status;
kCheck(kAlloc_GetObject(alloc, type, sockt));
if (!kSuccess(status = xkSocket_Init(*sockt, type, ipVersion, socketType, alloc)))
{
kAlloc_FreeRef(alloc, sockt);
}
return status;
}
kFx(kStatus) xkSocket_ConstructFromHandle(kSocket* sockt, kIpVersion ipVersion, kSocketType socktType, xkSocketHandle handle, kAlloc allocator)
{
kAlloc alloc = kAlloc_Fallback(allocator);
kType type = kTypeOf(kSocket);
kStatus status;
kCheck(kAlloc_GetObject(alloc, type, sockt));
if (!kSuccess(status = xkSocket_InitFromHandle(*sockt, type, ipVersion, socktType, handle, alloc)))
{
kAlloc_FreeRef(alloc, sockt);
}
return status;
}
kFx(kStatus) xkSocket_Init(kSocket sockt, kType type, kIpVersion ipVersion, kSocketType socketType, kAlloc allocator)
{
if (ipVersion != kIP_VERSION_4)
{
return kERROR_UNIMPLEMENTED;
}
else
{
k32s sockFamily = AF_INET;
k32s sockType = (socketType == kSOCKET_TYPE_TCP) ? SOCK_STREAM : SOCK_DGRAM;
xkSocketHandle handle = socket(sockFamily, sockType, 0);
kStatus status = kOK;
if (handle == xkSOCKET_INVALID_SOCKET)
{
status = kERROR_NETWORK;
}
else if (!kSuccess(status = xkSocket_InitFromHandle(sockt, type, ipVersion, socketType, handle, allocator)))
{
xkSocket_CloseHandle(handle);
}
return status;
}
}
kFx(kStatus) xkSocket_InitFromHandle(kSocket sockt, kType type, kIpVersion ipVersion, kSocketType socktType, xkSocketHandle handle, kAlloc allocator)
{
kObjR(kSocket, sockt);
kCheckArgs(handle != xkSOCKET_INVALID_SOCKET);
kCheck(kObject_Init(sockt, type, allocator));
obj->ipVersion = ipVersion;
obj->socketType = socktType;
obj->handle = handle;
obj->eventTypes = kSOCKET_EVENT_READ;
obj->eventStatus = 0;
obj->status = kOK;
obj->isBlocking = kTRUE;
return kOK;
}
kFx(kStatus) xkSocket_VRelease(kSocket sockt)
{
kObj(kSocket, sockt);
if (obj->handle != xkSOCKET_INVALID_SOCKET)
{
kSocket_Shutdown(sockt);
kCheck(xkSocket_CloseHandle(obj->handle));
}
kCheck(kObject_VRelease(sockt));
return kOK;
}
kFx(kStatus) kSocket_Bind(kSocket sockt, kIpAddress address, k32u port)
{
kObj(kSocket, sockt);
struct sockaddr_in sockAddr;
kCheck(obj->status);
kCheckArgs(address.version == kIP_VERSION_4);
kCheck(xkIpAddress_ToSockAddr(address, port, &sockAddr));
kCheck(bind(obj->handle, (struct sockaddr*)&sockAddr, sizeof(sockAddr)) == 0);
return kOK;
}
kFx(kStatus) kSocket_Connect(kSocket sockt, kIpAddress address, k32u port, k64u timeout)
{
kCheck(kSocket_BeginConnect(sockt, address, port));
kCheck(kSocket_EndConnect(sockt, timeout));
return kOK;
}
kFx(kStatus) kSocket_BeginConnect(kSocket sockt, kIpAddress address, k32u port)
{
kObj(kSocket, sockt);
struct sockaddr_in sockAddr;
kStatus exception;
kTry
{
kTest(obj->status);
kTestArgs(address.version == kIP_VERSION_4);
kTest(xkIpAddress_ToSockAddr(address, port, &sockAddr));
obj->wasBlocking = obj->isBlocking;
kTest(kSocket_SetBlocking(sockt, kFALSE));
obj->status = kERROR_IN_PROGRESS;
obj->beginConnectResult = connect(obj->handle, (struct sockaddr*)&sockAddr, sizeof(sockAddr));
obj->beginConnectLastError = xkSocket_GetLastError();
}
kCatch(&exception)
{
obj->status = exception;
kEndCatch(kOK);
}
return kOK;
}
kFx(kStatus) kSocket_EndConnect(kSocket sockt, k64u timeout)
{
kObj(kSocket, sockt);
fd_set exceptSet;
fd_set writeSet;
int selectResult = 0;
struct timeval tv;
kStatus exception;
kTry
{
if (obj->status != kERROR_IN_PROGRESS)
{
kThrow(obj->status);
}
obj->status = kOK;
if (obj->beginConnectResult == xkSOCKET_ERROR)
{
if (obj->beginConnectLastError == xkSOCKET_WOULD_BLOCK || obj->beginConnectLastError == xkSOCKET_IN_PROGRESS)
{
FD_ZERO(&writeSet);
FD_ZERO(&exceptSet);
FD_SET(obj->handle, &writeSet);
FD_SET(obj->handle, &exceptSet);
selectResult = xkSocket_Select((int)(obj->handle)+1, NULL, &writeSet, &exceptSet, xkSocket_FormatTimeVal(&tv, timeout));
if ((selectResult == 1) && !FD_ISSET(obj->handle, &exceptSet))
{
int errorCode;
socklen_t errorSize = sizeof(int);
kTest(getsockopt(obj->handle, SOL_SOCKET, SO_ERROR, (char*)&errorCode, &errorSize) == 0);
if (errorCode != 0)
{
kThrow(kERROR_NETWORK);
}
}
else if (selectResult == 0)
{
kThrow(kERROR_TIMEOUT);
}
else
{
kThrow(kERROR_NETWORK);
}
}
else
{
kThrow(kERROR_NETWORK);
}
}
if (obj->wasBlocking)
{
kTest(kSocket_SetBlocking(sockt, obj->wasBlocking));
}
}
kCatch(&exception)
{
obj->status = exception;
kEndCatch(exception);
}
return kOK;
}
kFx(kStatus) kSocket_Accept(kSocket sockt, kSocket* connection, kAlloc allocator)
{
kObj(kSocket, sockt);
xkSocketHandle handle = xkSOCKET_INVALID_SOCKET;
kStatus status = kOK;
kCheck(obj->status);
if ((handle = accept(obj->handle, 0, 0)) == xkSOCKET_INVALID_SOCKET)
{
*connection = kNULL;
}
else if (!kSuccess(status = xkSocket_ConstructFromHandle(connection, obj->ipVersion, kSOCKET_TYPE_TCP, handle, allocator)))
{
xkSocket_CloseHandle(handle);
}
return status;
}
kFx(kStatus) kSocket_JoinMulticastGroup(kSocket socket, kIpAddress group, kIpAddress iface)
{
kObj(kSocket, socket);
struct ip_mreq request;
request.imr_multiaddr.s_addr = kIpAddress_ToNet32u(group);
request.imr_interface.s_addr = kIpAddress_ToNet32u(iface);
kCheck(setsockopt(obj->handle, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*) &request, sizeof(request)) != xkSOCKET_ERROR);
return kOK;
}
kFx(kStatus) kSocket_LeaveMulticastGroup(kSocket socket, kIpAddress group, kIpAddress iface)
{
kObj(kSocket, socket);
struct ip_mreq request;
request.imr_multiaddr.s_addr = kIpAddress_ToNet32u(group);
request.imr_interface.s_addr = kIpAddress_ToNet32u(iface);
kCheck(setsockopt(obj->handle, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char*) &request, sizeof(request)) != xkSOCKET_ERROR);
return kOK;
}
kFx(kStatus) kSocket_Listen(kSocket sockt, kSize backlog)
{
kObj(kSocket, sockt);
kCheck(obj->status);
kCheck(listen(obj->handle, (int) backlog) != xkSOCKET_ERROR);
return kOK;
}
kFx(kStatus) kSocket_Shutdown(kSocket sockt)
{
kObj(kSocket, sockt);
if (!kIsError(obj->status))
{
xkSocket_ShutdownHandle(obj->handle);
obj->status = kERROR_CLOSED;
}
return kOK;
}
kFx(kStatus) kSocket_SetEvents(kSocket sockt, kSocketEvent events)
{
kObj(kSocket, sockt);
obj->eventTypes = events;
return kOK;
}
kFx(kSocketEvent) kSocket_Events(kSocket sockt)
{
kObj(kSocket, sockt);
return obj->eventStatus;
}
kFx(kStatus) kSocket_Wait(kSocket sockt, k64u timeout)
{
kObj(kSocket, sockt);
return xkSocket_WaitEx(sockt, obj->eventTypes, timeout);
}
kFx(kStatus) xkSocket_WaitEx(kSocket sockt, kSocketEvent events, k64u timeout)
{
kObj(kSocket, sockt);
struct timeval tv;
fd_set readSet, writeSet, exceptSet;
kStatus result;
kCheck(obj->status);
FD_ZERO(&readSet);
FD_ZERO(&writeSet);
FD_ZERO(&exceptSet);
if (events & kSOCKET_EVENT_READ) FD_SET(obj->handle, &readSet);
if (events & kSOCKET_EVENT_WRITE) FD_SET(obj->handle, &writeSet);
if (events & kSOCKET_EVENT_EXCEPT) FD_SET(obj->handle, &exceptSet);
obj->eventStatus = 0;
result = xkSocket_Select((int)(obj->handle)+1, &readSet, &writeSet, &exceptSet, xkSocket_FormatTimeVal(&tv, timeout));
if (result == 0)
{
return kERROR_TIMEOUT;
}
else if (result < 0)
{
obj->status = kERROR_STREAM;
return obj->status;
}
if ((events & kSOCKET_EVENT_READ) && FD_ISSET(obj->handle, &readSet)) obj->eventStatus |= kSOCKET_EVENT_READ;
if ((events & kSOCKET_EVENT_WRITE) && FD_ISSET(obj->handle, &writeSet)) obj->eventStatus |= kSOCKET_EVENT_WRITE;
if ((events & kSOCKET_EVENT_EXCEPT) && FD_ISSET(obj->handle, &exceptSet)) obj->eventStatus |= kSOCKET_EVENT_EXCEPT;
return kOK;
}
kFx(kStatus) xkSocket_Peek(kSocket sockt, void* buffer, kSize size, kSize* read)
{
return xkSocket_ReadImpl(sockt, buffer, size, read, xkSOCKET_MSG_PEEK);
}
kFx(kStatus) kSocket_Read(kSocket sockt, void* buffer, kSize size, kSize* read)
{
return xkSocket_ReadImpl(sockt, buffer, size, read, 0);
}
kFx(kStatus) xkSocket_ReadImpl(kSocket sockt, void* buffer, kSize size, kSize* read, k32s options)
{
kObj(kSocket, sockt);
kSSize result;
k32s socketError;
kStatus opStatus = kOK;
kCheck(obj->status);
if (size == 0)
{
return kOK;
}
result = xkSocket_Recv(sockt, buffer, size, options);
if (result > 0)
{
if (!kIsNull(read))
{
*read = (kSize)result;
}
}
else if (result == 0)
{
opStatus = kERROR_CLOSED;
obj->status = kERROR_CLOSED;
}
else
{
socketError = xkSocket_GetLastError();
if ((socketError == xkSOCKET_TIMEDOUT) || (socketError == xkSOCKET_WOULD_BLOCK))
{
if (!obj->isBlocking)
{
opStatus = kERROR_BUSY;
}
else
{
opStatus = kERROR_TIMEOUT;
if (obj->socketType == kSOCKET_TYPE_TCP)
{
obj->status = kERROR_TIMEOUT;
}
}
}
else
{
opStatus = kERROR_STREAM;
if (obj->socketType == kSOCKET_TYPE_TCP)
{
obj->status = kERROR_STREAM;
}
}
}
return opStatus;
}
kFx(kStatus) kSocket_ReadFrom(kSocket sockt, kIpEndPoint *endPoint, void* buffer, kSize size, kSize* read)
{
kObj(kSocket, sockt);
struct sockaddr_in sockAddr;
kSSize result;
k32s socketError;
kStatus opStatus = kOK;
kCheck(obj->status);
result = xkSocket_RecvFrom(sockt, buffer, size, &sockAddr);
if (result > 0)
{
if (!kIsNull(endPoint))
{
kCheck(xkIpAddress_FromSockAddr(&sockAddr, &endPoint->address, &endPoint->port));
}
if (!kIsNull(read))
{
*read = (kSize) result;
}
}
else if (result == 0)
{
opStatus = kERROR_CLOSED;
obj->status = kERROR_CLOSED;
}
else
{
socketError = xkSocket_GetLastError();
if ((socketError == xkSOCKET_TIMEDOUT) || (socketError == xkSOCKET_WOULD_BLOCK))
{
if (!obj->isBlocking)
{
opStatus = kERROR_BUSY;
}
else
{
opStatus = kERROR_TIMEOUT;
if (obj->socketType == kSOCKET_TYPE_TCP)
{
obj->status = kERROR_TIMEOUT;
}
}
}
else if (socketError == xkSOCKET_MSGSIZE)
{
opStatus = kERROR_INCOMPLETE;
}
else
{
opStatus = kERROR_STREAM;
if (obj->socketType == kSOCKET_TYPE_TCP)
{
obj->status = kERROR_STREAM;
}
}
}
return opStatus;
}
kFx(kStatus) kSocket_ReadFromEx(kSocket sockt, kIpEndPoint *endPoint, kSize* interfaceIndex, void* buffer, kSize size, kSize* read)
{
kObj(kSocket, sockt);
struct sockaddr_in sockAddr;
kSSize result;
k32s socketError;
kStatus opStatus = kOK;
kCheck(obj->status);
kCheckTrue(obj->socketType == kSOCKET_TYPE_UDP, kERROR_STATE);
result = xkSocket_RecvMessage(sockt, buffer, size, &sockAddr, interfaceIndex);
if (result > 0)
{
if (!kIsNull(endPoint))
{
kCheck(xkIpAddress_FromSockAddr(&sockAddr, &endPoint->address, &endPoint->port));
}
if (!kIsNull(read))
{
*read = (kSize)result;
}
}
else
{
socketError = xkSocket_GetLastError();
if ((socketError == xkSOCKET_TIMEDOUT) || (socketError == xkSOCKET_WOULD_BLOCK))
{
if (!obj->isBlocking)
{
opStatus = kERROR_BUSY;
}
else
{
opStatus = kERROR_TIMEOUT;
}
}
else if (socketError == xkSOCKET_MSGSIZE)
{
opStatus = kERROR_INCOMPLETE;
}
else
{
opStatus = kERROR_STREAM;
}
}
return opStatus;
}
kFx(kStatus) kSocket_Write(kSocket sockt, const void* buffer, kSize size, kSize* written)
{
kObj(kSocket, sockt);
kSSize result;
k32s socketError;
kStatus opStatus = kOK;
kCheck(obj->status);
*written = 0;
do
{
result = xkSocket_Send(sockt, (const kByte*)buffer + *written, size - *written);
if (result >= 0)
{
*written += (kSize) result;
}
else
{
socketError = xkSocket_GetLastError();
if ((socketError == xkSOCKET_TIMEDOUT) || (socketError == xkSOCKET_WOULD_BLOCK))
{
if (!obj->isBlocking)
{
opStatus = kERROR_BUSY;
}
else
{
opStatus = kERROR_TIMEOUT;
if (obj->socketType == kSOCKET_TYPE_TCP)
{
obj->status = kERROR_TIMEOUT;
}
}
}
else
{
opStatus = kERROR_STREAM;
if (obj->socketType == kSOCKET_TYPE_TCP)
{
obj->status = kERROR_STREAM;
}
}
}
}
while (obj->isBlocking && !kIsError(opStatus) && (*written < size));
return opStatus;
}
kFx(kStatus) kSocket_WriteTo(kSocket sockt, kIpAddress address, k32u port, const void* buffer, kSize size)
{
kObj(kSocket, sockt);
struct sockaddr_in sockAddr;
kSSize result;
k32s socketError;
kStatus opStatus = kOK;
kCheck(obj->status);
kCheckArgs(address.version == kIP_VERSION_4);
kCheck(xkIpAddress_ToSockAddr(address, port, &sockAddr));
result = xkSocket_SendTo(sockt, buffer, size, &sockAddr);
if (result < 0)
{
socketError = xkSocket_GetLastError();
if ((socketError == xkSOCKET_TIMEDOUT) || (socketError == xkSOCKET_WOULD_BLOCK))
{
if (!obj->isBlocking)
{
opStatus = kERROR_BUSY;
}
else
{
opStatus = kERROR_TIMEOUT;
if (obj->socketType == kSOCKET_TYPE_TCP)
{
obj->status = kERROR_TIMEOUT;
}
}
}
else if (socketError == xkSOCKET_MSGSIZE)
{
opStatus = kERROR_INCOMPLETE;
}
else
{
opStatus = kERROR_STREAM;
if (obj->socketType == kSOCKET_TYPE_TCP)
{
obj->status = kERROR_STREAM;
}
}
}
else if ((kSize)result != size)
{
opStatus = kERROR_INCOMPLETE;
}
return opStatus;
}
kFx(kStatus) kSocket_EnableBroadcast(kSocket sockt, kBool broadcast)
{
kObj(kSocket, sockt);
kBool value = (broadcast) ? kTRUE : kFALSE;
kCheck(obj->status);
kCheck(setsockopt(obj->handle, SOL_SOCKET, SO_BROADCAST, (char*)&value, sizeof(kBool)) != xkSOCKET_ERROR);
return kOK;
}
kFx(kStatus) kSocket_SetNoDelay(kSocket sockt, kBool noDelay)
{
kObj(kSocket, sockt);
kBool value = noDelay;
kCheck(obj->status);
kCheck(setsockopt(obj->handle, IPPROTO_TCP, TCP_NODELAY, (char*)&value, sizeof(kBool)) != xkSOCKET_ERROR);
return kOK;
}
kFx(kStatus) kSocket_SetLingerTime(kSocket sockt, k64u lingerTime)
{
kObj(kSocket, sockt);
struct linger linger;
kCheck(obj->status);
linger.l_onoff = 1;
linger.l_linger = (unsigned short) ((lingerTime + 999999)/1000000);
kCheck(setsockopt(obj->handle, SOL_SOCKET, SO_LINGER, (char*) &linger, sizeof(struct linger)) != xkSOCKET_ERROR);
return kOK;
}
kFx(kStatus) xkSocket_SetWriteLowWater(kSocket sockt, kSize size)
{
kObj(kSocket, sockt);
int value = (int) size;
kCheck(obj->status);
kCheck(setsockopt(obj->handle, SOL_SOCKET, SO_SNDLOWAT, (char*)&value, sizeof(int)) != xkSOCKET_ERROR);
return kOK;
}
kFx(kStatus) xkSocket_SetReadLowWater(kSocket sockt, kSize size)
{
kObj(kSocket, sockt);
int value = (int) kMin_(size, xkSOCKET_MAX_BUFFER);
kCheck(obj->status);
kCheck(setsockopt(obj->handle, SOL_SOCKET, SO_RCVLOWAT, (char*)&value, sizeof(int)) != xkSOCKET_ERROR);
return kOK;
}
kFx(kSize) xkSocket_WriteBuffer(kSocket sockt)
{
kObj(kSocket, sockt);
int optValue = 0;
socklen_t optLen = sizeof(optValue);
if (getsockopt(obj->handle, SOL_SOCKET, SO_SNDBUF, (char*)&optValue, &optLen) == xkSOCKET_ERROR)
{
return 0;
}
return (kSize)optValue;
}
kFx(kSize) xkSocket_ReadBuffer(kSocket sockt)
{
kObj(kSocket, sockt);
int optValue = 0;
socklen_t optLen = sizeof(optValue);
if (getsockopt(obj->handle, SOL_SOCKET, SO_RCVBUF, (char*)&optValue, &optLen) == xkSOCKET_ERROR)
{
return 0;
}
return (kSize)optValue;
}
kFx(kStatus) kSocket_LocalEndPoint(kSocket sockt, kIpEndPoint* endPoint)
{
kObj(kSocket, sockt);
struct sockaddr_in sockAddr;
socklen_t sockAddrLength = (socklen_t) sizeof(sockAddr);
kCheck(obj->status);
kCheck(getsockname(obj->handle, (struct sockaddr*)&sockAddr, &sockAddrLength) != xkSOCKET_ERROR);
kCheck(xkIpAddress_FromSockAddr(&sockAddr, &endPoint->address, &endPoint->port));
return kOK;
}
kFx(kStatus) kSocket_RemoteEndPoint(kSocket sockt, kIpEndPoint* endPoint)
{
kObj(kSocket, sockt);
struct sockaddr_in sockAddr;
socklen_t sockAddrLength = (socklen_t) sizeof(sockAddr);
kCheck(obj->status);
kCheck(getpeername(obj->handle, (struct sockaddr*)&sockAddr, &sockAddrLength) == 0);
kCheck(xkIpAddress_FromSockAddr(&sockAddr,&endPoint->address, &endPoint->port));
return kOK;
}
kFx(kStatus) kSocket_Status(kSocket sockt)
{
kObj(kSocket, sockt);
return obj->status;
}
kFx(kSize) kSocket_Handle(kSocket sockt)
{
kObj(kSocket, sockt);
return (kSize) obj->handle;
}
#if defined(K_WINDOWS)
kFx(kStatus) kSocket_EnableReuseAddress(kSocket sockt, kBool reuse)
{
kObj(kSocket, sockt);
int option = reuse;
kCheck(obj->status);
//FSS-1243: according to semi-credible internet gossip (and backed up by informal testing) Windows
//appears to ignore existing connections in the TIME_WAIT state by default when binding. as such, there
//doesn't appear to be any valid reason to use SO_REUSEADDR on Windows with TCP sockets (we don't consider
//"port stealing" to be valid). for UDP sockets, SO_REUSEADDR is required for broacast/multicast
//receive, so it's valid to use
if (obj->socketType == kSOCKET_TYPE_UDP)
{
kCheckState(setsockopt(obj->handle, SOL_SOCKET, SO_REUSEADDR, (char*)&option, sizeof(option)) != xkSOCKET_ERROR);
}
return kOK;
}
kFx(kSSize) xkSocket_Recv(kSocket sockt, void* buffer, kSize size, k32s options)
{
kObj(kSocket, sockt);
return recv(obj->handle, (char*)buffer, (int)kMin_(size, xkSOCKET_MAX_IO_SIZE), options);
}
kFx(kSSize) xkSocket_RecvFrom(kSocket sockt, void* buffer, kSize size, struct sockaddr_in* from)
{
kObj(kSocket, sockt);
int sockAddrLength = sizeof(struct sockaddr_in);
return recvfrom(obj->handle, (char*)buffer, (int) kMin_(size, xkSOCKET_MAX_IO_SIZE), 0, (struct sockaddr*)from, &sockAddrLength);
}
kFx(kSSize) xkSocket_RecvMessage(kSocket sockt, void* buffer, kSize size, struct sockaddr_in* from, kSize* interfaceIndex)
{
kObj(kSocket, sockt);
GUID WSARecvMsgGUID = WSAID_WSARECVMSG;
WSACMSGHDR* messageHeader = kNULL;
LPFN_WSARECVMSG recvMsgFx = kNULL;
WSABUF iovec[1] = { 0 };
WSAMSG message = { 0 };
DWORD bytesRead = 0;
kChar pktbuf[1024];
*interfaceIndex = kSIZE_NULL;
if (WSAIoctl(obj->handle, SIO_GET_EXTENSION_FUNCTION_POINTER,
&WSARecvMsgGUID, sizeof(WSARecvMsgGUID),
&recvMsgFx, sizeof(recvMsgFx),
&bytesRead, NULL, NULL) != 0)
{
return -1;
}
from->sin_family = AF_INET;
from->sin_port = htons(0);
iovec[0].buf = (kChar*)buffer;
iovec[0].len = (ULONG)size;
message.name = (struct sockaddr*)from;
message.namelen = sizeof(sockaddr_in);
message.lpBuffers = &iovec[0];
message.dwBufferCount = 1;
message.Control.buf = pktbuf;
message.Control.len = kCountOf(pktbuf);
message.dwFlags = 0;
if (recvMsgFx(obj->handle, &message, &bytesRead, NULL, NULL) != 0)
{
return -1;
}
messageHeader = WSA_CMSG_FIRSTHDR(&message);
if (!kIsNull(messageHeader) && (messageHeader->cmsg_type == IP_PKTINFO))
{
IN_PKTINFO* pktInfo = (IN_PKTINFO*)WSA_CMSG_DATA(messageHeader);
*interfaceIndex = pktInfo->ipi_ifindex;
}
return bytesRead;
}
kFx(kSSize) xkSocket_Send(kSocket sockt, const void* buffer, kSize size)
{
kObj(kSocket, sockt);
return send(obj->handle, (const char*)buffer, (int) kMin_(size, xkSOCKET_MAX_IO_SIZE), 0);
}
kFx(kSSize) xkSocket_SendTo(kSocket sockt, const void* buffer, kSize size, const struct sockaddr_in* to)
{
kObj(kSocket, sockt);
int sockAddrLength = sizeof(struct sockaddr_in);
return sendto(obj->handle, (const char*)buffer, (int) kMin_(size, xkSOCKET_MAX_IO_SIZE), 0, (const struct sockaddr*)to, sockAddrLength);
}
kFx(k32s) xkSocket_GetLastError()
{
return WSAGetLastError();
}
kFx(kStatus) xkSocket_ShutdownHandle(xkSocketHandle socktHandle)
{
shutdown(socktHandle, SD_BOTH);
return kOK;
}
kFx(kStatus) xkSocket_CloseHandle(xkSocketHandle socktHandle)
{
if (closesocket(socktHandle) != 0)
{
return kERROR_NETWORK;
}
return kOK;
}
kFx(kStatus) kSocket_SetBlocking(kSocket sockt, kBool isBlocking)
{
kObj(kSocket, sockt);
unsigned long nonBlocking = (unsigned long) !isBlocking;
kCheck(ioctlsocket(obj->handle, FIONBIO, &nonBlocking) == 0);
obj->isBlocking = isBlocking;
return kOK;
}
kFx(kStatus) kSocket_SetWriteBuffer(kSocket sockt, kSize size)
{
kObj(kSocket, sockt);
int value = (int) kMin_(size, xkSOCKET_MAX_BUFFER);
kCheck(obj->status);
kCheck(setsockopt(obj->handle, SOL_SOCKET, SO_SNDBUF, (char*)&value, sizeof(int)) != xkSOCKET_ERROR);
return kOK;
}
kFx(kStatus) kSocket_SetReadBuffer(kSocket sockt, kSize size)
{
kObj(kSocket, sockt);
int value = (int) kMin_(size, xkSOCKET_MAX_BUFFER);
kCheck(obj->status);
kCheck(setsockopt(obj->handle, SOL_SOCKET, SO_RCVBUF, (char*)&value, sizeof(int)) != xkSOCKET_ERROR);
return kOK;
}
kFx(kStatus) kSocket_SetWriteTimeout(kSocket sockt, k64u timeout)
{
kObj(kSocket, sockt);
int value = (int) (timeout + 999)/1000;
kCheck(setsockopt(obj->handle, SOL_SOCKET, SO_SNDTIMEO, (char*)&value, sizeof(int)) != xkSOCKET_ERROR);
return kOK;
}
kFx(kStatus) kSocket_SetReadTimeout(kSocket sockt, k64u timeout)
{
kObj(kSocket, sockt);
int value = (int) (timeout + 999)/1000;
kCheck(setsockopt(obj->handle, SOL_SOCKET, SO_RCVTIMEO, (char*)&value, sizeof(int)) != xkSOCKET_ERROR);
return kOK;
}
kFx(kStatus) kSocket_EnablePacketInfo(kSocket sockt, kBool enabled)
{
kObj(kSocket, sockt);
kCheck(obj->status);
kCheckTrue(obj->socketType == kSOCKET_TYPE_UDP, kERROR_STATE);
kCheck(setsockopt(obj->handle, IPPROTO_IP, IP_PKTINFO, (char*)&enabled, sizeof(kBool)) != xkSOCKET_ERROR);
return kOK;
}
kFx(kStatus) kSocket_BindToDevice(kSocket socket, const kChar* interfaceName)
{
//not supported; has no effect
return kOK;
}
#elif defined (K_TI_BIOS)
kFx(kStatus) kSocket_EnableReuseAddress(kSocket sockt, kBool reuse)
{
kObj(kSocket, sockt);
kBool value = reuse;
kCheck(obj->status);
kCheckState(setsockopt(obj->handle, SOL_SOCKET, SO_REUSEADDR, (char*)&value, sizeof(kBool)) != xkSOCKET_ERROR);
return kOK;
}
kFx(kSSize) xkSocket_Recv(kSocket sockt, void* buffer, kSize size, k32s options)
{
kObj(kSocket, sockt);
return recv(obj->handle, buffer, size, options);
}
kFx(kSSize) xkSocket_RecvFrom(kSocket sockt, void* buffer, kSize size, struct sockaddr_in* from)
{
kObj(kSocket, sockt);
socklen_t sockAddrLength = sizeof(struct sockaddr_in);
return recvfrom(obj->handle, buffer, size, 0, (struct sockaddr*)from, &sockAddrLength);
}
kFx(kSSize) xkSocket_RecvMessage(kSocket sockt, void* buffer, kSize size, struct sockaddr_in* from, kSize* interfaceIndex)
{
kObj(kSocket, sockt);
*interfaceIndex = 2; //convention
return xkSocket_RecvFrom(sockt, buffer, size, from);
}
kFx(kSSize) xkSocket_Send(kSocket sockt, const void* buffer, kSize size)
{
kObj(kSocket, sockt);
return send(obj->handle, (void*)buffer, size, 0);
}
kFx(kSSize) xkSocket_SendTo(kSocket sockt, const void* buffer, kSize size, const struct sockaddr_in* to)
{
kObj(kSocket, sockt);
socklen_t sockAddrLength = (socklen_t)sizeof(struct sockaddr_in);
return sendto(obj->handle, (void*)buffer, size, 0, (struct sockaddr*)to, sockAddrLength);
}
kFx(k32s) xkSocket_GetLastError()
{
return fdError();
}
kFx(kStatus) xkSocket_ShutdownHandle(xkSocketHandle socktHandle)
{
struct linger linger;
linger.l_onoff = 1;
linger.l_linger = 0;
//SYS/BIOS doesn't seem to implement shutdown properly, so we set the linger time to zero to force connection reset
setsockopt(socktHandle, SOL_SOCKET, SO_LINGER, (char*) &linger, sizeof(struct linger));
shutdown(socktHandle, SHUT_RDWR);
return kOK;
}
kFx(kStatus) xkSocket_CloseHandle(xkSocketHandle socktHandle)
{
fdClose(socktHandle);
return kOK;
}
kFx(kStatus) kSocket_SetBlocking(kSocket sockt, kBool isBlocking)
{
kObj(kSocket, sockt);
int blockingOpt = (int) isBlocking;
kCheck(setsockopt(obj->handle, SOL_SOCKET, SO_BLOCKING, &blockingOpt, sizeof(blockingOpt)) != xkSOCKET_ERROR);
obj->isBlocking = isBlocking;
return kOK;
}
kFx(kStatus) kSocket_SetWriteBuffer(kSocket sockt, kSize size)
{
kObj(kSocket, sockt);
int value = (int) kMin_(size, xkSOCKET_MAX_BUFFER);
kCheck(obj->status);
//using this option with a UDP socket generates "00000.553 mmFree: Double Free" condition in NDK stack (1.93)
if (obj->socketType != kSOCKET_TYPE_UDP)
{
kCheckTrue(setsockopt(obj->handle, SOL_SOCKET, SO_SNDBUF, (char*)&value, sizeof(int)) != xkSOCKET_ERROR, kERROR_OS);
}
return kOK;
}
kFx(kStatus) kSocket_SetReadBuffer(kSocket sockt, kSize size)
{
kObj(kSocket, sockt);
int value = (int) kMin_(size, xkSOCKET_MAX_BUFFER);
kCheck(obj->status);
//using this option with a UDP socket generates "00000.553 mmFree: Double Free" condition in NDK stack (1.93)
if (obj->socketType != kSOCKET_TYPE_UDP)
{
kCheckTrue(setsockopt(obj->handle, SOL_SOCKET, SO_RCVBUF, (char*)&value, sizeof(int)) != xkSOCKET_ERROR, kERROR_OS);
}
return kOK;
}
kFx(kStatus) kSocket_SetWriteTimeout(kSocket sockt, k64u timeout)
{
kObj(kSocket, sockt);
struct timeval tv;
kCheck(setsockopt(obj->handle, SOL_SOCKET, SO_SNDTIMEO, xkSocket_FormatTimeVal(&tv, timeout), sizeof(tv)) != xkSOCKET_ERROR);
return kOK;
}
kFx(kStatus) kSocket_SetReadTimeout(kSocket sockt, k64u timeout)
{
kObj(kSocket, sockt);
struct timeval tv;
kCheck(setsockopt(obj->handle, SOL_SOCKET, SO_RCVTIMEO, xkSocket_FormatTimeVal(&tv, timeout), sizeof(tv)) != xkSOCKET_ERROR);
return kOK;
}
kFx(kStatus) kSocket_EnablePacketInfo(kSocket sockt, kBool enabled)
{
kObj(kSocket, sockt);
return kOK;
}
kFx(kStatus) kSocket_BindToDevice(kSocket socket, const kChar* interfaceName)
{
//not supported; has no effect
return kOK;
}
#elif defined (K_VX_KERNEL)
kFx(kStatus) kSocket_EnableReuseAddress(kSocket sockt, kBool reuse)
{
kObj(kSocket, sockt);
kBool value = reuse;
kCheck(obj->status);
kCheckState(setsockopt(obj->handle, SOL_SOCKET, SO_REUSEADDR, (char*)&value, sizeof(kBool)) != xkSOCKET_ERROR);
return kOK;
}
kFx(kSSize) xkSocket_Recv(kSocket sockt, void* buffer, kSize size, k32s options)
{
kObj(kSocket, sockt);
return recv(obj->handle, buffer, size, options);
}
kFx(kSSize) xkSocket_RecvFrom(kSocket sockt, void* buffer, kSize size, struct sockaddr_in* from)
{
kObj(kSocket, sockt);
int sockAddrLength = (int) sizeof(struct sockaddr_in);
return recvfrom(obj->handle, buffer, size, 0, (struct sockaddr*)from, &sockAddrLength);
}
kFx(kSSize) xkSocket_RecvMessage(kSocket sockt, void* buffer, kSize size, struct sockaddr_in* from, kSize* interfaceIndex)
{
kObj(kSocket, sockt);
struct msghdr message;
struct iovec iovec[1];
kChar pktbuf[1024];
kSSize read = 0;
struct cmsghdr* cmptr = kNULL;
*interfaceIndex = kSIZE_NULL;
iovec[0].iov_base = (kChar*)buffer;
iovec[0].iov_len = size;
message.msg_name = from;
message.msg_namelen = sizeof(struct sockaddr_in);
message.msg_iov = iovec;
message.msg_iovlen = 1;
message.msg_control = pktbuf;
message.msg_controllen = kCountOf(pktbuf);
read = recvmsg(obj->handle, &message, 0);
cmptr = CMSG_FIRSTHDR(&message);
if (!kIsNull(cmptr) && (cmptr->cmsg_type == IP_PKTINFO))
{
struct in_pktinfo* pktInfo = (struct in_pktinfo*)CMSG_DATA(cmptr);
*interfaceIndex = pktInfo->ipi_ifindex;
}
return read;
}
kFx(kSSize) xkSocket_Send(kSocket sockt, const void* buffer, kSize size)
{
kObj(kSocket, sockt);
return send(obj->handle, buffer, size, 0);
}
kFx(kSSize) xkSocket_SendTo(kSocket sockt, const void* buffer, kSize size, const struct sockaddr_in* to)
{
kObj(kSocket, sockt);
int sockAddrLength = sizeof(struct sockaddr_in);
return sendto(obj->handle, buffer, size, 0, (const struct sockaddr*)to, sockAddrLength);
}
kFx(k32s) xkSocket_GetLastError()
{
return errno;
}
kFx(kStatus) xkSocket_ShutdownHandle(xkSocketHandle socktHandle)
{
shutdown(socktHandle, SHUT_RDWR);
return kOK;
}
kFx(kStatus) xkSocket_CloseHandle(xkSocketHandle socktHandle)
{
close(socktHandle);
return kOK;
}
kFx(kStatus) kSocket_SetBlocking(kSocket sockt, kBool isBlocking)
{
kObj(kSocket, sockt);
int nonBlocking = !isBlocking;
if (ioctl(obj->handle, FIONBIO, (int)&nonBlocking) == ERROR)
{
return kERROR_OS;
}
obj->isBlocking = isBlocking;
return kOK;
}
kFx(kStatus) kSocket_SetWriteBuffer(kSocket sockt, kSize size)
{
kObj(kSocket, sockt);
int value = (int) kMin_(size, xkSOCKET_MAX_BUFFER);
kCheck(obj->status);
kCheck(setsockopt(obj->handle, SOL_SOCKET, SO_SNDBUF, (char*)&value, sizeof(int)) != xkSOCKET_ERROR);
return kOK;
}
kFx(kStatus) kSocket_SetReadBuffer(kSocket sockt, kSize size)
{
kObj(kSocket, sockt);
int value = (int) kMin_(size, xkSOCKET_MAX_BUFFER);
kCheck(obj->status);
kCheck(setsockopt(obj->handle, SOL_SOCKET, SO_RCVBUF, (char*)&value, sizeof(int)) != xkSOCKET_ERROR);
return kOK;
}
kFx(kStatus) kSocket_SetWriteTimeout(kSocket sockt, k64u timeout)
{
/*
kObj(kSocket, sockt);
struct timeval tv;
int result = setsockopt(obj->handle, SOL_SOCKET, SO_SNDTIMEO, xkSocket_FormatTimeVal(&tv, timeout), sizeof(tv));
kCheck(result != xkSOCKET_ERROR);
*/
/*
* TODO: This option doesn't appear to be implemented in VxWorks 6.9; code above compiles, but always return an error.
* For now, we'll just return kOK; should file a bug report with Wind River, or just remove kSocket timeout feature if not needed.
*/
return kOK;
}
kFx(kStatus) kSocket_SetReadTimeout(kSocket sockt, k64u timeout)
{
kObj(kSocket, sockt);
struct timeval tv;
kCheck(setsockopt(obj->handle, SOL_SOCKET, SO_RCVTIMEO, xkSocket_FormatTimeVal(&tv, timeout), sizeof(tv)) != xkSOCKET_ERROR);
return kOK;
}
kFx(kStatus) kSocket_EnablePacketInfo(kSocket sockt, kBool enabled)
{
kObj(kSocket, sockt);
kCheck(obj->status);
kCheckTrue(obj->socketType == kSOCKET_TYPE_UDP, kERROR_STATE);
kCheck(setsockopt(obj->handle, IPPROTO_IP, IP_PKTINFO, (char*)&enabled, sizeof(kBool)) != xkSOCKET_ERROR);
return kOK;
}
#elif defined (K_POSIX)
kFx(kStatus) kSocket_EnableReuseAddress(kSocket sockt, kBool reuse)
{
kObj(kSocket, sockt);
kBool value = reuse;
kCheck(obj->status);
kCheckState(setsockopt(obj->handle, SOL_SOCKET, SO_REUSEADDR, (char*)&value, sizeof(kBool)) != xkSOCKET_ERROR);
return kOK;
}
kFx(kSSize) xkSocket_Recv(kSocket sockt, void* buffer, kSize size, k32s options)
{
kObj(kSocket, sockt);
return recv(obj->handle, buffer, size, options);
}
kFx(kSSize) xkSocket_RecvFrom(kSocket sockt, void* buffer, kSize size, struct sockaddr_in* from)
{
kObj(kSocket, sockt);
unsigned int sockAddrLength = sizeof(struct sockaddr_in);
return recvfrom(obj->handle, buffer, size, 0, (struct sockaddr*)from, &sockAddrLength);
}
kFx(kSSize) xkSocket_RecvMessage(kSocket sockt, void* buffer, kSize size, struct sockaddr_in* from, kSize* interfaceIndex)
{
kObj(kSocket, sockt);
struct msghdr message;
struct iovec iovec[1];
kChar pktbuf[1024];
kSSize read = 0;
struct cmsghdr* cmptr = kNULL;
*interfaceIndex = kSIZE_NULL;
iovec[0].iov_base = buffer;
iovec[0].iov_len = size;
message.msg_name = from;
message.msg_namelen = sizeof(struct sockaddr_in);
message.msg_iov = iovec;
message.msg_iovlen = 1;
message.msg_control = pktbuf;
message.msg_controllen = kCountOf(pktbuf);
read = recvmsg(obj->handle, &message, 0);
cmptr = CMSG_FIRSTHDR(&message);
if (!kIsNull(cmptr) && (cmptr->cmsg_type == IP_PKTINFO))
{
struct in_pktinfo* pktInfo = (struct in_pktinfo*)CMSG_DATA(cmptr);
*interfaceIndex = pktInfo->ipi_ifindex;
}
return read;
}
kFx(kSSize) xkSocket_Send(kSocket sockt, const void* buffer, kSize size)
{
kObj(kSocket, sockt);
return send(obj->handle, buffer, size, MSG_NOSIGNAL);
}
kFx(kSSize) xkSocket_SendTo(kSocket sockt, const void* buffer, kSize size, const struct sockaddr_in* to)
{
kObj(kSocket, sockt);
int sockAddrLength = sizeof(struct sockaddr_in);
#if defined(K_QNX)
return sendto(obj->handle, buffer, (int)kMin_(size, xkSOCKET_MAX_BUFFER), MSG_DONTROUTE, (const struct sockaddr*)to, sockAddrLength);
#else
return sendto(obj->handle, buffer, size, MSG_NOSIGNAL, (const struct sockaddr*)to, sockAddrLength);
#endif
}
kFx(k32s) xkSocket_GetLastError()
{
return errno;
}
kFx(kStatus) xkSocket_ShutdownHandle(xkSocketHandle socktHandle)
{
shutdown(socktHandle, SHUT_RDWR);
return kOK;
}
kFx(kStatus) xkSocket_CloseHandle(xkSocketHandle socktHandle)
{
close(socktHandle);
return kOK;
}
kFx(kStatus) kSocket_SetBlocking(kSocket sockt, kBool isBlocking)
{
kObj(kSocket, sockt);
int flags = fcntl(obj->handle, F_GETFL);
if (isBlocking)
{
fcntl(obj->handle, F_SETFL, flags &~O_NONBLOCK);
}
else
{
fcntl(obj->handle, F_SETFL, O_NONBLOCK);
}
obj->isBlocking = isBlocking;
return kOK;
}
kFx(kStatus) kSocket_SetWriteBuffer(kSocket sockt, kSize size)
{
kObj(kSocket, sockt);
int value = (int) kMin_(size, xkSOCKET_MAX_BUFFER);
kCheck(obj->status);
kCheck(setsockopt(obj->handle, SOL_SOCKET, SO_SNDBUF, (char*)&value, sizeof(int)) != xkSOCKET_ERROR);
return kOK;
}
kFx(kStatus) kSocket_SetReadBuffer(kSocket sockt, kSize size)
{
kObj(kSocket, sockt);
int value = (int) kMin_(size, xkSOCKET_MAX_BUFFER);
kCheck(obj->status);
kCheck(setsockopt(obj->handle, SOL_SOCKET, SO_RCVBUF, (char*)&value, sizeof(int)) != xkSOCKET_ERROR);
return kOK;
}
kFx(kStatus) kSocket_SetWriteTimeout(kSocket sockt, k64u timeout)
{
kObj(kSocket, sockt);
struct timeval tv;
kCheck(setsockopt(obj->handle, SOL_SOCKET, SO_SNDTIMEO, xkSocket_FormatTimeVal(&tv, timeout), sizeof(tv)) != xkSOCKET_ERROR);
return kOK;
}
kFx(kStatus) kSocket_SetReadTimeout(kSocket sockt, k64u timeout)
{
kObj(kSocket, sockt);
struct timeval tv;
kCheck(setsockopt(obj->handle, SOL_SOCKET, SO_RCVTIMEO, xkSocket_FormatTimeVal(&tv, timeout), sizeof(tv)) != xkSOCKET_ERROR);
return kOK;
}
kFx(kStatus) kSocket_EnablePacketInfo(kSocket sockt, kBool enabled)
{
kObj(kSocket, sockt);
kCheck(obj->status);
kCheckTrue(obj->socketType == kSOCKET_TYPE_UDP, kERROR_STATE);
kCheck(setsockopt(obj->handle, IPPROTO_IP, IP_PKTINFO, (char*)&enabled, sizeof(kBool)) != xkSOCKET_ERROR);
return kOK;
}
#if !defined(K_DARWIN)
kFx(kStatus) kSocket_BindToDevice(kSocket sockt, const kChar* interfaceName)
{
kObj(kSocket, sockt);
struct ifreq sender;
kCheckArgs(interfaceName[0] != 0);
kMemSet(&sender, 0, sizeof(sender));
kStrCopy(sender.ifr_name, kCountOf(sender.ifr_name), interfaceName);
kCheck(setsockopt(obj->handle, SOL_SOCKET, SO_BINDTODEVICE, &sender, sizeof(sender)) != xkSOCKET_ERROR);
return kOK;
}
#endif
#endif