简体   繁体   中英

Is it possible to access elements of structure using for loop indexing?

I tried to form an ip-packet by user input. I did till L4 only. l7 header including data I took as string. For L4 header user has to give values of different fields of l4, I tried converting them into sting and appending to packet. I wanted to similar for layer 3 too.

Its working fine, but in code I endup in writing similar code for different fields of L4. I mentioned them in blocks in code. Is possible to convert all 4 blocks into single block using for loop.

code part is:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct l4{
    unsigned short source_port;
    unsigned short dest_port;
    unsigned int length;
    unsigned short checksum;
}l4_struct;

void append_l7(char *packet , FILE *fp) {
    char l7_packet[255];
    fscanf(fp , "%[^\n]%*c" , l7_packet);
    strcpy(packet , l7_packet);
}

void append_l4(char *packet , FILE *fp) {
    char l4_header_string[255] , buf[255];
    memset(buf  , 0 ,  255);
    l4_struct l4_header;

//block 1
    fscanf(fp , "%hd" , &l4_header.source_port);
    sprintf(buf , "%x" , l4_header.source_port);
    strcpy(l4_header_string , buf);
    memset(buf  , 0 ,  255);

//block 2
    fscanf(fp , "%hd" , &l4_header.dest_port);
    sprintf(buf , "%s %.4x" , l4_header_string , l4_header.dest_port);
    strcpy(l4_header_string , buf);
    memset(buf  , 0 ,  255);

//block 3
    fscanf(fp , "%d" , &l4_header.length);
    sprintf(buf , "%s %.4x" , l4_header_string , l4_header.length);
    strcpy(l4_header_string , buf);
    memset(buf  , 0 ,  255);

//block 4
    fscanf(fp , "%hd" , &l4_header.checksum);
    sprintf(buf , "%s %.4x" , l4_header_string , l4_header.checksum);
    strcpy(l4_header_string , buf);
    memset(buf  , 0 ,  255);

//    strcat(l4_header_string , packet);
    sprintf(buf , "%s %s" , l4_header_string , packet);
    strcpy(packet , buf);
}

void append_l3(char *packet , FILE *fp) {

}

int main() {
    FILE *fp = fopen("input_packet.txt" , "r");
    int packet_size = 255; //We can take from user also
    char *packet = (char *)calloc(packet_size , sizeof(char));

    append_l7(packet  , fp);
    append_l4(packet , fp);
//    append_l3(packet , fp);

    //printing packet
    printf("\nPacket:%s\n" , packet);
//    printf("%hd\n%d\n" , sizeof(unsigned short) , sizeof(unsigned int));
    free(fp);
    free(packet);
}

And input_packet.txt is

ab c9 01 00 00 01 00 00 00 00 00 00 09 6d 63 63 6c 65 6c 6c 61 6e 02 63 73 05 6d 69 61 6d 69 03 65 64 75 00 00 01 00 01
58759
53
48
58144

Output:

Packet:e587 0035 0030 e320 ab c9 01 00 00 01 00 00 00 00 00 00 09 6d 63 63 6c 65 6c 6c 61 6e 02 63 73 05 6d 69 61 6d 69 03 65 64 75 00 00 01 00 01

I want append_l4( ) function something like below:

char **dptr = (char **) malloc(sizeof(char *) * 4);
dptr[0] = "source_port";
dptr[1] = "dest_port";
dptr[2] = "length";
dptr[3] = "checksum";

void append_l4(char *packet , FILE *fp) {
    char l4_header_string[255] , buf[255];
    memset(buf  , 0 ,  255);
    l4_struct l4_header;

    for(i = 0; i < 4; i++){
        fscanf(fp , "%(this type varies)" , &l4_header.dptr[i]);
        sprintf(buf , "%s %.4x" , l4_header_string , l4_header.dptr[i]);
        strcpy(l4_header_string , buf);
        memset(buf  , 0 ,  255);
    }

//    strcat(l4_header_string , packet);
    sprintf(buf , "%s %s" , l4_header_string , packet);
    strcpy(packet , buf);
}

Is it possible? If yes, Please suggest me how can I achieve this.

Iterating over a struct in C++ is similar but it is in C++.

My suggestion is that you try using a union , which will allow you to store "different" data types in the same memory location. Nonetheless, you'll have to handle your input data equally for all possible field size (which seems to be what you want). I have done that myself for building TCP packets and the following structure is pretty useful (specially for copy operations).

union packet_u
{
  uint8_t a[__TOTAL_STRUCT_SIZE__];
  struct
  {
      uint16_t field1;
      uint16_t field2;
      uint32_t field3;
      uint16_t field4;
  }
};

It should be straightforward to read the input file and save it on your structure, so I'll leave you to work on this idea. Also, you can change the smallest size you want to iterate over (ie, uint8_t a[...] ).

That snprintf + memcpy + memset(..., 0, ...) is just nonsense. You create a buffer, read to that buffer, than copy from that buffer to another buffer, then zero that buffer... Why not copy to the destination buffer all the time? snprintf returns the number of characters written, you can concatenate it's output by manipulating the position of it's first argument:

size_t pos = 0;

pos += sprintf(&l4_header_string[pos], "%x", l4_header.source_port);
pos += sprintf(&l4_header_string[pos], " %.4x", l4_header.<next field>);
pos += sprintf(&l4_header_string[pos], " %.4x", l4_header.<next field>);
pos += sprintf(&l4_header_string[pos], " %.4x", l4_header.<next field>);

Anyway, you can just do one scanf and one snprintf:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

typedef struct l4{
    unsigned short source_port;
    unsigned short dest_port;
    unsigned int length;
    unsigned short checksum;
}l4_struct;

void append_l7(char *packet , FILE *fp) {
    fgets(packet, 255, fp);
}

void append_l4(char *packet , FILE *fp) {
    l4_struct l4_header;

    fscanf(fp , "%hd %hd %d %hd" , 
        &l4_header.source_port,
        &l4_header.dest_port,
        &l4_header.length,
        &l4_header.checksum);
    // we can't snprintf(buffer, "%s", buffer) so we need to create a packet copy
    char *packetcopy = strdup(packet);
    assert(packetcopy != NULL);
    sprintf(packet, "%x %.4x %.4x %.4x %s",
        l4_header.source_port, 
        l4_header.dest_port,
        l4_header.length, 
        l4_header.checksum,
        packetcopy);
    free(packetcopy);
}

int main() {
    FILE *fp = fopen("input_packet.txt" , "r");
    int packet_size = 255; //We can take from user also
    char *packet = (char *)calloc(packet_size , sizeof(char));

    append_l7(packet, fp);
    append_l4(packet, fp);

    printf("Packet:%s\n" , packet);

    // free(fp); ????????
    fclose(fp);
    free(packet);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM