summaryrefslogtreecommitdiff
path: root/cmd/srv9p/gnet.c
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/srv9p/gnet.c')
-rw-r--r--cmd/srv9p/gnet.c283
1 files changed, 236 insertions, 47 deletions
diff --git a/cmd/srv9p/gnet.c b/cmd/srv9p/gnet.c
index d7e8717..5dd4a93 100644
--- a/cmd/srv9p/gnet.c
+++ b/cmd/srv9p/gnet.c
@@ -70,24 +70,35 @@ static inline bool RUN_PTHREAD(void *(*fn)(void *), void *args) {
return false;
}
-/* init() ( AKA socket(3) + listen(3) )****************************************/
+static inline ssize_t gnet_map_errno(ssize_t v) {
+ if (v >= 0)
+ return v;
+ switch (v) {
+ case ETIMEDOUT:
+ return NET_ETIMEDOUT;
+ default:
+ return NET_EOTHER;
+ }
+}
+
+/* TCP init() ( AKA socket(3) + listen(3) )************************************/
-static implements_net_conn *gnet_accept(implements_net_listener *_listener);
-static ssize_t gnet_read(implements_net_conn *conn, void *buf, size_t count);
-static ssize_t gnet_write(implements_net_conn *conn, void *buf, size_t count);
-static int gnet_close(implements_net_conn *conn, bool rd, bool wr);
+static implements_net_stream_conn *gnet_tcp_accept(implements_net_stream_listener *_listener);
+static ssize_t gnet_tcp_read(implements_net_stream_conn *conn, void *buf, size_t count);
+static ssize_t gnet_tcp_write(implements_net_stream_conn *conn, void *buf, size_t count);
+static int gnet_tcp_close(implements_net_stream_conn *conn, bool rd, bool wr);
-static struct net_listener_vtable gnet_listener_vtable = {
- .accept = gnet_accept,
+static struct net_stream_listener_vtable gnet_tcp_listener_vtable = {
+ .accept = gnet_tcp_accept,
};
-static struct net_conn_vtable gnet_conn_vtable = {
- .read = gnet_read,
- .write = gnet_write,
- .close = gnet_close,
+static struct net_stream_conn_vtable gnet_tcp_conn_vtable = {
+ .read = gnet_tcp_read,
+ .write = gnet_tcp_write,
+ .close = gnet_tcp_close,
};
-void gnet_listener_init(struct gnet_listener *self, uint16_t port) {
+void gnet_tcp_listener_init(struct gnet_tcp_listener *self, uint16_t port) {
int listenerfd;
union {
struct sockaddr_in in;
@@ -108,13 +119,13 @@ void gnet_listener_init(struct gnet_listener *self, uint16_t port) {
if (listen(listenerfd, 0) < 0)
error(1, errno, "listen");
- self->vtable = &gnet_listener_vtable;
+ self->vtable = &gnet_tcp_listener_vtable;
self->fd = listenerfd;
}
-/* accept() *******************************************************************/
+/* TCP accept() ***************************************************************/
-struct _pthread_accept_args {
+struct gnet_pthread_accept_args {
pthread_t cr_thread;
cid_t cr_coroutine;
@@ -123,8 +134,8 @@ struct _pthread_accept_args {
int *ret_connfd;
};
-static void *_pthread_accept(void *_args) {
- struct _pthread_accept_args *args = _args;
+static void *gnet_pthread_accept(void *_args) {
+ struct gnet_pthread_accept_args *args = _args;
*(args->ret_connfd) = accept(args->listenerfd, NULL, NULL);
if (*(args->ret_connfd) < 0)
*(args->ret_connfd) = -errno;
@@ -132,28 +143,29 @@ static void *_pthread_accept(void *_args) {
return NULL;
};
-static implements_net_conn *gnet_accept(implements_net_listener *_listener) {
- struct gnet_listener *listener = VCALL_SELF(struct gnet_listener, implements_net_listener, _listener);
+static implements_net_stream_conn *gnet_tcp_accept(implements_net_stream_listener *_listener) {
+ struct gnet_tcp_listener *listener =
+ VCALL_SELF(struct gnet_tcp_listener, implements_net_stream_listener, _listener);
assert(listener);
int ret_connfd;
- struct _pthread_accept_args args = {
+ struct gnet_pthread_accept_args args = {
.cr_thread = pthread_self(),
.cr_coroutine = cr_getcid(),
.listenerfd = listener->fd,
.ret_connfd = &ret_connfd,
};
- if (RUN_PTHREAD(_pthread_accept, &args))
+ if (RUN_PTHREAD(gnet_pthread_accept, &args))
return NULL;
- listener->active_conn.vtable = &gnet_conn_vtable;
+ listener->active_conn.vtable = &gnet_tcp_conn_vtable;
listener->active_conn.fd = ret_connfd;
return &listener->active_conn;
}
-/* read() *********************************************************************/
+/* TCP read() *****************************************************************/
-struct _pthread_read_args {
+struct gnet_pthread_read_args {
pthread_t cr_thread;
cid_t cr_coroutine;
@@ -164,21 +176,22 @@ struct _pthread_read_args {
ssize_t *ret;
};
-static void *_pthread_read(void *_args) {
- struct _pthread_read_args *args = _args;
+static void *gnet_pthread_read(void *_args) {
+ struct gnet_pthread_read_args *args = _args;
*(args->ret) = read(args->connfd, args->buf, args->count);
if (*(args->ret) < 0)
- *(args->ret) = -errno;
+ *(args->ret) = gnet_map_errno(-errno);
WAKE_COROUTINE(args);
return NULL;
};
-static ssize_t gnet_read(implements_net_conn *_conn, void *buf, size_t count) {
- struct _gnet_conn *conn = VCALL_SELF(struct _gnet_conn, implements_net_conn, _conn);
+static ssize_t gnet_tcp_read(implements_net_stream_conn *_conn, void *buf, size_t count) {
+ struct _gnet_tcp_conn *conn =
+ VCALL_SELF(struct _gnet_tcp_conn, implements_net_stream_conn, _conn);
assert(conn);
ssize_t ret;
- struct _pthread_read_args args = {
+ struct gnet_pthread_read_args args = {
.cr_thread = pthread_self(),
.cr_coroutine = cr_getcid(),
@@ -188,14 +201,14 @@ static ssize_t gnet_read(implements_net_conn *_conn, void *buf, size_t count) {
.ret = &ret,
};
- if (RUN_PTHREAD(_pthread_read, &args))
- return -1;
+ if (RUN_PTHREAD(gnet_pthread_read, &args))
+ return -NET_ETHREAD;
return ret;
}
-/* write() ********************************************************************/
+/* TCP write() ****************************************************************/
-struct _pthread_write_args {
+struct gnet_pthread_write_args {
pthread_t cr_thread;
cid_t cr_coroutine;
@@ -206,13 +219,13 @@ struct _pthread_write_args {
ssize_t *ret;
};
-static void *_pthread_write(void *_args) {
- struct _pthread_read_args *args = _args;
+static void *gnet_pthread_write(void *_args) {
+ struct gnet_pthread_read_args *args = _args;
size_t done = 0;
while (done < args->count) {
ssize_t r = write(args->connfd, args->buf, args->count);
if (r < 0) {
- *(args->ret) = -errno;
+ gnet_map_errno(-errno);
break;
}
done += r;
@@ -223,12 +236,13 @@ static void *_pthread_write(void *_args) {
return NULL;
};
-static ssize_t gnet_write(implements_net_conn *_conn, void *buf, size_t count) {
- struct _gnet_conn *conn = VCALL_SELF(struct _gnet_conn, implements_net_conn, _conn);
+static ssize_t gnet_tcp_write(implements_net_stream_conn *_conn, void *buf, size_t count) {
+ struct _gnet_tcp_conn *conn =
+ VCALL_SELF(struct _gnet_tcp_conn, implements_net_stream_conn, _conn);
assert(conn);
ssize_t ret;
- struct _pthread_write_args args = {
+ struct gnet_pthread_write_args args = {
.cr_thread = pthread_self(),
.cr_coroutine = cr_getcid(),
@@ -238,15 +252,16 @@ static ssize_t gnet_write(implements_net_conn *_conn, void *buf, size_t count) {
.ret = &ret,
};
- if (RUN_PTHREAD(_pthread_write, &args))
- return -1;
+ if (RUN_PTHREAD(gnet_pthread_write, &args))
+ return -NET_ETHREAD;
return ret;
}
-/* close() ********************************************************************/
+/* TCP close() ****************************************************************/
-static int gnet_close(implements_net_conn *_conn, bool rd, bool wr) {
- struct _gnet_conn *conn = VCALL_SELF(struct _gnet_conn, implements_net_conn, _conn);
+static int gnet_tcp_close(implements_net_stream_conn *_conn, bool rd, bool wr) {
+ struct _gnet_tcp_conn *conn =
+ VCALL_SELF(struct _gnet_tcp_conn, implements_net_stream_conn, _conn);
assert(conn);
int how;
@@ -257,6 +272,180 @@ static int gnet_close(implements_net_conn *_conn, bool rd, bool wr) {
else if (!rd && wr)
how = SHUT_WR;
else
- return -EINVAL;
- return shutdown(conn->fd, how) ? -errno : 0;
+ assert(false);
+ return gnet_map_errno(shutdown(conn->fd, how) ? -errno : 0);
+}
+
+/* UDP init() *****************************************************************/
+
+static ssize_t gnet_udp_sendto(struct net_packet_conn *self, void *buf, size_t len,
+ struct net_ip4_addr addr, uint16_t port);
+static ssize_t gnet_udp_recvfrom(struct net_packet_conn *self, void *buf, size_t len,
+ struct net_ip4_addr *ret_addr, uint16_t *ret_port);
+static int gnet_udp_close(struct net_packet_conn *self);
+
+static struct net_packet_conn_vtable gnet_udp_conn_vtable = {
+ .sendto = gnet_udp_sendto,
+ .recvfrom = gnet_udp_recvfrom,
+ .close = gnet_udp_close,
+};
+
+void gnet_udp_conn_init(struct gnet_udp_conn *self, uint16_t port) {
+ int fd;
+ union {
+ struct sockaddr_in in;
+ struct sockaddr gen;
+ struct sockaddr_storage stor;
+ } addr = { 0 };
+
+ gnet_init();
+
+ addr.in.sin_family = AF_INET;
+ addr.in.sin_port = htons(port);
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0)
+ error(1, errno, "socket");
+ if (bind(fd, &addr.gen, sizeof addr) < 0)
+ error(1, errno, "bind");
+
+ self->vtable = &gnet_udp_conn_vtable;
+ self->fd = fd;
+}
+
+/* UDP sendto() ***************************************************************/
+
+struct gnet_pthread_sendto_args {
+ pthread_t cr_thread;
+ cid_t cr_coroutine;
+
+ int connfd;
+ void *buf;
+ size_t count;
+ struct net_ip4_addr node;
+ uint16_t port;
+
+ ssize_t *ret;
+};
+
+static void *gnet_pthread_sendto(void *_args) {
+ struct gnet_pthread_sendto_args *args = _args;
+ union {
+ struct sockaddr_in in;
+ struct sockaddr gen;
+ struct sockaddr_storage stor;
+ } addr = { 0 };
+
+ addr.in.sin_family = AF_INET;
+ addr.in.sin_addr.s_addr =
+ (((uint32_t)args->node.octets[0])<<24) |
+ (((uint32_t)args->node.octets[1])<<16) |
+ (((uint32_t)args->node.octets[2])<< 8) |
+ (((uint32_t)args->node.octets[3])<< 0) ;
+ addr.in.sin_port = htons(args->port);
+ *(args->ret) = sendto(args->connfd, args->buf, args->count, 0, &addr.gen, sizeof(addr));
+ if (*(args->ret) < 0)
+ *(args->ret) = gnet_map_errno(-errno);
+ WAKE_COROUTINE(args);
+ return NULL;
+}
+
+static ssize_t gnet_udp_sendto(struct net_packet_conn *_conn, void *buf, size_t count,
+ struct net_ip4_addr node, uint16_t port) {
+ struct gnet_udp_conn *conn =
+ VCALL_SELF(struct gnet_udp_conn, implements_net_packet_conn, _conn);
+ assert(conn);
+
+ ssize_t ret;
+ struct gnet_pthread_sendto_args args = {
+ .cr_thread = pthread_self(),
+ .cr_coroutine = cr_getcid(),
+
+ .connfd = conn->fd,
+ .buf = buf,
+ .count = count,
+ .node = node,
+ .port = port,
+
+ .ret = &ret,
+ };
+ if (RUN_PTHREAD(gnet_pthread_sendto, &args))
+ return -NET_ETHREAD;
+ return ret;
+}
+
+/* UDP recvfrom() *************************************************************/
+
+struct gnet_pthread_recvfrom_args {
+ pthread_t cr_thread;
+ cid_t cr_coroutine;
+
+ int connfd;
+ void *buf;
+ size_t count;
+
+ ssize_t *ret_size;
+ struct net_ip4_addr *ret_node;
+ uint16_t *ret_port;
+};
+
+static void *gnet_pthread_recvfrom(void *_args) {
+ struct gnet_pthread_recvfrom_args *args = _args;
+
+ union {
+ struct sockaddr_in in;
+ struct sockaddr gen;
+ struct sockaddr_storage stor;
+ } addr = { 0 };
+ socklen_t addr_size;
+
+ *(args->ret_size) = recvfrom(args->connfd, args->buf, args->count, 0, &addr.gen, &addr_size);
+ if (*(args->ret_size) < 0)
+ *(args->ret_size) = gnet_map_errno(-errno);
+ else {
+ assert(addr.in.sin_family == AF_INET);
+ if (args->ret_node) {
+ args->ret_node->octets[0] = (addr.in.sin_addr.s_addr >> 24) & 0xFF;
+ args->ret_node->octets[1] = (addr.in.sin_addr.s_addr >> 16) & 0xFF;
+ args->ret_node->octets[2] = (addr.in.sin_addr.s_addr >> 8) & 0xFF;
+ args->ret_node->octets[3] = (addr.in.sin_addr.s_addr >> 0) & 0xFF;
+ }
+ if (args->ret_port)
+ (*args->ret_port) = ntohs(addr.in.sin_port);
+ }
+ WAKE_COROUTINE(args);
+ return NULL;
+}
+
+static ssize_t gnet_udp_recvfrom(struct net_packet_conn *_conn, void *buf, size_t count,
+ struct net_ip4_addr *ret_node, uint16_t *ret_port) {
+ struct gnet_udp_conn *conn =
+ VCALL_SELF(struct gnet_udp_conn, implements_net_packet_conn, _conn);
+ assert(conn);
+
+ ssize_t ret;
+ struct gnet_pthread_recvfrom_args args = {
+ .cr_thread = pthread_self(),
+ .cr_coroutine = cr_getcid(),
+
+ .connfd = conn->fd,
+ .buf = buf,
+ .count = count,
+
+ .ret_size = &ret,
+ .ret_node = ret_node,
+ .ret_port = ret_port,
+ };
+ if (RUN_PTHREAD(gnet_pthread_recvfrom, &args))
+ return -NET_ETHREAD;
+ return ret;
+}
+
+/* UDP close() ****************************************************************/
+
+static int gnet_udp_close(struct net_packet_conn *_conn) {
+ struct gnet_udp_conn *conn =
+ VCALL_SELF(struct gnet_udp_conn, implements_net_packet_conn, _conn);
+ assert(conn);
+
+ return gnet_map_errno(close(conn->fd) ? -errno : 0);
}