Когда вы говорите, что «накладываете» свою структуру данных на пакет (по крайней мере, это то, что вы говорите), значение, которое появляется в четырех или восьми байтах вашего члена данных указателя void*
(в зависимости от вашей платформы ), скорее всего, является значением внутри фрагмента asctp_init
или scpt_data
, а не фактическим указателем на этот фрагмент данных. Скорее всего, поэтому ваш указатель не равен NULL, но при разыменовывании значения в указателе происходит сбой сегмента.
Во-вторых, наложение структуры на сериализованные данные без прагм и/или директив компилятора при упаковке структуры может быть опасным... иногда то, как вы думаете, что компилятор может выделить/заполнить структуру, не совпадает с тем, как он на самом деле это делает, и тогда структура не соответствует фактическому формату пакета данных, и вы получите недопустимые значения.
Итак, я предполагаю, что прямо сейчас вы пытаетесь сделать что-то подобное, напрямую накладывая первые 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
}
}
Имейте в виду еще раз, что этот метод исправляет только проблемы с выравниванием... он не исправляет порядок следования байтов, поэтому будьте осторожны при чтении любых значений в многобайтовом типе данных.
person
Jason
schedule
16.08.2011
gdb
, то делайте это грязным способом, то есть многоprintf
. - person hari   schedule 16.08.2011