Код, который вы показали, в основном правильный путь, в котором вам нужно набрать sockaddr_storage
к конкретному типу sockaddr_...
, который вы хотите заполнить.
Однако вв случае sockaddr_in6
часть IN6ADDR_ANY_INIT
неверна.Используйте это вместо:
(*(struct sockaddr_in6*)&local_addrs).sin6_addr = in6addr_any;
IN6ADDR_ANY_INIT
- это макрос, который может использоваться только в статических объявлениях во время компиляции, например:
struct sockaddr_in6 in6 = {AF_INET6, port, 0, IN6ADDR_ANY_INIT, 0};
struct in6_addr addr = IN6ADDR_ANY_INIT;
IN6ADDR_ANY_INIT
нельзя использовать в назначениях во время выполнения, например:
struct sockaddr_in6 in6;
in6.sin6_addr = IN6ADDR_ANY_INIT; // ERROR
struct in6_addr addr;
addr = IN6ADDR_ANY_INIT; // ERROR
in6addr_any
, с другой стороны, является глобальной переменной, которую можно использоватьв назначениях во время выполнения.
И нет, вам не нужно malloc
структуру sockaddr_storage
.
При этом я бы предложил использовать некоторые локальные переменные, чтобы сделать код прощечитать:
if (sc->domain == AF_INET) {
struct sockaddr_in *in4 = (struct sockaddr_in*) &local_addrs;
in4->sin_family = AF_INET;
in4->sin_addr.s_addr = INADDR_ANY; // <-- inet_addr() is not needed for INADDR_ANY
in4->sin_port = htons(tcp_port);
}
else {
struct sockaddr_in6 *in6 = (struct sockaddr_in6*) &local_addrs;
in6->sin6_family = AF_INET6;
in6->sin6_addr = in6addr_any;
in6->sin6_port = htons(tcp_port);
/* note: sockaddr_in6 also has sin6_flowinfo and sin6_scope_id
fields that you may have to fill, too...
in6->sin6_flowinfo = ...;
in6->sin6_scope_id = ...;
*/
}
Или используйте вместо него union
:
union sockaddr_types {
struct sockaddr_storage storage;
struct sockaddr addr;
struct sockaddr_in in4;
struct sockaddr_in6 in6;
};
union sockaddr_types local_addrs;
if (sc->domain == AF_INET) {
local_addrs.in4.sin_family = AF_INET;
local_addrs.in4.sin_addr.s_addr = INADDR_ANY;
local_addrs.in4.sin_port = htons(tcp_port);
}
else {
local_addrs.in6.sin6_family = AF_INET6;
local_addrs.in6.sin6_addr = in6addr_any;
local_addrs.in6.sin6_port = htons(tcp_port);
/*
local_addrs.in6.sin6_flowinfo = ...;
local_addrs.in6.sin6_scope_id = ...;
*/
}
if ((ret = bind(sockfd, &local_addrs.addr, sizeof(local_addrs))) < 0) {
//error...
}
В любом случае, вам также следует рассмотреть возможность обнуления всего sockaddr_storage
для предварительного заполнения неиспользуемых полейперед тем, как заполнить то, что вам нужно:
memset(&local_addrs, 0, sizeof(local_addrs));