ipv6 support, UNTESTED, super hacky

This commit is contained in:
Josh Bleecher Snyder
2021-06-04 15:15:36 -07:00
parent 36a4741bc5
commit 75efd794a3
2 changed files with 45 additions and 33 deletions

View File

@@ -39,12 +39,13 @@ struct req {
struct msghdr hdr;
struct iovec iov;
struct sockaddr_in sa;
struct sockaddr_in6 sa6;
char *buf;
};
typedef struct req goreq;
static struct req *initializeReq(size_t sz) {
static struct req *initializeReq(size_t sz, int ipVersion) {
struct req *r = malloc(sizeof(struct req));
memset(r, 0, sizeof(*r));
r->buf = malloc(sz);
@@ -53,8 +54,16 @@ static struct req *initializeReq(size_t sz) {
r->iov.iov_len = sz;
r->hdr.msg_iov = &r->iov;
r->hdr.msg_iovlen = 1;
r->hdr.msg_name = &r->sa;
r->hdr.msg_namelen = sizeof(r->sa);
switch(ipVersion) {
case 4:
r->hdr.msg_name = &r->sa;
r->hdr.msg_namelen = sizeof(r->sa);
break;
case 6:
r->hdr.msg_name = &r->sa6;
r->hdr.msg_namelen = sizeof(r->sa6);
break;
}
return r;
}
@@ -70,22 +79,6 @@ static uint64_t packNIdx(int n, size_t idx) {
return (n64 << 32) | idx64;
}
static uint32_t ip(struct req *r) {
return ntohl(r->sa.sin_addr.s_addr);
}
static uint16_t port(struct req *r) {
return ntohs(r->sa.sin_port);
}
static uint32_t setIP(struct sockaddr_in *sa, uint32_t ip) {
sa->sin_addr.s_addr = htonl(ip);
}
static uint16_t setPort(struct sockaddr_in *sa, uint16_t port) {
sa->sin_port = htons(port);
}
// submit a recvmsg request via liburing
// TODO: What recvfrom support arrives, maybe use that instead?
static int submit_recvmsg_request(struct io_uring *ring, struct req *r, size_t idx) {

View File

@@ -45,6 +45,7 @@ type UDPConn struct {
recvReqs [8]*C.goreq
sendReqs [8]*C.goreq
sendReqC chan int // indices into sendReqs
is4 bool
}
func NewUDPConn(conn *net.UDPConn) (*UDPConn, error) {
@@ -54,8 +55,9 @@ func NewUDPConn(conn *net.UDPConn) (*UDPConn, error) {
if err != nil {
return nil, fmt.Errorf("failed to parse UDPConn local addr %s as IP: %w", local, err)
}
if !ip.IP().Is4() {
return nil, fmt.Errorf("uring only supports udp4 (for now), got local addr %s", local)
ipVersion := 6
if ip.IP().Is4() {
ipVersion = 4
}
// TODO: probe for system capabilities: https://unixism.net/loti/tutorial/probe_liburing.html
file, err := conn.File()
@@ -80,12 +82,13 @@ func NewUDPConn(conn *net.UDPConn) (*UDPConn, error) {
file: file,
fd: fd,
local: conn.LocalAddr(),
is4: ipVersion == 4,
}
// Initialize buffers
for _, reqs := range []*[8]*C.goreq{&u.recvReqs, &u.sendReqs} {
for i := range reqs {
reqs[i] = C.initializeReq(bufferSize)
reqs[i] = C.initializeReq(bufferSize, C.int(ipVersion))
}
}
@@ -134,11 +137,20 @@ func (u *UDPConn) ReadFromNetaddr(buf []byte) (int, netaddr.IPPort, error) {
return 0, netaddr.IPPort{}, fmt.Errorf("ReadFromNetaddr: %v", err)
}
r := u.recvReqs[idx]
ip := C.ip(r)
var ip4 [4]byte
binary.BigEndian.PutUint32(ip4[:], uint32(ip))
port := C.port(r)
ipp := netaddr.IPPortFrom(netaddr.IPFrom4(ip4), uint16(port))
var ip netaddr.IP
var port uint16
if u.is4 {
// TODO: native go endianness conversion routines so we don't have to call ntohl, etc.
var arr [4]byte
binary.BigEndian.PutUint32(arr[:], uint32(C.ntohl(r.sa.sin_addr.s_addr)))
ip = netaddr.IPFrom4(arr)
port = uint16(C.ntohs(r.sa.sin_port))
} else {
ip = netaddr.IPFrom16(*(*[16]byte)((unsafe.Pointer)((&r.sa6.sin6_addr))))
port = uint16(C.ntohs(r.sa6.sin6_port))
}
ipp := netaddr.IPPortFrom(ip, port)
rbuf := sliceOf(r.buf, n)
copy(buf, rbuf)
// Queue up a new request.
@@ -226,10 +238,17 @@ func (u *UDPConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
rbuf := sliceOf(r.buf, len(p))
copy(rbuf, p)
ip := binary.BigEndian.Uint32(udpAddr.IP)
C.setIP(&r.sa, C.uint32_t(ip))
C.setPort(&r.sa, C.uint16_t(udpAddr.Port))
if u.is4 {
// TODO: native go endianness conversion routines so we don't have to call ntohl, etc.
ipu32 := binary.BigEndian.Uint32(udpAddr.IP)
r.sa.sin_addr.s_addr = C.htonl(C.uint32_t(ipu32))
r.sa.sin_port = C.htons(C.uint16_t(udpAddr.Port))
} else {
dst := (*[16]byte)((unsafe.Pointer)(&r.sa6.sin6_addr))
src := (*[16]byte)((unsafe.Pointer)(&udpAddr.IP[0]))
*dst = *src
r.sa6.sin6_port = C.htons(C.uint16_t(udpAddr.Port))
}
C.submit_sendmsg_request(
u.sendRing, // ring
r,
@@ -300,10 +319,10 @@ func NewFile(file *os.File) (*File, error) {
// Initialize buffers
for i := range &u.readReqs {
u.readReqs[i] = C.initializeReq(bufferSize)
u.readReqs[i] = C.initializeReq(bufferSize, 0)
}
for i := range &u.writeReqs {
u.writeReqs[i] = C.initializeReq(bufferSize)
u.writeReqs[i] = C.initializeReq(bufferSize, 0)
}
// Initialize read half.