Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Failure sending data over UDP blocking socket #2389

Closed
jenia81 opened this issue Aug 8, 2016 · 9 comments
Closed

Failure sending data over UDP blocking socket #2389

jenia81 opened this issue Aug 8, 2016 · 9 comments

Comments

@jenia81
Copy link

jenia81 commented Aug 8, 2016

The following scenario fails:

  1. Create UDP blocking socket
  2. Set timeout to the socket
  3. Try to receive message on UDP socket. If no message was sent, recvfrom() will fail with NSAPI_ERROR_WOULD_BLOCK error.
  4. Try to send message on UDP socket. The sendto() will fail with NSAPI_ERROR_PARAMETER error.

Attached is sample app that recreates this problem (rename it to .cpp)
udp_socket_example.txt
Should be compiled with following command:
"mbed compile -t GCC_ARM -m K64F --source ."

@jenia81
Copy link
Author

jenia81 commented Aug 8, 2016

@trianglee
@sg-

@sg-
Copy link
Contributor

sg- commented Aug 8, 2016

@geky

@geky
Copy link
Contributor

geky commented Aug 8, 2016

Hi Jenia, thanks for reporting this issue.

The NSAPI_ERROR_PARAMETER is actually the expected behavior. The recvfrom function modifies the SocketAddress in place, if a recvfrom call fails the SocketAddress is set to null (represented as “0.0.0.0”). The following sendto call fails with NSAPI_ERROR_PARAMETER because the address “0.0.0.0” is an invalid IP address.

The address argument to the recvfrom function is useful for UDP servers, but usually unnecessary for applications where the server address is known beforehand. In this case, a NULL address can be used instead since it is safely ignored:

//some message is sent on UDP socket
sentBytes = _socket->sendto(*_socketAddress, messageOut, messageSize);

// message is received on UDP socket
recievedBytes = _socket->recvfrom(NULL, messageIn, messageBufferSize);
if (recievedBytes == NSAPI_ERROR_WOULD_BLOCK){
    //some message is sent on UDP socket
    sentBytes = _socket->sendto(*_socketAddress, messageOut, messageSize);
}

Let me know if you find an issue with this.

@hasnainvirk
Copy link
Contributor

@jenia81 I think I have found the culprit here. There is nothing wrong with APIs. I itested with the code provided by you with a simple python UDP server running on my home machine. The only issue I found was that the ARM machine (office laptop) firewall was blocking my traffic. So I ran the UDP server on my personal machine and made sure that the socket was opened.

I would also suggest you to use some other port than 5683 (which is a coap port). Use something like 6005. Also, for this test call sendto() first and then call recvfrom() so as to get a response from our dummy server. I had added some code to enable traces , you can remove it if you wish. I tried with both removing the CLIENT from mbed_app.json and keeping it, reponse is just the same.

So I am pretty sure that the issue is with your setup rather than mbed-os/client or any other networking APIs.

How to reproduce what I did:

  1. A dummy UDP server
from socket import *

address('0.0.0.0', 6005)
server_socket = socket(AF_INET, SOCK_DGRAM)
server_socket.bind(address)

while(1):
       print "Listening"
       recv_data, addr = server_socket.recvfrom(2048)
       print recv_data
       if recv_data == "PING"
               print "Responding"
               server_socket.sendto("Got it", addr)
  1. Your client code
/******YOUR CODE******/
#include "mbed.h"
#include "rtos.h"
#include "EthernetInterface.h"

#include <UDPSocket.h>
#include "SocketAddress.h"

EthernetInterface gEth;
#define SERVER_ADDRESS "192.168.1.100" //My machine's address
#define SERVER_PORT 6005

#include "mbed-trace/mbed_trace.h"

Serial output(USBTX, USBRX);

void trace_printer(const char* str) {
    printf("%s", str);
}


static bool DeviceIpAddrGet()
{
    int retries = 5;

    while (retries--) {
        const char *ip = gEth.get_ip_address();
        if (ip != NULL) {
            printf("Device IP address: %s\r\n", ip);
            return true;
        }
        else {
            wait(0.2);
        }
    }

    printf("Failed retrieving device IP address\r\n");
    return false; /* failed to retrieve a valid IP address */
}


int main(int argc, char *argv[])
{

    mbed_trace_init();
    mbed_trace_print_function_set(trace_printer);
    output.baud(115200);

    char messageOut[] = "PING";
    char messageIn[100];

    int rc = gEth.connect();
    if (rc != 0) {
        printf("Failed connecting to ethernet interface!\r\n");
        return EXIT_FAILURE;
    }

    // Get device IP address - this should yield a factory IP address
    DeviceIpAddrGet();

    UDPSocket *_socket;
    SocketAddress *_socketAddress;
    int sentBytes;
    int recievedBytes;

    _socketAddress = new SocketAddress((NetworkInterface*)&gEth, SERVER_ADDRESS, SERVER_PORT);
    _socket = new UDPSocket((NetworkInterface*)&gEth);

    _socket->set_blocking(true);
    _socket->set_timeout(3000);

    sentBytes = _socket->sendto(*_socketAddress, messageOut, strlen(messageOut));
    if (sentBytes == NSAPI_ERROR_WOULD_BLOCK) {
        printf("Timeout error  %i \r\n", sentBytes);
    }
    else if (sentBytes < 0) {
        printf("Failed sending data to the socket %i \r\n", sentBytes);
    }
    else if ((unsigned)sentBytes != strlen(messageOut)) {
        printf("Error data size was send , packet size %i, sent bytes messageSize %i \r\n", strlen(messageOut), sentBytes);
    }

        recievedBytes = _socket->recvfrom(_socketAddress, messageIn, sizeof(messageIn));
        if (recievedBytes == NSAPI_ERROR_WOULD_BLOCK){
            printf("Failed to receive data from the socket %i \r\n", recievedBytes); //should be warn level
        }
        else if (recievedBytes < 0) {
            printf("Failed to receive data from the socket %i \r\n", recievedBytes);
        }

    return 0;
}

@jenia81
Copy link
Author

jenia81 commented Aug 9, 2016

@geky
Using NULL parameter in recvfrom() function indeed solved the problem.
By the way, the same code worked with previous mbed-os I worked with (with socketAddress parameter).
I have another question though, I want to check that the received packet was sent from the address that I expect (the one that I send data to).
Is there any API you expose that can tell me from which IP the received packed had arrived?

@hasnainvirk the issue was that if recvfrom() fails because there is no data received (the error would be then NSAPI_ERROR_WOULD_BLOCK), then next sendto fails too.

@geky
Copy link
Contributor

geky commented Aug 9, 2016

Glad it worked for you.

Unfortunately, in previous versions of mbed-os the state of the address after a failed recvfrom was undefined. Most network interfaces didn’t bother to modify the address until an actual packet had arrived, so the code would usually work. Imagine what would happen if I sent a random packet to the port you happened to be listening on, the original address would be lost. The recent changes made the behavior of a failed recvfrom more consistent.

As for checking that checking that the received packet is from the correct source, your best bet is to create a temporary SocketAddress:

//some message is sent on UDP socket
sentBytes = _socket->sendto(*_socketAddress, messageOut, messageSize);

// message is received on UDP socket
SocketAddress sourceAddress;
recievedBytes = _socket->recvfrom(&sourceAddress, messageIn, messageBufferSize);
if (recievedBytes >= 0) {
    // successfully received a message
    if (strcmp(_socketAddress.get_ip_address(), &sourceAddress.get_ip_address()) == 0) {
        // _socketAddress and sourceAddress are the same
        sentBytes = _socket->sendto(*_socketAddress, messageOut, messageSize);
    }
}

You were right that the recvfrom address parameter is how you get the packet’s source address, however there needs to be a temporary to avoid overwriting the _socketAddress.

@hasnainvirk
Copy link
Contributor

@jenia81 Yup I understood that. That's why if you notice, I changed the pattern of calls in your code and mentioned it in the comment that this is an example of showing you that it works.

@hasnainvirk
Copy link
Contributor

@jenia81 Can you please close this issue then if you are happy with the discussion ?

@jenia81
Copy link
Author

jenia81 commented Aug 9, 2016

@geky I've added the code you suggested and it works now.
Closing the issue.
Thanks!

@jenia81 jenia81 closed this as completed Aug 9, 2016
artokin pushed a commit to artokin/mbed-os that referenced this issue Aug 17, 2020
…..48609ae

48609ae Merge branch 'release_internal' into release_external
62d8586 Ignore ns_monitor when receiving Ack (ARMmbed#2417)
3323f36 Add support for Ethernet RA dns configuration
d8e7d40 Iotthd 4239 (ARMmbed#2414)
b46f3c6 add empty function for ws_stack_info_get
fc97980 Changed RADIUS shared secret length to 16-bit value
f827ffc Added information API to Wi-SUN and border router
8f1f9d5 EDFE error handling update
51bf94e Fix adaptation interface unit tests (ARMmbed#2409)
0860b57 FHSS_WS: Fixed reading unicast remaining slots (ARMmbed#2408)
4d8c03b Border Router RADIUS client basic authentication functionality (ARMmbed#2406)
fbfada9 Adaptation IF: Allocate fragmentation buffer only if needed (ARMmbed#2407)
66f1bff Added storing of PAN version to NVM on BR
89826ce Iotthd 4224 (ARMmbed#2403)
3fc1ae2 BR EUI-64 is now selected for 4WH using PMKID on 4WH Message 1
af8438e Timing tool traces (ARMmbed#2401)
7938795 Fixed new PD data request for check if EDFE exchange is active.
85ab8fd Extented Frame exchange support
86b1f27 Merge pull request ARMmbed#2399 from ARMmbed/IOTTHD-4220
fed69e0 Add missing test method to ws_empty_functions
6b58e26 Add EDFE mode to Socket API setsockopt
1283077 Test API to adjust 6LoWPAN fragmentation MTU size (ARMmbed#2398)
e787874 Init MAC MTU size based on driver MTU size (ARMmbed#2397)
bf8e89e Ignore neighbors using unsupported channel function (ARMmbed#2395)
1c263fd FHSS exclude channel usage from mask and Brazilian Domain support
841dcbe MAC: Configurable data whitening (ARMmbed#2393)
9a10d66 Fix global address detection (ARMmbed#2392)
f27fe86 Corrected network name and PAN ID change on auth start
bcce0ed Clarified border router routing table API description
e4630a4 Wi-SUN interface now informs address changes as interface events
2174374 Fix error found by coverity (ARMmbed#2389)
843254a MPL: traces for transmit and receive message (ARMmbed#2387)

git-subtree-dir: features/nanostack/sal-stack-nanostack
git-subtree-split: 48609ae
artokin pushed a commit to artokin/mbed-os that referenced this issue Aug 18, 2020
…..48609ae

48609ae Merge branch 'release_internal' into release_external
62d8586 Ignore ns_monitor when receiving Ack (ARMmbed#2417)
3323f36 Add support for Ethernet RA dns configuration
d8e7d40 Iotthd 4239 (ARMmbed#2414)
b46f3c6 add empty function for ws_stack_info_get
fc97980 Changed RADIUS shared secret length to 16-bit value
f827ffc Added information API to Wi-SUN and border router
8f1f9d5 EDFE error handling update
51bf94e Fix adaptation interface unit tests (ARMmbed#2409)
0860b57 FHSS_WS: Fixed reading unicast remaining slots (ARMmbed#2408)
4d8c03b Border Router RADIUS client basic authentication functionality (ARMmbed#2406)
fbfada9 Adaptation IF: Allocate fragmentation buffer only if needed (ARMmbed#2407)
66f1bff Added storing of PAN version to NVM on BR
89826ce Iotthd 4224 (ARMmbed#2403)
3fc1ae2 BR EUI-64 is now selected for 4WH using PMKID on 4WH Message 1
af8438e Timing tool traces (ARMmbed#2401)
7938795 Fixed new PD data request for check if EDFE exchange is active.
85ab8fd Extented Frame exchange support
86b1f27 Merge pull request ARMmbed#2399 from ARMmbed/IOTTHD-4220
fed69e0 Add missing test method to ws_empty_functions
6b58e26 Add EDFE mode to Socket API setsockopt
1283077 Test API to adjust 6LoWPAN fragmentation MTU size (ARMmbed#2398)
e787874 Init MAC MTU size based on driver MTU size (ARMmbed#2397)
bf8e89e Ignore neighbors using unsupported channel function (ARMmbed#2395)
1c263fd FHSS exclude channel usage from mask and Brazilian Domain support
841dcbe MAC: Configurable data whitening (ARMmbed#2393)
9a10d66 Fix global address detection (ARMmbed#2392)
f27fe86 Corrected network name and PAN ID change on auth start
bcce0ed Clarified border router routing table API description
e4630a4 Wi-SUN interface now informs address changes as interface events
2174374 Fix error found by coverity (ARMmbed#2389)
843254a MPL: traces for transmit and receive message (ARMmbed#2387)

git-subtree-dir: features/nanostack/sal-stack-nanostack
git-subtree-split: 48609ae
artokin pushed a commit to artokin/mbed-os that referenced this issue Aug 21, 2020
…3fe574..48609ae

48609ae Merge branch 'release_internal' into release_external
62d8586 Ignore ns_monitor when receiving Ack (ARMmbed#2417)
3323f36 Add support for Ethernet RA dns configuration
d8e7d40 Iotthd 4239 (ARMmbed#2414)
b46f3c6 add empty function for ws_stack_info_get
fc97980 Changed RADIUS shared secret length to 16-bit value
f827ffc Added information API to Wi-SUN and border router
8f1f9d5 EDFE error handling update
51bf94e Fix adaptation interface unit tests (ARMmbed#2409)
0860b57 FHSS_WS: Fixed reading unicast remaining slots (ARMmbed#2408)
4d8c03b Border Router RADIUS client basic authentication functionality (ARMmbed#2406)
fbfada9 Adaptation IF: Allocate fragmentation buffer only if needed (ARMmbed#2407)
66f1bff Added storing of PAN version to NVM on BR
89826ce Iotthd 4224 (ARMmbed#2403)
3fc1ae2 BR EUI-64 is now selected for 4WH using PMKID on 4WH Message 1
af8438e Timing tool traces (ARMmbed#2401)
7938795 Fixed new PD data request for check if EDFE exchange is active.
85ab8fd Extented Frame exchange support
86b1f27 Merge pull request ARMmbed#2399 from ARMmbed/IOTTHD-4220
fed69e0 Add missing test method to ws_empty_functions
6b58e26 Add EDFE mode to Socket API setsockopt
1283077 Test API to adjust 6LoWPAN fragmentation MTU size (ARMmbed#2398)
e787874 Init MAC MTU size based on driver MTU size (ARMmbed#2397)
bf8e89e Ignore neighbors using unsupported channel function (ARMmbed#2395)
1c263fd FHSS exclude channel usage from mask and Brazilian Domain support
841dcbe MAC: Configurable data whitening (ARMmbed#2393)
9a10d66 Fix global address detection (ARMmbed#2392)
f27fe86 Corrected network name and PAN ID change on auth start
bcce0ed Clarified border router routing table API description
e4630a4 Wi-SUN interface now informs address changes as interface events
2174374 Fix error found by coverity (ARMmbed#2389)
843254a MPL: traces for transmit and receive message (ARMmbed#2387)

git-subtree-dir: connectivity/nanostack/sal-stack-nanostack
git-subtree-split: 48609ae
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants