MySQL源码中处理客户端不同地址族的源码

来源:互联网 发布:白银大非农数据分析 编辑:程序博客网 时间:2024/06/09 16:22

ws2def.h文件中定义的结构:

typedef struct sockaddr_storage {

    ADDRESS_FAMILYss_family;      // addressfamily

 

    CHAR __ss_pad1[_SS_PAD1SIZE];  // 6 byte pad, thisis to make

                                   //   implementationspecific pad up to

                                   //   alignment fieldthat follows explicit

                                   //   in the datastructure

    __int64 __ss_align;            // Fieldto force desired structure

    CHAR __ss_pad2[_SS_PAD2SIZE];  // 112 byte pad toachieve desired size;

                                   //   _SS_MAXSIZEvalue minus size of

                                   //   ss_family,__ss_pad1, and

                                   //   __ss_alignfields is 112

} SOCKADDR_STORAGE_LH,*PSOCKADDR_STORAGE_LH, FAR *LPSOCKADDR_STORAGE_LH;

微软说明:

The SOCKADDR_STORAGE structure stores socket addressinformation. Since the SOCKADDR_STORAGE structure is sufficiently large tostore address information for IPv4, IPv6, or other address families, its usepromotes protocol-family and protocol-version independence and simplifies cross-platformdevelopment. Use the SOCKADDR_STORAGEstructure in place of the sockaddr structure.可用用来存储不同协议族的地址结构,在跨平台的环境中,用来代替sockaddr结构。sockaddr不能用于夸平台结构中吗?不会吧。

其中:

#define _SS_MAXSIZE 128                 //Maximum size

#define _SS_ALIGNSIZE (sizeof(__int64)) // Desired alignment

 

#if(_WIN32_WINNT >=0x0600)

#define _SS_PAD1SIZE (_SS_ALIGNSIZE - sizeof(USHORT))

#define _SS_PAD2SIZE (_SS_MAXSIZE - (sizeof(USHORT) + _SS_PAD1SIZE+ _SS_ALIGNSIZE))

#else

#define _SS_PAD1SIZE (_SS_ALIGNSIZE - sizeof(short))

#define _SS_PAD2SIZE (_SS_MAXSIZE - (sizeof(short) + _SS_PAD1SIZE/

                                                    + _SS_ALIGNSIZE))

#endif //(_WIN32_WINNT >= 0x0600)

可以看出,整个sockaddr_storage结构大小为128个字节。

 

而在MySQLst_vio结构中对IP地址就是使用该结构,而不是以往使用的addr_in了,这是为了处理IPv4IPv6而定义的吧。

看看下面在MySQL中获取客户端的处理流程吧

通过客户端套接字à获取客户端sockaddr->获取客户端IP和端口

调用函数getpeername->getnameinfo

源码如下:

/**

  Return IP address and port of a VIO clientsocket.

 

  The function returns an IPv4 address if IPv6support is disabled.

 

  The function returns an IPv4 address if theclient socket is associated

  with an IPv4-compatible or IPv4-mapped IPv6address. Otherwise, the native

  IPv6 address is returned.

*/

 

my_bool vio_peer_addr(Vio *vio, char *ip_buffer, uint16 *port,

                      size_tip_buffer_size)

{

  DBUG_ENTER("vio_peer_addr");

  DBUG_PRINT("enter", ("Clientsocked fd: %d", (int) vio->sd));

 

  if (vio->localhost)//是本机的话,当然简单了

  {

    /*

      Initialize vio->remote andvio->addLen. Set vio->remote to IPv4 loopback

     address.

    */

    struct in_addr *ip4=&((struct sockaddr_in*) &(vio->remote))->sin_addr;

 

    vio->remote.ss_family=AF_INET;

    vio->addrLen= sizeof (struct sockaddr_in);

 

    ip4->s_addr= htonl(INADDR_LOOPBACK);

 

    /* Initializeip_buffer and port. */

 

    strmov(ip_buffer, "127.0.0.1");

    *port=0;

  }

  else

  {

    int err_code;

    char port_buffer[NI_MAXSERV];

 

    struct sockaddr_storage addr_storage;

    struct sockaddr *addr=(struct sockaddr*) &addr_storage;

    size_socketaddr_length= sizeof(addr_storage);

 

    /* Get sockaddrby socked fd. */

 

    err_code=getpeername(vio->sd, addr, &addr_length);

 

    if (err_code)

    {

      DBUG_PRINT("exit", ("getpeername()gave error: %d", socket_errno));

      DBUG_RETURN(TRUE);

    }

 

    /* Normalize IPaddress. */

 

    vio_get_normalized_ip(addr, addr_length,

                          (struct sockaddr *)&vio->remote,&vio->addrLen);

 

    /* Get IP address& port number. */

 

    err_code=vio_getnameinfo((structsockaddr *) &vio->remote,

                              ip_buffer, ip_buffer_size,

                              port_buffer, NI_MAXSERV,

                              NI_NUMERICHOST | NI_NUMERICSERV);

 

    if (err_code)

    {

      DBUG_PRINT("exit", ("getnameinfo()gave error: %s",

                          gai_strerror(err_code)));

      DBUG_RETURN(TRUE);

    }

 

    *port= (uint16) strtol(port_buffer, NULL,10);

  }

 

  DBUG_PRINT("exit", ("ClientIP address: %s; port: %d",

                      (constchar *) ip_buffer,

                      (int)*port));

  DBUG_RETURN(FALSE);

}

 

针对不同协议族进行处理:

 

/**

  Convert a sock-address (AF_INET or AF_INET6)into the "normalized" form,

  which is the IPv4 form for IPv4-mapped orIPv4-compatible IPv6 addresses.

 

  @note Background: when IPv4 and IPv6 are usedsimultaneously, IPv4

  addresses may be written in a form ofIPv4-mapped or IPv4-compatible IPv6

  addresses. That means, one address (a.b.c.d)can be written in three forms:

    - IPv4: a.b.c.d;

    - IPv4-compatible IPv6: ::a.b.c.d;

    - IPv4-mapped IPv4: ::ffff:a.b.c.d;

 

  Having three forms of one address makes it alittle difficult to compare

  addresses with each other (theIPv4-compatible IPv6-address of foo.bar

  will be different from the IPv4-mappedIPv6-address of foo.bar).

 

  @note This function can be made public whenit's needed.

 

  @param src        [in] source IP address (AF_INET orAF_INET6).

  @param src_length [in] length of the src.

  @param dst        [out] a buffer to store normalized IPaddress

                          (sockaddr_storage).

  @param dst_length [out] actual length of thenormalized IP address.

*/

static void vio_get_normalized_ip(conststruct sockaddr*src,

                                  int src_length,

                                  struct sockaddr *dst,

                                  int *dst_length)

{

  switch (src->sa_family){

  case AF_INET:

    memcpy(dst, src, src_length);

    *dst_length=src_length;

    break;

 

#ifdef HAVE_IPV6

  case AF_INET6:

  {

    const struct sockaddr_in6*src_addr6= (conststruct sockaddr_in6*) src;

    const struct in6_addr *src_ip6= &(src_addr6->sin6_addr);

    const uint32 *src_ip6_int32=(uint32 *) src_ip6->s6_addr;

 

    if (IN6_IS_ADDR_V4MAPPED(src_ip6)|| IN6_IS_ADDR_V4COMPAT(src_ip6))

    {

      struct sockaddr_in *dst_ip4=(struct sockaddr_in*) dst;

 

      /*判断该地址是否是从IPv4转换而来的,如果是,则转换成IPv4地址

        This is an IPv4-mapped orIPv4-compatible IPv6 address. It should

        be converted to the IPv4 form.

      */

 

      *dst_length=sizeof (struct sockaddr_in);

 

      memset(dst_ip4, 0, *dst_length);

      dst_ip4->sin_family= AF_INET;

      dst_ip4->sin_port= src_addr6->sin6_port;

 

      /*

        In an IPv4 mapped or compatibleaddress, the last 32 bits represent

        the IPv4 address. The byte orders forIPv6 and IPv4 addresses are

        the same, so a simple copy is possible.

      */

      dst_ip4->sin_addr.s_addr=src_ip6_int32[3];

    }

    else

    {

      /* This is a"native" IPv6 address. */

 

      memcpy(dst, src, src_length);

      *dst_length=src_length;

    }

 

    break;

  }

#endif /* HAVE_IPV6 */

  }

}

IPv6地址结构:

typedef struct sockaddr_in6 {

    ADDRESS_FAMILYsin6_family; //AF_INET6.

    USHORT sin6_port;           //Transport level port number.

    ULONG  sin6_flowinfo;       // IPv6 flowinformation.

    IN6_ADDRsin6_addr;         // IPv6address.

    union {

        ULONGsin6_scope_id;     // Set ofinterfaces for a scope.

        SCOPE_IDsin6_scope_struct;

    };

} SOCKADDR_IN6_LH,*PSOCKADDR_IN6_LH, FAR*LPSOCKADDR_IN6_LH;

 

 

下面就到了返回套接字地址的IP和端口了,MySQL函数调用如下:

/**

  This is a wrapper for the systemgetnameinfo(), because different OS

  differ in the getnameinfo() implementation:

    - Solaris 10 requires that the 2nd argument(salen) must match the

      actual size of the struct sockaddr_storagepassed to it;

    - Mac OS X has sockaddr_in::sin_len andsockaddr_in6::sin6_len and

      requires them to be filled.

*/

 

int vio_getnameinfo(const struct sockaddr *sa,

                    char*hostname, size_thostname_size,

                    char*port, size_tport_size,

                    intflags)

{

  int sa_length= 0;

 

  switch (sa->sa_family){

  case AF_INET:

    sa_length=sizeof (struct sockaddr_in);

#ifdef HAVE_SOCKADDR_IN_SIN_LEN

    ((struct sockaddr_in *) sa)->sin_len= sa_length;

#endif /* HAVE_SOCKADDR_IN_SIN_LEN */

    break;

 

#ifdef HAVE_IPV6

  case AF_INET6:

    sa_length=sizeof (struct sockaddr_in6);

# ifdef HAVE_SOCKADDR_IN6_SIN6_LEN

    ((struct sockaddr_in6 *) sa)->sin6_len= sa_length;

# endif /* HAVE_SOCKADDR_IN6_SIN6_LEN*/

    break;

#endif /* HAVE_IPV6 */

  }

 

  return getnameinfo(sa,sa_length,

                     hostname,hostname_size,

                     port,port_size,

                     flags);//使用该函数完成调用

}

 

 个人学习笔记,可能写得较乱,哈哈

原创粉丝点击