MySQL源码中处理客户端不同地址族的源码
2011-06-18 12:15
183 查看
在ws2def.h文件中定义的结构:
typedef struct sockaddr_storage {
ADDRESS_FAMILY
ss_family; // address
family
CHAR __ss_pad1[_SS_PAD1SIZE]; // 6 byte pad, this
is to make
// implementation
specific pad up to
// alignment field
that follows explicit
// in the data
structure
__int64 __ss_align; // Field
to force desired structure
CHAR __ss_pad2[_SS_PAD2SIZE]; // 112 byte pad to
achieve desired size;
// _SS_MAXSIZE
value minus size of
// ss_family,
__ss_pad1, and
// __ss_align
fields is 112
} SOCKADDR_STORAGE_LH,
*PSOCKADDR_STORAGE_LH, FAR *LPSOCKADDR_STORAGE_LH;
微软说明:
The SOCKADDR_STORAGE structure stores socket address
information. Since the SOCKADDR_STORAGE structure is sufficiently large to
store address information for IPv4, IPv6, or other address families, its use
promotes protocol-family and protocol-version independence and simplifies cross-platform
development. 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个字节。
而在MySQL中st_vio结构中对IP地址就是使用该结构,而不是以往使用的addr_in了,这是为了处理IPv4和IPv6而定义的吧。
看看下面在MySQL中获取客户端的处理流程吧
通过客户端套接字à获取客户端sockaddr->获取客户端IP和端口
调用函数getpeername->getnameinfo
源码如下:
/**
Return IP address and port of a VIO client
socket.
The function returns an IPv4 address if IPv6
support is disabled.
The function returns an IPv4 address if the
client socket is associated
with an IPv4-compatible or IPv4-mapped IPv6
address. Otherwise, the native
IPv6 address is returned.
*/
my_bool vio_peer_addr(Vio *vio, char *ip_buffer, uint16 *port,
size_t
ip_buffer_size)
{
DBUG_ENTER("vio_peer_addr");
DBUG_PRINT("enter", ("Client
socked fd: %d", (int) vio->sd));
if (vio->localhost)//是本机的话,当然简单了
{
/*
Initialize vio->remote and
vio->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);
/* Initialize
ip_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_socket
addr_length= sizeof
(addr_storage);
/* Get sockaddr
by 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 IP
address. */
vio_get_normalized_ip(addr, addr_length,
(struct sockaddr *)
&vio->remote,
&vio->addrLen);
/* Get IP address
& port number. */
err_code=
vio_getnameinfo((struct
sockaddr *) &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", ("Client
IP address: %s; port: %d",
(const
char *) 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 or
IPv4-compatible IPv6 addresses.
@note Background: when IPv4 and IPv6 are used
simultaneously, IPv4
addresses may be written in a form of
IPv4-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 a
little difficult to compare
addresses with each other (the
IPv4-compatible IPv6-address of foo.bar
will be different from the IPv4-mapped
IPv6-address of foo.bar).
@note This function can be made public when
it's needed.
@param src [in] source IP address (AF_INET or
AF_INET6).
@param src_length [in] length of the src.
@param dst [out] a buffer to store normalized IP
address
(sockaddr_storage).
@param dst_length [out] actual length of the
normalized IP address.
*/
static void vio_get_normalized_ip(const
struct 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 H***E_IPV6
case AF_INET6:
{
const struct sockaddr_in6
*src_addr6= (const
struct 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 or
IPv4-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 compatible
address, the last 32 bits represent
the IPv4 address. The byte orders for
IPv6 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 /* H***E_IPV6 */
}
}
IPv6地址结构:
typedef struct sockaddr_in6 {
ADDRESS_FAMILY
sin6_family; //
AF_INET6.
USHORT sin6_port; //
Transport level port number.
ULONG sin6_flowinfo; // IPv6 flow
information.
IN6_ADDR
sin6_addr; // IPv6
address.
union {
ULONG
sin6_scope_id; // Set of
interfaces for a scope.
SCOPE_ID
sin6_scope_struct;
};
} SOCKADDR_IN6_LH,
*PSOCKADDR_IN6_LH, FAR
*LPSOCKADDR_IN6_LH;
下面就到了返回套接字地址的IP和端口了,MySQL函数调用如下:
/**
This is a wrapper for the system
getnameinfo(), 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_storage
passed to it;
- Mac OS X has sockaddr_in::sin_len and
sockaddr_in6::sin6_len and
requires them to be filled.
*/
int vio_getnameinfo(const struct sockaddr *sa,
char
*hostname, size_t
hostname_size,
char
*port, size_t
port_size,
int
flags)
{
int sa_length= 0;
switch (sa->sa_family)
{
case AF_INET:
sa_length=
sizeof (struct sockaddr_in);
#ifdef H***E_SOCKADDR_IN_SIN_LEN
((struct sockaddr_in *) sa)->sin_len= sa_length;
#endif /* H***E_SOCKADDR_IN_SIN_LEN */
break;
#ifdef H***E_IPV6
case AF_INET6:
sa_length=
sizeof (struct sockaddr_in6);
# ifdef H***E_SOCKADDR_IN6_SIN6_LEN
((struct sockaddr_in6 *) sa)->sin6_len= sa_length;
# endif /* H***E_SOCKADDR_IN6_SIN6_LEN
*/
break;
#endif /* H***E_IPV6 */
}
return getnameinfo(sa,
sa_length,
hostname,
hostname_size,
port,
port_size,
flags);//使用该函数完成调用
}
个人学习笔记,可能写得较乱,哈哈
typedef struct sockaddr_storage {
ADDRESS_FAMILY
ss_family; // address
family
CHAR __ss_pad1[_SS_PAD1SIZE]; // 6 byte pad, this
is to make
// implementation
specific pad up to
// alignment field
that follows explicit
// in the data
structure
__int64 __ss_align; // Field
to force desired structure
CHAR __ss_pad2[_SS_PAD2SIZE]; // 112 byte pad to
achieve desired size;
// _SS_MAXSIZE
value minus size of
// ss_family,
__ss_pad1, and
// __ss_align
fields is 112
} SOCKADDR_STORAGE_LH,
*PSOCKADDR_STORAGE_LH, FAR *LPSOCKADDR_STORAGE_LH;
微软说明:
The SOCKADDR_STORAGE structure stores socket address
information. Since the SOCKADDR_STORAGE structure is sufficiently large to
store address information for IPv4, IPv6, or other address families, its use
promotes protocol-family and protocol-version independence and simplifies cross-platform
development. 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个字节。
而在MySQL中st_vio结构中对IP地址就是使用该结构,而不是以往使用的addr_in了,这是为了处理IPv4和IPv6而定义的吧。
看看下面在MySQL中获取客户端的处理流程吧
通过客户端套接字à获取客户端sockaddr->获取客户端IP和端口
调用函数getpeername->getnameinfo
源码如下:
/**
Return IP address and port of a VIO client
socket.
The function returns an IPv4 address if IPv6
support is disabled.
The function returns an IPv4 address if the
client socket is associated
with an IPv4-compatible or IPv4-mapped IPv6
address. Otherwise, the native
IPv6 address is returned.
*/
my_bool vio_peer_addr(Vio *vio, char *ip_buffer, uint16 *port,
size_t
ip_buffer_size)
{
DBUG_ENTER("vio_peer_addr");
DBUG_PRINT("enter", ("Client
socked fd: %d", (int) vio->sd));
if (vio->localhost)//是本机的话,当然简单了
{
/*
Initialize vio->remote and
vio->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);
/* Initialize
ip_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_socket
addr_length= sizeof
(addr_storage);
/* Get sockaddr
by 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 IP
address. */
vio_get_normalized_ip(addr, addr_length,
(struct sockaddr *)
&vio->remote,
&vio->addrLen);
/* Get IP address
& port number. */
err_code=
vio_getnameinfo((struct
sockaddr *) &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", ("Client
IP address: %s; port: %d",
(const
char *) 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 or
IPv4-compatible IPv6 addresses.
@note Background: when IPv4 and IPv6 are used
simultaneously, IPv4
addresses may be written in a form of
IPv4-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 a
little difficult to compare
addresses with each other (the
IPv4-compatible IPv6-address of foo.bar
will be different from the IPv4-mapped
IPv6-address of foo.bar).
@note This function can be made public when
it's needed.
@param src [in] source IP address (AF_INET or
AF_INET6).
@param src_length [in] length of the src.
@param dst [out] a buffer to store normalized IP
address
(sockaddr_storage).
@param dst_length [out] actual length of the
normalized IP address.
*/
static void vio_get_normalized_ip(const
struct 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 H***E_IPV6
case AF_INET6:
{
const struct sockaddr_in6
*src_addr6= (const
struct 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 or
IPv4-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 compatible
address, the last 32 bits represent
the IPv4 address. The byte orders for
IPv6 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 /* H***E_IPV6 */
}
}
IPv6地址结构:
typedef struct sockaddr_in6 {
ADDRESS_FAMILY
sin6_family; //
AF_INET6.
USHORT sin6_port; //
Transport level port number.
ULONG sin6_flowinfo; // IPv6 flow
information.
IN6_ADDR
sin6_addr; // IPv6
address.
union {
ULONG
sin6_scope_id; // Set of
interfaces for a scope.
SCOPE_ID
sin6_scope_struct;
};
} SOCKADDR_IN6_LH,
*PSOCKADDR_IN6_LH, FAR
*LPSOCKADDR_IN6_LH;
下面就到了返回套接字地址的IP和端口了,MySQL函数调用如下:
/**
This is a wrapper for the system
getnameinfo(), 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_storage
passed to it;
- Mac OS X has sockaddr_in::sin_len and
sockaddr_in6::sin6_len and
requires them to be filled.
*/
int vio_getnameinfo(const struct sockaddr *sa,
char
*hostname, size_t
hostname_size,
char
*port, size_t
port_size,
int
flags)
{
int sa_length= 0;
switch (sa->sa_family)
{
case AF_INET:
sa_length=
sizeof (struct sockaddr_in);
#ifdef H***E_SOCKADDR_IN_SIN_LEN
((struct sockaddr_in *) sa)->sin_len= sa_length;
#endif /* H***E_SOCKADDR_IN_SIN_LEN */
break;
#ifdef H***E_IPV6
case AF_INET6:
sa_length=
sizeof (struct sockaddr_in6);
# ifdef H***E_SOCKADDR_IN6_SIN6_LEN
((struct sockaddr_in6 *) sa)->sin6_len= sa_length;
# endif /* H***E_SOCKADDR_IN6_SIN6_LEN
*/
break;
#endif /* H***E_IPV6 */
}
return getnameinfo(sa,
sa_length,
hostname,
hostname_size,
port,
port_size,
flags);//使用该函数完成调用
}
个人学习笔记,可能写得较乱,哈哈
相关文章推荐
- mysql 源码学习笔记:客户端连接处理流程
- mysql与sqlite在处理并发问题时的不同
- 传奇源码分析-客户端(游戏逻辑处理源分析五 服务器端响应)
- Dubbo源码阅读之 服务端和客户端处理链
- 传奇源码分析-客户端(游戏逻辑处理源分析四)
- 加入数据库mysql实现android注册登陆功能的客户端服务器源码与解析socket
- 加入数据库mysql实现android注册登陆功能的客户端服务器源码与解析
- mysql客户端连接失败处理方法(can't connect to MySQL server on localhost'(10060))
- 前端控制器是整个MVC框架中最为核心的一块,它主要用来拦截符合要求的外部请求,并把请求分发到不同的控制器去处理,根据控制器处理后的结果,生成相应的响应发送到客户端。前端控制器既可以使用Filter实现(Struts2采用这种方式),也可以使用Servlet来实现(spring MVC框架)。
- 传奇源码分析-客户端(游戏逻辑处理源分析五 服务器端响应)
- LAMP架构客户端请求PHP(带有mysql)页面处理的流程
- C#连接Access、SQL Server、Oracle、MySQL、DB2和SyBase六种不同数据库的程序源码
- 传奇源码分析-客户端(游戏逻辑处理源分析一)
- Mysql异常问题排查与处理——mysql的DNS反向解析和客户端网卡重启
- windws下mysql客户端登陆服务器选用字符集的不同造成的语句执行效果不正确
- mysql如何处理一个客户端的连接
- 传奇源码分析-客户端(游戏逻辑处理源分析一)
- 论坛源码推荐(3月25日):类似QQ客户端进度加载效果 简化Objective-C中的日期和时间处理
- zookeeper源码阅读分析笔记--客户端服务端通信机制以及session超时、过期处理
- MySQL一个线程处理一个连接源码