mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-10-28 05:08:22 +00:00
sockets: initial impl
This commit is contained in:
@@ -35,7 +35,12 @@ extern syscall_openat
|
||||
extern syscall_chroot
|
||||
extern syscall_mkdirat
|
||||
extern syscall_clock_gettime
|
||||
func_count equ 34
|
||||
extern syscall_socket
|
||||
extern syscall_bind
|
||||
extern syscall_listen
|
||||
extern syscall_connect
|
||||
extern syscall_accept
|
||||
func_count equ 39
|
||||
|
||||
|
||||
func_table:
|
||||
@@ -73,6 +78,11 @@ func_table:
|
||||
dq syscall_chroot
|
||||
dq syscall_mkdirat
|
||||
dq syscall_clock_gettime
|
||||
dq syscall_socket
|
||||
dq syscall_bind
|
||||
dq syscall_listen
|
||||
dq syscall_connect
|
||||
dq syscall_accept
|
||||
section .text
|
||||
global asm_syscall_entry
|
||||
|
||||
|
||||
+22
-1
@@ -161,8 +161,29 @@ static int tmpfs_chmod(vnode_t* node, mode_t mode){
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tmpfs_mksocket(dirnode_t* parent, char* name, mode_t mode){
|
||||
|
||||
vnode_t* node = vfs_newnode(name, parent->vnode.fs, NULL);
|
||||
|
||||
if(!node)
|
||||
return ENOMEM;
|
||||
|
||||
if(!hashtable_insert(&parent->children, name, node)){
|
||||
vfs_destroynode(node);
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
stat* st = &node->st;
|
||||
|
||||
st->st_mode = MAKETYPE(TYPE_SOCKET) | mode;
|
||||
st->st_blksize = PAGE_SIZE;
|
||||
st->st_ino = parent->vnode.fs->data++;
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
static fscalls_t funcs = {
|
||||
tmpfs_mount, tmpfs_unmount, tmpfs_open, tmpfs_close, tmpfs_mkdir, tmpfs_create, tmpfs_write, tmpfs_read, tmpfs_getdirent, tmpfs_chmod
|
||||
tmpfs_mount, tmpfs_unmount, tmpfs_open, tmpfs_close, tmpfs_mkdir, tmpfs_create, tmpfs_write, tmpfs_read, tmpfs_getdirent, tmpfs_chmod, tmpfs_mksocket
|
||||
};
|
||||
|
||||
|
||||
|
||||
+37
-2
@@ -206,6 +206,7 @@ int vfs_getdirent(dirnode_t* node, dent_t* buff, size_t count, uintmax_t offset,
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
int vfs_open(vnode_t** buff, dirnode_t* ref, char* path){
|
||||
|
||||
vnode_t* node;
|
||||
@@ -258,8 +259,43 @@ int vfs_create(dirnode_t* ref, char* path, mode_t mode){
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vfs_mkdir(dirnode_t* ref, char* path, mode_t mode){
|
||||
int vfs_mksocket(dirnode_t* ref, char* path, mode_t mode){
|
||||
|
||||
dirnode_t* parent = NULL;
|
||||
dirnode_t* buff = NULL;
|
||||
|
||||
char name[512];
|
||||
|
||||
spinlock_acquire(&lock);
|
||||
|
||||
int result = vfs_resolvepath(&buff, &parent, ref, path, name);
|
||||
|
||||
if(buff){
|
||||
spinlock_release(&lock);
|
||||
return EEXIST;
|
||||
}
|
||||
|
||||
if(!parent){
|
||||
spinlock_release(&lock);
|
||||
return result;
|
||||
}
|
||||
|
||||
if(!parent->vnode.fs->calls->mksocket){
|
||||
spinlock_release(&lock);
|
||||
return ENOSYS;
|
||||
}
|
||||
|
||||
result = parent->vnode.fs->calls->mksocket(parent, name, mode);
|
||||
|
||||
spinlock_release(&lock);
|
||||
|
||||
if(result) return result;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vfs_mkdir(dirnode_t* ref, char* path, mode_t mode){
|
||||
|
||||
dirnode_t* parent = NULL;
|
||||
dirnode_t* buff = NULL;
|
||||
|
||||
@@ -279,7 +315,6 @@ int vfs_mkdir(dirnode_t* ref, char* path, mode_t mode){
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
result = parent->vnode.fs->calls->mkdir(parent, name, mode);
|
||||
|
||||
spinlock_release(&lock);
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
#ifndef _SOCKET_H_INCLUDE
|
||||
#define _SOCKET_H_INCLUDE
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <kernel/event.h>
|
||||
#include <kernel/unsocket.h>
|
||||
#include <ringbuffer.h>
|
||||
|
||||
#define SOCKET_STATE_UNBOUND 0
|
||||
#define SOCKET_STATE_BOUND 1
|
||||
#define SOCKET_STATE_LISTENING 2
|
||||
#define SOCKET_STATE_CONNECTED 3
|
||||
|
||||
#define SOCK_STREAM 1
|
||||
#define AF_UNIX 1
|
||||
|
||||
typedef struct _socket_t{
|
||||
int lock;
|
||||
int family;
|
||||
int type;
|
||||
int protocol;
|
||||
struct _socket_t* peer;
|
||||
size_t backlogsize;
|
||||
off_t backlogend;
|
||||
struct _socket_t** backlog;
|
||||
event_t connectevent; // when the socket is listening and this is fired, someone used connect() on the socket
|
||||
event_t acceptevent; // when a socket is waiting for a connection to be accepted, it sleeps on this
|
||||
int state;
|
||||
union {
|
||||
sockaddr_un addr_un;
|
||||
};
|
||||
size_t addrlen;
|
||||
ringbuffer_t buffer;
|
||||
} socket_t;
|
||||
|
||||
static inline int socket_addtobacklog(socket_t* listener, socket_t* client){
|
||||
if(listener->backlogend == listener->backlogsize)
|
||||
return ECONNREFUSED;
|
||||
|
||||
listener->backlog[listener->backlogend++] = client;
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static inline socket_t* socket_popfrombacklog(socket_t* listener){
|
||||
|
||||
socket_t* sock = listener->backlog[0];
|
||||
listener->backlogend--;
|
||||
|
||||
memcpy(listener->backlog, listener->backlog+1, sizeof(socket_t*)*listener->backlogend);
|
||||
|
||||
listener->backlog[listener->backlogend];
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
int socket_connect(struct _socket_t* sock, void* addr, size_t addrlen);
|
||||
int socket_new(socket_t** returnptr, int family, int type, int protocol);
|
||||
int socket_bind(struct _socket_t* sock, void* addr, size_t addrlen);
|
||||
int socket_listen(struct _socket_t* sock, int backlog);
|
||||
int socket_accept(socket_t** peer, socket_t* sock, void* addr, size_t* addrlen);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,16 @@
|
||||
#ifndef _UNSOCKET_H_INCLUDE
|
||||
#define _UNSOCKET_H_INCLUDE
|
||||
|
||||
#include <kernel/socket.h>
|
||||
|
||||
typedef struct {
|
||||
short sun_family;
|
||||
char sun_path[108];
|
||||
} sockaddr_un;
|
||||
|
||||
struct _socket_t;
|
||||
|
||||
int unsocket_new(struct _socket_t** returnptr, int type, int protocol);
|
||||
int unsocket_bind(struct _socket_t* sock, sockaddr_un* addr, size_t addrlen);
|
||||
|
||||
#endif
|
||||
@@ -63,9 +63,11 @@ typedef struct _fscalls_t {
|
||||
int (*getdirent)(dirnode_t* node, dent_t* buff, size_t count, uintmax_t offset, size_t* readcount);
|
||||
// change file mode
|
||||
int (*chmod)(vnode_t* node, mode_t mode);
|
||||
// create socket in address
|
||||
int (*mksocket)(dirnode_t* ref, char* path, mode_t mode);
|
||||
} fscalls_t;
|
||||
|
||||
|
||||
int vfs_mksocket(dirnode_t* ref, char* path, mode_t mode);
|
||||
int vfs_mount(dirnode_t* ref, char* device, char* mountpoint, char* fs, int mountflags, void* fsinfo);
|
||||
int vfs_umount(dirnode_t* ref, char* mountpoint);
|
||||
int vfs_open(vnode_t** buf, dirnode_t* ref, char* path);
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
#include <kernel/socket.h>
|
||||
#include <kernel/unsocket.h>
|
||||
#include <errno.h>
|
||||
#include <kernel/alloc.h>
|
||||
#include <arch/spinlock.h>
|
||||
|
||||
int socket_new(struct _socket_t** returnptr, int family, int type, int protocol){
|
||||
|
||||
switch(family){
|
||||
case AF_UNIX:
|
||||
return unsocket_new(returnptr, type, protocol);
|
||||
break;
|
||||
default:
|
||||
return EAFNOSUPPORT;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// TODO move around locks and tests
|
||||
|
||||
int socket_bind(struct _socket_t* sock, void* addr, size_t addrlen){
|
||||
|
||||
if(sock->addrlen)
|
||||
return EINVAL;
|
||||
|
||||
switch(sock->family){
|
||||
case AF_UNIX:
|
||||
return unsocket_bind(sock, addr, addrlen);
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
int socket_listen(struct _socket_t* sock, int backlog){
|
||||
|
||||
// XXX check if the socket supports listening?
|
||||
|
||||
int err = 0;
|
||||
|
||||
spinlock_acquire(&sock->lock);
|
||||
|
||||
// XXX limit backlog
|
||||
|
||||
if(sock->state != SOCKET_STATE_BOUND || backlog == 0){
|
||||
err = EINVAL;
|
||||
goto _ret;
|
||||
}
|
||||
|
||||
sock->backlog = alloc(backlog*sizeof(socket_t**));
|
||||
|
||||
if(!sock->backlog){
|
||||
err = ENOMEM;
|
||||
goto _ret;
|
||||
}
|
||||
|
||||
sock->backlogsize = backlog;
|
||||
sock->state = SOCKET_STATE_LISTENING;
|
||||
|
||||
_ret:
|
||||
|
||||
spinlock_release(&sock->lock);
|
||||
|
||||
return err;
|
||||
|
||||
}
|
||||
|
||||
int socket_connect(struct _socket_t* sock, void* addr, size_t addrlen){
|
||||
|
||||
switch(sock->family){
|
||||
case AF_UNIX:
|
||||
return unsocket_connect(sock, addr, addrlen);
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int socket_accept(socket_t** peer, socket_t* sock, void* addr, size_t* addrlen){
|
||||
switch(sock->family){
|
||||
case AF_UNIX:
|
||||
return unsocket_accept(peer, sock, addr, addrlen);
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
#include <kernel/syscalls.h>
|
||||
#include <kernel/socket.h>
|
||||
#include <kernel/fd.h>
|
||||
#include <arch/cls.h>
|
||||
#include <arch/spinlock.h>
|
||||
|
||||
extern fs_t kerneltmpfs;
|
||||
|
||||
syscallret syscall_accept(int sockfd, void* addr, size_t* addrlen){
|
||||
|
||||
syscallret retv;
|
||||
retv.ret = -1;
|
||||
|
||||
if(addr > USER_SPACE_END){
|
||||
retv.errno = EFAULT;
|
||||
return retv;
|
||||
}
|
||||
|
||||
proc_t* proc = arch_getcls()->thread->proc;
|
||||
|
||||
// access sockfd
|
||||
|
||||
fd_t* fd;
|
||||
|
||||
int err = fd_access(&proc->fdtable, &fd, sockfd);
|
||||
|
||||
if(err){
|
||||
retv.errno = err;
|
||||
return retv;
|
||||
}
|
||||
|
||||
if(GETTYPE(fd->mode) != TYPE_SOCKET){
|
||||
retv.errno = ENOTSOCK;
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
socket_t* listenersock = fd->node->objdata;
|
||||
|
||||
// create new fd
|
||||
|
||||
fd_t* connfd = NULL;
|
||||
int connifd;
|
||||
|
||||
retv.errno = fd_alloc(&proc->fdtable, &connfd, &connifd, 0);
|
||||
|
||||
if(retv.errno)
|
||||
goto _fail;
|
||||
|
||||
connfd->node = vfs_newnode("SOCKET", &kerneltmpfs, NULL);
|
||||
if(!connfd->node){
|
||||
retv.errno = ENOMEM;
|
||||
goto _fail;
|
||||
}
|
||||
connfd->mode = 0777 | MAKETYPE(TYPE_SOCKET);
|
||||
connfd->node->refcount = 1;
|
||||
connfd->node->st.st_mode = connfd->mode;
|
||||
|
||||
// create socket for new fd
|
||||
|
||||
socket_t* connsock;
|
||||
|
||||
retv.errno = socket_new(&connsock, listenersock->family, listenersock->type, listenersock->protocol);
|
||||
|
||||
// get peer
|
||||
|
||||
socket_t* peer;
|
||||
|
||||
retv.errno = socket_accept(&peer, listenersock, addr, addrlen);
|
||||
|
||||
if(retv.errno)
|
||||
goto _fail;
|
||||
|
||||
connsock->peer = peer;
|
||||
connsock->state = SOCKET_STATE_CONNECTED;
|
||||
|
||||
spinlock_acquire(&peer->lock);
|
||||
|
||||
peer->peer = connsock;
|
||||
|
||||
event_signal(&peer->acceptevent, true);
|
||||
|
||||
spinlock_release(&peer->lock);
|
||||
|
||||
fd_release(fd);
|
||||
|
||||
retv.ret = connifd;
|
||||
|
||||
memcpy(addr, &peer->addr_un, peer->addrlen);
|
||||
*addrlen = peer->addrlen;
|
||||
|
||||
return retv;
|
||||
|
||||
_fail:
|
||||
|
||||
fd_release(fd);
|
||||
|
||||
if(connfd){
|
||||
fd_release(connfd);
|
||||
fd_free(&proc->fdtable, connifd);
|
||||
}
|
||||
|
||||
return retv;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
#include <kernel/syscalls.h>
|
||||
#include <kernel/fd.h>
|
||||
#include <arch/cls.h>
|
||||
#include <errno.h>
|
||||
#include <kernel/vmm.h>
|
||||
#include <sys/stat.h>
|
||||
#include <kernel/socket.h>
|
||||
|
||||
syscallret syscall_bind(int sockfd, void* addr, size_t addrlen){
|
||||
|
||||
syscallret retv;
|
||||
retv.ret = -1;
|
||||
|
||||
if(addr > USER_SPACE_END){
|
||||
retv.errno = EFAULT;
|
||||
return retv;
|
||||
}
|
||||
|
||||
proc_t* proc = arch_getcls()->thread->proc;
|
||||
|
||||
fd_t* fd;
|
||||
|
||||
int err = fd_access(&proc->fdtable, &fd, sockfd);
|
||||
|
||||
if(err){
|
||||
retv.errno = err;
|
||||
return retv;
|
||||
}
|
||||
|
||||
|
||||
if(GETTYPE(fd->mode) != TYPE_SOCKET){
|
||||
retv.errno = ENOTSOCK;
|
||||
goto _ret;
|
||||
}
|
||||
|
||||
retv.errno = socket_bind(fd->node->objdata, addr, addrlen);
|
||||
|
||||
_ret:
|
||||
|
||||
fd_release(fd);
|
||||
|
||||
return retv;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
#include <kernel/syscalls.h>
|
||||
#include <kernel/fd.h>
|
||||
#include <arch/cls.h>
|
||||
#include <errno.h>
|
||||
#include <kernel/vmm.h>
|
||||
#include <sys/stat.h>
|
||||
#include <kernel/socket.h>
|
||||
|
||||
syscallret syscall_connect(int sockfd, void* addr, size_t addrlen){
|
||||
|
||||
syscallret retv;
|
||||
retv.ret = -1;
|
||||
|
||||
if(addr > USER_SPACE_END){
|
||||
retv.errno = EFAULT;
|
||||
return retv;
|
||||
}
|
||||
|
||||
proc_t* proc = arch_getcls()->thread->proc;
|
||||
|
||||
fd_t* fd;
|
||||
|
||||
int err = fd_access(&proc->fdtable, &fd, sockfd);
|
||||
|
||||
if(err){
|
||||
retv.errno = err;
|
||||
return retv;
|
||||
}
|
||||
|
||||
|
||||
if(GETTYPE(fd->mode) != TYPE_SOCKET){
|
||||
retv.errno = ENOTSOCK;
|
||||
goto _ret;
|
||||
}
|
||||
|
||||
retv.errno = socket_connect(fd->node->objdata, addr, addrlen);
|
||||
|
||||
_ret:
|
||||
|
||||
fd_release(fd);
|
||||
|
||||
return retv;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
#include <kernel/syscalls.h>
|
||||
#include <kernel/fd.h>
|
||||
#include <arch/cls.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <kernel/socket.h>
|
||||
|
||||
syscallret syscall_listen(int sockfd, int backlog){
|
||||
|
||||
syscallret retv;
|
||||
retv.ret = -1;
|
||||
|
||||
proc_t* proc = arch_getcls()->thread->proc;
|
||||
|
||||
fd_t* fd;
|
||||
|
||||
int err = fd_access(&proc->fdtable, &fd, sockfd);
|
||||
|
||||
if(err){
|
||||
retv.errno = err;
|
||||
return retv;
|
||||
}
|
||||
|
||||
|
||||
if(GETTYPE(fd->mode) != TYPE_SOCKET){
|
||||
retv.errno = ENOTSOCK;
|
||||
goto _ret;
|
||||
}
|
||||
|
||||
retv.errno = socket_listen(fd->node->objdata, backlog);
|
||||
|
||||
_ret:
|
||||
|
||||
fd_release(fd);
|
||||
|
||||
return retv;
|
||||
|
||||
}
|
||||
@@ -95,6 +95,11 @@ syscallret syscall_openat(int dirfd, const char* pathname, int flags, mode_t mod
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
if(GETTYPE(file->st.st_mode) == TYPE_SOCKET){
|
||||
retv.errno = ENXIO;
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
|
||||
fd->node = file;
|
||||
fd->mode = file->st.st_mode;
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
#include <kernel/syscalls.h>
|
||||
#include <kernel/socket.h>
|
||||
#include <kernel/fd.h>
|
||||
#include <arch/cls.h>
|
||||
|
||||
extern fs_t kerneltmpfs;
|
||||
|
||||
syscallret syscall_socket(int domain, int type, int protocol){
|
||||
|
||||
syscallret retv;
|
||||
retv.ret = -1;
|
||||
|
||||
proc_t* proc = arch_getcls()->thread->proc;
|
||||
|
||||
fd_t* fd = NULL;
|
||||
int ifd;
|
||||
|
||||
retv.errno = fd_alloc(&proc->fdtable, &fd, &ifd, 0);
|
||||
|
||||
if(retv.errno)
|
||||
return retv;
|
||||
|
||||
fd->node = vfs_newnode("SOCKET", &kerneltmpfs, NULL);
|
||||
if(!fd->node){
|
||||
retv.errno = ENOMEM;
|
||||
goto _fail;
|
||||
}
|
||||
fd->mode = 0777 | MAKETYPE(TYPE_SOCKET);
|
||||
fd->node->refcount = 1;
|
||||
fd->node->st.st_mode = fd->mode;
|
||||
|
||||
socket_t* sock;
|
||||
|
||||
retv.errno = socket_new(&sock, domain, type, protocol);
|
||||
|
||||
if(retv.errno)
|
||||
goto _fail;
|
||||
|
||||
fd->node->objdata = sock;
|
||||
|
||||
fd_release(fd);
|
||||
|
||||
retv.ret = ifd;
|
||||
return retv;
|
||||
|
||||
_fail:
|
||||
|
||||
if(fd){
|
||||
fd_release(fd);
|
||||
fd_free(&proc->fdtable, ifd);
|
||||
}
|
||||
|
||||
return retv;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
#include <kernel/socket.h>
|
||||
#include <kernel/unsocket.h>
|
||||
#include <kernel/alloc.h>
|
||||
#include <arch/cls.h>
|
||||
#include <errno.h>
|
||||
#include <arch/spinlock.h>
|
||||
#include <string.h>
|
||||
#include <kernel/vfs.h>
|
||||
#include <arch/interrupt.h>
|
||||
|
||||
int unsocket_new(socket_t** returnptr, int type, int protocol){
|
||||
|
||||
if(type != SOCK_STREAM)
|
||||
return EINVAL;
|
||||
|
||||
socket_t* socket = alloc(sizeof(socket_t));
|
||||
|
||||
if(!socket)
|
||||
return ENOMEM;
|
||||
|
||||
socket->family = AF_UNIX;
|
||||
socket->type = type;
|
||||
socket->protocol = protocol;
|
||||
socket->state = SOCKET_STATE_UNBOUND;
|
||||
if(ringbuffer_init(&socket->buffer, 1024*128)){ // 128kb for socket buff
|
||||
free(socket);
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
*returnptr = socket;
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int unsocket_bind(struct _socket_t* sock, sockaddr_un* addr, size_t addrlen){
|
||||
|
||||
// copy address
|
||||
|
||||
if(addrlen > sizeof(sockaddr_un))
|
||||
return EINVAL;
|
||||
|
||||
sockaddr_un unaddr;
|
||||
|
||||
memcpy(&unaddr, addr, addrlen);
|
||||
|
||||
if(unaddr.sun_family != AF_UNIX)
|
||||
return EINVAL;
|
||||
|
||||
// create and prepare the socket node
|
||||
|
||||
spinlock_acquire(&sock->lock);
|
||||
|
||||
proc_t* proc = arch_getcls()->thread->proc;
|
||||
|
||||
int err = vfs_mksocket(unaddr.sun_path[0] == '/' ? proc->root : proc->cwd, unaddr.sun_path, 0777 & ~proc->umask);
|
||||
|
||||
if(err)
|
||||
goto _return;
|
||||
|
||||
vnode_t* socketnode;
|
||||
|
||||
err = vfs_open(&socketnode, unaddr.sun_path[0] == '/' ? proc->root : proc->cwd, unaddr.sun_path);
|
||||
|
||||
if(err)
|
||||
goto _return;
|
||||
|
||||
socketnode->objdata = sock;
|
||||
|
||||
sock->addr_un = unaddr;
|
||||
sock->addrlen = addrlen;
|
||||
sock->state = SOCKET_STATE_BOUND;
|
||||
err = 0;
|
||||
|
||||
_return:
|
||||
|
||||
spinlock_release(&sock->lock);
|
||||
|
||||
return err;
|
||||
|
||||
}
|
||||
|
||||
int unsocket_connect(struct _socket_t* sock, void* addr, size_t addrlen){
|
||||
|
||||
// copy address
|
||||
|
||||
socket_t* peer = NULL;
|
||||
|
||||
if(addrlen > sizeof(sockaddr_un))
|
||||
return EINVAL;
|
||||
|
||||
sockaddr_un addr_un;
|
||||
memcpy(&addr_un, addr, addrlen);
|
||||
|
||||
if(addr_un.sun_family != AF_UNIX)
|
||||
return EAFNOSUPPORT;
|
||||
|
||||
// do a few checks on the socket to see if the request is valid
|
||||
|
||||
proc_t* proc = arch_getcls()->thread->proc;
|
||||
|
||||
int err = 0;
|
||||
|
||||
spinlock_acquire(&sock->lock);
|
||||
|
||||
if(sock->state == SOCKET_STATE_LISTENING){
|
||||
err = EINVAL;
|
||||
goto _return;
|
||||
}
|
||||
|
||||
if(sock->state == SOCKET_STATE_CONNECTED){
|
||||
err = EISCONN;
|
||||
goto _return;
|
||||
}
|
||||
|
||||
vnode_t* vnode = NULL;
|
||||
|
||||
err = vfs_open(&vnode, addr_un.sun_path[0] == '/' ? proc->root : proc->cwd, addr_un.sun_path);
|
||||
|
||||
if(err)
|
||||
goto _return;
|
||||
|
||||
if(GETTYPE(vnode->st.st_mode) != TYPE_SOCKET){
|
||||
err = ENOTSOCK;
|
||||
goto _return;
|
||||
}
|
||||
|
||||
peer = vnode->objdata;
|
||||
|
||||
spinlock_acquire(&peer->lock);
|
||||
|
||||
if(peer->type != sock->type){
|
||||
err = EPROTOTYPE;
|
||||
goto _return;
|
||||
}
|
||||
|
||||
if(peer->state != SOCKET_STATE_LISTENING){
|
||||
err = ECONNREFUSED;
|
||||
goto _return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
err = socket_addtobacklog(peer, sock);
|
||||
if(err)
|
||||
goto _return;
|
||||
|
||||
arch_interrupt_disable();
|
||||
event_signal(&peer->connectevent, false);
|
||||
|
||||
spinlock_release(&peer->lock);
|
||||
spinlock_release(&sock->lock);
|
||||
|
||||
err = event_wait(&sock->acceptevent, true);
|
||||
|
||||
spinlock_acquire(&peer->lock);
|
||||
spinlock_acquire(&sock->lock);
|
||||
|
||||
// TODO remove from backlog!
|
||||
if(err)
|
||||
goto _return;
|
||||
|
||||
|
||||
_return:
|
||||
|
||||
if(peer)
|
||||
spinlock_release(&peer->lock);
|
||||
|
||||
if(vnode)
|
||||
vfs_close(vnode);
|
||||
|
||||
spinlock_release(&sock->lock);
|
||||
|
||||
return err;
|
||||
|
||||
}
|
||||
|
||||
int unsocket_accept(socket_t** peer, socket_t* sock, void* addr, size_t* addrlen){
|
||||
|
||||
// TODO abort
|
||||
|
||||
size_t len = *addrlen;
|
||||
|
||||
int err = 0;
|
||||
|
||||
if(*addrlen > sizeof(sockaddr_un))
|
||||
return EINVAL;
|
||||
|
||||
|
||||
spinlock_acquire(&sock->lock);
|
||||
|
||||
if(sock->state != SOCKET_STATE_LISTENING){
|
||||
err = EINVAL;
|
||||
goto _return;
|
||||
}
|
||||
|
||||
// TODO interruptble
|
||||
|
||||
while(!sock->backlogend){
|
||||
spinlock_release(&sock->lock);
|
||||
event_wait(&sock->connectevent, true);
|
||||
spinlock_acquire(&sock->lock);
|
||||
}
|
||||
|
||||
*peer = socket_popfrombacklog(sock);
|
||||
|
||||
spinlock_release(&sock->lock);
|
||||
|
||||
_return:
|
||||
|
||||
return err;
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user