Выравнивание данных с сетевым программированием - PullRequest
1 голос
/ 03 октября 2010

Я немного запутался в отношении выравнивания данных.На x86 мы обычно принимаем выравнивание как должное.Тем не менее, я программирую в системе, которая очень строгая и выдаст ошибку, если я попытаюсь получить доступ к невыровненным данным.

Вот моя проблема:

Сначала я покажу вамнекоторые структуры у меня есть:

struct sniff_ethernet {
  u_char ether_dhost[6]; /* Destination host address */
  u_char ether_shost[6]; /* Source host address */
  u_short ether_type; /* IP? ARP? RARP? etc */
};

struct sniff_ip {
  u_char ip_vhl;  /* version << 4 | header length >> 2 */
  u_char ip_tos;  /* type of service */
  u_short ip_len;  /* total length */
  u_short ip_id;  /* identification */
  u_short ip_off;  /* fragment offset field */
  u_char ip_ttl;  /* time to live */
  u_char ip_p;  /* protocol */
  u_short ip_sum;  /* checksum */
  struct in_addr ip_src,ip_dst; /* source and dest address */
 };

Я имею дело с pcap.Pcap вернет мне указатель на пакет данных:

u_char *packet;

Предположим, пакет составляет пару сотен байтов.Обычно я выполняю приведение этого пакета к нескольким указателям структуры, чтобы я мог получить прямой доступ к данным.

struct sniff_ethernet *seth = (struct sniff_ethernet *) packet;
struct sniff_ip *sip = (struct sniff_ip *) (packet + 14); // 14 is the size of an ethernet header

Хорошо.Так что все выглядит отлично, верно?На x86 все работает нормально.На любой другой архитектуре, которая имеет строгое выравнивание, у меня возникают проблемы при доступе к некоторым значениям, и это обычно приводит к сигбусу.Например:

sip->ip_len = 0x32AA;

или

u_short val = sip->ip_len;

приводит к ошибке.Я предполагаю это, потому что это смещено в памяти от броска.Каков обычно лучший способ справиться с этим, выполняя такие броски?

1 Ответ

2 голосов
/ 03 октября 2010

Простой способ использования memcpy

struct sniff_ip sip;
memcpy(&sip, packet + 14, sizeof(sip));

Это предполагает, что ваши две машины используют один и тот же порядок байтов и тщательно учитывают заполнение структуры.

Более сложный и общий способ справиться с этим - построить значения из отдельных байтов:

u_short val;
int offset = 14 + offsetof(sniff_ip, ip_len);
val = packet[offset] + (packet[offset+1] << 8); // assuming little endian packet

Конечно, вы, вероятно, использовали бы функцию или макрос, чтобы абстрагировать это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...