SO_RCVTIMEO option on LwIP - c

I'm using LwIP with FreeRTOS. My project is based on the example on this URL FreeRTOS with LwIP project. I'm also using LPC1769 with LPCXpresso version 6. CMSIS version 2.
I'm using LwIP to stream MP3 files with a UDP socket. The transfer has a nice speed but the thing is that sometimes lwip_recvfrom blocks after thousands of operations.
I can never see the timeout condition. I think I'm doing something wrong.
The followed steps are:
int socket = lwip_socket(AF_INET, SOCK_DGRAM, 0);
if(lwip_setsockopt( socket,
SOL_SOCKET,
SO_RCVTIMEO,
(int)timeoutTimeInMiliSeconds,
sizeof(int)) == -1)
{
return -1;
}
....
if(lwip_bind(protocolConfig.socket,
(struct sockaddr *)&sLocalAddr,
sizeof(sLocalAddr)) == -1)
{
return -1;
}
bytesWritten = lwip_sendto( socket,
transmitBuffer,
transmitBufferIndex,
0,
(struct sockaddr *)&sDestAddr,
sizeof(sDestAddr));
.....
bytesReceived = lwip_recvfrom( socket,
receptionBuffer,
receptionBufferSize,
0,
NULL,
NULL);
if(bytesReceived < 0)
{
//Error stuff, this condition is never reached.
}
Somebody knows what's wrong here?

Problem solved.
lwip_setsockopt has this prototype:
int lwip_setsockopt(int socket, int level, int option_name,const void *option_value, socklen_t option_len);
And I was sending by copy the value of option_value.
The timeout is working fine.

Related

Binding to a UDP socket for IOCP using C

I am trying to read from a UDP port, from a local (loopback) application, using IOCP. IOCP works fine for TCP/IP, but I am unable to open the socket properly for UDP.
This is what I am doing:
// same as for tcp/ip
struct sockaddr_in remoteAddr = { 0 };
remoteAddr.sin_addr.s_addr = LOOPBACK_ADDRESS;
remoteAddr.sin_family = AF_INET;
remoteAddr.sin_port = htons(portNumber);
// using SOCK_DGRAM here
SOCKET sock = INVALID_SOCKET;
sock = WSASocketW(AF_INET, SOCK_DGRAM, IPPROTO_IP,
NULL, 0, WSA_FLAG_OVERLAPPED);
if( sock == INVALID_SOCKET ) {
LOG("WSASocketW failed: %d", WSAGetLastError());
return;
}
nRet = WSAConnect(*sock, (const struct sockaddr*)&remoteAddr, sizeof(remoteAddr),
NULL, NULL, NULL, NULL);
if (nRet == SOCKET_ERROR)
{
LOG("WSAConnect failed: %d", WSAGetLastError());
return;
}
nRet = WSARecv(sock, &wsabuf, 1, NULL, &flags, &overlapped, NULL);
if (nRet == SOCKET_ERROR && (ERROR_IO_PENDING != WSAGetLastError()))
{
LOG("WSARecv failed: %d", WSAGetLastError());
return;
}
// no errors of any kind
LOG("seems good so far");
Everything passes without errors, but GetQueuedCompletionStatus inside the worker loop thread never returns. If I do the same thing to connect to a TCP socket (just replace SOCK_DGRAM with SOCK_STREAM basically), I get data inside the loop.
Am I doing something obviously wrong?
(Btw) I know I could use WSARecvFrom, but I would like to reuse as much code as possible from the TCP socket. I.e. hopefully, set everything up and then post WSARecv calls inside the worker thread regardless of the type of the socket (WSARecv is supposed to work with UDP properly, AFAIK).
Managed to get it to work, thanks to the comment by #WouterHuysentruit.
Basically, if I want to receive UDP packets using WSARecv, I need to bind. If I want to send UDP packets using WSASend, I need to connect. So the following works:
if (port_type == incoming_packets)
{
// bind to port
ret = bind(*sock, (const struct sockaddr*)&remoteAddr, sizeof(remoteAddr));
...
WSARecv(...);
}
else
{
// this can send to a loopback udp port which is bound in
// a different application
ret = WSAConnect(*sock, (const struct sockaddr*)&remoteAddr, sizeof(remoteAddr), ...);
...
WSASend(...);
}
As others have pointed out, WSAReceiveFrom/WSASendTo are usually a better choice for UDP, but in this case I can support multiple port types using IOCP transparently.

How do I bind to a default interface when using packet mode in C?

First, I'm new to socket programming, so I might be missing something obvious.
Goal:
I'm trying to write a small utility to hand-craft ARP frames and send them on the wire, then listen for replies. I am using AF_PACKET, SOCK_DGRAM so the kernel handles the Ethernet header/trailer, but I get raw access to the data portion of the frame on send and receive.
The application is diagnostic in nature, so existing APIs and userland tools aren't suitable. I'm trying to find one (or more) devices in a broadcast domain that respond to ARP requests, but I'm not at all concerned with populating the system ARP cache or anything like that.
Question:
I would like the user to be able to specify an interface by name, or use an appropriate default instead. So far, everything works perfectly if I specify the interface... but if I don't, I'm not sure how best to deal with bind() and sendto().
Details:
Here's a representative sample of the code in question. Assume that *cfg points to a pre-allocated struct, with cfg->interface.name == "eth0":
int i;
int sock;
void *buf;
struct my_config_options *cfg;
struct ifreq ifr;
struct sockaddr_ll addr;
struct pollfd pfd;
// Packet buffer
buf = malloc(BUF_LEN);
if (buf == NULL) {
return 0;
}
// Open a socket
sock = socket(AF_PACKET, SOCK_DGRAM, 0);
if (sock_fd == -1) {
return 0;
}
// Get interface index
strncpy(ifr.ifr_name, cfg->interface.name, IFNAMSIZ);
if (ioctl(sock, SIOCGIFINDEX, &ifr) == -1) {
return 0;
}
cfg->interface.idx = ifr.ifr_ifindex;
// Get source MAC address
if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1) {
return 0;
}
for (i = 0; i < 6; i++) {
cfg->interface.mac[i] = ifr.ifr_hwaddr.sa_data[i];
}
// Get source IP address
if (ioctl(sock, SIOCGIFADDR, &ifr) == -1) {
return 0;
}
cfg->interface.ip = ((struct sockaddr_in *)(&ifr.ifr_addr))->sin_addr.s_addr;
// Bind socket to interface
memset(&addr, 0x00, sizeof(addr));
addr.sll_family = AF_PACKET;
addr.sll_protocol = htons(ETH_P_ARP);
addr.sll_ifindex = cfg->interface.idx;
if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
close(sock);
return 0;
}
...
// Send an ARP request
memset(&addr, 0x00, sizeof(addr));
addr.sll_family = AF_PACKET;
addr.sll_protocol = htons(ETH_P_ARP);
addr.sll_ifindex = cfg->interface.idx;
addr.sll_halen = ETH_ALEN;
for (i = 0; i < 6; i++) {
addr.sll_addr[i] = 0xff;
}
if (sendto(sock, buf, BUF_LEN, 0, (struct sockaddr *)&addr, sizeof(addr)) != BUF_LEN) {
close(sock);
return 0;
}
while (1) {
pfd.fd = sock;
pfd.events = POLLIN;
pfd.revents = 0;
i = poll(&pfd, 1, cfg->delay);
// Error
if (i < 0) {
close(sock);
return 0;
}
// Timed out
if (i == 0) {
break;
}
// Read buffered packet
i = sizeof(addr);
i = recvfrom(sock, buf, BUF_LEN, MSG_DONTWAIT, (struct sockaddr*)&addr, &i);
if (i < 0) {
close(sock);
return 0;
}
// Handle received data
...
}
So far so good.
However, I don't know what to tell bind() if I don't have an interface name or an interface index. The man pages are rather sparse on detail when it comes to packet mode. Apparently, I can bind to "0.0.0.0" for all interfaces, but I'm not working at the IP layer here -- I have a sockaddr_ll struct.
Is there a good way to tell bind() to pick an appropriate interface? Is that even a reasonable request at layer-2?
Possible Solutions:
1) Pick the first interface that is UP and not loopback.
2) Go one step further and check the assigned address.
I don't know if either of these is really desirable, though. I kind of want the code to "do the right thing" here -- that is, what the user would expect. So, if there's a conventional order to how any given tool chooses the egress interface, that's what I want to do.
I suspect many tools rely on the routing table to choose the best interface, but that's not a great fit here. Normally, ARP traffic is bound to the subnet you're in. In this case, the user might be looking for misconfigured devices, or devices on a parallel network in the same broadcast domain. (That is: If everything is working properly, they don't need this tool. So all bets are off.)
Now, I'm not 100% certain how other hosts will cope with ARP requests sourced from IPs not in their subnet, but that's a problem for another day.
TLDR:
Is there a deterministic way to pick "the correct egress interface" (if such a thing exists) on a host with more than one, if you can't depend on the routing table?
First of all, as you noticed already, you are not working on IP layer - but then, you need a raw socket, so open it with these parameters: AF_PACKET, SOCK_RAW, IPPROTO_RAW.
For getting a list of all interfaces, see here. Still you need criteria to select the appropriate one. I found code examples for sending and receiving raw ethernet frames, including selecting the interface from command line parameter. I did not verify if they are working, but you might have a look at.
If it is sufficient to you just to distinguish if your interface is wired or wireless, see here.
At last just a hint: If your programme still does not work, you might not have the appropriate privilege (CAP_NET_RAW), as described here.

Cannot sniff UDP packets in C without Wireshark running

I have a setup that looks like this:
Target ---- Switch ---- Switch ---- Windows computer
|
Linux computer
So I have a target connected to a switch it sends out UDP-packets for debug purpose. Normally these packets goes to a Windows computer for analysis, this works. I have now added a Linux computer as well, to get the same data to both Linux and Windows I have setup a managed switch to mirror the traffic, this works fine when I look in Wireshark. I have then written a simple C-application for analysing the data on the Linux computer, this software does only work if Wireshark is running at the same time. Otherwise it does not receive any data from the target. Why is this?
int main()
{
int saddr_size, data_size;
struct sockaddr saddr;
unsigned char *buffer = (unsigned char *) malloc(BUFFER_SIZE);
printf("Starting...\n");
int sock_raw = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (sock_raw < 0)
{
printf("Socket Error");
return 1;
}
while (1)
{
saddr_size = sizeof saddr;
data_size = recvfrom(sock_raw, buffer, BUFFER_SIZE, 0, &saddr, (socklen_t*) &saddr_size);
if (data_size < 0)
{
printf("Recvfrom error , failed to get packets\n");
return 1;
}
processPacket(buffer);
}
close(sock_raw);
printf("Finished");
return 0;
}
The data coming from the target are sent on a format similar to RTP and is addressed to the Windows computer.
So to sum up; Why do I not receive any data from the target in my C-application without Wireshark running?
Same as here, you need to put the interface (not socket as I originally posted) into promiscuous mode. Wireshark does that, which is why your code works when Wireshark is running.
Just a guess: promiscuous mode is not turned on and the ethernet controller is discarding frames not addressed to it.

How to correctly reuse a socket for sending UDP packets?

I have a function that gets called each time I want to send a UDP packet.
Things work great if I take these steps:
Create the socket
Set the socket options
Send the packet
Close the socket
However, I don't want to incur the overhead of constantly creating the socket each time the function is called.
Is there a preferred way to handle this? I only want to create the socket once, then keep re-using it. I've tried doing this by introducing a "first_time" flag - but when I take this approach, the sendto() function starts failing with an errno 0x23.
Since I'm working in VxWorks - it's unclear to me whether this error code is ENOTSUP (VxWorks Error Code) or EWOULDBLOCK (sendto error code). Either way, I'm not what the fix is.
See my code below.
/* Global Scope */
int send_socket = 0;
int first_time = 1;
void myFunction(...)
{
if (first_time == 1)
{
first_time = 0;
send_socket = socket(PF_INET , SOCK_RAW , IPPROTO_UDP);
if(send_socket < 0)
perror("socket() error");
/* Inform the kernel do not fill up the packet structure. */
/* We will build our own... */
if(setsockopt(send_socket, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) < 0)
perror("setsockopt() error");
}
// ... populate buffer ...
if(sendto(send_socket,
*buffer,
my_ip_header->total_length,
0,
(struct sockaddr *)&sin,
sizeof(sin)) < 0)
{
perror("sendto error");
}
// Normally I'd close the socket right here...
// But I don't want to do this, because I want to use it later!
// close(send_socket);
}
You use raw socket, not the UDP as you stated. Try to use SOCK_DGRAM flag when creating the socket.

sendto : Resource temporarily unavailable (errno 11)

I am having a problem with sendto.
I have a receiver who receives UPD packets with recvfrom and then replies to the sender using sendto.
Unfortunately, I am getting errno 11 (Resource temporarily unavailable). I am using two sockets.
The first packet is actually sent but not the ones afterwards:
sendto :: Success
error: 0.
sendto :: Resource temporarily unavailable
error: 11.
sendto :: Resource temporarily unavailable
...
This is an extract of my code:
int sockfd, sockSend;
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
perror("socket");
if ((sockSend = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
perror("socket");
if (fcntl(sockfd, F_SETOWN, getpid()) < 0) {
perror("fcntl");
}
if (fcntl(sockfd, F_SETFL, O_RDONLY | O_NONBLOCK | FASYNC) < 0) {
perror("fcntl");
}
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr))
< 0)
perror("bind");
And in a SIGIO handler:
len = sizeof(recv_addr);
char buffer[payload];
bzero(buffer, payload);
n = recvfrom(sockfd, buffer, payload, MSG_DONTWAIT, (struct sockaddr *)&recv_addr, &len);
while (n > 0) {
sprintf(response, "%d\n%d\n%d\n", items, target_buf, pb_sp);
sendto(sockSend, response, strlen(response), 0, (struct sockaddr *) &recv_addr, sizeof(recv_addr));
// sleep(1);
perror("sendto :");
printf("error: %d.\n", errno);
}
Could this issue come because the port is still hot, and I need to wait before reusing it? I've tried to change port but it hasn't helped.
Update: If the sleep(1) is commented out, then the packets actually get send!
Thanks a lot for your help.
The error you are getting:
EAGAIN or EWOULDBLOCK: The socket is marked nonblocking and the requested operation would block. POSIX.1-2001 allows either error to be returned for this case, and does not require these constants to have the same value, so a portable application should check for both possibilities.
You set the socket to non-blocking (O_NONBLOCK). The socket is still busy sending the previous message. You cannot send another until the first has finished sending. That's why sleeping helped.
Don't set it to non-blocking, or try again after select says you can.
If you have to set the socket to non-blocking, you can do it safely (and only?) using select:
select() and pselect() allow a program to monitor multiple file descriptors, waiting until one or more of the file descriptors become "ready" for some class of I/O operation (e.g., input possible). A file descriptor is considered ready if it is possible to perform the corresponding I/O operation (e.g., read(2)) without blocking.

Resources