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 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 by LeonidM Veteran of the Digi Community (4,355 points)
selected May 19 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.
...