Does UDP socket need heartbeat message

Hello,

I am running UDP protocol on RCM3315 and the task is to listen on one UDP Multicast Port and IP and send to another UDP Multicast Port and IP. I am also allowing for Telnet connection on another socket.

The Rabbit board is on a switch which handles multicast traffic.
The board is assigned a static IP address on the switch.

The following code is running tcp_tick and my_tick() which handles the states of connection. The switch cases handle send and receive port states.

Why do I need to use udp_send() with a heartbeat message to be able to receive packets?
See under “// Check the timer–if it has expired, send another heartbeat packet” comment.

If I comment the heartbeat message out, the receive interrupts but reads all zeroes.

Any idea of what the heartbeat message doing?


void main()
{
   unsigned int connectionDelayCnt = 0, statusDelayCnt = 0;

   io_init();

   memset(state, 0, sizeof(state));

   while (1) {

      costate               //TCPIP
      {
         tcp_listen (&socket, TCPIPPORT, 0, 0, NULL, 0);

         while (!sock_established(&socket) && sock_bytesready(&socket) == -1)
         {
            remoteConnection = 0;
            yield;
         }

         while (sock_established(&socket))
          {
            if (!remoteConnection)
            {
               tcpipCommandCounter = 0;
               delay (100);
               remoteConnection = 1;
               tcpipCommandReceived = 1;   //must fool TransmitData routine
               sprintf (outputBuf, "%s", commandPrompt);
               TransmitTCPData(prompt);
               tcpipCommandReceived = 0;
            }
            ReadTCPIPData();
            yield;
         }
         sock_close (&socket);
        }

      costate
      {
         if (pd_havelink(0) != 0)      // check if link exists
            // Drive the TCP/IP stack
            tcp_tick(NULL);
            // Drive UDP state machine
            my_tick();
      }

      costate                  //Send Message approximately every second
      {
         if (++statusDelayCnt == 5000)
         {
            statusDelayCnt = 0;

            sendmsg();
         }
      }

      costate                  //CONNECTION
      {
         if (++connectionDelayCnt == 500)
         {
            connectionDelayCnt = 0;

            SetConnection();
         }
      }

   } // end while (1)
} // end main()


// Do processing on the multicast sockets
xmem void my_tick(void)
{
   auto int i;
   auto int retval;
   auto longword remip;
   auto word remport;
   auto char ipbuf[16];
   unsigned long msg_id;

   // Process socket 0 (Multicast Write)
   switch (state[0].state) {
      case MCAST_OPENING:
         // Open the multicast socket
         retval = udp_extopen(&state[0].sock, IF_ETH0,
                        myFlashArray.port_udp_multi_write, inet_addr
                        (myFlashArray.ip_udp_multi_write),
                        myFlashArray.port_udp_multi_write, NULL, 0, 0);
         if (retval == 0) {
            // Error opening the socket
            printf("Error opening socket %d!
", 0);
            state[0].state = MCAST_CLOSED;
         }
         else {
            // Set the interval timer, and advance to the next state
            state[0].timer = set_timeout(conf[0].interval);
            state[0].state = MCAST_CLOSING;
         }
         break;
      case MCAST_CLOSING:
         sock_close(&state[0].sock);
         state[0].state = MCAST_CLOSED;
         break;
      case MCAST_CLOSED:
         // Do nothing
         break;
      default:
         // There is no transition to a state other than the ones listed
         // above.  So, if we reach this "state", then something is
         // dreadfully wrong.
         printf("Error in state machine!  Not in a known state...
");
         exit(1);
   }

   // Process socket 1 (Multicast Read)
   switch (state[1].state) {
      case MCAST_OPENING:
         // Open the multicast socket
         retval = udp_extopen(&state[1].sock, IF_ETH0,
                        myFlashArray.port_udp_multi_read, inet_addr
                        (myFlashArray.ip_udp_multi_read),
                        myFlashArray.port_udp_multi_read, NULL, 0, 0);
         if (retval == 0) {
            // Error opening the socket
            printf("Error opening socket %d!
", 1);
            state[1].state = MCAST_CLOSED;
         }
         else {
            // Set the interval timer, and advance to the next state
            state[1].timer = set_timeout(conf[1].interval);
            state[1].state = MCAST_RUNNING;
         }
         break;
      case MCAST_RUNNING:
         // Check for any incoming datagrams
         retval = udp_recvfrom(&state[1].sock, bufferUDP, strlen(bufferUDP),
                           &remip, &remport);
         if (retval < -1) {
            // Error reading from the socket
            printf("Error reading from socket %d!
", 1);
            state[1].state = MCAST_CLOSING;
         }
         else if (retval >= 0) {
            // NULL terminate the buffer and print a message
            bufferUDP[retval] = '\0';
            inet_ntoa(ipbuf, remip);
            printf("Received on socket %d from %s port %u:
", 1, ipbuf, remport);
            printf("%02X%02X%02X%02X%02X%s
", bufferUDP[0], bufferUDP[1], bufferUDP[2],
                                       bufferUDP[3], bufferUDP[4], &bufferUDP[5]);
            msg_id = ((0x000000FF & bufferUDP[0]) << 24) | ((0x000000FF & bufferUDP[1]) << 16) | ((0x000000FF & bufferUDP[2]) << 8) | (0x000000FF & bufferUDP[3]);
            if (msg_id == myFlashArray.cmd_query_id)
            {
               outputBufUDP[0] = (0xFF000000 & myFlashArray.query_resp_id) >> 24;
               outputBufUDP[1] = (0x00FF0000 & myFlashArray.query_resp_id) >> 16;
               outputBufUDP[2] = (0x0000FF00 & myFlashArray.query_resp_id) >> 8;
               outputBufUDP[3] =  0x000000FF & myFlashArray.query_resp_id;
               outputBufUDP[4] = bufferUDP[4]; //cmd/query enumerator

               if (bufferUDP[4] == 0x01)
               {
                  sprintf(&outputBufUDP[5], "%s", myFlashArray.unitid);
                  udp_sendto(&state[0].sock, outputBufUDP, strlen(&outputBufUDP[5]) + 6, inet_addr(myFlashArray.ip_udp_multi_write), myFlashArray.port_udp_multi_write);
               }
               if (bufferUDP[4] == 0x02)
               {
                  sprintf(&outputBufUDP[5], "%s", myFlashArray.serialnum);
                  udp_sendto(&state[0].sock, outputBufUDP, strlen(&outputBufUDP[5]) + 6, inet_addr(myFlashArray.ip_udp_multi_write), myFlashArray.port_udp_multi_write);
               }
            }
         }

         // Check the timer--if it has expired, send another heartbeat packet
         if (chk_timeout(state[1].timer)) {
            state[1].timer = set_timeout(conf[1].interval);
            sprintf(bufferUDP, "Heartbeat packet #%ld on socket %d
",
                    state[1].pkts_sent, 1);
            retval = udp_send(&state[1].sock, bufferUDP, strlen(bufferUDP)+1);
            state[1].pkts_sent += 1;
            if (retval < 0) {
               printf("Error sending on socket %d!
", 1);
               state[1].state = MCAST_CLOSING;
            }
         }
         break;
      case MCAST_CLOSING:
         sock_close(&state[1].sock);
         state[1].state = MCAST_CLOSED;
         break;
      case MCAST_CLOSED:
         // Do nothing
         break;
      default:
         // There is no transition to a state other than the ones listed
         // above.  So, if we reach this "state", then something is
         // dreadfully wrong.
         printf("Error in state machine!  Not in a known state...
");
         exit(1);
   }
}

1 Like

Some thoughts:

  • Instead of your loops, you can use “waitfor(DelayMs(1000));” to introduce a delay in your costates.
  • Your multicast write socket needs a MCAST_RUNNING state where you just keep it open, maybe checking the status and reopening it if it closes for some reason (but there shouldn’t be any reason for it to close). It’s possible that the repeated open/close sequence contributes to your problems, especially if the IP address matches the one used for your multicast read socket.
  • BIG BUG: your udp_recvfrom() should be using sizeof(bufferUDP) instead of strlen(bufferUDP) as the buffer size parameter.
  • I don’t believe it’s necessary to send a heartbeat message. That code is in the sample so there’s multicast traffic if your running the sample with two Rabbit modules.
  • You can define IGMP_VERBOSE in your program, and see what sorts of IGMP-related messages appear on STDOUT (which should identify multicast join/leave).
  • Note that sprintf() returns the number of bytes written to the string, and you can use that value instead of immediately calling strlen() on the written string.
1 Like