diff options
author | Luke T. Shumaker <lukeshu@lukeshu.com> | 2025-04-15 01:03:39 -0600 |
---|---|---|
committer | Luke T. Shumaker <lukeshu@lukeshu.com> | 2025-04-15 01:03:39 -0600 |
commit | 0450e14b3a86e4448537c03253eeebf509f8909e (patch) | |
tree | c3a38f842b610d0f72b9e1c0aba45c186b443bf0 /lib9p/srv_include | |
parent | b1fcc4ac2f244dddd869054db5dc6753c099a3e0 (diff) | |
parent | ab99adc111425dd93a062e67b19943860296ecca (diff) |
Merge branch 'lukeshu/9p-fixes'
Diffstat (limited to 'lib9p/srv_include')
-rw-r--r-- | lib9p/srv_include/lib9p/srv.h | 226 |
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_ */ |