Sending ASCII characters and int in the same UDP packet

Viewed 567

I need to send a packet via UDP socket in which there will be a six digit number written as ASCII string and after a new line character, same number but as int in bytes, like this: 31 32 33 34 35 36 0A 00 01 E2 40 which corresponds to 123456\n(123456) - integer is in brackets. So far I can send my string and my newline char, but when it comes to an int I get that 0 bytes were written into the buffer and nothing from my int buffer array is sent. Additionally, if I check text content of int buffer array it has weird amount of "Fs": 00 01 FFFFFFE2 40

This is my UDP client:

#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>


char buf[11];

int main(int argc, char **argv)
{
    struct sockaddr_in adr;
    int sock, r;
    unsigned int port;
    char abcd[512];
    char intBuff[4];
    unsigned int index = 123456;
    unsigned int networkHost;
    networkHost = htonl(index);

    memcpy(intBuff, (char*)&networkHost,sizeof(uint32_t));
    printf("Int buffer: ");
      for(int i=0; i<sizeof(uint32_t); i++){
        printf("%02X ", intBuff[i]); //Output is 00 01 FFFFFFE2 40
    }

    int x1 = sprintf(buf,"%s\n","123456"); 
    printf("\n1st data write: %i\n", x1); //7 bytes are written


    int x2 = sprintf(&buf[x1], "%s",intBuff); 
    printf("2nd data write: %i\n", x2); //0 bytes are written


    //SERVER
    printf("IP: ");
    scanf("%s", abcd);
    printf("PORT: ");
    scanf("%u", &port);

    sock = socket(AF_INET, SOCK_DGRAM, 0);
    adr.sin_family = AF_INET;
    adr.sin_port = htons(port);
    adr.sin_addr.s_addr = inet_addr(abcd);


    r = sendto(sock,
               buf,
               11,
               0,
               (struct sockaddr*) &adr,
               sizeof(adr));

    close(sock);
    return 0;
}

2 Answers

The problem

The strange value occurs because your array of char is signed, and the compiler interprets it as signed integer when you pass it to printf.

Do not use sprintf(...,"%s", ...) to copy binary data that potentially contains zero byte, because "%s" format will suddenly stop copying when it reaches \0 null char.


Solution

  1. Use unsigned char, so the compiler does not interpret it as signed integer when it pass the data to printf.
  2. Use memcpy to copy the intBuff to buf.

Code example


#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <arpa/inet.h>

int main() {
    unsigned char buf[11];
    unsigned char intBuff[sizeof(uint32_t)];
    uint32_t index = 123456;
    uint32_t networkHost;
    networkHost = htonl(index);

    memcpy(intBuff, &networkHost, sizeof(networkHost));

    for (int i=0; i < sizeof(intBuff); i++){
      printf("%02x ", intBuff[i]);
    }

    int x1 = sprintf(buf,"%s\n","123456"); 
    printf("\n1st data write: %i\n", x1); // 7 bytes are written


    // It is certain that the write is sizeof(intBuff) in size.
    memcpy(&buf[x1], intBuff, sizeof(intBuff));

    int total_len = x1 + sizeof(intBuff);

    printf("Packed data: ");
    for (int i = 0; i < total_len; i++) {
      printf("%02x ", buf[i]);
    }

    putchar('\n');
}

Output

ammarfaizi2@integral:/tmp$ gcc x.c -o x 
ammarfaizi2@integral:/tmp$ ./x
00 01 e2 40 
1st data write: 7
Packed data: 31 32 33 34 35 36 0a 00 01 e2 40 
ammarfaizi2@integral:/tmp$ 

The bytes that represent an integer may, in general, have any values, as the integer takes on various values. So a byte may be zero. Then writing those bytes to a buffer using printf with %s will stop at the zero byte, because %s expects a string. The definition of a string is that it is a sequence of characters whose end is marked by a zero byte.

With the value you are using, the first byte is a zero, so printf stops immediately, and no bytes are written.

Instead of using printf to copy the bytes into the buffer, just copy them directly with memcpy:

memcpy(&buf[x1], &networkHost, sizeof networkHost);

You do not need intBuff at all and can remove it from your program.

Related