Когда вы говорите, что «накладываете» свою структуру данных на пакет (по крайней мере, это то, о чем вы говорите), значение, которое появляется в четырех или восьми байтах вашего void*
указателя на элемент данных указателя(в зависимости от вашей платформы), скорее всего, это значение внутри блока sctp_init
или scpt_data
, а не фактический указатель на этот блок данных.По всей вероятности, ваш указатель не равен NULL, но при использовании разыменования значения в указателе происходит сбой сегмента.
Во-вторых, наложение структуры на сериализованные данные без прагм и / или директив компилятора при упаковкеstruture может быть опасным ... иногда вы думаете, что компилятор может распределить / дополнить структуру не так, как он фактически делает это, и тогда структура не соответствует фактическому формату пакета данных, и вы закончитес недопустимыми значениями.
Итак, я предполагаю, что сейчас вы пытаетесь сделать что-то подобное, накладывая первые N байтов вашего пакета структурой scpt_header
:
|scpt_header .........|void*|
|packet information ..|scpt_chunk.................|
Это не очень переносимо и может вызвать много головных болей, особенно когда вы вставляете в ситуацию проблемы с порядком следования байтов в сети.Что вам действительно нужно, так это то, что вы копируете содержимое своего пакета SCPT во внутреннюю структуру данных, например, связанный список, которым вы можете затем правильно манипулировать.
Один из способов может выглядеть следующим образом:
#include <arpa/inet.h>
unsigned char* packet_buffer = malloc(sizeof(PACKET_SIZE));
//... proceed to copy into the buffer however you are reading your packet
//now fill in your structure
unsigned char* temp = packet_buffer;
struct sctp_header header_data;
header_data.src_port = ntohs(*((uint16_t*)temp));
temp += sizeof(uint16_t);
header_data.dstport = ntohs(*((uint16_t*)temp));
temp += sizeof(uint16_t);
header_data.vtag = ntohl(*((uint32_t*)temp));
temp += sizeof(uint32_t);
//... keep going for all data members
//allocate memory for the first chunk (we'll assume you checked and it's a data chunk)
header_data.chunks = malloc(sizeof(sctp_data));
scpt_data* temp_chunk_ptr = header_data.chunks;
//copy the rest of the packet chunks into your linked-list data-structure
while (temp < (packet_buffer + PACKET_SIZE))
{
temp_chunk_ptr->tsn = ntohl(*((uint32_t*)temp));
temp += sizeof(uint32_t);
//... keep going for the rest of this data chunk
//allocate memory in your linked list for the next data-chunk
temp_chunk_ptr->data = malloc(sizeof(scpt_data));
temp_chunk_ptr = temp_chunk_ptr->data;
}
//free the packet buffer when you're done since you now have copied the data into a linked
//list data-structure in memory
free(packet_buffer);
Этот подход может показаться громоздким, но, к сожалению, если вы собираетесь решать проблемы с порядком байтов и порядком байтов, вы не сможете просто наложить структуру данных напакетные данные переносимым на платформу способом, даже если вы объявляете их как упакованную структуру данных.Объявление упакованной структуры данных приведет к правильному выравниванию байтов, но не устранит проблемы с порядком байтов, что будут делать функции, такие как ntohs
и ntohl
.
Также не позволяйте вашему scpt_header
выйдите из области видимости, не разрушая связанный список, которым он «владеет», иначе вы получите утечку памяти.
Обновление : Если вы все еще хотите перейтиналожив маршрут, сначала убедитесь, что вы используете директиву компилятора, чтобы упаковать свою структуру, чтобы не было добавлено дополнение.В gcc это будет
typdef struct sctp_header {
uint16_t srcport;
uint16_t dstport;
uint32_t vtag;
uint32_t chksum;
} __attribute__((packed)) sctp_header;
typedef struct sctp_data
{
uint8_t ctype;
uint8_t cflags;
uint16_t clength;
uint32_t tsn;
uint16_t stream_id;
uint16_t stream_seq;
uint32_t pp_id;
} __attribute__((packed)) sctp_data;
typedef struct sctp_init
{
uint8_t ctype;
uint8_t cflags;
uint16_t clength;
uint32_t initate_tag;
uint32_t a_rwnd;
uint16_t num_out_streams;
uint16_t num_in_streams;
uint32_t tsn;
} __attribute__((packed)) sctp_init;
, но это будет нечто другое в других компиляторах.Также обратите внимание, что я немного изменил ваши структуры, чтобы лучше отразить, как они на самом деле представлены пакетом SCTP в памяти.Поскольку размер двух разных типов пакетов различен, мы не можем действительно выполнить объединение и наложить это в памяти ... объединение будет технически размером с самый большой член типа чанка, и это будет создавать проблемы, когдамы пытаемся создать массивы и т. д. Я также избавляюсь от указателей ... Я вижу, что вы пытаетесь с ними делать, но опять же, поскольку вы хотите наложить эти структуры данных на пакетные данные,это снова вызовет проблемы, так как вы на самом деле пытаетесь «сдвинуть» данные.Изменения в ваших исходных структурах данных были сделаны для того, чтобы фактически отражать, как данные размещаются в памяти без какого-либо необычного смещения или приведения указателя.Поскольку тип каждого пакета представлен unsigned char
, теперь мы можем сделать следующее:
enum chunk_type { DATA = 0, INIT = 1 };
unsigned char* packet_buffer = malloc(sizeof(PACKET_SIZE));
//... copy the packet into your buffer
unsigned char* temp = packet_buffer;
sctp_header* header_ptr = temp;
temp += sizeof(sctp_header);
//... do something with your header
//now read the rest of the packets
while (temp < (packet_buffer + PACKET_SIZE))
{
switch(*temp)
{
case DATA:
sctp_data* data_ptr = temp;
//... do something with the data
temp += data_ptr->clength;
break;
case INIT:
sctp_init* init_ptr = temp;
// ... do something with your init type
temp += init_ptr->clength;
break;
default:
//do some error correction here
}
}
Имейте в виду, что этот метод исправляет только проблемы с выравниванием ... он не исправляет дляпорядковый номер, поэтому будьте осторожны, когда вы читаете любые значения в многобайтовом типе данных.