Weird string operations' results on socket buffer

61 Views Asked by At

I have an application receiving text messages on a TCP socket using recv(). In this case, it is the TI-RTOS' variant of recv() called NDK_recv(): the other side sends one message in one packet, but depending on timing, sometimes recv() gets more than one message at once from the receive buffer. As I need to parse message by message, I am looking for the first newline in the buffer containing the received data "buffer" and then I copy that part to a structure containing a string element "ac.recv".

"bp = strchr(buffer, 10);" should return a pointer to the first occurrence of character 10 in buffer. For some reason, however, I noticed that in some cases it only returns the second occurrence. Here is the code:

n = NDK_recv(s, buffer, sizeof(buffer), 0);
if (n > 1)
{
    buffer[n] = 0;
    // look for the stop-character in the buffer
    bp = strchr(buffer, 10);
    while (bp)
    {
        i = bp - buffer - 1;
        strncpy(ac.recv, buffer, i);
        ac.recv[i] = 0;
        if (strchr(ac.recv, 10))
        {
            i++;
        }                
        Mailbox_post(m_sll_in, &ac, BIOS_NO_WAIT);
        bp = strchr(bp + 1, 10);
    }
}

Expected behavior:

  1. Store first match of \n to bp.

  2. Store the position of bp to i (minus 1 to get rid of \n).

  3. Copy i characters from buffer to ac.recv.

  4. Terminate ac.recv at position i.

At this point there is no point at all why ac.recv should recv any \n character and so "strchr(ac.recv, 10)" shall never ever return anything but NULL. But it does!

The debugger (TI CCS / Eclipse) stopped at line 214 where you have the i++ statement:

enter image description here

Above you can see value 56 for i and address 0x20014F37 for bp, however buffer has the first "10" at position 28 (0x20014F1A) with 57 (0x20014F37) being the second match out of three.

enter image description here

enter image description here

How can this be? I have done/excluded:

  • Replace strchr function by for-loop, same result.

  • Add a Task_sleep(500); between recv and strchr just to see if there is "something" going on in the background.

  • No other thread is writing into that memory area or executing the same function. All variables are only at function-level.

What am I missing here?!

2

There are 2 best solutions below

0
GandhiGandhi On

I think the problem you're running into has to do with how the data is copied from the network packet buffer to the RTOS message ac.recv in this line.

        // Always copies from the beginning of the buffer (buffer) not the beginning of the next line
        strncpy(ac.recv, buffer, i);

I tried to mock this code up to run locally like below. In the example, you can see that "hello\nworld" gets copied to the rtos message buffer on the second time through the bp loop.

#include <stdio.h>
#include <string.h>
int main() {
  int i;
  char *bp;
  char buffer[100] = "hello\nworld\n";
  char ac_recv[100];
  int n = strlen(buffer);

  if (n > 1) {
    buffer[n] = 0;
    // look for the stop-character in the buffer
    bp = strchr(buffer, 10);
    while (bp) {
      i = bp - buffer - 1;
      strncpy(ac_recv, buffer, i);
      ac_recv[i] = 0;
      if (strchr(ac_recv, 10)) {
        i++;
      }
      printf("ac_recv: %s\n", ac_recv);
      bp = strchr(bp + 1, 10);
    }
  }
  return 0;
}
0
Peter On

Jonathan Leffler had the right answer in the comments:

n = NDK_recv(s, buffer, sizeof(buffer) - 1, 0);

The - 1 is crucial to avoid writing outside of the bounds of the array.