/* lib9p/tests/test_server/main.c - Main entry point for test 9P server * * Copyright (C) 2024-2025 Luke T. Shumaker * SPDX-License-Identifier: AGPL-3.0-or-later */ #include #include #include #include /* for atoi() */ #include #include #include #include #include #include #include #include #include "static.h" #include "fs_shutdown.h" #include "fs_slowread.h" /* configuration **************************************************************/ #include "config.h" #ifndef CONFIG_SRV9P_NUM_CONNS #error config.h must define CONFIG_SRV9P_NUM_CONNS #endif /* globals ********************************************************************/ static lo_interface lib9p_srv_file get_root(struct lib9p_srv_ctx *, struct lib9p_s); const char *hexdig = "0123456789abcdef"; struct { uint16_t port; struct hostnet_tcp_listener listeners[CONFIG_SRV9P_NUM_CONNS]; struct lib9p_srv srv; FILE *logstream; } globals = { .srv = (struct lib9p_srv){ .rootdir = get_root, }, }; /* file tree ******************************************************************/ #define STATIC_FILE(N, STRNAME, SYMNAME) \ UTIL9P_STATIC_FILE(N, STRNAME, \ .data_start = _binary_static_##SYMNAME##_start, \ .data_end = _binary_static_##SYMNAME##_end) #define STATIC_DIR(N, STRNAME, ...) \ UTIL9P_STATIC_DIR(N, STRNAME, __VA_ARGS__) #define API_FILE(N, STRNAME, SYMNAME, ...) \ lo_box_##SYMNAME##_file_as_lib9p_srv_file(&((struct SYMNAME##_file){ \ .name = STRNAME, \ .pathnum = N \ __VA_OPT__(,) __VA_ARGS__ \ })) struct lib9p_srv_file root = STATIC_DIR(1, "", STATIC_DIR(2, "Documentation", STATIC_FILE(3, "x", Documentation_x_txt), ), STATIC_FILE(4, "README.md", README_md), API_FILE(5, "shutdown", shutdown, .listeners = globals.listeners, .nlisteners = LM_ARRAY_LEN(globals.listeners)), API_FILE(6, "slowread", slowread, .flushable = false), API_FILE(7, "slowread-flushable", slowread, .flushable = true), ); static lo_interface lib9p_srv_file get_root(struct lib9p_srv_ctx *LM_UNUSED(ctx), struct lib9p_s LM_UNUSED(treename)) { return root; } /* main ***********************************************************************/ static COROUTINE read_cr(void *_i) { int i = *((int *)_i); cr_begin(); hostnet_tcp_listener_init(&globals.listeners[i], globals.port); lib9p_srv_read_cr(&globals.srv, lo_box_hostnet_tcplist_as_net_stream_listener(&globals.listeners[i])); cr_end(); } static COROUTINE init_cr(void *) { cr_begin(); sleep_for_ms(1); for (int i = 0; i < CONFIG_SRV9P_NUM_CONNS; i++) { char name[] = {'r', 'e', 'a', 'd', '-', hexdig[i], '\0'}; if (!coroutine_add(name, read_cr, &i)) error(1, 0, "coroutine_add(read_cr, &i)"); } for (int i = 0; i < 2*CONFIG_SRV9P_NUM_CONNS; i++) { char name[] = {'w', 'r', 'i', 't', 'e', '-', hexdig[i], '\0'}; if (!coroutine_add(name, lib9p_srv_write_cr, &globals.srv)) error(1, 0, "coroutine_add(lib9p_srv_write_cr, &globals.srv)"); } cr_exit(); } static void log_fct(char character, void *_stream) { FILE *stream = _stream; putc(character, stream); putchar(character); } static void log_msg(struct lib9p_srv_ctx *ctx, enum lib9p_msg_type typ, void *hostmsg) { /* It sucks that %v trips -Wformat and -Wformat-extra-args * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47781 */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wformat" #pragma GCC diagnostic ignored "-Wformat-extra-args" fmt_fctprintf(log_fct, globals.logstream, "%c %v\n", typ % 2 ? '<' : '>', lo_box_lib9p_msg_as_fmt_formatter(&ctx->basectx, typ, hostmsg)); #pragma GCC diagnostic pop fflush(globals.logstream); } int main(int argc, char *argv[]) { if (argc != 3) error(2, 0, "usage: %s PORT_NUMBER LOGFILE", argv[0]); globals.port = atoi(argv[1]); globals.logstream = fopen(argv[2], "w"); if (!globals.logstream) error(2, errno, "fopen"); globals.srv.msglog = log_msg; struct hostclock clock_monotonic = { .clock_id = CLOCK_MONOTONIC, }; bootclock = lo_box_hostclock_as_alarmclock(&clock_monotonic); coroutine_add("init", init_cr, NULL); coroutine_main(); fclose(globals.logstream); return 0; }