Search code examples
clwip

is it possible to use udp_sendto to resend an UDP packet?


I have this code

Only as example to show the intention of resending some info (retry)

static char server_req [] = "INIT_PREVIEW";

static void
halt_task ( void )
{
    while ( true )
        ;
}
void
tst_task ( Tst_struct * tst_p )
{
    struct udp_pcb  *   my_udp  = NULL;
    struct pbuf     *   p       = NULL;
    ip4_addr_t          server_ip;

    // Wait 3 seconds for everything to start
    vTaskDelay ( pdMS_TO_TICKS ( 3000 ) );

    // Creates udp
    if ( (my_udp = udp_new ()) == NULL )
        halt_task ();

    udp_bind  ( my_udp, IP_ADDR_ANY, 10000 );

    if ( (p = pbuf_alloc ( PBUF_TRANSPORT, sizeof ( server_req ), PBUF_RAM )) == NULL )
        halt_task ();

    inet_aton ( "195.168.1.90", & server_ip );

    memcpy ( p->payload, server_req, sizeof ( server_req ) );

    for ( int tries = 1 ; tries <= 3 ; tries ++ ) {
        udp_sendto  ( my_udp, p, & server_ip, 10000 );
        vTaskDelay  ( pdMS_TO_TICKS ( 500 ) );
    }

    halt_task ();
}

here is wireshark output

first packet

second packet

as it can be seen:

  • not sent 3 times but only 2
  • 2nd time it sends more (garbage) data

any idea?

thanks in advance


Solution

  • I know that in your case you're using lwIP library, but more in general it is quite easy to "resend" a UDP packet (and that should apply to lwIP too):

    void test(void) {
      int sockfd = init_socket_somehow();
      bind_socket_somehow(sockfd);
    
      // example loop that resends packets the same way they are received:
      while (1) {
        struct sockaddr sender; // this will store info about the sender
        socklen_t sender_size; // this will store sender address' size
    
        uint8_t buff[500]; // this will store the UDP packet contents
        size_t buff_size; // this will store buff's size
    
        ssize_t bytes = recvfrom(sockfd, buff, 500, 0, &sender, &sender_size);
    
        if (bytes > 0) {
          buff_size = (size_t) bytes;
    
          // we have received some data via UDP, now we will resend the same data back to the sender
          sendto(sockfd, buff, buff_size, 0, &sender, sender_size);
        }
      }
    }
    

    NOTE: take this snippet more like pseudocode (it just shows the logic; no error checks are made); you can adapt it in order to use it in your program.

    EDIT:

    The previous snippet resends received packets, which is not what you asked, so this following snippet can be used to resend the same packet more than once:

    // send packet "packet" three times
    uint8_t packet[100]; // fill the packet with some content to send
    struct sockaddr dest = ...; // get the destination address and port somehow
    socklen_t dest_size = ...; // and also the destination address' size
    
    for (size_t i = 0; i < 3; i += 1) {
      sendto(sockfd, packet, 100, 0, &dest, dest_size);
    }
    

    I've looked around on the Internet and, as you already noted in your answer, the lwIP library behaves quite strangely in some cases.

    But I also found out that lwIP supports a BSD socket interface (i.e.: the same functions that I used in my code snippets and that are widely used on Linux and other OSes: socket(), bind(), recvfrom(), sendto(), etc.), so my suggestion is to use the BSD socket functions when using the lwIP library in order to have a (hopefully) more predictable behavior.

    This link should help you using BSD socket API with lwIP library.