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

439 lines
11 KiB
C++

/**
* @file kUdpClient.cpp
*
* @internal
* Copyright (C) 2008-2021 by LMI Technologies Inc.
* Licensed under the MIT License.
* Redistributed files must retain the above copyright notice.
*/
#include <kApi/Io/kUdpClient.h>
#include <kApi/Io/kSocket.h>
#include <kApi/Threads/kTimer.h>
kBeginClassEx(k, kUdpClient)
kAddPrivateVMethod(kUdpClient, kObject, VRelease)
kAddPrivateVMethod(kUdpClient, kStream, VReadSomeImpl)
kAddPrivateVMethod(kUdpClient, kStream, VWriteImpl)
kAddPrivateVMethod(kUdpClient, kStream, VFlush)
kAddPrivateVMethod(kUdpClient, kStream, VFill)
kEndClassEx()
kFx(kStatus) kUdpClient_Construct(kUdpClient* client, kIpVersion ipVersion, kAlloc allocator)
{
kAlloc alloc = kAlloc_Fallback(allocator);
kStatus status;
kCheck(kAlloc_GetObject(alloc, kTypeOf(kUdpClient), client));
if (!kSuccess(status = xkUdpClient_Init(*client, kTypeOf(kUdpClient), ipVersion, alloc)))
{
kAlloc_FreeRef(alloc, client);
}
return status;
}
kFx(kStatus) xkUdpClient_Init(kUdpClient client, kType type, kIpVersion ipVersion, kAlloc allocator)
{
kObjR(kUdpClient, client);
kStatus status;
kCheck(kStream_Init(client, type, allocator));
obj->socket = kNULL;
kTry
{
kTest(kSocket_Construct(&obj->socket, ipVersion, kSOCKET_TYPE_UDP, allocator));
kTest(kSocket_SetBlocking(obj->socket, kFALSE));
}
kCatch(&status)
{
xkUdpClient_VRelease(client);
kEndCatch(status);
}
return kOK;
}
kFx(kStatus) xkUdpClient_VRelease(kUdpClient client)
{
kObj(kUdpClient, client);
kCheck(kObject_Destroy(obj->socket));
kCheck(kObject_FreeMem(client, obj->base.readBuffer));
kCheck(kObject_FreeMem(client, obj->base.writeBuffer));
kCheck(kStream_VRelease(client));
return kOK;
}
kFx(kStatus) kUdpClient_Bind(kUdpClient client, kIpAddress address, k32u port)
{
kObj(kUdpClient, client);
//Work-around for SYS/BIOS; see kUdpClient_EnableBroadcastReceive comments
#if defined(K_TI_BIOS) || defined (K_VX_KERNEL)
if (obj->isBroacastReceiver)
{
address = kIpAddress_AnyV4();
}
#endif
return kSocket_Bind(obj->socket, address, port);
}
kFx(kStatus) kUdpClient_JoinMulticastGroup(kUdpClient client, kIpAddress group, kIpAddress iface)
{
kObj(kUdpClient, client);
return kSocket_JoinMulticastGroup(obj->socket, group, iface);
}
kFx(kStatus) kUdpClient_LeaveMulticastGroup(kUdpClient client, kIpAddress group, kIpAddress iface)
{
kObj(kUdpClient, client);
return kSocket_LeaveMulticastGroup(obj->socket, group, iface);
}
kFx(kStatus) kUdpClient_ReadFrom(kUdpClient client, kIpEndPoint* endPoint, void* buffer, kSize capacity, kSize* received, k64u timeout)
{
kObj(kUdpClient, client);
kStatus opStatus;
opStatus = kSocket_ReadFrom(obj->socket, endPoint, buffer, capacity, received);
if ((opStatus == kERROR_BUSY) && (timeout > 0))
{
kCheck(kSocket_SetEvents(obj->socket, kSOCKET_EVENT_READ));
kCheck(kSocket_Wait(obj->socket, timeout));
opStatus = kSocket_ReadFrom(obj->socket, endPoint, buffer, capacity, received);
}
if (kSuccess(opStatus))
{
obj->base.bytesRead += (k64u) *received;
}
return opStatus;
}
kFx(kStatus) kUdpClient_WriteTo(kUdpClient client, const void* buffer, kSize size, kIpAddress address, k32u port, k64u timeout)
{
kObj(kUdpClient, client);
kStatus opStatus;
opStatus = kSocket_WriteTo(obj->socket, address, port, buffer, size);
if ((opStatus == kERROR_BUSY) && (timeout > 0))
{
k64u startTime = kTimer_Now();
k64u elapsed = 0;
k64u opTimeout = 0;
kCheck(kSocket_SetEvents(obj->socket, kSOCKET_EVENT_WRITE));
do
{
elapsed = kTimer_Now() - startTime;
if (elapsed < timeout)
{
opTimeout = (timeout == kINFINITE) ? timeout : timeout - elapsed;
if (kSuccess(kSocket_Wait(obj->socket, opTimeout)))
{
opStatus = kSocket_WriteTo(obj->socket, address, port, buffer, size);
}
}
}
while ((opStatus == kERROR_BUSY) && (elapsed < timeout));
}
if (opStatus == kERROR_BUSY)
{
opStatus = kERROR_TIMEOUT;
}
if (kSuccess(opStatus))
{
obj->base.bytesWritten += (k64u) size;
}
return opStatus;
}
kFx(kStatus) kUdpClient_Receive(kUdpClient client, kIpEndPoint* endPoint, kSize* received, k64u timeout)
{
kObj(kUdpClient, client);
kStatus opStatus;
kCheckState(!kIsNull(obj->base.readBuffer));
opStatus = kSocket_ReadFrom(obj->socket, endPoint, obj->base.readBuffer, obj->base.readCapacity, &obj->base.readEnd);
if ((opStatus == kERROR_BUSY) && (timeout > 0))
{
kCheck(kSocket_SetEvents(obj->socket, kSOCKET_EVENT_READ));
kCheck(kSocket_Wait(obj->socket, timeout));
opStatus = kSocket_ReadFrom(obj->socket, endPoint, obj->base.readBuffer, obj->base.readCapacity, &obj->base.readEnd);
}
if (kSuccess(opStatus))
{
obj->base.readBegin = 0;
obj->base.bytesRead += (k64u) obj->base.readEnd;
if (!kIsNull(received))
{
*received = obj->base.readEnd;
}
}
return opStatus;
}
kFx(kStatus) kUdpClient_ReceiveEx(kUdpClient client, kIpEndPoint* endPoint, kSize* received, k64u timeout, kSize* interfaceIndex)
{
kObj(kUdpClient, client);
kStatus opStatus;
kCheckState(!kIsNull(obj->base.readBuffer));
opStatus = kSocket_ReadFromEx(obj->socket, endPoint, interfaceIndex, obj->base.readBuffer, obj->base.readCapacity, &obj->base.readEnd);
if ((opStatus == kERROR_BUSY) && (timeout > 0))
{
kCheck(kSocket_SetEvents(obj->socket, kSOCKET_EVENT_READ));
kCheck(kSocket_Wait(obj->socket, timeout));
opStatus = kSocket_ReadFromEx(obj->socket, endPoint, interfaceIndex, obj->base.readBuffer, obj->base.readCapacity, &obj->base.readEnd);
}
if (kSuccess(opStatus))
{
obj->base.readBegin = 0;
obj->base.bytesRead += (k64u)obj->base.readEnd;
if (!kIsNull(received))
{
*received = obj->base.readEnd;
}
}
return opStatus;
}
kFx(kStatus) kUdpClient_Send(kUdpClient client, kIpAddress address, k32u port, k64u timeout, kBool clear)
{
kObj(kUdpClient, client);
kStatus opStatus;
kCheckState(!kIsNull(obj->base.writeBuffer));
opStatus = kSocket_WriteTo(obj->socket, address, port, obj->base.writeBuffer, obj->base.writeBegin);
if ((opStatus == kERROR_BUSY) && (timeout > 0))
{
k64u startTime = kTimer_Now();
k64u elapsed = 0;
k64u opTimeout = 0;
kCheck(kSocket_SetEvents(obj->socket, kSOCKET_EVENT_WRITE));
do
{
elapsed = kTimer_Now() - startTime;
if (elapsed < timeout)
{
opTimeout = (timeout == kINFINITE) ? timeout : timeout - elapsed;
if (kSuccess(kSocket_Wait(obj->socket, opTimeout)))
{
opStatus = kSocket_WriteTo(obj->socket, address, port, obj->base.writeBuffer, obj->base.writeBegin);
}
}
}
while ((opStatus == kERROR_BUSY) && (elapsed < timeout));
}
if (opStatus == kERROR_BUSY)
{
opStatus = kERROR_TIMEOUT;
}
if (kSuccess(opStatus))
{
obj->base.bytesWritten += (k64u)obj->base.writeBegin;
}
if (clear)
{
obj->base.writeBegin = 0;
}
return opStatus;
}
kFx(kStatus) kUdpClient_Clear(kUdpClient client)
{
kObj(kUdpClient, client);
obj->base.writeBegin = 0;
return kOK;
}
kFx(kStatus) xkUdpClient_VReadSomeImpl(kUdpClient client, void* buffer, kSize minCount, kSize maxCount, kSize* bytesRead)
{
kObj(kUdpClient, client);
kSize copyCount;
kCheckState(!kIsNull(obj->base.readBuffer));
kCheckState(minCount <= (obj->base.readEnd - obj->base.readBegin));
copyCount = kMin_(maxCount, obj->base.readEnd - obj->base.readBegin);
kMemCopy(buffer, &obj->base.readBuffer[obj->base.readBegin], copyCount);
obj->base.readBegin += copyCount;
if (!kIsNull(bytesRead))
{
*bytesRead = copyCount;
}
return kOK;
}
kFx(kStatus) xkUdpClient_VWriteImpl(kUdpClient client, const void* buffer, kSize size)
{
kObj(kUdpClient, client);
kCheckState(!kIsNull(obj->base.writeBuffer));
kCheckState(size <= (obj->base.writeEnd - obj->base.writeBegin));
kMemCopy(&obj->base.writeBuffer[obj->base.writeBegin], buffer, size);
obj->base.writeBegin += size;
return kOK;
}
kFx(kStatus) xkUdpClient_VFlush(kUdpClient client)
{
return kOK;
}
kFx(kStatus) xkUdpClient_VFill(kUdpClient client)
{
return kERROR_STATE;
}
kFx(kStatus) kUdpClient_EnableBroadcast(kUdpClient client, kBool broadcast)
{
kObj(kUdpClient, client);
return kSocket_EnableBroadcast(obj->socket, broadcast);
}
kFx(kStatus) kUdpClient_EnablePacketInfo(kUdpClient client, kBool enabled)
{
kObj(kUdpClient, client);
return kSocket_EnablePacketInfo(obj->socket, enabled);
}
kFx(kStatus) kUdpClient_EnableBroadcastReceive(kUdpClient client, kBool broadcast)
{
kObj(kUdpClient, client);
obj->isBroacastReceiver = broadcast;
return kOK;
}
kFx(kStatus) kUdpClient_EnableReuseAddress(kUdpClient client, kBool reuse)
{
kObj(kUdpClient, client);
return kSocket_EnableReuseAddress(obj->socket, reuse);
}
kFx(kStatus) kUdpClient_SetWriteBuffers(kUdpClient client, kSSize socketSize, kSSize clientSize)
{
kObj(kUdpClient, client);
kCheckState(obj->base.writeBegin == 0);
if (socketSize >= 0)
{
kCheck(kSocket_SetWriteBuffer(obj->socket, (kSize)socketSize));
}
if (clientSize >= 0)
{
kCheck(kObject_FreeMemRef(client, &obj->base.writeBuffer));
obj->base.writeCapacity = 0;
obj->base.writeBegin = 0;
obj->base.writeEnd = 0;
if (clientSize > 0)
{
kCheck(kObject_GetMem(client, (kSize)clientSize, &obj->base.writeBuffer));
obj->base.writeCapacity = (kSize)clientSize;
obj->base.writeEnd = (kSize)clientSize;
}
}
return kOK;
}
kFx(kStatus) kUdpClient_SetReadBuffers(kUdpClient client, kSSize socketSize, kSSize clientSize)
{
kObj(kUdpClient, client);
kCheckState((obj->base.readEnd - obj->base.readBegin) == 0);
if (socketSize >= 0)
{
kCheck(kSocket_SetReadBuffer(obj->socket, (kSize)socketSize));
}
if (clientSize >= 0)
{
kCheck(kObject_FreeMemRef(client, &obj->base.readBuffer));
obj->base.readCapacity = 0;
obj->base.readBegin = 0;
obj->base.readEnd = 0;
if (clientSize > 0)
{
kCheck(kObject_GetMem(client, (kSize)clientSize, &obj->base.readBuffer));
obj->base.readCapacity = (kSize)clientSize;
}
}
return kOK;
}
kFx(kSocket) kUdpClient_Socket(kUdpClient client)
{
kObj(kUdpClient, client);
return obj->socket;
}
kFx(kStatus) kUdpClient_LocalEndPoint(kUdpClient client, kIpEndPoint* endPoint)
{
kObj(kUdpClient, client);
return kSocket_LocalEndPoint(obj->socket,endPoint);
}