返回错误IP地址的dualstack套接字上的getnameinfo()函数?

时间:2014-12-19 14:57:58

标签: c linux sockets system-calls ipv4

我在dualstack套接字上使用TCP accept()函数。接下来我尝试使用getnameinfo()打印IPV4映射的Ipv6客户端地址。对于第一个连接到accept(),getnameinfo()正确返回IPv4-Ipv6客户端源地址。但对于病房中的第二个客户端,它首先返回相同的IPv4映射的Ipv6地址。任何人都可以帮助我吗?

伪代码:

struct sockaddr_storage client_ip;
socklen_t sock_len = sizeof(client_ip);
char buffer[INET6_ADDRSTRLEN];
struct sockaddr_in sa4;
static char *pclient_ipv4_addr = NULL;

while(1)
{
  fd = accept(master_fd, (struct sockaddr*)&client_ip, &sock_len);

  if (!getnameinfo((struct sockaddr*)&client_ip, sock_len, buffer,
          sizeof(buffer),0,0,NI_NUMERICHOST))
  {
    pclient_ipv4_addr = buffer;
    if (client_ip.ss_family==AF_INET6)
    {
      struct sockaddr_in6 *sa6=(struct sockaddr_in6*)&client_ip;
      if (IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr))
      {
        memset(&sa4,0,sizeof(sa4));
        sa4.sin_family=AF_INET;
        sa4.sin_port=sa6->sin6_port;
        memcpy(&sa4.sin_addr.s_addr, sa6->sin6_addr.s6_addr+12, 4);
        memcpy(&client_ip, &sa4,sizeof(sa4));
        sock_len=sizeof(sa4);
        pclient_ipv4_addr = inet_ntoa(sa4.sin_addr);
        printf("IPV4 add is %s\n", pclient_ipv4_addr );
      }
    }

  }

  memset(buffer, 0 , INET6_ADDRSTRLEN);
}

例如:对于第一个客户端,pclient_ipv4_addr是“192.168.208.13”,那么对于下一个客户端也是 pclient_ipv4_addr正在打印相同的地址。不可重入getnameinfo(0任何问题?如何 能解决这个问题?

1 个答案:

答案 0 :(得分:1)

尝试更像这样的事情:

struct sockaddr_storage client_ip;
socklen_t sock_len;

while(1)
{
  sock_len = sizeof(client_ip);
  fd = accept(master_fd, (struct sockaddr*)&client_ip, &sock_len);

  if (fd == -1)
    break;

  if (client_ip.ss_family==AF_INET)
  {
    struct sockaddr_in *sa4 = (struct sockaddr_in*) &client_ip;
    printf("IPv4 add is %s\n", inet_ntoa(sa4->sin_addr) );
  }
  else if (client_ip.ss_family==AF_INET6)
  {
    struct sockaddr_in6 *sa6 = (struct sockaddr_in6*) &client_ip;
    if (IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr))
    {
      struct in_addr a4;
      memcpy(&a4, sa6->sin6_addr.s6_addr+12, 4);
      printf("IPv4 add is %s\n", inet_ntoa(a4) );
    }
    else
    {
      char buffer[INET6_ADDRSTRLEN];
      if (getnameinfo((struct sockaddr*)&client_ip, sock_len, buffer, sizeof(buffer), 0, 0, NI_NUMERICHOST) == 0)
        printf("IPv6 add is %s\n", buffer );
    }
  }
}