Home/Support/Support Forum/9P9215 Net+OS UDP Receive
Welcome to Digi Forum, where you can ask questions and receive answers from other members of the community.

9P9215 Net+OS UDP Receive

0 votes
Embarrasingly simple requirement that I can't make work! Using Net+OS patched to a few months ago, on a 9P-9215. I want to have a single socket set up to receive all UDP packets with a specific port number. All the non-Digi resources indicate that this is as simple as opening a socket, binding it to the port number (and, optionally, a specific local address) and calling recv() or recvfrom(). However recv() always fails with error 128 - "Socket is not connected". I found the Digi documentation on UDP sockets to be a little sparse, and it didn't always tie up with non-Digi sources.

I've stripped most of the error checking from the following code (since no errors):
#define SNMP_MESSAGE_PORT 161
#define NET_RX_BUFFER_SIZE 512

SOCKET mainSock;
struct sockaddr_in rxAddr;
int errCode;

mainSock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); // Create the socket to start - using UDP
/* Set blocking socket explicitly, to be certain */
int sockOption = 1;
setsockopt(mainSock, SOL_SOCKET, SO_BIO, (char *)&sockOption, sizeof(sockOption));

rxAddr.sin_addr.s_addr = htonl(localIp); // also used INADDR_ANY
rxAddr.sin_family = AF_INET;
rxAddr.sin_len = sizeof(rxAddr);
rxAddr.sin_port = htons(SNMP_MESSAGE_PORT);
bind(mainSock,(struct sockaddr *)&rxAddr, sizeof(rxAddr));

struct fd_set masterReadSet;
struct fd_set readSet;
int rxLen;
static char rxBuffer[NET_RX_BUFFER_SIZE]; // Fixed UDP receive buffer

/* Pre-calculate the set of sockets for select() */
FD_ZERO(&masterReadSet);
FD_SET(mainSock, &masterReadSet);

for (;;)
{
readSet = masterReadSet;
errCode = select(mainSock + 1, &readSet, NULL, NULL, NULL);
if (errCode == 0) // 0 is a timeout - might happen after a very long time - can ignore.
{
continue;
}
if (errCode < 0) // -1 is an error.
{
errCode = getErrno(); // Always error code 128 here
continue;
}
/*
* Now see if we have any receive data to process
*/
if (FD_ISSET(mainSock, &readSet))
{
rxLen = recv(mainSock, rxBuffer, NET_RX_BUFFER_SIZE, 0);
if (rxLen <= 0)
{ // No data - some sort of network error (or could potentially get empty packet)
errCode = getErrno();
continue;
}
tx_thread_sleep(1);
}

When I send a UDP packet to the device, the select() duly triggers, but recv() always gives an error (apparently without blocking; if I comment out the select(), recv() completes immediately).

I've tried a different port number, among other things.

Am I missing something really obvious?
asked May 18, 2021 in NET+OS by steved2 Seasoned Professional (183 points)

Please log in or register to answer this question.

1 Answer

0 votes
 
Best answer
Please take a look at C:\netos75\src\examples\Cpptest\ example
This should work as well:
https://www.geeksforgeeks.org/udp-server-client-implementation-c/
answered May 18, 2021 by LeonidM Veteran of the Digi Community (4,411 points)
selected May 19, 2021 by steved2
Thanks for the prompt response. I'd actually used the www.geeksforgeeks.org example as a basis for my own code. However I don't need the sender address, so used recv() instead of recvfrom().
According to both Digi and all the online documentation, recv() is equivalent to: recvfrom(fd, buf, len, flags, NULL, 0);
And online says "The recv() call is normally used only on a connected socket" - note "normally", not "can only be used".
In the context of the Treck stack, none of this is correct. I changed my call to use recvfrom(), and it all started working!

Incidentally, there's a bug in the example code in CSocket.cxx. It starts in CSocket::Create(), where it is assumed that a socket number of zero is invalid. Not the case! (Already been bitten by that one). I imagine that misconception has been propagated through the code.
...