Skip to content
Snippets Groups Projects
Commit 6c4486e9 authored by Marek Vavrusa's avatar Marek Vavrusa
Browse files

Initial IPv6 sockets support.

Setting flag DISABLE_IPV6 disables IPv6.
Using IPv6 poses a performance regression:
* Dual-stack API with IPv4 addresses: ~2%
* Using IPv6 addresses: ~22%

Commit refs #461.
parent be2fc144
No related branches found
No related tags found
No related merge requests found
......@@ -33,8 +33,8 @@ cute_server *cute_create()
conf_iface_t *iface = (conf_iface_t*)n;
// Create TCP+UDP sockets
int udp_sock = socket_create(PF_INET, SOCK_DGRAM);
if (socket_bind(udp_sock, iface->address, iface->port) < 0) {
int udp_sock = socket_create(iface->family, SOCK_DGRAM);
if (socket_bind(udp_sock, iface->family, iface->address, iface->port) < 0) {
log_server_error("Could not bind to "
"UDP interface on '%s:%d'.\n",
iface->address, iface->port);
......@@ -46,8 +46,8 @@ cute_server *cute_create()
setsockopt(udp_sock, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt));
setsockopt(udp_sock, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
int tcp_sock = socket_create(PF_INET, SOCK_STREAM);
if (socket_bind(tcp_sock, iface->address, iface->port) < 0) {
int tcp_sock = socket_create(iface->family, SOCK_STREAM);
if (socket_bind(tcp_sock, iface->family, iface->address, iface->port) < 0) {
log_server_error("Could not bind to "
"TCP interface on '%s:%d'.\n",
iface->address, iface->port);
......@@ -67,6 +67,8 @@ cute_server *cute_create()
for (int i = 0; i < tcp_loaded; ++i) {
close(tcp_socks[i]);
}
free(udp_socks);
free(tcp_socks);
return 0;
}
......@@ -85,6 +87,7 @@ cute_server *cute_create()
server->zone_db = dnslib_zonedb_new();
if (server->zone_db == NULL) {
ERR_ALLOC_FAILED;
return NULL;
}
......@@ -119,6 +122,9 @@ cute_server *cute_create()
dt_repurpose(unit->threads[0], &tcp_master, 0);
cute_create_handler(server, tcp_socks[i], unit);
}
free(udp_socks);
free(tcp_socks);
debug_server("Done\n\n");
return server;
......
......@@ -17,41 +17,100 @@ int socket_create(int family, int type)
return socket(family, type, 0);
}
int socket_connect(int socket, const char *addr, unsigned short port)
int socket_connect(int fd, const char *addr, unsigned short port)
{
// Create socket
struct hostent *hent = gethostbyname(addr);
if (hent == 0) {
int ret = 0;
struct addrinfo hints, *res;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if ((ret = getaddrinfo(addr, NULL, &hints, &res)) != 0) {
return -1;
}
// Prepare host address
struct sockaddr_in saddr;
socklen_t addrlen = sizeof(struct sockaddr_in);
saddr.sin_family = AF_INET;
saddr.sin_port = htons(port);
memcpy(&saddr.sin_addr, hent->h_addr, hent->h_length);
/* Evaluate address type. */
struct sockaddr *saddr = 0;
socklen_t addrlen = 0;
#ifndef DISABLE_IPV6
if (res->ai_family == AF_INET6) {
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6*)res->ai_addr;
ipv6->sin6_port = htons(port);
saddr = (struct sockaddr*)ipv6;
addrlen = sizeof(struct sockaddr_in6);
}
#endif
if (res->ai_family == AF_INET) {
struct sockaddr_in *ipv4 = (struct sockaddr_in*)res->ai_addr;
ipv4->sin_port = htons(port);
saddr = (struct sockaddr*)ipv4;
addrlen = sizeof(struct sockaddr_in);
}
/* Connect. */
ret = -1;
if (addr) {
ret = connect(fd, saddr, addrlen);
}
// Connect to host
return connect(socket, (struct sockaddr *)&saddr, addrlen);
/* Free addresses. */
freeaddrinfo(res);
return ret;
}
int socket_bind(int socket, const char *addr, unsigned short port)
int socket_bind(int socket, int family, const char *addr, unsigned short port)
{
// Initialize socket address
// Check address family
struct sockaddr* paddr = 0;
socklen_t addrlen = 0;
struct sockaddr_in saddr;
socklen_t addrlen = sizeof(struct sockaddr_in);
if (getsockname(socket, &saddr, &addrlen) < 0) {
#ifndef DISABLE_IPV6
struct sockaddr_in6 saddr6;
#endif
if (family == AF_INET) {
// Initialize socket address
paddr = (struct sockaddr*)&saddr;
addrlen = sizeof(saddr);
if (getsockname(socket, paddr, &addrlen) < 0) {
return -1;
}
// Set address and port
saddr.sin_port = htons(port);
if (inet_pton(family, addr, &saddr.sin_addr) < 0) {
saddr.sin_addr.s_addr = INADDR_ANY;
char buf[INET_ADDRSTRLEN];
inet_ntop(family, &saddr.sin_addr, buf, sizeof(buf));
log_error("%s: address %s is invalid, using %s instead\n",
__func__, addr, buf);
}
} else {
#ifdef DISABLE_IPV6
log_error("%s: ipv6 support disabled\n", __func__);
return -1;
}
// Set address and port
saddr.sin_port = htons(port);
saddr.sin_addr.s_addr = inet_addr(addr);
if (saddr.sin_addr.s_addr == INADDR_NONE) {
log_error("%s: address %s is invalid, using 0.0.0.0 instead",
__func__, addr);
saddr.sin_addr.s_addr = htonl(INADDR_ANY);
#else
// Initialize socket address
paddr = (struct sockaddr*)&saddr6;
addrlen = sizeof(saddr6);
if (getsockname(socket, paddr, &addrlen) < 0) {
return -1;
}
// Set address and port
saddr6.sin6_port = htons(port);
if (inet_pton(family, addr, &saddr6.sin6_addr) < 0) {
memcpy(&saddr6.sin6_addr, &in6addr_any, sizeof(in6addr_any));
char buf[INET6_ADDRSTRLEN];
inet_ntop(family, &saddr6.sin6_addr, buf, sizeof(buf));
log_error("%s: address %s is invalid, using %s instead\n",
__func__, addr, buf);
}
#endif
}
// Reuse old address if taken
......@@ -63,7 +122,7 @@ int socket_bind(int socket, const char *addr, unsigned short port)
}
// Bind to specified address
int res = bind(socket, (struct sockaddr *)& saddr, sizeof(saddr));
int res = bind(socket, paddr, addrlen);
if (res < 0) {
log_error("%s: cannot bind socket (errno %d): %s.\n",
__func__, errno, strerror(errno));
......@@ -78,28 +137,6 @@ int socket_listen(int socket, int backlog_size)
return listen(socket, backlog_size);
}
ssize_t socket_recv(int socket, void *buf, size_t len, int flags)
{
return recv(socket, buf, len, flags);
}
ssize_t socket_recvfrom(int socket, void *buf, size_t len, int flags,
struct sockaddr *from, socklen_t *fromlen)
{
return recvfrom(socket, buf, len, flags, from, fromlen);
}
ssize_t socket_send(int socket, const void *buf, size_t len, int flags)
{
return send(socket, buf, len, flags);
}
ssize_t socket_sendto(int socket, const void *buf, size_t len, int flags,
const struct sockaddr *to, socklen_t tolen)
{
return sendto(socket, buf, len, flags, to, tolen);
}
int socket_close(int socket)
{
return close(socket);
......
......@@ -29,7 +29,7 @@ enum {
* \brief Create socket.
*
* \param family Socket family (PF_INET, PF_IPX, PF_PACKET, PF_UNIX).
* \param type Socket type (SOCK_STREAM, SOCK_DGRAM, SOCK_RAW).
* \param type Socket type (SOCK_STREAM, SOCK_DGRAM, SOCK_RAW).
*
* \retval 0 On success.
* \retval <0 If an error occured.
......@@ -39,42 +39,43 @@ int socket_create(int family, int type);
/*!
* \brief Connect to remote host.
*
* \param socket Socket filedescriptor.
* \param addr Requested address.
* \param port Requested port.
* \param fd Socket filedescriptor.
* \param addr Requested address.
* \param port Requested port.
*
* \retval 0 On success.
* \retval <0 If an error occured.
*/
int socket_connect(int socket, const char *addr, unsigned short port);
int socket_connect(int fd, const char *addr, unsigned short port);
/*!
* \brief Listen on given socket.
*
* \param socket Socket filedescriptor.
* \param addr Requested address.
* \param port Requested port.
* \param fd Socket filedescriptor.
* \param family Socket family.
* \param addr Requested address.
* \param port Requested port.
*
* \retval 0 On success.
* \retval <0 If an error occured.
*/
int socket_bind(int socket, const char *addr, unsigned short port);
int socket_bind(int fd, int family, const char *addr, unsigned short port);
/*!
* \brief Listen on given TCP socket.
*
* \param socket Socket filedescriptor.
* \param fd Socket filedescriptor.
* \param backlog_size Requested TCP backlog size.
*
* \retval 0 On success.
* \retval <0 If an error occured.
*/
int socket_listen(int socket, int backlog_size);
int socket_listen(int fd, int backlog_size);
/*!
* \brief Receive data from connection-mode socket.
*
* \param socket Socket filedescriptor.
* \param fd Socket filedescriptor.
* \param buf Destination buffer.
* \param len Maximum data length.
* \param flags Additional flags.
......@@ -82,12 +83,15 @@ int socket_listen(int socket, int backlog_size);
* \retval 0 On success.
* \retval <0 If an error occured.
*/
ssize_t socket_recv(int socket, void *buf, size_t len, int flags);
static inline ssize_t socket_recv(int socket, void *buf, size_t len, int flags)
{
return recv(socket, buf, len, flags);
}
/*!
* \brief Receive data from datagram-mode socket.
*
* \param socket Socket filedescriptor.
* \param fd Socket filedescriptor.
* \param buf Destination buffer.
* \param len Maximum data length.
* \param flags Additional flags.
......@@ -97,13 +101,17 @@ ssize_t socket_recv(int socket, void *buf, size_t len, int flags);
* \retval 0 On success.
* \retval <0 If an error occured.
*/
ssize_t socket_recvfrom(int socket, void *buf, size_t len, int flags,
struct sockaddr *from, socklen_t *fromlen);
static inline ssize_t socket_recvfrom(int socket, void *buf, size_t len,
int flags, struct sockaddr *from,
socklen_t *fromlen)
{
return recvfrom(socket, buf, len, flags, from, fromlen);
}
/*!
* \brief Send data to connection-mode socket.
*
* \param socket Socket filedescriptor.
* \param fd Socket filedescriptor.
* \param buf Source buffer.
* \param len Data length.
* \param flags Additional flags.
......@@ -111,12 +119,16 @@ ssize_t socket_recvfrom(int socket, void *buf, size_t len, int flags,
* \retval 0 On success.
* \retval <0 If an error occured.
*/
ssize_t socket_send(int socket, const void *buf, size_t len, int flags);
static inline ssize_t socket_send(int socket, const void *buf, size_t len,
int flags)
{
return send(socket, buf, len, flags);
}
/*!
* \brief Send data to datagram-mode socket.
*
* \param socket Socket filedescriptor.
* \param fd Socket filedescriptor.
* \param buf Source buffer.
* \param len Data length.
* \param flags Additional flags.
......@@ -126,18 +138,21 @@ ssize_t socket_send(int socket, const void *buf, size_t len, int flags);
* \retval 0 On success.
* \retval <0 If an error occured.
*/
ssize_t socket_sendto(int socket, const void *buf, size_t len, int flags,
const struct sockaddr *to, socklen_t tolen);
static inline ssize_t socket_sendto(int socket, const void *buf, size_t len,
int flags, const struct sockaddr *to,
socklen_t tolen)
{
return sendto(socket, buf, len, flags, to, tolen);
}
/*!
* \brief Close and deinitialize socket.
*
* \param socket Socket filedescriptor.
* \param fd Socket filedescriptor.
*
* \retval 0 On success.
* \retval <0 If an error occured.
*/
int socket_close(int socket);
int socket_close(int fd);
#endif // _CUTEDNS_SOCKET_H_
......
......@@ -31,7 +31,11 @@ int udp_master(dthread_t *thread)
*/
uint8_t inbuf[SOCKET_MTU_SZ];
uint8_t outbuf[SOCKET_MTU_SZ];
#ifdef DISABLE_IPV6
struct sockaddr_in faddr;
#else
struct sockaddr_in6 faddr;
#endif
int addrsize = sizeof(faddr);
/* in case of STAT_COMPILE the following code will declare thread_stat
......@@ -95,20 +99,16 @@ int udp_master(dthread_t *thread)
debug_net_hex((const char *) outbuf, answer_size);
// Send datagram
for (;;) {
res = socket_sendto(sock, outbuf, answer_size,0,
(struct sockaddr *) &faddr,
(socklen_t) addrsize);
// Check result
if (res != answer_size) {
log_error("udp: %s: failed: %d - %s.\n",
"socket_sendto()",
res, strerror(res));
continue;
}
break;
res = socket_sendto(sock, outbuf, answer_size,0,
(struct sockaddr *) &faddr,
(socklen_t) addrsize);
// Check result
if (res != answer_size) {
log_error("udp: %s: failed: %d - %s.\n",
"socket_sendto()",
res, strerror(res));
continue;
}
stat_get_second(thread_stat);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment