summaryrefslogtreecommitdiff
path: root/lib9p/srv_include
diff options
context:
space:
mode:
authorLuke T. Shumaker <lukeshu@lukeshu.com>2025-04-15 01:03:39 -0600
committerLuke T. Shumaker <lukeshu@lukeshu.com>2025-04-15 01:03:39 -0600
commit0450e14b3a86e4448537c03253eeebf509f8909e (patch)
treec3a38f842b610d0f72b9e1c0aba45c186b443bf0 /lib9p/srv_include
parentb1fcc4ac2f244dddd869054db5dc6753c099a3e0 (diff)
parentab99adc111425dd93a062e67b19943860296ecca (diff)
Merge branch 'lukeshu/9p-fixes'
Diffstat (limited to 'lib9p/srv_include')
-rw-r--r--lib9p/srv_include/lib9p/srv.h226
1 files changed, 226 insertions, 0 deletions
diff --git a/lib9p/srv_include/lib9p/srv.h b/lib9p/srv_include/lib9p/srv.h
new file mode 100644
index 0000000..db5be41
--- /dev/null
+++ b/lib9p/srv_include/lib9p/srv.h
@@ -0,0 +1,226 @@
+/* lib9p/srv.h - 9P server
+ *
+ * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#ifndef _LIB9P_SRV_H_
+#define _LIB9P_SRV_H_
+
+#include <libcr/coroutine.h>
+#include <libcr_ipc/rpc.h>
+#include <libcr_ipc/chan.h>
+#include <libhw/generic/net.h>
+#include <libmisc/assert.h>
+#include <libmisc/private.h>
+#include <libobj/obj.h>
+
+#include <lib9p/core.h>
+
+/* context ********************************************************************/
+
+CR_CHAN_DECLARE(_lib9p_srv_flushch, bool);
+
+struct lib9p_srv_authinfo {
+ lib9p_nuid_t uid;
+ struct lib9p_s uname;
+
+ BEGIN_PRIVATE(LIB9P_SRV_H);
+ unsigned int refcount;
+ END_PRIVATE(LIB9P_SRV_H);
+};
+
+struct lib9p_srv_ctx {
+ struct lib9p_ctx basectx;
+ struct lib9p_srv_authinfo *authinfo;
+
+ BEGIN_PRIVATE(LIB9P_SRV_H);
+ struct _lib9p_srv_sess *parent_sess;
+ lib9p_tag_t tag;
+ uint8_t *net_bytes;
+ _lib9p_srv_flushch_t flushch;
+ END_PRIVATE(LIB9P_SRV_H);
+};
+
+bool lib9p_srv_flush_requested(struct lib9p_srv_ctx *ctx);
+
+void lib9p_srv_acknowledge_flush(struct lib9p_srv_ctx *ctx);
+
+/* interface definitions ******************************************************/
+
+lo_interface lib9p_srv_fio;
+lo_interface lib9p_srv_dio;
+
+/* FIXME: I don't like that the pointers returned by stat() and
+ * pread() have to remain live after they return. Perhaps a
+ * `respond()`-callback? But that just reads as gross in C.
+ *
+ * FIXME: It would be nice if pread() could return more than 1 iovec.
+ */
+#define lib9p_srv_file_LO_IFACE \
+ /* resource management **********************************************/ \
+ \
+ /** \
+ * free() is be called when all FIDs associated with the file are \
+ * clunked. \
+ * \
+ * free() MUST NOT error. \
+ */ \
+ LO_FUNC(void , free ) \
+ \
+ /** \
+ * qid() is called frequently and returns the current QID of the file. \
+ * The .path field MUST never change, the .type field may change in \
+ * response to wstat() calls (but the QT_DIR bit MUST NOT change), and \
+ * the .vers field may change frequently in response to any number of \
+ * things (wstat(), write(), or non-9P events). \
+ * \
+ * qid() MUST NOT error. \
+ */ \
+ LO_FUNC(struct lib9p_qid , qid ) \
+ \
+ /* non-"opened" generic I/O *****************************************/ \
+ \
+ LO_FUNC(struct lib9p_stat , stat , struct lib9p_srv_ctx *) \
+ LO_FUNC(void , wstat , struct lib9p_srv_ctx *, \
+ struct lib9p_stat new) \
+ LO_FUNC(void , remove , struct lib9p_srv_ctx *) \
+ \
+ /* non-"opened" directory I/O ***************************************/ \
+ \
+ LO_FUNC(lo_interface lib9p_srv_file, dwalk , struct lib9p_srv_ctx *, \
+ struct lib9p_s childname) \
+ LO_FUNC(lo_interface lib9p_srv_file, dcreate, struct lib9p_srv_ctx *, \
+ struct lib9p_s childname, \
+ lib9p_dm_t perm, \
+ lib9p_o_t flags) \
+ \
+ /* open() for I/O ***************************************************/ \
+ \
+ LO_FUNC(lo_interface lib9p_srv_fio , fopen , struct lib9p_srv_ctx *, \
+ bool rd, bool wr, \
+ bool trunc) \
+ LO_FUNC(lo_interface lib9p_srv_dio , dopen , struct lib9p_srv_ctx *)
+LO_INTERFACE(lib9p_srv_file);
+
+#define lib9p_srv_fio_LO_IFACE \
+ LO_FUNC(struct lib9p_qid , qid ) \
+ LO_FUNC(void , iofree ) \
+ LO_FUNC(uint32_t , iounit ) \
+ LO_FUNC(void , pread , struct lib9p_srv_ctx *, \
+ uint32_t byte_count, \
+ uint64_t byte_offset, \
+ struct iovec *ret) \
+ LO_FUNC(uint32_t , pwrite , struct lib9p_srv_ctx *, \
+ void *buf, \
+ uint32_t byte_count, \
+ uint64_t byte_offset)
+LO_INTERFACE(lib9p_srv_fio);
+
+/* FIXME: The dio interface just feels clunky. I'm not in a rush to
+ * change it because util9p_static_dir is already implemented and I
+ * don't anticipate the sbc-harness needing another dio
+ * implementation. But if I wanted lib9p to be used outside of
+ * sbc-harness, this is one of the first things that I'd want to
+ * change.
+ */
+#define lib9p_srv_dio_LO_IFACE \
+ LO_FUNC(struct lib9p_qid , qid ) \
+ LO_FUNC(void , iofree ) \
+ LO_FUNC(size_t /* <- obj cnt */ , dread , struct lib9p_srv_ctx *, \
+ uint8_t *buf, \
+ /* num bytes -> */ uint32_t byte_count, \
+ /* starting at this object -> */ size_t obj_offset)
+LO_INTERFACE(lib9p_srv_dio);
+
+#define LIB9P_SRV_NOTDIR(TYP, NAM) \
+ static lo_interface lib9p_srv_file NAM##_dwalk (TYP *, struct lib9p_srv_ctx *, struct lib9p_s) { assert_notreached("not a directory"); } \
+ static lo_interface lib9p_srv_file NAM##_dcreate(TYP *, struct lib9p_srv_ctx *, struct lib9p_s, lib9p_dm_t, lib9p_o_t) { assert_notreached("not a directory"); } \
+ static lo_interface lib9p_srv_dio NAM##_dopen (TYP *, struct lib9p_srv_ctx *) { assert_notreached("not a directory"); }
+
+#define LIB9P_SRV_NOTFILE(TYP, NAM) \
+ static lo_interface lib9p_srv_fio NAM##_fopen (TYP *, struct lib9p_srv_ctx *, bool, bool, bool) { assert_notreached("not a file"); }
+
+/* main server entrypoints ****************************************************/
+
+CR_RPC_DECLARE(_lib9p_srv_reqch, struct lib9p_srv_ctx *, bool);
+
+#if CONFIG_9P_ENABLE_9P2000_p9p
+#define net_stream_conn_unix_LO_IFACE \
+ LO_NEST(net_stream_conn) \
+ /** Returns 0 on success, -errno on error. */ \
+ LO_FUNC(int, send_unix_fd, int fd)
+LO_INTERFACE(net_stream_conn_unix);
+#endif
+
+struct lib9p_srv {
+ /* Things you provide */
+ void /*TODO*/ (*auth )(struct lib9p_srv_ctx *, struct lib9p_s treename); /* optional */
+ lo_interface lib9p_srv_file (*rootdir)(struct lib9p_srv_ctx *, struct lib9p_s treename);
+ void (*msglog )(struct lib9p_srv_ctx *, enum lib9p_msg_type, void *hostmsg); /* optional */
+#if CONFIG_9P_ENABLE_9P2000_p9p
+ lo_interface net_stream_conn_unix (*type_assert_unix)(lo_interface net_stream_conn); /* optional */
+#endif
+
+ /* For internal use */
+ BEGIN_PRIVATE(LIB9P_SRV_H);
+ unsigned int readers;
+ unsigned int writers;
+ _lib9p_srv_reqch_t _reqch;
+ END_PRIVATE(LIB9P_SRV_H);
+};
+
+/**
+ * In a loop loop, accept a connection call lib9p_srv_read() on it.
+ * If LO_CALL(listener, accept) fails, then the function returns.
+ *
+ * When the last lib9p_srv_accept_and_read_loop() instance for a given
+ * `srv` returns, it will signal all lib9p_srv_worker_loop() calls to
+ * return.
+ *
+ * @param srv: The server configuration and state; has an associated
+ * pool of lib9p_srv_worker_loop() coroutines.
+ *
+ * @param listener: The listener object to accept connections from.
+ */
+void lib9p_srv_accept_and_read_loop(struct lib9p_srv *srv, lo_interface net_stream_listener listener);
+
+/**
+ * You should probably not call this directly; you should probably use
+ * lib9p_srv_accept_and_read_loop().
+ *
+ * Given an already-established stream connection (i.e. a TCP
+ * connection), service that connection; return once the connection is
+ * closed. Requests are dispatched to a pool of
+ * lib9p_srv_worker_loop() coroutines with the same `srv`.
+ *
+ * Will just close the connection if a T-message has a size[4] <7.
+ *
+ * @param srv: The server configuration and state; has an associated
+ * pool of lib9p_srv_worker_loop() coroutines.
+ *
+ * @param conn: The listener object to accept connections from.
+ *
+ * Errors that this function itself may send to clients:
+ *
+ * @errno L_EMSGSIZE T-message has size[4] bigger than max_msg_size
+ * @errno L_EDOM Tversion specified an impossibly small max_msg_size
+ * @errno L_EOPNOTSUPP T-message has an R-message type, or an unrecognized T-message type
+ * @errno L_EBADMSG T-message has wrong size[4] for its content, or has invalid UTF-8
+ * @errno L_ERANGE R-message does not fit into max_msg_size
+ */
+void lib9p_srv_read(struct lib9p_srv *srv, lo_interface net_stream_conn conn);
+
+
+
+/**
+ * In a loop, service requests to the `struct lib9p_srv *srv` argument
+ * that have been read by lib9p_srv_accept_and_read_loop() /
+ * lib9p_srv_read(). A "NULL" request causes the function to return.
+ *
+ * @param srv: The server configuration and state; has an associated
+ * pool of lib9p_srv_accept_and_read_loop() coroutines.
+ */
+void lib9p_srv_worker_loop(struct lib9p_srv *srv);
+
+#endif /* _LIB9P_SRV_H_ */