[simulation] add simul_utils.h for socket operation helpers (#9879)

This commit introduces a new module, `simul_utils.h`, under
`simulation` platform. This module provides common utility functions,
primarily related to socket operations (for emulation of radio or
TREL interface). The new functions are used by `radio.c` and
`trel.c`, consolidating code and preventing repetition.
This commit is contained in:
Abtin Keshavarzian
2024-02-28 11:28:00 -08:00
committed by GitHub
parent acfdcfd2ff
commit 5960215508
6 changed files with 432 additions and 311 deletions
@@ -72,6 +72,7 @@ add_library(openthread-simulation
misc.c
multipan.c
radio.c
simul_utils.c
spi-stubs.c
system.c
trel.c
+29 -153
View File
@@ -41,14 +41,12 @@
#include <openthread/platform/radio.h>
#include <openthread/platform/time.h>
#include "simul_utils.h"
#include "utils/code_utils.h"
#include "utils/link_metrics.h"
#include "utils/mac_frame.h"
#include "utils/soft_source_match_table.h"
// The IPv4 group for receiving packets of radio simulation
#define OT_RADIO_GROUP "224.0.0.116"
#define MS_PER_S 1000
#define US_PER_MS 1000
@@ -75,11 +73,9 @@ extern int sSockFd;
extern uint16_t sPortBase;
extern uint16_t sPortOffset;
#else
static int sTxFd = -1;
static int sRxFd = -1;
static uint16_t sPortBase = 9000;
static uint16_t sPortOffset = 0;
static uint16_t sPort = 0;
static utilsSocket sSocket;
static uint16_t sPortBase = 9000;
static uint16_t sPortOffset = 0;
#endif
static int8_t sEnergyScanResult = OT_RADIO_RSSI_INVALID;
@@ -190,6 +186,8 @@ static bool NodeIdFilterIsConnectable(uint16_t aNodeId)
{
bool isConnectable = true;
otEXPECT_ACTION(aNodeId != gNodeId, isConnectable = false);
switch (sFilterMode)
{
case kFilterOff:
@@ -202,6 +200,7 @@ static bool NodeIdFilterIsConnectable(uint16_t aNodeId)
break;
}
exit:
return isConnectable;
}
@@ -407,82 +406,15 @@ void otPlatRadioSetPromiscuous(otInstance *aInstance, bool aEnable)
sPromiscuous = aEnable;
}
#if OPENTHREAD_SIMULATION_VIRTUAL_TIME == 0
static void initFds(void)
{
int fd;
int one = 1;
struct sockaddr_in sockaddr;
memset(&sockaddr, 0, sizeof(sockaddr));
otEXPECT_ACTION((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) != -1, perror("socket(sTxFd)"));
sPort = (uint16_t)(sPortBase + sPortOffset + gNodeId);
sockaddr.sin_family = AF_INET;
sockaddr.sin_port = htons(sPort);
sockaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
otEXPECT_ACTION(setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &sockaddr.sin_addr, sizeof(sockaddr.sin_addr)) != -1,
perror("setsockopt(sTxFd, IP_MULTICAST_IF)"));
otEXPECT_ACTION(setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &one, sizeof(one)) != -1,
perror("setsockopt(sRxFd, IP_MULTICAST_LOOP)"));
otEXPECT_ACTION(bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) != -1, perror("bind(sTxFd)"));
// Tx fd is successfully initialized.
sTxFd = fd;
otEXPECT_ACTION((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) != -1, perror("socket(sRxFd)"));
otEXPECT_ACTION(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) != -1,
perror("setsockopt(sRxFd, SO_REUSEADDR)"));
otEXPECT_ACTION(setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) != -1,
perror("setsockopt(sRxFd, SO_REUSEPORT)"));
{
struct ip_mreqn mreq;
memset(&mreq, 0, sizeof(mreq));
inet_pton(AF_INET, OT_RADIO_GROUP, &mreq.imr_multiaddr);
// Always use loopback device to send simulation packets.
mreq.imr_address.s_addr = inet_addr("127.0.0.1");
otEXPECT_ACTION(setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &mreq.imr_address, sizeof(mreq.imr_address)) != -1,
perror("setsockopt(sRxFd, IP_MULTICAST_IF)"));
otEXPECT_ACTION(setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) != -1,
perror("setsockopt(sRxFd, IP_ADD_MEMBERSHIP)"));
}
sockaddr.sin_family = AF_INET;
sockaddr.sin_port = htons((uint16_t)(sPortBase + sPortOffset));
sockaddr.sin_addr.s_addr = inet_addr(OT_RADIO_GROUP);
otEXPECT_ACTION(bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) != -1, perror("bind(sRxFd)"));
// Rx fd is successfully initialized.
sRxFd = fd;
exit:
if (sRxFd == -1 || sTxFd == -1)
{
exit(EXIT_FAILURE);
}
}
#endif // OPENTHREAD_SIMULATION_VIRTUAL_TIME == 0
void platformRadioInit(void)
{
#if OPENTHREAD_SIMULATION_VIRTUAL_TIME == 0
#if !OPENTHREAD_SIMULATION_VIRTUAL_TIME
parseFromEnvAsUint16("PORT_BASE", &sPortBase);
parseFromEnvAsUint16("PORT_OFFSET", &sPortOffset);
sPortOffset *= (MAX_NETWORK_SIZE + 1);
initFds();
#endif // OPENTHREAD_SIMULATION_VIRTUAL_TIME == 0
utilsInitSocket(&sSocket, sPortBase + sPortOffset);
#endif
sReceiveFrame.mPsdu = sReceiveMessage.mPsdu;
sTransmitFrame.mPsdu = sTransmitMessage.mPsdu;
@@ -859,24 +791,14 @@ void platformRadioReceive(otInstance *aInstance, uint8_t *aBuf, uint16_t aBufLen
#else
void platformRadioUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, struct timeval *aTimeout, int *aMaxFd)
{
if (aReadFdSet != NULL && (sState != OT_RADIO_STATE_TRANSMIT || sTxWait))
if (sState != OT_RADIO_STATE_TRANSMIT || sTxWait)
{
FD_SET(sRxFd, aReadFdSet);
if (aMaxFd != NULL && *aMaxFd < sRxFd)
{
*aMaxFd = sRxFd;
}
utilsAddSocketRxFd(&sSocket, aReadFdSet, aMaxFd);
}
if (aWriteFdSet != NULL && platformRadioIsTransmitPending())
if (platformRadioIsTransmitPending())
{
FD_SET(sTxFd, aWriteFdSet);
if (aMaxFd != NULL && *aMaxFd < sTxFd)
{
*aMaxFd = sTxFd;
}
utilsAddSocketTxFd(&sSocket, aWriteFdSet, aMaxFd);
}
if (sEnergyScanning)
@@ -900,18 +822,7 @@ void platformRadioUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, struct ti
}
// no need to close in virtual time mode.
void platformRadioDeinit(void)
{
if (sRxFd != -1)
{
close(sRxFd);
}
if (sTxFd != -1)
{
close(sTxFd);
}
}
void platformRadioDeinit(void) { utilsDeinitSocket(&sSocket); }
#endif // OPENTHREAD_SIMULATION_VIRTUAL_TIME
void platformRadioProcess(otInstance *aInstance, const fd_set *aReadFdSet, const fd_set *aWriteFdSet)
@@ -919,41 +830,22 @@ void platformRadioProcess(otInstance *aInstance, const fd_set *aReadFdSet, const
OT_UNUSED_VARIABLE(aReadFdSet);
OT_UNUSED_VARIABLE(aWriteFdSet);
#if OPENTHREAD_SIMULATION_VIRTUAL_TIME == 0
if (FD_ISSET(sRxFd, aReadFdSet))
#if !OPENTHREAD_SIMULATION_VIRTUAL_TIME
if (utilsCanSocketReceive(&sSocket, aReadFdSet))
{
struct sockaddr_in sockaddr;
socklen_t len = sizeof(sockaddr);
ssize_t rval;
uint16_t senderNodeId;
uint16_t len;
memset(&sockaddr, 0, sizeof(sockaddr));
rval =
recvfrom(sRxFd, (char *)&sReceiveMessage, sizeof(sReceiveMessage), 0, (struct sockaddr *)&sockaddr, &len);
len = utilsReceiveFromSocket(&sSocket, &sReceiveMessage, sizeof(sReceiveMessage), &senderNodeId);
if (rval > 0)
if (NodeIdFilterIsConnectable(senderNodeId))
{
uint16_t srcPort = ntohs(sockaddr.sin_port);
uint16_t srcNodeId = srcPort - sPortOffset - sPortBase;
if (NodeIdFilterIsConnectable(srcNodeId) && srcPort != sPort)
{
sReceiveFrame.mLength = (uint16_t)(rval - 1);
radioReceive(aInstance);
}
}
else if (rval == 0)
{
// socket is closed, which should not happen
assert(false);
}
else if (errno != EINTR && errno != EAGAIN)
{
perror("recvfrom(sRxFd)");
exit(EXIT_FAILURE);
sReceiveFrame.mLength = len - 1;
radioReceive(aInstance);
}
}
#endif // OPENTHREAD_SIMULATION_VIRTUAL_TIME == 0
#endif
if (platformRadioIsTransmitPending())
{
radioSendMessage(aInstance);
@@ -968,33 +860,17 @@ void platformRadioProcess(otInstance *aInstance, const fd_set *aReadFdSet, const
void radioTransmit(struct RadioMessage *aMessage, const struct otRadioFrame *aFrame)
{
#if OPENTHREAD_SIMULATION_VIRTUAL_TIME == 0
ssize_t rval;
struct sockaddr_in sockaddr;
memset(&sockaddr, 0, sizeof(sockaddr));
sockaddr.sin_family = AF_INET;
inet_pton(AF_INET, OT_RADIO_GROUP, &sockaddr.sin_addr);
sockaddr.sin_port = htons((uint16_t)(sPortBase + sPortOffset));
rval =
sendto(sTxFd, (const char *)aMessage, 1 + aFrame->mLength, 0, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
if (rval < 0)
{
perror("sendto(sTxFd)");
exit(EXIT_FAILURE);
}
#else // OPENTHREAD_SIMULATION_VIRTUAL_TIME == 0
#if !OPENTHREAD_SIMULATION_VIRTUAL_TIME
utilsSendOverSocket(&sSocket, aMessage, aFrame->mLength + 1); // + 1 is for `mChannel`
#else
struct Event event;
event.mDelay = 1; // 1us for now
event.mEvent = OT_SIM_EVENT_RADIO_RECEIVED;
event.mDataLength = 1 + aFrame->mLength; // include channel in first byte
memcpy(event.mData, aMessage, event.mDataLength);
otSimSendEvent(&event);
#endif // OPENTHREAD_SIMULATION_VIRTUAL_TIME == 0
#endif
}
void radioSendAck(void)
+226
View File
@@ -0,0 +1,226 @@
/*
* Copyright (c) 2024, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "simul_utils.h"
#include <errno.h>
#include <sys/time.h>
#include "utils/code_utils.h"
#define UTILS_SOCKET_LOCAL_HOST_ADDR "127.0.0.1"
#define UTILS_SOCKET_GROUP_ADDR "224.0.0.116"
void utilsAddFdToFdSet(int aFd, fd_set *aFdSet, int *aMaxFd)
{
otEXPECT(aFd >= 0);
otEXPECT(aFdSet != NULL);
FD_SET(aFd, aFdSet);
otEXPECT(aMaxFd != NULL);
if (*aMaxFd < aFd)
{
*aMaxFd = aFd;
}
exit:
return;
}
void utilsInitSocket(utilsSocket *aSocket, uint16_t aPortBase)
{
int fd;
int one = 1;
int rval;
struct sockaddr_in sockaddr;
struct ip_mreqn mreq;
aSocket->mInitialized = false;
aSocket->mPortBase = aPortBase;
aSocket->mPort = (uint16_t)(aSocket->mPortBase + gNodeId);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Prepare `mTxFd`
fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
otEXPECT_ACTION(fd != -1, perror("socket(TxFd)"));
memset(&sockaddr, 0, sizeof(sockaddr));
sockaddr.sin_family = AF_INET;
sockaddr.sin_port = htons(aSocket->mPort);
sockaddr.sin_addr.s_addr = inet_addr(UTILS_SOCKET_LOCAL_HOST_ADDR);
rval = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &sockaddr.sin_addr, sizeof(sockaddr.sin_addr));
otEXPECT_ACTION(rval != -1, perror("setsockopt(TxFd, IP_MULTICAST_IF)"));
rval = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &one, sizeof(one));
otEXPECT_ACTION(rval != -1, perror("setsockopt(TxFd, IP_MULTICAST_LOOP)"));
rval = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
otEXPECT_ACTION(rval != -1, perror("bind(TxFd)"));
aSocket->mTxFd = fd;
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Prepare `mRxFd`
fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
otEXPECT_ACTION(fd != -1, perror("socket(RxFd)"));
rval = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
otEXPECT_ACTION(rval != -1, perror("setsockopt(RxFd, SO_REUSEADDR)"));
rval = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));
otEXPECT_ACTION(rval != -1, perror("setsockopt(RxFd, SO_REUSEPORT)"));
memset(&mreq, 0, sizeof(mreq));
inet_pton(AF_INET, UTILS_SOCKET_GROUP_ADDR, &mreq.imr_multiaddr);
mreq.imr_address.s_addr = inet_addr(UTILS_SOCKET_LOCAL_HOST_ADDR);
rval = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &mreq.imr_address, sizeof(mreq.imr_address));
otEXPECT_ACTION(rval != -1, perror("setsockopt(RxFd, IP_MULTICAST_IF)"));
rval = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
otEXPECT_ACTION(rval != -1, perror("setsockopt(RxFd, IP_ADD_MEMBERSHIP)"));
sockaddr.sin_family = AF_INET;
sockaddr.sin_port = htons(aSocket->mPortBase);
sockaddr.sin_addr.s_addr = inet_addr(UTILS_SOCKET_GROUP_ADDR);
rval = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
otEXPECT_ACTION(rval != -1, perror("bind(RxFd)"));
aSocket->mRxFd = fd;
aSocket->mInitialized = true;
exit:
if (!aSocket->mInitialized)
{
exit(EXIT_FAILURE);
}
}
void utilsDeinitSocket(utilsSocket *aSocket)
{
if (aSocket->mInitialized)
{
close(aSocket->mRxFd);
close(aSocket->mTxFd);
aSocket->mInitialized = false;
}
}
void utilsAddSocketRxFd(const utilsSocket *aSocket, fd_set *aFdSet, int *aMaxFd)
{
otEXPECT(aSocket->mInitialized);
utilsAddFdToFdSet(aSocket->mRxFd, aFdSet, aMaxFd);
exit:
return;
}
void utilsAddSocketTxFd(const utilsSocket *aSocket, fd_set *aFdSet, int *aMaxFd)
{
otEXPECT(aSocket->mInitialized);
utilsAddFdToFdSet(aSocket->mTxFd, aFdSet, aMaxFd);
exit:
return;
}
bool utilsCanSocketReceive(const utilsSocket *aSocket, const fd_set *aReadFdSet)
{
return aSocket->mInitialized && FD_ISSET(aSocket->mRxFd, aReadFdSet);
}
bool utilsCanSocketSend(const utilsSocket *aSocket, const fd_set *aWriteFdSet)
{
return aSocket->mInitialized && FD_ISSET(aSocket->mTxFd, aWriteFdSet);
}
uint16_t utilsReceiveFromSocket(const utilsSocket *aSocket,
void *aBuffer,
uint16_t aBufferSize,
uint16_t *aSenderNodeId)
{
struct sockaddr_in sockaddr;
socklen_t socklen = sizeof(sockaddr);
ssize_t rval;
uint16_t len = 0;
memset(&sockaddr, 0, sizeof(sockaddr));
rval = recvfrom(aSocket->mRxFd, (char *)aBuffer, aBufferSize, 0, (struct sockaddr *)&sockaddr, &socklen);
if (rval > 0)
{
uint16_t senderPort = ntohs(sockaddr.sin_port);
if (aSenderNodeId != NULL)
{
*aSenderNodeId = (uint16_t)(senderPort - aSocket->mPortBase);
}
len = (uint16_t)rval;
}
else if (rval == 0)
{
assert(false);
}
else if (errno != EINTR && errno != EAGAIN)
{
perror("recvfrom(RxFd)");
exit(EXIT_FAILURE);
}
return len;
}
void utilsSendOverSocket(const utilsSocket *aSocket, const void *aBuffer, uint16_t aBufferLength)
{
ssize_t rval;
struct sockaddr_in sockaddr;
memset(&sockaddr, 0, sizeof(sockaddr));
sockaddr.sin_family = AF_INET;
sockaddr.sin_port = htons(aSocket->mPortBase);
inet_pton(AF_INET, UTILS_SOCKET_GROUP_ADDR, &sockaddr.sin_addr);
rval =
sendto(aSocket->mTxFd, (const char *)aBuffer, aBufferLength, 0, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
if (rval < 0)
{
perror("sendto(sTxFd)");
exit(EXIT_FAILURE);
}
}
+149
View File
@@ -0,0 +1,149 @@
/*
* Copyright (c) 2024, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef PLATFORM_SIMULATION_SOCKET_UTILS_H_
#define PLATFORM_SIMULATION_SOCKET_UTILS_H_
#include "platform-simulation.h"
/**
* Represents a socket for communication with other simulation node.
*
* This is used for emulation of 15.4 radio or other interfaces.
*
*/
typedef struct utilsSocket
{
bool mInitialized; ///< Whether or not initialized.
int mTxFd; ///< RX file descriptor.
int mRxFd; ///< TX file descriptor.
uint16_t mPortBase; ///< Base port number value.
uint16_t mPort; ///< The port number used by this node
} utilsSocket;
/**
* Adds a file descriptor (FD) to a given FD set.
*
* @param[in] aFd The FD to add.
* @param[in] aFdSet The FD set to add to.
* @param[in] aMaxFd A pointer to track maximum FD in @p aFdSet (can be NULL).
*
*/
void utilsAddFdToFdSet(int aFd, fd_set *aFdSet, int *aMaxFd);
/**
* Initializes the socket.
*
* @param[in] aSocket The socket to initialize.
* @param[in] aPortBase The base port number value. Nodes will determine their port as `aPortBased + gNodeId`.
*
*/
void utilsInitSocket(utilsSocket *aSocket, uint16_t aPortBase);
/**
* De-initializes the socket.
*
* @param[in] aSocket The socket to de-initialize.
*
*/
void utilsDeinitSocket(utilsSocket *aSocket);
/**
* Adds sockets RX FD to a given FD set.
*
* @param[in] aSocket The socket.
* @param[in] aFdSet The (read) FD set to add to.
* @param[in] aMaxFd A pointer to track maximum FD in @p aFdSet (can be NULL).
*
*/
void utilsAddSocketRxFd(const utilsSocket *aSocket, fd_set *aFdSet, int *aMaxFd);
/**
* Adds sockets TX FD to a given FD set.
*
* @param[in] aSocket The socket.
* @param[in] aFdSet The (write) FD set to add to.
* @param[in] aMaxFd A pointer to track maximum FD in @p aFdSet (can be NULL).
*
*/
void utilsAddSocketTxFd(const utilsSocket *aSocket, fd_set *aFdSet, int *aMaxFd);
/**
* Indicates whether the socket can receive.
*
* @param[in] aSocket The socket.
* @param[in] aReadFdSet The read FD set.
*
* @retval TRUE The socket RX FD is in @p aReadFdSet, and socket can receive.
* @retval FALSE The socket RX FD is not in @p aReadFdSet. Socket is not ready to receive.
*
*/
bool utilsCanSocketReceive(const utilsSocket *aSocket, const fd_set *aReadFdSet);
/**
* Indicates whether the socket can send.
*
* @param[in] aSocket The socket.
* @param[in] aFdSet The write FD set.
*
* @retval TRUE The socket TX FD is in @p aWriteFdSet, and socket can send.
* @retval FALSE The socket TX FD is not in @p aWriteFdSet. Socket is not ready to send.
*
*/
bool utilsCanSocketSend(const utilsSocket *aSocket, const fd_set *aWriteFdSet);
/**
* Receives data from socket.
*
* MUST be used when `utilsCanSocketReceive()` returns `TRUE.
*
* @param[in] aSocket The socket.
* @param[out] aBuffer The buffer to output the read content.
* @param[in] aBufferSize Maximum size of buffer in bytes.
* @param[out] aSenderNodeId A pointer to return the Node ID of the sender (derived from the port number).
* Can be NULL if not needed.
*
* @returns The number of received bytes written into @p aBuffer.
*
*/
uint16_t utilsReceiveFromSocket(const utilsSocket *aSocket,
void *aBuffer,
uint16_t aBufferSize,
uint16_t *aSenderNodeId);
/**
* Sends data over the socket.
*
* @param[in] aSocket The socket.
* @param[in] aBuffer The buffer containing the bytes to sent.
* @param[in] aBufferSize Size of data in @p buffer in bytes.
*
*/
void utilsSendOverSocket(const utilsSocket *aSocket, const void *aBuffer, uint16_t aBufferLength);
#endif // PLATFORM_SIMULATION_SOCKET_UTILS_H_
+20 -131
View File
@@ -31,6 +31,7 @@
#include <openthread/random_noncrypto.h>
#include <openthread/platform/trel.h>
#include "simul_utils.h"
#include "utils/code_utils.h"
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
@@ -38,8 +39,6 @@
// Change DEBUG_LOG to all extra logging
#define DEBUG_LOG 0
// The IPv4 group for receiving
#define TREL_SIM_GROUP "224.0.0.116"
#define TREL_SIM_PORT 9200
#define TREL_MAX_PACKET_SIZE 1800
@@ -67,11 +66,9 @@ typedef struct Message
static uint8_t sNumPendingTx = 0;
static Message sPendingTx[TREL_MAX_PENDING_TX];
static int sTxFd = -1;
static int sRxFd = -1;
static uint16_t sPortOffset = 0;
static bool sEnabled = false;
static uint16_t sUdpPort;
static utilsSocket sSocket;
static uint16_t sPortOffset = 0;
static bool sEnabled = false;
static bool sServiceRegistered = false;
static uint16_t sServicePort;
@@ -117,80 +114,6 @@ static const char *messageTypeToString(MessageType aType)
}
#endif
static void initFds(void)
{
int fd;
int one = 1;
struct sockaddr_in sockaddr;
struct ip_mreqn mreq;
memset(&sockaddr, 0, sizeof(sockaddr));
otEXPECT_ACTION((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) != -1, perror("socket(sTxFd)"));
sUdpPort = (uint16_t)(TREL_SIM_PORT + sPortOffset + gNodeId);
sockaddr.sin_family = AF_INET;
sockaddr.sin_port = htons(sUdpPort);
sockaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
otEXPECT_ACTION(setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &sockaddr.sin_addr, sizeof(sockaddr.sin_addr)) != -1,
perror("setsockopt(sTxFd, IP_MULTICAST_IF)"));
otEXPECT_ACTION(setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &one, sizeof(one)) != -1,
perror("setsockopt(sTxFd, IP_MULTICAST_LOOP)"));
otEXPECT_ACTION(bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) != -1, perror("bind(sTxFd)"));
// Tx fd is successfully initialized.
sTxFd = fd;
otEXPECT_ACTION((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) != -1, perror("socket(sRxFd)"));
otEXPECT_ACTION(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) != -1,
perror("setsockopt(sRxFd, SO_REUSEADDR)"));
otEXPECT_ACTION(setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) != -1,
perror("setsockopt(sRxFd, SO_REUSEPORT)"));
memset(&mreq, 0, sizeof(mreq));
inet_pton(AF_INET, TREL_SIM_GROUP, &mreq.imr_multiaddr);
// Always use loopback device to send simulation packets.
mreq.imr_address.s_addr = inet_addr("127.0.0.1");
otEXPECT_ACTION(setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &mreq.imr_address, sizeof(mreq.imr_address)) != -1,
perror("setsockopt(sRxFd, IP_MULTICAST_IF)"));
otEXPECT_ACTION(setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) != -1,
perror("setsockopt(sRxFd, IP_ADD_MEMBERSHIP)"));
sockaddr.sin_family = AF_INET;
sockaddr.sin_port = htons((uint16_t)(TREL_SIM_PORT + sPortOffset));
sockaddr.sin_addr.s_addr = inet_addr(TREL_SIM_GROUP);
otEXPECT_ACTION(bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) != -1, perror("bind(sRxFd)"));
// Rx fd is successfully initialized.
sRxFd = fd;
exit:
if (sRxFd == -1 || sTxFd == -1)
{
exit(EXIT_FAILURE);
}
}
static void deinitFds(void)
{
if (sRxFd != -1)
{
close(sRxFd);
}
if (sTxFd != -1)
{
close(sTxFd);
}
}
static uint16_t getMessageSize(const Message *aMessage)
{
return (uint16_t)(&aMessage->mData[aMessage->mDataLength] - (const uint8_t *)aMessage);
@@ -198,31 +121,13 @@ static uint16_t getMessageSize(const Message *aMessage)
static void sendPendingTxMessages(void)
{
ssize_t rval;
struct sockaddr_in sockaddr;
memset(&sockaddr, 0, sizeof(sockaddr));
sockaddr.sin_family = AF_INET;
inet_pton(AF_INET, TREL_SIM_GROUP, &sockaddr.sin_addr);
sockaddr.sin_port = htons((uint16_t)(TREL_SIM_PORT + sPortOffset));
for (uint8_t i = 0; i < sNumPendingTx; i++)
{
uint16_t size = getMessageSize(&sPendingTx[i]);
#if DEBUG_LOG
fprintf(stderr, "\r\n[trel-sim] Sending message (num:%d, type:%s, port:%u)\r\n", i,
messageTypeToString(sPendingTx[i].mType), sPendingTx[i].mSockAddr.mPort);
#endif
rval = sendto(sTxFd, &sPendingTx[i], size, 0, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
if (rval < 0)
{
perror("sendto(sTxFd)");
exit(EXIT_FAILURE);
}
utilsSendOverSocket(&sSocket, &sPendingTx[i], getMessageSize(&sPendingTx[i]));
}
sNumPendingTx = 0;
@@ -279,7 +184,7 @@ static void processMessage(otInstance *aInstance, Message *aMessage, uint16_t aL
switch (aMessage->mType)
{
case TREL_DATA_MESSAGE:
otEXPECT(aMessage->mSockAddr.mPort == sUdpPort);
otEXPECT(aMessage->mSockAddr.mPort == sSocket.mPort);
otPlatTrelHandleReceived(aInstance, aMessage->mData, aMessage->mDataLength);
break;
@@ -309,7 +214,7 @@ void otPlatTrelEnable(otInstance *aInstance, uint16_t *aUdpPort)
{
OT_UNUSED_VARIABLE(aInstance);
*aUdpPort = sUdpPort;
*aUdpPort = sSocket.mPort;
#if DEBUG_LOG
fprintf(stderr, "\r\n[trel-sim] otPlatTrelEnable() *aUdpPort=%u\r\n", *aUdpPort);
@@ -417,62 +322,46 @@ void platformTrelInit(uint32_t aSpeedUpFactor)
sPortOffset *= (MAX_NETWORK_SIZE + 1);
}
initFds();
utilsInitSocket(&sSocket, TREL_SIM_PORT + sPortOffset);
OT_UNUSED_VARIABLE(aSpeedUpFactor);
}
void platformTrelDeinit(void) { deinitFds(); }
void platformTrelDeinit(void) { utilsDeinitSocket(&sSocket); }
void platformTrelUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, struct timeval *aTimeout, int *aMaxFd)
{
OT_UNUSED_VARIABLE(aTimeout);
// Always ready to receive
if (aReadFdSet != NULL)
utilsAddSocketRxFd(&sSocket, aReadFdSet, aMaxFd);
if (sNumPendingTx > 0)
{
FD_SET(sRxFd, aReadFdSet);
if (aMaxFd != NULL && *aMaxFd < sRxFd)
{
*aMaxFd = sRxFd;
}
}
if ((aWriteFdSet != NULL) && (sNumPendingTx > 0))
{
FD_SET(sTxFd, aWriteFdSet);
if (aMaxFd != NULL && *aMaxFd < sTxFd)
{
*aMaxFd = sTxFd;
}
utilsAddSocketTxFd(&sSocket, aWriteFdSet, aMaxFd);
}
}
void platformTrelProcess(otInstance *aInstance, const fd_set *aReadFdSet, const fd_set *aWriteFdSet)
{
if (FD_ISSET(sTxFd, aWriteFdSet) && (sNumPendingTx > 0))
if ((sNumPendingTx > 0) && utilsCanSocketSend(&sSocket, aWriteFdSet))
{
sendPendingTxMessages();
}
if (FD_ISSET(sRxFd, aReadFdSet))
if (utilsCanSocketReceive(&sSocket, aReadFdSet))
{
Message message;
ssize_t rval;
Message message;
uint16_t len;
message.mDataLength = 0;
rval = recvfrom(sRxFd, (char *)&message, sizeof(message), 0, NULL, NULL);
len = utilsReceiveFromSocket(&sSocket, &message, sizeof(message), NULL);
if (rval < 0)
if (len > 0)
{
perror("recvfrom(sRxFd)");
exit(EXIT_FAILURE);
processMessage(aInstance, &message, len);
}
processMessage(aInstance, &message, (uint16_t)(rval));
}
}
+7 -27
View File
@@ -40,6 +40,7 @@
#include <openthread/platform/debug_uart.h>
#include "simul_utils.h"
#include "utils/code_utils.h"
#include "utils/uart.h"
@@ -172,34 +173,13 @@ exit:
void platformUartUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, fd_set *aErrorFdSet, int *aMaxFd)
{
if (aReadFdSet != NULL)
utilsAddFdToFdSet(s_in_fd, aReadFdSet, aMaxFd);
utilsAddFdToFdSet(s_in_fd, aErrorFdSet, aMaxFd);
if ((s_write_length > 0))
{
FD_SET(s_in_fd, aReadFdSet);
if (aErrorFdSet != NULL)
{
FD_SET(s_in_fd, aErrorFdSet);
}
if (aMaxFd != NULL && *aMaxFd < s_in_fd)
{
*aMaxFd = s_in_fd;
}
}
if ((aWriteFdSet != NULL) && (s_write_length > 0))
{
FD_SET(s_out_fd, aWriteFdSet);
if (aErrorFdSet != NULL)
{
FD_SET(s_out_fd, aErrorFdSet);
}
if (aMaxFd != NULL && *aMaxFd < s_out_fd)
{
*aMaxFd = s_out_fd;
}
utilsAddFdToFdSet(s_out_fd, aWriteFdSet, aMaxFd);
utilsAddFdToFdSet(s_out_fd, aErrorFdSet, aMaxFd);
}
}