mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-11-02 07:28:21 +00:00
socket: initial implementation
This commit is contained in:
@@ -0,0 +1,141 @@
|
|||||||
|
#include <kernel/vfs.h>
|
||||||
|
#include <kernel/slab.h>
|
||||||
|
#include <kernel/alloc.h>
|
||||||
|
#include <kernel/timekeeper.h>
|
||||||
|
#include <kernel/vmm.h>
|
||||||
|
#include <logging.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <kernel/abi.h>
|
||||||
|
#include <kernel/poll.h>
|
||||||
|
#include <kernel/sock.h>
|
||||||
|
|
||||||
|
static scache_t *nodecache;
|
||||||
|
static uintmax_t currentinode;
|
||||||
|
|
||||||
|
int sockfs_open(vnode_t **node, int flags, cred_t *cred) {
|
||||||
|
return ENOSYS; // not needed
|
||||||
|
}
|
||||||
|
|
||||||
|
int sockfs_close(vnode_t *node, int flags, cred_t *cred) {
|
||||||
|
return ENOSYS; // not needed
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
return socket->ops->recv(socket, NULL, 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);
|
||||||
|
return socket->ops->send(socket, NULL, buffer, size, flags, writec);
|
||||||
|
}
|
||||||
|
|
||||||
|
int sockfs_poll(vnode_t *node, polldata_t *data, int events) {
|
||||||
|
socket_t *socket = SOCKFS_SOCKET_FROM_NODE(node);
|
||||||
|
return socket->ops->poll(socket, data, events);
|
||||||
|
}
|
||||||
|
|
||||||
|
int sockfs_getattr(vnode_t *node, vattr_t *attr, cred_t *cred) {
|
||||||
|
socketnode_t *socketnode = (socketnode_t *)node;
|
||||||
|
|
||||||
|
VOP_LOCK(node);
|
||||||
|
*attr = socketnode->attr;
|
||||||
|
attr->type = node->type;
|
||||||
|
VOP_UNLOCK(node);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sockfs_setattr(vnode_t *node, vattr_t *attr, cred_t *cred) {
|
||||||
|
socketnode_t *socketnode = (socketnode_t *)node;
|
||||||
|
VOP_LOCK(node);
|
||||||
|
|
||||||
|
socketnode->attr.gid = attr->gid;
|
||||||
|
socketnode->attr.uid = attr->uid;
|
||||||
|
socketnode->attr.mode = attr->mode;
|
||||||
|
socketnode->attr.atime = attr->atime;
|
||||||
|
socketnode->attr.mtime = attr->mtime;
|
||||||
|
socketnode->attr.ctime = attr->ctime;
|
||||||
|
|
||||||
|
VOP_UNLOCK(node);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// arg can be in userspace
|
||||||
|
int sockfs_ioctl(vnode_t *node, unsigned long request, void *arg, int *result) {
|
||||||
|
switch (request) {
|
||||||
|
case SIOCGIFHWADDR:
|
||||||
|
ifreq_t *ifreq = arg;
|
||||||
|
netdev_t *netdev = netdev_getdev(ifreq->name);
|
||||||
|
if (netdev) {
|
||||||
|
memcpy(ifreq->addr.addr, netdev->mac.address, sizeof(mac_t));
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return ENODEV;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int sockfs_inactive(vnode_t *node) {
|
||||||
|
socket_t *socket = SOCKFS_SOCKET_FROM_NODE(node);
|
||||||
|
VOP_LOCK(node);
|
||||||
|
socket->ops->destroy(socket);
|
||||||
|
slab_free(nodecache, node);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sockfs_enodev() {
|
||||||
|
return ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
static vops_t vnops = {
|
||||||
|
.create = sockfs_enodev,
|
||||||
|
.open = sockfs_open,
|
||||||
|
.close = sockfs_close,
|
||||||
|
.getattr = sockfs_getattr,
|
||||||
|
.setattr = sockfs_setattr,
|
||||||
|
.lookup = sockfs_enodev,
|
||||||
|
.poll = sockfs_poll,
|
||||||
|
.read = sockfs_read,
|
||||||
|
.write = sockfs_write,
|
||||||
|
.access = sockfs_enodev,
|
||||||
|
.unlink = sockfs_enodev,
|
||||||
|
.link = sockfs_enodev,
|
||||||
|
.symlink = sockfs_enodev,
|
||||||
|
.readlink = sockfs_enodev,
|
||||||
|
.inactive = sockfs_inactive,
|
||||||
|
.mmap = sockfs_enodev,
|
||||||
|
.munmap = sockfs_enodev,
|
||||||
|
.getdents = sockfs_enodev,
|
||||||
|
.resize = sockfs_enodev,
|
||||||
|
.rename = sockfs_enodev,
|
||||||
|
.ioctl = sockfs_ioctl
|
||||||
|
};
|
||||||
|
|
||||||
|
static void ctor(scache_t *cache, void *obj) {
|
||||||
|
socketnode_t *node = obj;
|
||||||
|
memset(node, 0, sizeof(socketnode_t));
|
||||||
|
VOP_INIT(&node->vnode, &vnops, 0, V_TYPE_SOCKET, NULL);
|
||||||
|
node->attr.inode = ++currentinode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sockfs_init() {
|
||||||
|
nodecache = slab_newcache(sizeof(socketnode_t), 0, ctor, ctor);
|
||||||
|
__assert(nodecache);
|
||||||
|
}
|
||||||
|
|
||||||
|
int sockfs_newsocket(vnode_t **nodep, socket_t *socket) {
|
||||||
|
__assert(_cpu()->intstatus);
|
||||||
|
vnode_t *vnode = slab_allocate(nodecache);
|
||||||
|
socketnode_t *node = (socketnode_t *)vnode;
|
||||||
|
if (node == NULL)
|
||||||
|
return ENOMEM;
|
||||||
|
|
||||||
|
node->socket = socket;
|
||||||
|
*nodep = vnode;
|
||||||
|
POLL_INITHEADER(&socket->pollheader);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
#ifndef _SOCK_H
|
||||||
|
#define _SOCK_H
|
||||||
|
|
||||||
|
#include <kernel/net.h>
|
||||||
|
#include <kernel/vfs.h>
|
||||||
|
#include <mutex.h>
|
||||||
|
#include <kernel/poll.h>
|
||||||
|
|
||||||
|
#define SOCKET_STATE_UNBOUND 0
|
||||||
|
#define SOCKET_STATE_BOUND 1
|
||||||
|
#define SOCKET_STATE_CONNECTED 2
|
||||||
|
#define SOCKET_STATE_LISTENING 3
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
struct socketops_t *ops;
|
||||||
|
mutex_t mutex;
|
||||||
|
int state;
|
||||||
|
int broadcast;
|
||||||
|
netdev_t *netdev;
|
||||||
|
pollheader_t pollheader;
|
||||||
|
int type;
|
||||||
|
} socket_t;
|
||||||
|
|
||||||
|
typedef struct socketops_t {
|
||||||
|
int (*bind)(socket_t *socket, sockaddr_t *addr);
|
||||||
|
int (*send)(socket_t *socket, sockaddr_t *addr, void *buffer, size_t count, uintmax_t flags, size_t *sendcount);
|
||||||
|
int (*recv)(socket_t *socket, sockaddr_t *addr, void *buffer, size_t count, uintmax_t flags, size_t *recvcount);
|
||||||
|
int (*poll)(socket_t *socket, polldata_t *data, int events);
|
||||||
|
void (*destroy)(socket_t *socket);
|
||||||
|
} socketops_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
vnode_t vnode;
|
||||||
|
vattr_t attr;
|
||||||
|
socket_t *socket;
|
||||||
|
} socketnode_t;
|
||||||
|
|
||||||
|
#define SOCKET_TYPE_UDP 0
|
||||||
|
#define SOCKFS_SOCKET_FROM_NODE(nodep) (((socketnode_t *)(nodep))->socket)
|
||||||
|
|
||||||
|
static inline int sock_convertaddress(sockaddr_t *sockaddr, abisockaddr_t *abisockaddr) {
|
||||||
|
switch (abisockaddr->type) {
|
||||||
|
case AF_INET:
|
||||||
|
inaddr_t *inaddr = (inaddr_t *)abisockaddr;
|
||||||
|
sockaddr->ipv4addr.addr = be_to_cpu_d(inaddr->sin_addr);
|
||||||
|
sockaddr->ipv4addr.port = be_to_cpu_w(inaddr->sin_port);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int sock_addrtoabiaddr(int socktype, sockaddr_t *sockaddr, abisockaddr_t *abisockaddr) {
|
||||||
|
switch (socktype) {
|
||||||
|
case SOCKET_TYPE_UDP:
|
||||||
|
inaddr_t *inaddr = (inaddr_t *)abisockaddr;
|
||||||
|
inaddr->sin_addr = cpu_to_be_d(sockaddr->ipv4addr.addr);
|
||||||
|
inaddr->sin_port = cpu_to_be_w(sockaddr->ipv4addr.port);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int sock_copymsghdr(msghdr_t *khdr, msghdr_t *uhdr) {
|
||||||
|
memcpy(khdr, uhdr, sizeof(msghdr_t));
|
||||||
|
iovec_t *iovectmp = alloc(sizeof(iovec_t) * khdr->iovcount);
|
||||||
|
if (iovectmp == NULL)
|
||||||
|
return ENOMEM;
|
||||||
|
memcpy(iovectmp, khdr->iov, sizeof(iovec_t) * khdr->iovcount);
|
||||||
|
khdr->iov = iovectmp;
|
||||||
|
|
||||||
|
if (khdr->addr) {
|
||||||
|
abisockaddr_t *addrtmp = alloc(khdr->addrlen);
|
||||||
|
if (addrtmp == NULL) {
|
||||||
|
free(iovectmp);
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
memcpy(addrtmp, khdr->addr, khdr->addrlen);
|
||||||
|
khdr->addr = addrtmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void sock_freemsghdr(msghdr_t *hdr) {
|
||||||
|
free(hdr->iov);
|
||||||
|
free(hdr->addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
socket_t *udp_createsocket();
|
||||||
|
socket_t *socket_create(int type);
|
||||||
|
int sockfs_newsocket(vnode_t **vnodep, socket_t *socket);
|
||||||
|
void sockfs_init();
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
#include <kernel/sock.h>
|
||||||
|
#include <logging.h>
|
||||||
|
|
||||||
|
static socket_t *(*createsocket[])() = {
|
||||||
|
udp_createsocket
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
socket_t *socket_create(int type) {
|
||||||
|
__assert(type < sizeof(createsocket) / sizeof(createsocket[0]));
|
||||||
|
return createsocket[type]();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user