Thread: constructing and parsing network packet

  1. #1
    Registered User
    Join Date
    Apr 2012
    Posts
    7

    constructing and parsing network packet

    I have the following packet format:
    Code:
       1B       4B      1B    1B    string   2 bytes    1B      string  
    +------+----------+---+--------+---~~--+---------+--------+---~~---+
    | type | lifetime | 2 | length | Name  | Counter | length |  Data  |
    +------+----------+---+--------+---~~--+---------+--------+---~~---+
    
    
    typedef struct pkt_data {
        u_char pkt_type;
        u_int lifetime;
        u_char type;
        u_char len_name;
        u_char name[100];
        u_short counter;
        u_char len_data;
        u_char data[200];
    }__attribute__((__packed__)) Data;
    Here is the code for constructing and parsing the packet:
    Code:
    int buildDataPacket(u_int _lifetime, u_char* _name, u_short _counter, u_char* _data, u_char* _dataPacket) {
        Data *ndata=NULL;
        u_char *ptr;
    
    
        memset(_dataPacket, 0, 512);
    
    
        ndata = (Data *) _dataPacket;
        ndata->pkt_type = 2;
        ndata->lifetime = htonl(_lifetime);
        ndata->type = 2;
        ndata->len_name = strlen(_name);
    
    
        ptr = (u_char *)ndata + (3 * sizeof(u_char)) + sizeof(u_int);
        strncpy((char *)ptr, (char *)_name, strlen(_name));
    
    
        u_short counter = htons(_counter);
        u_char datalen = strlen(_data);
    
    
        ptr = ptr + strlen(_name);
        memcpy(ptr, &counter, sizeof(u_short));
        ptr = ptr + sizeof(u_short);
        memcpy(ptr, &datalen, sizeof(u_char));
        ptr = ptr + sizeof(u_char);
        strncpy((char *)ptr, (char *)_data, strlen(_data));
        ptr = ptr + strlen(_data);
    
    
        return (ptr - (u_char *)_dataPacket);
    }
    
    
    int processDataPacket(u_char* _dataPacket, u_short _pktLen)
    {
        if (!_dataPacket || !_pktLen) {
                return -1;
        }
    
    
        Data *dataPkt;
        dataPkt = (Data *)_dataPacket;
    
    
        printf("Lifetime: %d\n", ntohl(dataPkt->lifetime));
        printf("Name: %s\n", dataPkt->name);
        printf("Counter: %d\n", dataPkt->counter);
        printf("Data: %s\n", dataPkt->data);
    
    
        return 0;
    }
    When I sniffed the packet in wireshark, I found that the construction of the packet is according to the format. But "counter" and "len_data" values are zero even though I set them accordingly. Also when I receive the packet, the full packet is not stored in the buffer.
    Code:
    rval=recvfrom(inet_sock, buf, BUFLEN-1, MSG_DONTWAIT, (struct sockaddr *) &dest_sin, &socklen);
    
    
    buf[rval]=0;
    fprintf(stderr, "Received: %d (%d) bytes containing %s", rval, strlen(buf), buf);
    'rval' returns correct total num of bytes but 'buf' is terminated after "name". strlen(buf) returns the length of the packet only until the name. So "data" is empty in processDataPacket. Please guide me on how to construct and parse this packet.

  2. #2
    Registered User
    Join Date
    Mar 2011
    Posts
    546
    Code:
        ptr = ptr + strlen(_name);
        memcpy(ptr, &counter, sizeof(u_short));
    if the length of _name is less than the allocated size (100) in the struct , then this will write counter and datalen at the wrong location. so if you are looking in the packet at the location Data.name + 100, you will see 0's. shouldn't this be

    Code:
        ptr = ptr + sizeof(Data.name);
    the two calls to strlen would also explain why your buffer is coming up short.

  3. #3
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    You should avoid using identifiers that start with an _, I believe they're reserved for the implementation (i.e. compiler) to use, so you may conflict with some special compiler identifiers.

    When you build your packet, you put counter and len_data immediately after name, where name is just the data plus a null terminator. For example, if name is "foo", counter is only 4 bytes after the start of name. When you unpack your struct however, you simply point dataPkt to the start of the buffer and try to access dataPkt->counter. But that's 100 bytes after the start of name, because your struct declared name to be a 100 char array.

    You can see this if you use the offsetof macro to print how many bytes from the beginning of dataPkt it thinks counter is in the unpacking function.

    One option is to "scan" dataPkt for the null terminator of the name field, and start copying counter, len_data, etc from that point.

  4. #4
    Registered User
    Join Date
    Apr 2012
    Posts
    7
    Ok, thanks for your replies.
    Is there a way I can change the packet length to be variable based on the length of 'name' and 'data' strings instead of fixing 100 and 200 as the lengths. I tried using char* instead of char[100], but I get segmentation fault when I construct the packet.
    One more problem is that, when I do recvfrom, 'buf' does not display the whole packet even though 'rval' returns total num of bytes of the whole packet. I think due to the zeroes after the name string, buf is terminated and hence displays packet only till end of name. How do I fix this?

  5. #5
    Registered User
    Join Date
    Mar 2011
    Posts
    546
    the alternative to a fixed struct is to have a format that can be read sequentially, something like what anduril suggested. a few fixed fields, then variable length strings that you find by reading up to the terminating 0. or by preceding them with a length. then you don't use a struct at all, just a buffer and a pointer, incremented pretty much like what you are doing.

  6. #6
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    Quote Originally Posted by ddd View Post
    Is there a way I can change the packet length to be variable based on the length of 'name' and 'data' strings instead of fixing 100 and 200 as the lengths. I tried using char* instead of char[100], but I get segmentation fault when I construct the packet.
    Do you really need 100 or 200 character names? Would 16 work? Then you could transmit the whole buffer every time, and if you only use a 4 byte name, you're only wasting 12 bytes instead of 96, so it's not too bad. Otherwise, leave your struct as-is. When you pack it, only copy strlen(name) bytes (or strlen(name)+1 if you want to transmit the null terminator), like you do now. Make sure your unpacking code only copies the right number of bytes for name back into the struct. It would help to move data_len before your name field in the struct so it will be at a fixed offset from the start of the struct. Then you can read it and calculate the length of name by data_len - sizeof(everything in the struct except name).

    One more problem is that, when I do recvfrom, 'buf' does not display the whole packet even though 'rval' returns total num of bytes of the whole packet. I think due to the zeroes after the name string, buf is terminated and hence displays packet only till end of name. How do I fix this?
    What do you mean "buf does not display". Display where? How? In a debugger? If you copy the null terminator for the name field into the buffer, then strlen and any attempt to print the whole packet wont work right, but you shouldn't print the whole packet anyhow, since it contains binary data and may not print right, or may cause problems with your terminal.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. network packet analyzer (sniffer)
    By sauravjyotisrv in forum Linux Programming
    Replies: 3
    Last Post: 03-29-2012, 10:03 AM
  2. Replies: 11
    Last Post: 07-27-2011, 01:44 PM
  3. Complex struct organization (network/packet-related)
    By brooksbp in forum C Programming
    Replies: 6
    Last Post: 08-16-2008, 10:38 PM
  4. Problem while constructing IP packet and sending using socket() system call
    By cavestine in forum Networking/Device Communication
    Replies: 10
    Last Post: 10-15-2007, 05:49 AM
  5. constructing frames...
    By Devil Panther in forum Networking/Device Communication
    Replies: 20
    Last Post: 08-09-2004, 12:34 PM

Tags for this Thread