Azure Sphere - UDP recv returned Resource temporarily unavailable

yash chabria 21 Reputation points
2020-09-25T01:35:19.22+00:00

I am experiencing issue with udp reception

msg_len = sendto(sock_down, (const char*)buff_req, sizeof buff_req,
MSG_CONFIRM, (const struct sockaddr*)&hostaddr,
sizeof(hostaddr));

    clock_gettime(CLOCK_MONOTONIC, &send_time);
    pthread_mutex_lock(&mx_meas_dw);
    meas_dw_pull_sent += 1;
    pthread_mutex_unlock(&mx_meas_dw);
    req_ack = false;
    autoquit_cnt++;

    /* listen to packets and process them until a new PULL request must be sent */
    recv_time = send_time;
    while ((int)difftimespec(recv_time, send_time) < keepalive_time) {

        /* try to receive a datagram */
     //   msg_len = recv(sock_down, (void*)buff_down, (sizeof buff_down) - 1, 0);
        msg_len = recvfrom(sock_down, (char*)buff_down, (sizeof buff_down) - 1,
            MSG_WAITALL, (struct sockaddr*)&hostaddr,
            &msg_len);
        clock_gettime(CLOCK_MONOTONIC, &recv_time);

        /* if no network message was received, got back to listening sock_down socket */
        if (msg_len == -1) {

             Log_Debug("WARNING: [down] recv returned %s\n", strerror(errno)); /* too verbose */
            continue;
        }
Azure Sphere
Azure Sphere
An Azure internet of things security solution including hardware, operating system, and cloud components.
157 questions
{count} votes

2 answers

Sort by: Most helpful
  1. yash chabria 21 Reputation points
    2020-11-17T02:26:54.837+00:00

    Finally I got answer from MS:

    #include <stdio.h>  //printf
    #include <string.h> //memset
    #include <stdlib.h> //exit(0);
    #include <arpa/inet.h>
    #include <sys/socket.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    #include <netinet/in.h>
    
    #define SERVER "xxx.xxx.xxx.xxx"
    #define BUFLEN 512  //Max length of buffer
    #define PORT 1709   //The port on which to send data
    
    
    
    void die(char* s)
    {
        perror(s);
        exit(1);
    }
    
    void UdpTest()
    {
        struct sockaddr_in si_server;
        int s;
        unsigned int slen;
    
        struct sockaddr_in si_client; // Additional structure
    
        char buf[BUFLEN];
        char message[BUFLEN];
    
    
        if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
        {
            die("socket");
        }
    
        //const char* nic = "wlan0";
        //const size_t len = strlen(nic);
    
    
        memset((char*)&si_server, 0, sizeof(si_server));
        si_server.sin_family = AF_INET;
        si_server.sin_port = htons(PORT);
    
        if (inet_aton(SERVER, &si_server.sin_addr) == 0)
        {
            fprintf(stderr, "inet_aton() failed\n");
            exit(1);
        }
    
    
        // Additional initialization
        memset((char*)&si_client, 0, sizeof(si_client));
        si_client.sin_family = AF_INET;
        si_client.sin_addr.s_addr = htonl(INADDR_ANY);
        si_client.sin_port = htons(PORT);
        bind(s, (struct sockaddr*)&si_client, sizeof(si_client));
    
    
        for (int i = 0; i < 20; i++)
        {
            sprintf(message, "This is message %i", i);
            printf("Sending: %s\n", message);
    
    
            //send the message
            if (sendto(s, message, strlen(message), 0, (struct sockaddr*)&si_server, sizeof(si_server)) == -1)
            {
                die("sendto()");
            }
    
            //receive a reply and print it
            //clear the buffer by filling null, it might have previously received data
            memset(buf, '\0', BUFLEN);
            int recv_len;
            //try to receive some data, this is a blocking call
    
            if (-1 == (recv_len = recvfrom(s, buf, BUFLEN, 0, (struct sockaddr*)&si_client, &slen)))
            {
                die("recvfrom()");
            }
    
            buf[recv_len] = '\0';
            printf("Received: %s\n", buf);
            sleep(1);
        }
       close(s);
    }
    
    1 person found this answer helpful.
    0 comments No comments

  2. Mark Radbourne 6 Reputation points Microsoft Employee
    2020-11-25T18:13:00.34+00:00

    Adding additional details:

    The issue is caused by the manner in which UDP works. Typically a UDP client will specify the remote server's port number in a sockaddr_in structure that is passed to sendto function. In this instance it is sending a UDP packet to the server's port 1709. When the server responds to this packet it will send it to the port that is specified as the source port by the client. If that is not set by the client then the TCP stack will select a random port. On a Sphere this is a problem since you have to specify in the manifest which ports are open to receive UDP packets. You can't possibly predict the port number that TCP will select for the source port thus the message will be rejected by the Sphere.

    In order to fix this, you must declare a second sockaddr_in structure and add the port to which the response is to be sent. In this instance this is also 1709. This structure is then passed to the bind call. When the packet is sent the server will see the selected port as the source port and respond on that in the same manner however, this will now be the known port number of, in this example, 1709. The Sphere manifest specifies that UDP messages can be received on port 1709 so it will successfully receive the message. The pertinent lines in the code above can be found at 57 through 61.

    1 person found this answer helpful.
    0 comments No comments