sockopt.[hc] support IPv6

pull/37/head
YuQing 2019-09-26 21:27:19 +08:00
parent 82eee4ddd0
commit 28d175523d
3 changed files with 324 additions and 74 deletions

View File

@ -1,9 +1,10 @@
Version 1.41 2019-09-22 Version 1.41 2019-09-27
* change CIDR network_bits range from [16, 32) to [10, 32) * change CIDR network_bits range from [16, 32) to [10, 32)
* ini_file_reader.c: fix empty string compare * ini_file_reader.c: fix empty string compare
* multi_socket_client.c: code refine * multi_socket_client.c: code refine
* sockopt.[hc] support IPv6
Version 1.40 2018-11-09 Version 1.40 2018-11-09
* add function conn_pool_parse_server_info and conn_pool_load_server_info * add function conn_pool_parse_server_info and conn_pool_load_server_info

View File

@ -462,35 +462,35 @@ int tcpsenddata_nb(int sock, void* data, const int size, const int timeout)
return 0; return 0;
} }
int setsockaddrbyip(const char *ip, const short port, struct sockaddr_in *addr, int setsockaddrbyip(const char *ip, const short port, sockaddr_convert_t *convert)
struct sockaddr_in6 *addr6, void **output, int *size)
{ {
int domain; int af;
void *dest; void *dest;
if (is_ipv6_addr(ip)) if (is_ipv6_addr(ip))
{ {
*output = addr6; convert->len = sizeof(convert->sa.addr6);
*size = sizeof(*addr6); dest = &convert->sa.addr6.sin6_addr;
dest = &addr6->sin6_addr;
domain = AF_INET6; af = AF_INET6;
addr6->sin6_family = PF_INET6; convert->sa.addr6.sin6_family = PF_INET6;
addr6->sin6_port = htons(port); convert->sa.addr6.sin6_port = htons(port);
} }
else //ipv4 else //ipv4
{ {
*output = addr; convert->len = sizeof(convert->sa.addr4);
*size = sizeof(*addr); dest = &convert->sa.addr4.sin_addr;
dest = &addr->sin_addr;
domain = AF_INET; af = AF_INET;
addr->sin_family = PF_INET; convert->sa.addr4.sin_family = PF_INET;
addr->sin_port = htons(port); convert->sa.addr4.sin_port = htons(port);
} }
if (inet_pton(domain, ip, dest) == 0) if (inet_pton(af, ip, dest) == 0)
{ {
logError("file: "__FILE__", line: %d, "
"invalid %s ip address: %s", __LINE__,
(af == AF_INET ? "IPv4" : "IPv6"), ip);
return EINVAL; return EINVAL;
} }
return 0; return 0;
@ -499,18 +499,14 @@ int setsockaddrbyip(const char *ip, const short port, struct sockaddr_in *addr,
int connectserverbyip(int sock, const char *server_ip, const short server_port) int connectserverbyip(int sock, const char *server_ip, const short server_port)
{ {
int result; int result;
struct sockaddr_in addr; sockaddr_convert_t convert;
struct sockaddr_in6 addr6;
void *dest;
int size;
if ((result=setsockaddrbyip(server_ip, server_port, &addr, &addr6, if ((result=setsockaddrbyip(server_ip, server_port, &convert)) != 0)
&dest, &size)) != 0)
{ {
return result; return result;
} }
if (connect(sock, (const struct sockaddr*)dest, size) < 0) if (connect(sock, &convert.sa.addr, convert.len) < 0)
{ {
return errno != 0 ? errno : EINTR; return errno != 0 ? errno : EINTR;
} }
@ -535,13 +531,9 @@ int connectserverbyip_nb_ex(int sock, const char *server_ip, \
struct pollfd pollfds; struct pollfd pollfds;
#endif #endif
struct sockaddr_in addr; sockaddr_convert_t convert;
struct sockaddr_in6 addr6;
void *dest;
int size;
if ((result=setsockaddrbyip(server_ip, server_port, &addr, &addr6, if ((result=setsockaddrbyip(server_ip, server_port, &convert)) != 0)
&dest, &size)) != 0)
{ {
return result; return result;
} }
@ -576,7 +568,7 @@ int connectserverbyip_nb_ex(int sock, const char *server_ip, \
do do
{ {
if (connect(sock, (const struct sockaddr*)dest, size) < 0) if (connect(sock, &convert.sa.addr, convert.len) < 0)
{ {
result = errno != 0 ? errno : EINPROGRESS; result = errno != 0 ? errno : EINPROGRESS;
if (result != EINPROGRESS) if (result != EINPROGRESS)
@ -634,16 +626,99 @@ int connectserverbyip_nb_ex(int sock, const char *server_ip, \
return result; return result;
} }
int socketClientEx2(int af, const char *server_ip,
const short server_port, const int timeout,
const int flags, const char *bind_ipaddr, int *err_no)
{
int sock;
bool auto_detect;
if (af == AF_UNSPEC)
{
af = is_ipv6_addr(server_ip) ? AF_INET6 : AF_INET;
}
sock = socket(af, SOCK_STREAM, 0);
if (sock < 0)
{
*err_no = errno != 0 ? errno : EMFILE;
logError("file: "__FILE__", line: %d, " \
"socket create failed, errno: %d, error info: %s", \
__LINE__, errno, STRERROR(errno));
return -1;
}
if (flags != 0)
{
*err_no = fd_add_flags(sock, flags);
if (*err_no != 0)
{
close(sock);
return -2;
}
}
if (bind_ipaddr != NULL && *bind_ipaddr != '\0')
{
*err_no = socketBind2(af, sock, bind_ipaddr, 0);
if (*err_no != 0)
{
close(sock);
return -3;
}
}
auto_detect = ((flags & O_NONBLOCK) == 0);
*err_no = connectserverbyip_nb_ex(sock, server_ip,
server_port, timeout, auto_detect);
if (*err_no != 0)
{
close(sock);
return -4;
}
return sock;
}
const char * fc_inet_ntop(const struct sockaddr *addr,
char *buff, const int bufferSize)
{
void *sin_addr;
const char *output;
if (addr->sa_family == AF_INET) {
sin_addr = &((struct sockaddr_in *)addr)->sin_addr;
} else if (addr->sa_family == AF_INET6) {
sin_addr = &((struct sockaddr_in6 *)addr)->sin6_addr;
} else {
*buff = '\0';
logWarning("file: "__FILE__", line: %d, "
"unkown family: %d", __LINE__, addr->sa_family);
return NULL;
}
if ((output=inet_ntop(addr->sa_family, sin_addr, buff, bufferSize)) == NULL)
{
*buff = '\0';
logWarning("file: "__FILE__", line: %d, "
"call inet_ntop fail, "
"errno: %d, error info: %s",
__LINE__, errno, STRERROR(errno));
}
return output;
}
in_addr_t getIpaddr(getnamefunc getname, int sock, \ in_addr_t getIpaddr(getnamefunc getname, int sock, \
char *buff, const int bufferSize) char *buff, const int bufferSize)
{ {
struct sockaddr_in addr; struct sockaddr addr;
socklen_t addrlen; socklen_t addrlen;
memset(&addr, 0, sizeof(addr)); memset(&addr, 0, sizeof(addr));
addrlen = sizeof(addr); addrlen = sizeof(addr);
if (getname(sock, (struct sockaddr *)&addr, &addrlen) != 0) if (getname(sock, &addr, &addrlen) != 0)
{ {
*buff = '\0'; *buff = '\0';
return INADDR_NONE; return INADDR_NONE;
@ -651,31 +726,29 @@ in_addr_t getIpaddr(getnamefunc getname, int sock, \
if (addrlen > 0) if (addrlen > 0)
{ {
if (inet_ntop(AF_INET, &addr.sin_addr, buff, bufferSize) == NULL) fc_inet_ntop(&addr, buff, bufferSize);
{
*buff = '\0';
}
} }
else else
{ {
*buff = '\0'; *buff = '\0';
} }
return addr.sin_addr.s_addr; return ((struct sockaddr_in *)&addr)->sin_addr.s_addr; //DO NOT support IPv6
} }
char *getHostnameByIp(const char *szIpAddr, char *buff, const int bufferSize) char *getHostnameByIp(const char *szIpAddr, char *buff, const int bufferSize)
{ {
struct in_addr ip_addr;
struct hostent *ent; struct hostent *ent;
sockaddr_convert_t convert;
if (inet_pton(AF_INET, szIpAddr, &ip_addr) != 1) if (setsockaddrbyip(szIpAddr, 0, &convert) != 0)
{ {
*buff = '\0'; *buff = '\0';
return buff; return buff;
} }
ent = gethostbyaddr((char *)&ip_addr, sizeof(ip_addr), AF_INET); ent = gethostbyaddr(&convert.sa.addr, convert.len,
convert.sa.addr.sa_family);
if (ent == NULL || ent->h_name == NULL) if (ent == NULL || ent->h_name == NULL)
{ {
*buff = '\0'; *buff = '\0';
@ -839,32 +912,40 @@ int nbaccept(int sock, const int timeout, int *err_no)
return result; return result;
} }
int socketBind(int sock, const char *bind_ipaddr, const int port) int socketBind2(int af, int sock, const char *bind_ipaddr, const int port)
{ {
struct sockaddr_in bindaddr; sockaddr_convert_t convert;
int result;
bindaddr.sin_family = AF_INET; convert.sa.addr.sa_family = af;
bindaddr.sin_port = htons(port);
if (bind_ipaddr == NULL || *bind_ipaddr == '\0') if (bind_ipaddr == NULL || *bind_ipaddr == '\0')
{ {
bindaddr.sin_addr.s_addr = INADDR_ANY; if (af == AF_INET)
{
convert.len = sizeof(convert.sa.addr4);
convert.sa.addr4.sin_port = htons(port);
convert.sa.addr4.sin_addr.s_addr = INADDR_ANY;
} }
else else
{ {
if (inet_pton(AF_INET, bind_ipaddr, &bindaddr.sin_addr) == 0) convert.len = sizeof(convert.sa.addr6);
convert.sa.addr6.sin6_port = htons(port);
convert.sa.addr6.sin6_addr = in6addr_any;
}
}
else
{ {
logError("file: "__FILE__", line: %d, " \ if ((result=setsockaddrbyip(bind_ipaddr, port, &convert)) != 0)
"invalid ip addr %s", \ {
__LINE__, bind_ipaddr); return result;
return EINVAL;
} }
} }
if (bind(sock, (struct sockaddr*)&bindaddr, sizeof(bindaddr)) < 0) if (bind(sock, &convert.sa.addr, convert.len) < 0)
{ {
logError("file: "__FILE__", line: %d, " \ logError("file: "__FILE__", line: %d, "
"bind port %d failed, " \ "bind port %d failed, "
"errno: %d, error info: %s.", \ "errno: %d, error info: %s.",
__LINE__, port, errno, STRERROR(errno)); __LINE__, port, errno, STRERROR(errno));
return errno != 0 ? errno : ENOMEM; return errno != 0 ? errno : ENOMEM;
} }
@ -872,12 +953,22 @@ int socketBind(int sock, const char *bind_ipaddr, const int port)
return 0; return 0;
} }
int socketServer(const char *bind_ipaddr, const int port, int *err_no) int socketBind(int sock, const char *bind_ipaddr, const int port)
{
return socketBind2(AF_INET, sock, bind_ipaddr, port);
}
int socketBindIPv6(int sock, const char *bind_ipaddr, const int port)
{
return socketBind2(AF_INET6, sock, bind_ipaddr, port);
}
int socketServer2(int af, const char *bind_ipaddr, const int port, int *err_no)
{ {
int sock; int sock;
int result; int result;
sock = socket(AF_INET, SOCK_STREAM, 0); sock = socket(af, SOCK_STREAM, 0);
if (sock < 0) if (sock < 0)
{ {
*err_no = errno != 0 ? errno : EMFILE; *err_no = errno != 0 ? errno : EMFILE;
@ -900,7 +991,7 @@ int socketServer(const char *bind_ipaddr, const int port, int *err_no)
return -2; return -2;
} }
if ((*err_no=socketBind(sock, bind_ipaddr, port)) != 0) if ((*err_no=socketBind2(af, sock, bind_ipaddr, port)) != 0)
{ {
close(sock); close(sock);
return -3; return -3;
@ -921,6 +1012,16 @@ int socketServer(const char *bind_ipaddr, const int port, int *err_no)
return sock; return sock;
} }
int socketServer(const char *bind_ipaddr, const int port, int *err_no)
{
return socketServer2(AF_INET, bind_ipaddr, port, err_no);
}
int socketServerIPv6(const char *bind_ipaddr, const int port, int *err_no)
{
return socketServer2(AF_INET6, bind_ipaddr, port, err_no);
}
int tcprecvfile(int sock, const char *filename, const int64_t file_bytes, \ int tcprecvfile(int sock, const char *filename, const int64_t file_bytes, \
const int fsync_after_written_bytes, const int timeout, \ const int fsync_after_written_bytes, const int timeout, \
int64_t *true_file_bytes) int64_t *true_file_bytes)

View File

@ -32,6 +32,15 @@ typedef struct ip_addr_s {
int socket_domain; int socket_domain;
} ip_addr_t; } ip_addr_t;
typedef struct sockaddr_convert_s {
socklen_t len;
union {
struct sockaddr addr;
struct sockaddr_in addr4;
struct sockaddr_in6 addr6;
} sa;
} sockaddr_convert_t;
#ifdef SO_NOSIGPIPE #ifdef SO_NOSIGPIPE
#define SET_SOCKOPT_NOSIGPIPE(sock) \ #define SET_SOCKOPT_NOSIGPIPE(sock) \
do { \ do { \
@ -238,7 +247,7 @@ in_addr_t getIpaddr(getnamefunc getname, int sock, \
*/ */
char *getHostnameByIp(const char *szIpAddr, char *buff, const int bufferSize); char *getHostnameByIp(const char *szIpAddr, char *buff, const int bufferSize);
/** get by ip address by it's hostname /** get by IPv4 address by it's hostname
* parameters: * parameters:
* name: the hostname * name: the hostname
* buff: buffer to store the ip address * buff: buffer to store the ip address
@ -256,7 +265,7 @@ in_addr_t getIpaddrByName(const char *name, char *buff, const int bufferSize);
*/ */
int getIpaddrsByName(const char *name, ip_addr_t *ip_addr_arr, const int ip_addr_arr_size); int getIpaddrsByName(const char *name, ip_addr_t *ip_addr_arr, const int ip_addr_arr_size);
/** bind wrapper /** bind wrapper for IPv4
* parameters: * parameters:
* sock: the socket * sock: the socket
* bind_ipaddr: the ip address to bind * bind_ipaddr: the ip address to bind
@ -265,7 +274,26 @@ int getIpaddrsByName(const char *name, ip_addr_t *ip_addr_arr, const int ip_addr
*/ */
int socketBind(int sock, const char *bind_ipaddr, const int port); int socketBind(int sock, const char *bind_ipaddr, const int port);
/** start a socket server (socket, bind and listen) /** bind wrapper for IPv6
* parameters:
* sock: the socket
* bind_ipaddr: the ip address to bind
* port: the port to bind
* return: error no, 0 success, != 0 fail
*/
int socketBindIPv6(int sock, const char *bind_ipaddr, const int port);
/** bind wrapper for IPv4 or IPv6
* parameters:
* af: family, AF_INET or AF_INET6
* sock: the socket
* bind_ipaddr: the ip address to bind
* port: the port to bind
* return: error no, 0 success, != 0 fail
*/
int socketBind2(int af, int sock, const char *bind_ipaddr, const int port);
/** start a socket server for IPv4 (socket, bind and listen)
* parameters: * parameters:
* sock: the socket * sock: the socket
* bind_ipaddr: the ip address to bind * bind_ipaddr: the ip address to bind
@ -275,6 +303,130 @@ int socketBind(int sock, const char *bind_ipaddr, const int port);
*/ */
int socketServer(const char *bind_ipaddr, const int port, int *err_no); int socketServer(const char *bind_ipaddr, const int port, int *err_no);
/** start a socket server for IPv6 (socket, bind and listen)
* parameters:
* sock: the socket
* bind_ipaddr: the ip address to bind
* port: the port to bind
* err_no: store the error no
* return: >= 0 server socket, < 0 fail
*/
int socketServerIPv6(const char *bind_ipaddr, const int port, int *err_no);
/** start a socket server for IPv4 or IPv6 (socket, bind and listen)
* parameters:
* af: family, AF_INET or AF_INET6
* sock: the socket
* bind_ipaddr: the ip address to bind
* port: the port to bind
* err_no: store the error no
* return: >= 0 server socket, < 0 fail
*/
int socketServer2(int af, const char *bind_ipaddr, const int port, int *err_no);
/** connect to server
* parameters:
* af: family, AF_UNSPEC (auto dectect), AF_INET or AF_INET6
* server_ip: ip address of the server
* server_port: port of the server
* timeout: connect timeout in seconds
* flags: socket flags such as O_NONBLOCK for non-block socket
* bind_ipaddr: the ip address to bind, NULL or empty for bind ANY
* err_no: store the error no
* return: >= 0 server socket, < 0 fail
*/
int socketClientEx2(int af, const char *server_ip,
const short server_port, const int timeout,
const int flags, const char *bind_ipaddr, int *err_no);
/** connect to server
* parameters:
* server_ip: ip address of the server
* server_port: port of the server
* timeout: connect timeout in seconds
* flags: socket flags such as O_NONBLOCK for non-block socket
* bind_ipaddr: the ip address to bind, NULL or empty for bind ANY
* err_no: store the error no
* return: >= 0 server socket, < 0 fail
*/
static inline int socketClientExAuto(const char *server_ip,
const short server_port, const int timeout,
const int flags, const char *bind_ipaddr, int *err_no)
{
return socketClientEx2(AF_UNSPEC, server_ip, server_port,
timeout, flags, bind_ipaddr, err_no);
}
/** connect to server
* parameters:
* server_ip: ip address of the server
* server_port: port of the server
* timeout: connect timeout in seconds
* flags: socket flags such as O_NONBLOCK for non-block socket
* bind_ipaddr: the ip address to bind, NULL or empty for bind ANY
* err_no: store the error no
* return: >= 0 server socket, < 0 fail
*/
static inline int socketClientAuto(const char *server_ip,
const short server_port, const int timeout,
const int flags, int *err_no)
{
return socketClientEx2(AF_UNSPEC, server_ip, server_port,
timeout, flags, NULL, err_no);
}
/** connect to server
* parameters:
* af: family, AF_UNSPEC (auto dectect), AF_INET or AF_INET6
* server_ip: ip address of the server
* server_port: port of the server
* timeout: connect timeout in seconds
* flags: socket flags such as O_NONBLOCK for non-block socket
* err_no: store the error no
* return: >= 0 server socket, < 0 fail
*/
static inline int socketClient2(int af, const char *server_ip,
const short server_port, const int timeout,
const int flags, int *err_no)
{
return socketClientEx2(af, server_ip, server_port,
timeout, flags, NULL, err_no);
}
/** connect to server with IPv4 socket
* parameters:
* server_ip: ip address of the server
* server_port: port of the server
* timeout: connect timeout in seconds
* flags: socket flags such as O_NONBLOCK for non-block socket
* err_no: store the error no
* return: >= 0 server socket, < 0 fail
*/
static inline int socketClient(const char *server_ip,
const short server_port, const int timeout,
const int flags, int *err_no)
{
return socketClient2(AF_INET, server_ip, server_port,
timeout, flags, err_no);
}
/** connect to server with IPv6 socket
* parameters:
* server_ip: ip address of the server
* server_port: port of the server
* timeout: connect timeout in seconds
* flags: socket flags such as O_NONBLOCK for non-block socket
* err_no: store the error no
* return: >= 0 server socket, < 0 fail
*/
static inline int socketClientIPv6(const char *server_ip,
const short server_port, const int timeout,
const int flags, int *err_no)
{
return socketClient2(AF_INET6, server_ip, server_port,
timeout, flags, err_no);
}
#define tcprecvdata(sock, data, size, timeout) \ #define tcprecvdata(sock, data, size, timeout) \
tcprecvdata_ex(sock, data, size, timeout, NULL) tcprecvdata_ex(sock, data, size, timeout, NULL)
@ -374,18 +526,14 @@ int gethostaddrs(char **if_alias_prefixes, const int prefix_count, \
*/ */
int getifconfigs(FastIFConfig *if_configs, const int max_count, int *count); int getifconfigs(FastIFConfig *if_configs, const int max_count, int *count);
/** set socket address by ip /** set socket address by ip and port
* parameters: * parameters:
* ip: the ip address * ip: the ip address
* port: the port * port: the port
* addr: ipv4 addr * convert: the convert struct for IPv4 and IPv6 compatibility
* addr6: ipv6 addr
* output: return addr pointer
* size: return the size of addr
* return: error no, 0 success, != 0 fail * return: error no, 0 success, != 0 fail
*/ */
int setsockaddrbyip(const char *ip, const short port, struct sockaddr_in *addr, int setsockaddrbyip(const char *ip, const short port, sockaddr_convert_t *convert);
struct sockaddr_in6 *addr6, void **output, int *size);
static inline bool is_ipv6_addr(const char *ip) static inline bool is_ipv6_addr(const char *ip)
{ {