util: Split construction of bind socket address from the rest of sock_l4()
sock_l4() creates, binds and otherwise prepares a new socket. It builds the socket address to bind from separately provided address and port. However, we have use cases coming up where it's more natural to construct the socket address in the caller. Prepare for this by adding sock_l4_sa() which takes a pre-constructed socket address, and rewriting sock_l4() in terms of it. Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
This commit is contained in:
parent
4070bac7a4
commit
523fbc5af7
1 changed files with 70 additions and 53 deletions
123
util.c
123
util.c
|
@ -33,36 +33,25 @@
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sock_l4() - Create and bind socket for given L4, add to epoll list
|
* sock_l4_sa() - Create and bind socket to socket address, add to epoll list
|
||||||
* @c: Execution context
|
* @c: Execution context
|
||||||
* @af: Address family, AF_INET or AF_INET6
|
|
||||||
* @proto: Protocol number
|
* @proto: Protocol number
|
||||||
* @bind_addr: Address for binding, NULL for any
|
* @sa: Socket address to bind to
|
||||||
|
* @sl: Length of @sa
|
||||||
* @ifname: Interface for binding, NULL for any
|
* @ifname: Interface for binding, NULL for any
|
||||||
* @port: Port, host order
|
* @v6only: Set IPV6_V6ONLY socket option
|
||||||
* @data: epoll reference portion for protocol handlers
|
* @data: epoll reference portion for protocol handlers
|
||||||
*
|
*
|
||||||
* Return: newly created socket, negative error code on failure
|
* Return: newly created socket, negative error code on failure
|
||||||
*/
|
*/
|
||||||
int sock_l4(const struct ctx *c, sa_family_t af, uint8_t proto,
|
static int sock_l4_sa(const struct ctx *c, uint8_t proto,
|
||||||
const void *bind_addr, const char *ifname, uint16_t port,
|
const void *sa, socklen_t sl,
|
||||||
uint32_t data)
|
const char *ifname, bool v6only, uint32_t data)
|
||||||
{
|
{
|
||||||
|
sa_family_t af = ((const struct sockaddr *)sa)->sa_family;
|
||||||
union epoll_ref ref = { .data = data };
|
union epoll_ref ref = { .data = data };
|
||||||
struct sockaddr_in addr4 = {
|
|
||||||
.sin_family = AF_INET,
|
|
||||||
.sin_port = htons(port),
|
|
||||||
{ 0 }, { 0 },
|
|
||||||
};
|
|
||||||
struct sockaddr_in6 addr6 = {
|
|
||||||
.sin6_family = AF_INET6,
|
|
||||||
.sin6_port = htons(port),
|
|
||||||
0, IN6ADDR_ANY_INIT, 0,
|
|
||||||
};
|
|
||||||
const struct sockaddr *sa;
|
|
||||||
bool dual_stack = false;
|
|
||||||
int fd, sl, y = 1, ret;
|
|
||||||
struct epoll_event ev;
|
struct epoll_event ev;
|
||||||
|
int fd, y = 1, ret;
|
||||||
|
|
||||||
switch (proto) {
|
switch (proto) {
|
||||||
case IPPROTO_TCP:
|
case IPPROTO_TCP:
|
||||||
|
@ -79,13 +68,6 @@ int sock_l4(const struct ctx *c, sa_family_t af, uint8_t proto,
|
||||||
return -EPFNOSUPPORT; /* Not implemented. */
|
return -EPFNOSUPPORT; /* Not implemented. */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (af == AF_UNSPEC) {
|
|
||||||
if (!DUAL_STACK_SOCKETS || bind_addr)
|
|
||||||
return -EINVAL;
|
|
||||||
dual_stack = true;
|
|
||||||
af = AF_INET6;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (proto == IPPROTO_TCP)
|
if (proto == IPPROTO_TCP)
|
||||||
fd = socket(af, SOCK_STREAM | SOCK_NONBLOCK, proto);
|
fd = socket(af, SOCK_STREAM | SOCK_NONBLOCK, proto);
|
||||||
else
|
else
|
||||||
|
@ -104,30 +86,9 @@ int sock_l4(const struct ctx *c, sa_family_t af, uint8_t proto,
|
||||||
|
|
||||||
ref.fd = fd;
|
ref.fd = fd;
|
||||||
|
|
||||||
if (af == AF_INET) {
|
if (v6only)
|
||||||
if (bind_addr)
|
if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &y, sizeof(y)))
|
||||||
addr4.sin_addr = *(struct in_addr *)bind_addr;
|
debug("Failed to set IPV6_V6ONLY on socket %i", fd);
|
||||||
|
|
||||||
sa = (const struct sockaddr *)&addr4;
|
|
||||||
sl = sizeof(addr4);
|
|
||||||
} else {
|
|
||||||
if (bind_addr) {
|
|
||||||
addr6.sin6_addr = *(struct in6_addr *)bind_addr;
|
|
||||||
|
|
||||||
if (!memcmp(bind_addr, &c->ip6.addr_ll,
|
|
||||||
sizeof(c->ip6.addr_ll)))
|
|
||||||
addr6.sin6_scope_id = c->ifi6;
|
|
||||||
}
|
|
||||||
|
|
||||||
sa = (const struct sockaddr *)&addr6;
|
|
||||||
sl = sizeof(addr6);
|
|
||||||
|
|
||||||
if (!dual_stack)
|
|
||||||
if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY,
|
|
||||||
&y, sizeof(y)))
|
|
||||||
debug("Failed to set IPV6_V6ONLY on socket %i",
|
|
||||||
fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &y, sizeof(y)))
|
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &y, sizeof(y)))
|
||||||
debug("Failed to set SO_REUSEADDR on socket %i", fd);
|
debug("Failed to set SO_REUSEADDR on socket %i", fd);
|
||||||
|
@ -140,9 +101,12 @@ int sock_l4(const struct ctx *c, sa_family_t af, uint8_t proto,
|
||||||
*/
|
*/
|
||||||
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
|
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
|
||||||
ifname, strlen(ifname))) {
|
ifname, strlen(ifname))) {
|
||||||
|
char str[SOCKADDR_STRLEN];
|
||||||
|
|
||||||
ret = -errno;
|
ret = -errno;
|
||||||
warn("Can't bind %s socket for port %u to %s, closing",
|
warn("Can't bind %s socket for %s to %s, closing",
|
||||||
EPOLL_TYPE_STR(proto), port, ifname);
|
EPOLL_TYPE_STR(proto),
|
||||||
|
sockaddr_ntop(sa, str, sizeof(str)), ifname);
|
||||||
close(fd);
|
close(fd);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -178,6 +142,59 @@ int sock_l4(const struct ctx *c, sa_family_t af, uint8_t proto,
|
||||||
|
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* sock_l4() - Create and bind socket for given L4, add to epoll list
|
||||||
|
* @c: Execution context
|
||||||
|
* @af: Address family, AF_INET or AF_INET6
|
||||||
|
* @proto: Protocol number
|
||||||
|
* @bind_addr: Address for binding, NULL for any
|
||||||
|
* @ifname: Interface for binding, NULL for any
|
||||||
|
* @port: Port, host order
|
||||||
|
* @data: epoll reference portion for protocol handlers
|
||||||
|
*
|
||||||
|
* Return: newly created socket, negative error code on failure
|
||||||
|
*/
|
||||||
|
int sock_l4(const struct ctx *c, sa_family_t af, uint8_t proto,
|
||||||
|
const void *bind_addr, const char *ifname, uint16_t port,
|
||||||
|
uint32_t data)
|
||||||
|
{
|
||||||
|
switch (af) {
|
||||||
|
case AF_INET: {
|
||||||
|
struct sockaddr_in addr4 = {
|
||||||
|
.sin_family = AF_INET,
|
||||||
|
.sin_port = htons(port),
|
||||||
|
{ 0 }, { 0 },
|
||||||
|
};
|
||||||
|
if (bind_addr)
|
||||||
|
addr4.sin_addr = *(struct in_addr *)bind_addr;
|
||||||
|
return sock_l4_sa(c, proto, &addr4, sizeof(addr4), ifname,
|
||||||
|
false, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
case AF_UNSPEC:
|
||||||
|
if (!DUAL_STACK_SOCKETS || bind_addr)
|
||||||
|
return -EINVAL;
|
||||||
|
/* fallthrough */
|
||||||
|
case AF_INET6: {
|
||||||
|
struct sockaddr_in6 addr6 = {
|
||||||
|
.sin6_family = AF_INET6,
|
||||||
|
.sin6_port = htons(port),
|
||||||
|
0, IN6ADDR_ANY_INIT, 0,
|
||||||
|
};
|
||||||
|
if (bind_addr) {
|
||||||
|
addr6.sin6_addr = *(struct in6_addr *)bind_addr;
|
||||||
|
|
||||||
|
if (!memcmp(bind_addr, &c->ip6.addr_ll,
|
||||||
|
sizeof(c->ip6.addr_ll)))
|
||||||
|
addr6.sin6_scope_id = c->ifi6;
|
||||||
|
}
|
||||||
|
return sock_l4_sa(c, proto, &addr6, sizeof(addr6), ifname,
|
||||||
|
af == AF_INET6, data);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sock_probe_mem() - Check if setting high SO_SNDBUF and SO_RCVBUF is allowed
|
* sock_probe_mem() - Check if setting high SO_SNDBUF and SO_RCVBUF is allowed
|
||||||
|
|
Loading…
Reference in a new issue