C ++ Linux getpeername y getsockname devuelven solo el puerto

In my Linux C++ application I'm using getpeername and getsockname. when IPv6 enabled on the OS, both getpeername and getsockname return only port!

código:

int GetSockAndPeer(int sock) 
{     
   struct sockaddr_storage ss;    
   socklen_t salen = sizeof(ss);    
   struct sockaddr *sa;   
   struct addrinfo hints, *paddr, *paddrp;     
   sa = (struct sockaddr *)&ss;   
   if (getpeername(sock, sa, &salen) != 0) 
   {           
       return -1;     
   } 
   if (getsockname(sock, sa, &salen) != 0) 
   {           
       return -1;     
   } 
} 

sa variable hold after the systemcalls in sa_data only the sa_data[0] and sa_data[1] which means port. all the other bytes are 0;

¿¿¿Alguna ayuda???

preguntado el 09 de enero de 11 a las 11:01

Related to the majority of your questions, RFC2553: Basic Socket Interface Extensions for IPv6 (faqs.org/rfcs/rfc2553.html) would be a good reading. Otherwise use a library such as boost.ASIO (boost.org/doc/libs/1_45_0/doc/html/boost_asio.html) with support for IPv4/IPv6 build in. -

That code shouldn't even compile if you have sufficient compiler warnings/errors enabled: it doesn't return any value at all if the conditionals are not taken. As for helping us to help you, some explanation of what you are trying to do would be useful. -

2 Respuestas

Relacionado con RFC2553 tienes que usar el IN6_IS_ADDR_V4MAPPED y IN6_IS_ADDR_V4COMPAT macros to identify if there is any usable IPv4 information available within yours socket_storage, or to be exact the sockaddr_in6 estructura:

struct sockaddr_in6 {
    sa_family_t     sin6_family;    /* AF_INET6 */
    in_port_t       sin6_port;      /* transport layer port # */
    uint32_t        sin6_flowinfo;  /* IPv6 traffic class & flow info */
    struct in6_addr sin6_addr;      /* IPv6 address */
    uint32_t        sin6_scope_id;  /* set of interfaces for a scope */
};

If both macros returns true, the IPv4 address is in sockaddr_in6.sin6_addr[12-15]:

printf("%u.%u.%u.%u\n", sockaddr_in6.sin6_addr[12], sockaddr_in6.sin6_addr[13], \
                        sockaddr_in6.sin6_addr[14], sockaddr_in6.sin6_addr[15])

Respondido el 09 de enero de 11 a las 18:01

how to convert from sockaddr_in6 to sockaddr_in in this case? - gln

@gln, I am not sure if this answers your question but if you are having problem in moving from IPv4 to IPv6, this link might help: beej.us/guide/bgnet/output/html/multipage/ip4to6.html. Please scroll down to see the text. - Peatón imprudente

It's important to remember that, unless a socket is connected (or, for a connectionless socket, has transferred data), there may not be any IP addresses, local or remote, associated with the socket.

Let's say the computer is multihomed and has both local and Internet IP addresses. Maybe even multiple local network IP addresses. If you choose to bind a socket to "any" local address (using an INADDR_ANY-type flag), or never call bind() in the first place, the socket API does not have a single local IP address associated with the socket, just a port number at the most. When you call connect() on a socket, the system chooses which local IP to use based on who you are connecting to. So if you connect to a machine over the Internet, your Internet IP is associated with the socket, and if you connect to a machine on the local network, your LAN IP address is used.

So may sure that you connect() to a remote computer or bind() to a specific local IP before you use getsockname(). I wonder if enabling IPv6 has caused your machine to see multiple potential local IPs to use. Obviously you much be connected to a machine to use getpeername().

Respondido el 12 de enero de 12 a las 04:01

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.