Sockaddr union и getaddrinfo ()

Я пишу программу сокета UDP, которой предоставляется адрес из командной строки.

Чтобы упростить отправку и запись, я использую getaddrinfo для преобразования адреса в структуру sockaddr: либо sockaddr_in, либо sockaddr_in6. Теперь я понимаю, что я должен использовать союз sockaddrs:

typedef union address
{
struct sockaddr s;
struct sockaddr_in s4;
struct sockaddr_in6 s6;
struct sockaddr_storage ss;
} address_t;

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

struct addrinfo hint, *serv = NULL;
address_t addr;

hint.ai_family = AF_UNSPEC;
hint.ai_flags = 0;
hint.ai_socktype = SOCK_DGRAM;
hint.ai_protocol = IPPROTO_UDP;

ret = getaddrinfo(address_sr.c_str(), s_port.c_str(), &hint, &serv);
//address_sr and s_port are strings with the address and port

switch (serv->ai_addr) {
case AF_INET: {
addr->s4 = * (sockaddr_in*) serv->ai_addr;
//Here I want to fill the address_t struct with information
//This line causes a segfault
}
break;
case AF_INET6: {
addr->s6 = * (sockaddr_in6*) serv->ai_addr;
//Conversion here
}
break;

Также копируем память:

    memcpy(&addr, serv->ai_addr, serv->ai_addrlen);

Вызывает и segfault.

Как именно я должен это сделать? Я пробовал дюжину разных способов, и я просто не могу понять это. Как мне добавить адрес от addrinfo в этот союз? Я использую sockaddr_storage или sockaddr_ins?

РЕДАКТИРОВАТЬ: редактирование для ясности и дополнительной информации кода.

0

Решение

Вам нужно отменить ссылку на указатель.

addr->s4 = *(sockaddr_in*) serv->ai_addr;
1

Другие решения

Я думаю, что вы не получаете getaddrinfo право.

О третьем аргументе:

const struct addrinfo *hints

Аргумент hints указывает на структуру addrinfo, которая определяет
критерии выбора структур адреса сокета, возвращаемых в
список, на который указывает рез. Если подсказки не равны NULL, это указывает на addrinfo
структура, в которой указываются ai_family, ai_socktype и ai_protocol
критерии, которые ограничивают набор адресов сокетов, возвращаемых
getaddrinfo () […]

Например, вы можете запросить только семейство адресов IPv4 и / или только сокеты датаграмм (что может быть хорошо, если вы попытаетесь использовать UDP).
По сути, вы предоставляете экземпляр addrinfo, устанавливаете поля интереса, а затем передаете указатель на него функции в качестве третьего аргумента:

struct addrinfo hints;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;    /* Allow IPv4 or IPv6 */
hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */

ret = getaddrinfo(address_sr.c_str(), s_port.c_str(), &hint, &serv);

В этом примере функция может вернуть не один, а целый список структур адресов:

Функция getaddrinfo () выделяет и инициализирует связанный список
структуры addrinfo, по одной на каждый сетевой адрес, соответствующий узлу
и обслуживание, с учетом любых ограничений, наложенных намеками и возвратами
указатель на начало списка в рез. Элементы в связанном
список связан полем ai_next.

Таким образом, вы должны просмотреть результат функции следующим образом:

for (rp = serv; rp != NULL; rp = rp->ai_next)

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

1

sockaddr_storage достаточно большой, чтобы держать любой sockaddr_... типа, таким образом, делая address_t такой же большой. Итак, я бы просто memcpy() целиком serv->ai_addr в одну операцию и избавиться от switchНапример:

struct addrinfo hints = {};
struct addrinfo *addrs, *serv;
address_t addr;

hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
...

ret = getaddrinfo(address_sr.c_str(), s_port.c_str(), &hint, &addrs);
if (ret == 0)
{
for (serv = addrs; serv != NULL; serv = serv->ai_next)
{
memcpy(&addr, serv->ai_addr, serv->ai_addrlen);
...
}
freeaddrinfo(addrs);
}
0
По вопросам рекламы [email protected]