sockets: use new iovec interface

This commit is contained in:
Matheus
2024-09-21 10:53:49 -03:00
parent 3868b667cb
commit fb2fa68752
10 changed files with 89 additions and 87 deletions
+2 -28
View File
@@ -26,38 +26,12 @@ int sockfs_close(vnode_t *node, int flags, cred_t *cred) {
int sockfs_read(vnode_t *node, void *buffer, size_t size, uintmax_t offset, int flags, size_t *readc, cred_t *cred) {
socket_t *socket = SOCKFS_SOCKET_FROM_NODE(node);
sockdesc_t desc = {
.addr = NULL,
.buffer = buffer,
.count = size,
.flags = flags,
.donecount = 0,
.ctrl = NULL,
.ctrllen = 0
};
int e = socket->ops->recv(socket, &desc);
*readc = desc.donecount;
return e;
return socket_read(socket, buffer, size, flags, readc);
}
int sockfs_write(vnode_t *node, void *buffer, size_t size, uintmax_t offset, int flags, size_t *writec, cred_t *cred) {
socket_t *socket = SOCKFS_SOCKET_FROM_NODE(node);
sockdesc_t desc = {
.addr = NULL,
.buffer = buffer,
.count = size,
.flags = flags,
.donecount = 0,
.ctrl = NULL,
.ctrllen = 0
};
int e = socket->ops->send(socket, &desc);
*writec = desc.donecount;
return e;
return socket_write(socket, buffer, size, flags, writec);
}
int sockfs_poll(vnode_t *node, polldata_t *data, int events) {
+2 -2
View File
@@ -47,12 +47,12 @@ int iovec_iterator_copy_from_buffer(iovec_iterator_t *iovec_iterator, void *buff
// copies byte_count bytes from the iovec_iterator into the ringbuffer
// returns the number of bytes copied
// NOTE: the iovec can have userspace addresses. in this case, the copy can possibly fail by returning RINGBUFFER_USER_COPY_FAILED
size_t iovec_iterator_copy_to_ringbuffer(iovec_iterator_t *iovec_iterator, ringbuffer_t *ringbuffer, size_t byte_count);
size_t iovec_iterator_write_to_ringbuffer(iovec_iterator_t *iovec_iterator, ringbuffer_t *ringbuffer, size_t byte_count);
// copies byte_count bytes from the ringbuffer into the iovec_iterator
// returns the number of bytes copied
// NOTE: the iovec can have userspace addresses. in this case, the copy can possibly fail with RINGBUFFER_USER_COPY_FAILED
size_t iovec_iterator_copy_from_ringbuffer(iovec_iterator_t *iovec_iterator, ringbuffer_t *ringbuffer, size_t byte_count);
size_t iovec_iterator_read_from_ringbuffer(iovec_iterator_t *iovec_iterator, ringbuffer_t *ringbuffer, size_t byte_count);
// copies byte_count bytes from the ringbuffer into the iovec_iterator, without moving the ringbuffer read pointer
// returns the number of bytes copied
+1 -1
View File
@@ -78,7 +78,7 @@ void udp_process(netdev_t *netdev, void *buffer, uint32_t ip);
void arp_process(netdev_t *netdev, void *buffer);
void tcp_process(netdev_t *netdev, void *buffer, ipv4frame_t *ipv4frame);
int arp_lookup(netdev_t *netdev, uint32_t ip, mac_t *mac);
int udp_sendpacket(void *buffer, size_t packetsize, uint32_t ip, uint16_t srcport, uint16_t dstport, netdev_t *broadcastdev);
int udp_sendpacket(iovec_iterator_t *iovec_iterator, size_t packetsize, uint32_t ip, uint16_t srcport, uint16_t dstport, netdev_t *broadcastdev);
int ipv4_sendpacket(void *buffer, size_t packetsize, uint32_t ip, int proto, netdev_t *broadcastdev);
size_t ipv4_getmtu(uint32_t ip);
uint32_t ipv4_getnetdevip(uint32_t ip);
+48 -1
View File
@@ -39,7 +39,7 @@ typedef struct {
typedef struct {
sockaddr_t *addr;
void *buffer;
iovec_iterator_t iovec_iterator;
size_t count;
uintmax_t flags;
size_t donecount;
@@ -79,6 +79,53 @@ typedef struct {
#define SOCKET_TYPE_TCP 2
#define SOCKFS_SOCKET_FROM_NODE(nodep) (((socketnode_t *)(nodep))->socket)
static inline int socket_read(socket_t *socket, void *buffer, size_t size, uintmax_t flags, size_t *bytes_read) {
sockdesc_t desc = {
.addr = NULL,
.count = size,
.flags = flags,
.donecount = 0,
.ctrl = NULL,
.ctrllen = 0
};
iovec_t iovec = {
.addr = buffer,
.len = size
};
iovec_iterator_init(&desc.iovec_iterator, &iovec, 1);
int e = socket->ops->recv(socket, &desc);
*bytes_read = desc.donecount;
return e;
}
static inline int socket_write(socket_t *socket, void *buffer, size_t size, uintmax_t flags, size_t *bytes_written) {
sockdesc_t desc = {
.addr = NULL,
.count = size,
.flags = flags,
.donecount = 0,
.ctrl = NULL,
.ctrllen = 0
};
iovec_t iovec = {
.addr = buffer,
.len = size
};
iovec_iterator_init(&desc.iovec_iterator, &iovec, 1);
int e = socket->ops->send(socket, &desc);
*bytes_written = desc.donecount;
return e;
}
static inline int sock_convertaddress(sockaddr_t *sockaddr, abisockaddr_t *abisockaddr) {
switch (abisockaddr->type) {
case AF_INET:
+7 -5
View File
@@ -119,7 +119,7 @@ int iovec_iterator_copy_from_buffer(iovec_iterator_t *iovec_iterator, void *buff
return error;
}
size_t iovec_iterator_copy_to_ringbuffer(iovec_iterator_t *iovec_iterator, ringbuffer_t *ringbuffer, size_t byte_count) {
size_t iovec_iterator_write_to_ringbuffer(iovec_iterator_t *iovec_iterator, ringbuffer_t *ringbuffer, size_t byte_count) {
size_t iterator_offset_save = iovec_iterator->total_offset;
size_t remaining_total = min(byte_count, iovec_iterator->total_size - iovec_iterator->total_offset);
size_t total_done = 0;
@@ -140,6 +140,7 @@ size_t iovec_iterator_copy_to_ringbuffer(iovec_iterator_t *iovec_iterator, ringb
break;
iovec_iterator_skip(iovec_iterator, copy_current);
remaining_total -= current_done;
total_done += current_done;
if (total_done == byte_count || iovec_iterator_finished(iovec_iterator))
@@ -154,7 +155,7 @@ size_t iovec_iterator_copy_to_ringbuffer(iovec_iterator_t *iovec_iterator, ringb
return total_done;
}
size_t iovec_iterator_peek_from_ringbuffer(iovec_iterator_t *iovec_iterator, ringbuffer_t *ringbuffer, size_t byte_count, uintmax_t ringbuffer_offset) {
size_t iovec_iterator_peek_from_ringbuffer(iovec_iterator_t *iovec_iterator, ringbuffer_t *ringbuffer, size_t offset, size_t byte_count) {
size_t iterator_offset_save = iovec_iterator->total_offset;
size_t remaining_total = min(byte_count, iovec_iterator->total_size - iovec_iterator->total_offset);
size_t total_done = 0;
@@ -164,12 +165,13 @@ size_t iovec_iterator_peek_from_ringbuffer(iovec_iterator_t *iovec_iterator, rin
size_t remaining_current = iovec_iterator->current->len - iovec_iterator->current_offset;
size_t copy_current = min(remaining_current, remaining_total);
current_done = ringbuffer_peek(ringbuffer, (void *)((uintptr_t)iovec_iterator->current->addr + iovec_iterator->current_offset), total_done, copy_current);
current_done = ringbuffer_peek(ringbuffer, (void *)((uintptr_t)iovec_iterator->current->addr + iovec_iterator->current_offset), offset + total_done, copy_current);
if (current_done == 0 || current_done == RINGBUFFER_USER_COPY_FAILED)
break;
iovec_iterator_skip(iovec_iterator, copy_current);
total_done += current_done;
remaining_total -= current_done;
if (total_done == byte_count || iovec_iterator_finished(iovec_iterator))
break;
@@ -183,8 +185,8 @@ size_t iovec_iterator_peek_from_ringbuffer(iovec_iterator_t *iovec_iterator, rin
return total_done;
}
size_t iovec_iterator_copy_from_ringbuffer(iovec_iterator_t *iovec_iterator, ringbuffer_t *ringbuffer, size_t byte_count) {
size_t done = iovec_iterator_peek_from_ringbuffer(iovec_iterator, ringbuffer, byte_count, 0);
size_t iovec_iterator_read_from_ringbuffer(iovec_iterator_t *iovec_iterator, ringbuffer_t *ringbuffer, size_t byte_count) {
size_t done = iovec_iterator_peek_from_ringbuffer(iovec_iterator, ringbuffer, 0, byte_count);
if (done == RINGBUFFER_USER_COPY_FAILED)
return done;
+3 -3
View File
@@ -363,7 +363,7 @@ static int localsock_send(socket_t *socket, sockdesc_t *sockdesc) {
goto leave;
}
sockdesc->donecount = ringbuffer_write(&peer->ringbuffer, sockdesc->buffer, sockdesc->count);
sockdesc->donecount = iovec_iterator_write_to_ringbuffer(&sockdesc->iovec_iterator, &peer->ringbuffer, sockdesc->count);
if (sockdesc->donecount == RINGBUFFER_USER_COPY_FAILED) {
error = EFAULT;
goto leave;
@@ -467,13 +467,13 @@ static int localsock_recv(socket_t *socket, sockdesc_t *sockdesc) {
}
if (flags & SOCKET_RECV_FLAGS_PEEK) {
sockdesc->donecount = ringbuffer_peek(&localsocket->ringbuffer, sockdesc->buffer, 0, recvcount);
sockdesc->donecount = iovec_iterator_peek_from_ringbuffer(&sockdesc->iovec_iterator, &localsocket->ringbuffer, 0, recvcount);
if (sockdesc->donecount == RINGBUFFER_USER_COPY_FAILED) {
error = EFAULT;
goto leave;
}
} else {
sockdesc->donecount = ringbuffer_read(&localsocket->ringbuffer, sockdesc->buffer, recvcount);
sockdesc->donecount = iovec_iterator_read_from_ringbuffer(&sockdesc->iovec_iterator, &localsocket->ringbuffer, recvcount);
if (sockdesc->donecount == RINGBUFFER_USER_COPY_FAILED) {
error = EPIPE;
goto leave;
+3 -3
View File
@@ -1305,7 +1305,7 @@ static int tcp_send(socket_t *socket, sockdesc_t *sockdesc) {
size_t writesize = min(TCB_RINGBUFFER_SIZE - RINGBUFFER_DATACOUNT(&tcb->transmitbuffer), sockdesc->count);
__assert(writesize);
sockdesc->donecount = ringbuffer_write(&tcb->transmitbuffer, sockdesc->buffer, writesize);
sockdesc->donecount = iovec_iterator_write_to_ringbuffer(&sockdesc->iovec_iterator, &tcb->transmitbuffer, writesize);
if (sockdesc->donecount == RINGBUFFER_USER_COPY_FAILED) {
error = EFAULT;
goto leave;
@@ -1386,13 +1386,13 @@ static int tcp_recv(socket_t *socket, sockdesc_t *sockdesc) {
size_t copycount = min(RINGBUFFER_DATACOUNT(&tcb->receivebuffer), sockdesc->count);
if (flags & SOCKET_RECV_FLAGS_PEEK) {
sockdesc->donecount = ringbuffer_peek(&tcb->receivebuffer, sockdesc->buffer, 0, copycount);
sockdesc->donecount = iovec_iterator_peek_from_ringbuffer(&sockdesc->iovec_iterator, &tcb->receivebuffer, 0, copycount);
if (sockdesc->donecount == RINGBUFFER_USER_COPY_FAILED) {
error = EFAULT;
goto cleanup;
}
} else {
sockdesc->donecount = ringbuffer_read(&tcb->receivebuffer, sockdesc->buffer, copycount);
sockdesc->donecount = iovec_iterator_read_from_ringbuffer(&sockdesc->iovec_iterator, &tcb->receivebuffer, copycount);
if (sockdesc->donecount == RINGBUFFER_USER_COPY_FAILED) {
error = EFAULT;
goto cleanup;
+11 -10
View File
@@ -32,7 +32,7 @@ typedef struct {
static socket_t *ports[65536];
static spinlock_t portlock;
int udp_sendpacket(void *buffer, size_t size, uint32_t ip, uint16_t srcport, uint16_t dstport, netdev_t *broadcastnetdev) {
int udp_sendpacket(iovec_iterator_t *iovec_iterator, size_t size, uint32_t ip, uint16_t srcport, uint16_t dstport, netdev_t *broadcastnetdev) {
void *newbuff = alloc(size + sizeof(udpframe_t));
if (newbuff == NULL)
return ENOMEM;
@@ -45,7 +45,7 @@ int udp_sendpacket(void *buffer, size_t size, uint32_t ip, uint16_t srcport, uin
};
memcpy(newbuff, &frame, sizeof(udpframe_t));
int error = USERCOPY_POSSIBLY_FROM_USER((void *)((uintptr_t)newbuff + sizeof(udpframe_t)), buffer, size);
int error = iovec_iterator_copy_to_buffer(iovec_iterator, (void *)((uintptr_t)newbuff + sizeof(udpframe_t)), size);
if (error)
goto leave;
@@ -203,7 +203,7 @@ static int udp_send(socket_t *socket, sockdesc_t *sockdesc) {
socket->state = SOCKET_STATE_BOUND;
}
e = udp_sendpacket(sockdesc->buffer, sockdesc->count, sockdesc->addr ? sockdesc->addr->ipv4addr.addr : udpsocket->peeraddress,
e = udp_sendpacket(&sockdesc->iovec_iterator, sockdesc->count, sockdesc->addr ? sockdesc->addr->ipv4addr.addr : udpsocket->peeraddress,
udpsocket->port, sockdesc->addr ? sockdesc->addr->ipv4addr.port : udpsocket->peerport, udpsocket->socket.netdev);
sockdesc->donecount = sockdesc->count;
@@ -261,16 +261,20 @@ static int udp_recv(socket_t *socket, sockdesc_t *sockdesc) {
// this abuses an asterisk on the ringbuffer implementation that makes it not need locking when
// something is reading and something is writing simultaneously.
// this is done to not need to disable interrupts as the ringbuffer_peek could take a fault
// this is done to not need to disable interrupts as the iovec_peek_from_ringbuffer could take a fault
// multiple readers cannot happen because of the socket mutex and the write on the side of the
// NIC is protected by the ringbuffer lock
// NIC is protected by the ringbuffer lock. The ringbuffer lock is taken when reading the desc to ensure that
// the whole packet has reached the ringbuffer
size_t copycount;
dataheader_t header;
long ipl = spinlock_acquireraiseipl(&udpsocket->ringbufferlock, IPL_DPC);
__assert(ringbuffer_peek(&udpsocket->ringbuffer, &header, 0, sizeof(header)) == sizeof(header));
spinlock_releaseloweripl(&udpsocket->ringbufferlock, ipl);
copycount = min(header.length, sockdesc->count);
sockdesc->donecount = ringbuffer_peek(&udpsocket->ringbuffer, sockdesc->buffer, sizeof(header), copycount);
sockdesc->donecount = iovec_iterator_peek_from_ringbuffer(&sockdesc->iovec_iterator, &udpsocket->ringbuffer, sizeof(header), copycount);
if (sockdesc->donecount == RINGBUFFER_USER_COPY_FAILED) {
e = EFAULT;
goto cleanup;
@@ -279,11 +283,8 @@ static int udp_recv(socket_t *socket, sockdesc_t *sockdesc) {
__assert(sockdesc->donecount == copycount);
// remove the message if not asked to peek
if ((flags & SOCKET_RECV_FLAGS_PEEK) == 0) {
bool status = spinlock_acquireirqclear(&udpsocket->ringbufferlock);
if ((flags & SOCKET_RECV_FLAGS_PEEK) == 0)
ringbuffer_truncate(&udpsocket->ringbuffer, sizeof(header) + header.length);
spinlock_releaseirqrestore(&udpsocket->ringbufferlock, status);
}
sockdesc->donecount = copycount;
sockdesc->addr->ipv4addr.addr = header.peer;
+6 -16
View File
@@ -28,10 +28,10 @@ syscallret_t syscall_recvmsg(context_t *, int fd, msghdr_t *umsghdr, int flags)
return ret;
}
void *buffer = vmm_map(NULL, buffersize, VMM_FLAGS_ALLOCATE, ARCH_MMU_FLAGS_READ | ARCH_MMU_FLAGS_WRITE | ARCH_MMU_FLAGS_NOEXEC, NULL);
if (buffer == NULL) {
ret.errno = ENOMEM;
goto cleanup;
if (iovec_user_check(msghdr.iov, msghdr.iovcount) == false) {
ret.errno = EFAULT;
sock_freemsghdr(&msghdr);
return ret;
}
file = fd_get(fd);
@@ -57,7 +57,6 @@ syscallret_t syscall_recvmsg(context_t *, int fd, msghdr_t *umsghdr, int flags)
sockdesc_t desc = {
.addr = &sockaddr,
.buffer = buffer,
.count = buffersize,
.flags = fileflagstovnodeflags(file->flags) | recvflags,
.donecount = 0,
@@ -66,18 +65,12 @@ syscallret_t syscall_recvmsg(context_t *, int fd, msghdr_t *umsghdr, int flags)
.ctrldone = 0
};
iovec_iterator_init(&desc.iovec_iterator, msghdr.iov, msghdr.iovcount);
ret.errno = socket->ops->recv(socket, &desc);
if (ret.errno)
goto cleanup;
uintmax_t iovoffset = 0;
for (int i = 0; i < msghdr.iovcount; ++i) {
ret.errno = usercopy_touser(msghdr.iov[i].addr, (void *)((uintptr_t)buffer + iovoffset), msghdr.iov[i].len);
if (ret.errno)
goto cleanup;
iovoffset += msghdr.iov[i].len;
}
if (msghdr.addr) {
abisockaddr_t abisockaddr;
ret.errno = sock_addrtoabiaddr(socket->type, &sockaddr, &abisockaddr);
@@ -120,9 +113,6 @@ syscallret_t syscall_recvmsg(context_t *, int fd, msghdr_t *umsghdr, int flags)
if (file)
fd_release(file);
if (buffer)
vmm_unmap(buffer, buffersize, 0);
sock_freemsghdr(&msghdr);
return ret;
}
+6 -18
View File
@@ -23,20 +23,10 @@ syscallret_t syscall_sendmsg(context_t *, int fd, msghdr_t *umsghdr, int flags)
return ret;
}
void *buffer = vmm_map(NULL, buffersize, VMM_FLAGS_ALLOCATE, ARCH_MMU_FLAGS_READ | ARCH_MMU_FLAGS_WRITE | ARCH_MMU_FLAGS_NOEXEC, NULL);
if (buffer == NULL) {
ret.errno = ENOMEM;
goto cleanup;
}
uintmax_t iovoffset = 0;
for (int i = 0; i < msghdr.iovcount; ++i) {
ret.errno = usercopy_fromuser((void *)((uintptr_t)buffer + iovoffset), msghdr.iov[i].addr, msghdr.iov[i].len);
if (ret.errno)
goto cleanup;
iovoffset += msghdr.iov[i].len;
if (iovec_user_check(msghdr.iov, msghdr.iovcount) == false) {
ret.errno = EFAULT;
sock_freemsghdr(&msghdr);
return ret;
}
file = fd_get(fd);
@@ -61,7 +51,6 @@ syscallret_t syscall_sendmsg(context_t *, int fd, msghdr_t *umsghdr, int flags)
sockdesc_t desc = {
.addr = msghdr.addr ? &sockaddr : NULL,
.buffer = buffer,
.count = buffersize,
.flags = fileflagstovnodeflags(file->flags) | ((flags & MSG_NOSIGNAL) ? SOCKET_SEND_FLAGS_NOSIGNAL : 0),
.donecount = 0,
@@ -70,6 +59,8 @@ syscallret_t syscall_sendmsg(context_t *, int fd, msghdr_t *umsghdr, int flags)
.ctrldone = 0
};
iovec_iterator_init(&desc.iovec_iterator, msghdr.iov, msghdr.iovcount);
ret.errno = socket->ops->send(socket, &desc);
ret.ret = ret.errno ? -1 : desc.donecount;
@@ -77,9 +68,6 @@ syscallret_t syscall_sendmsg(context_t *, int fd, msghdr_t *umsghdr, int flags)
if (file)
fd_release(file);
if (buffer)
vmm_unmap(buffer, buffersize, 0);
sock_freemsghdr(&msghdr);
return ret;
}