c - recvfrom not receiving depending on ai_family used -
i'm trying head around socket programming , have encountered unexpected (for me) behaviour.
when try send data "localhost" , set addrinfo.ai_family af_inet message send isn't coming through client process host process (recvfrom() doesn't return). if set af_inet6 fine. same af_unspec in case picks ipv6 addrinfo (first in list). both host , client use same ai_family of course.
i've tried code copy pasted beej's guide network programming had same result. i'm using dgram sockets.
i tried connecting different pc got opposite results, ipv4 worked fine, ipv6 did not. gather may due me using '6to4 gateway'. have no idea means.
the problem related own machine code work on ipv4 on machine tested on. can't if it's sending or receiving problem.
what prevent me sending or receiving data to/from localhost using af_inet sockets?
i'm on windows7 64bit machine compiling mingw. if makes difference i'm running same program host , client processes different arguments. ran release , debug programs (so it's not same program twice) got same results.
thanks in advance , apologies if considered stupid question.
code:
typedef struct addrinfo addrinfo_t; typedef struct sockaddr_storage sockaddr_storage_t; typedef struct sockaddr_in sockaddr_in_t; typedef struct sockaddr_in6 sockaddr_in6_t; void connect_to_server(const char* server_name, const char* message) { int status; init_networking(); addrinfo_t hints; addrinfo_t* res; memset(&hints, 0, sizeof(addrinfo_t)); hints.ai_family = af_inet; //or af_inet6 hints.ai_socktype = sock_dgram; if ((status = getaddrinfo(server_name, "4950", &hints, &res)) != 0) { fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status)); exit(1); } socket s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (s == -1) { fprintf(stderr, "could not create socket, errno: %u\n", errno); exit(1); } int bytes_sent = sendto(s, message, strlen(message), 0, res->ai_addr, res->ai_addrlen); close(s); printf("sent %i bytes port %i\n", bytes_sent, ((sockaddr_in_t*)res->ai_addr)->sin_port); freeaddrinfo(res); } void setup_server() { int status; init_networking(); addrinfo_t hints; addrinfo_t* res; memset(&hints, 0, sizeof(addrinfo_t)); hints.ai_family = af_inet; //or af_inet6 hints.ai_socktype = sock_dgram; hints.ai_flags = ai_passive; if ((status = getaddrinfo(null, "4950", &hints, &res)) != 0) { fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status)); exit(1); } socket s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (s == -1) { fprintf(stderr, "could not create socket, errno: %u\n", errno); exit(1); } //bind socket own address (mostly port number contained in address) if (bind(s, res->ai_addr, res->ai_addrlen) < 0) { fprintf(stderr, "failed bind, errno: %u\n", errno); exit(1); } freeaddrinfo(res); const size_t read_buffer_size = 1024; void* read_buffer = malloc(read_buffer_size); sockaddr_storage_t peer_address; int peer_address_length = sizeof(sockaddr_storage_t); sockaddr_storage_t own_sock_addr; int own_sock_addr_len = sizeof(sockaddr_storage_t); getsockname(s, (struct sockaddr*)&own_sock_addr, &own_sock_addr_len); printf("listening on port %i\n", ((sockaddr_in_t*)&own_sock_addr)->sin_port); int bytes_received = recvfrom(s, read_buffer, read_buffer_size-1, 0, (struct sockaddr*)&peer_address, &peer_address_length ); printf("received %i byte message:\n%s\n", bytes_received, (char*)read_buffer); }
af_inet
ipv4, , af_inet6
ipv6. when sending ipv4 datagram, receiver must receiving data on destination ip/port using either ipv4 socket or ipv6 dual stack socket (an ipv6 socket accepts both ipv4 , ipv6 traffic). when sending ipv6 datagram, receiver must receiving data using ipv6 socket. otherwise, datagram ignored, sounds 1 machine using ipv6 socket ignores ipv4 datagram, , other machine using ipv4 socket ignores ipv6 datagram.
when calling getaddrinfo()
, specifying af_unspec
address family in both client , server. af_unspec
tells getaddrinfo()
want both ipv4 , ipv6 addresses, returns linked list potentially contains multiple entries of available ipv4 and ipv6 addresses. on server side, creating single listening socket first entry in list, may ipv4 or ipv6. on client side, creating single sending socket first entry in list, may ipv4 or ipv6. actual address families used in both operations going random , may mismatch each other @ times.
on server side, need either:
use
af_inet
oraf_inet6
directly, instead ofaf_unspec
, , code client accordingly match.loop through entire
addrinfo
list creating separate listening socket every entry. way, clients can send data ip/port family server listening on.use
af_inet6
when creating listening socket(s), enable dual stack functionality on them (vista+ only) can receive both ipv4 , ipv6 datagrams. have pay attention address family reportedsockaddr
recvfrom()
returns in order know whether given datagram using ipv4 or ipv6.
on client side, need use af_inet
or af_inet6
directly, instead of af_unspec
, depending on server listening on. not make sense use af_unspec
udp client socket (it make sense tcp client socket), unless udp protocol implementing replies each datagram ack. without that, client has no way know whether server accepting ipv4 or ipv6 datagrams (unless user tells app). acks, client loop through returned addrinfo
list, sending datagram entry in list, wait few seconds ack, , if not received move on next entry in list, repeating needed until ack arrives or list exhausted.
Comments
Post a Comment