#include #include #include #include #include #include #include #include #include #include #include #include "net9p.h" /* "T" messages are client->server requests, and "R" messages are * server->client responses. I do not know what the Plan 9 designers * intended "T" and "R" to stand for. */ enum v9fs_msg_type { /* "9P2000" base protocol * https://ericvh.github.io/9p-rfc/rfc9p2000.html * https://github.com/ericvh/9p-rfc/blob/master/9p2000.xml * * But due to incompleteness, the Plan 9 manual section-5 and * the Plan 9 headers (particularly fcall.h) are a better * references. */ V9FS_Tversion = 100, /* "412" "4s" */ V9FS_Rversion = 101, /* "412" "4s" */ V9FS_Tauth = 102, /* "412" "4ss" */ V9FS_Rauth = 103, /* "412" "TODO" */ V9FS_Tattach = 104, /* "412" "TODO" */ V9FS_Rattach = 105, /* "412" "TODO" */ /*V9FS_Terror = 106, /* There is no Terror request, only Rerror responses */ V9FS_Rerror = 107, /* "412" "TODO" */ V9FS_Tflush = 108, /* "412" "TODO" */ V9FS_Rflush = 109, /* "412" "TODO" */ V9FS_Twalk = 110, /* "412" "TODO" */ V9FS_Rwalk = 111, /* "412" "TODO" */ V9FS_Topen = 112, /* "412" "TODO" */ V9FS_Ropen = 113, /* "412" "TODO" */ V9FS_Tcreate = 114, /* "412" "TODO" */ V9FS_Rcreate = 115, /* "412" "TODO" */ V9FS_Tread = 116, /* "412" "TODO" */ V9FS_Rread = 117, /* "412" "TODO" */ V9FS_Twrite = 118, /* "412" "TODO" */ V9FS_Rwrite = 119, /* "412" "TODO" */ V9FS_Tclunk = 120, /* "412" "TODO" */ V9FS_Rclunk = 121, /* "412" "TODO" */ V9FS_Tremove = 122, /* "412" "TODO" */ V9FS_Rremove = 123, /* "412" "TODO" */ V9FS_Tstat = 124, /* "412" "TODO" */ V9FS_Rstat = 125, /* "412" "TODO" */ V9FS_Twstat = 126, /* "412" "TODO" */ V9FS_Rwstat = 127, /* "412" "TODO" */ /* "9P2000.u" Unix extension * https://ericvh.github.io/9p-rfc/rfc9p2000.u.html * https://github.com/ericvh/9p-rfc/blob/master/9p2000.u.xml */ /* "9P2000.L" Linux extension * https://github.com/ericvh/9p-rfc/blob/master/9p2000.L.xml */ V9FS_TLERROR = 6, V9FS_RLERROR, V9FS_TSTATFS = 8, V9FS_RSTATFS, V9FS_TLOPEN = 12, V9FS_RLOPEN, V9FS_TLCREATE = 14, V9FS_RLCREATE, V9FS_TSYMLINK = 16, V9FS_RSYMLINK, V9FS_TMKNOD = 18, V9FS_RMKNOD, V9FS_TRENAME = 20, V9FS_RRENAME, V9FS_TREADLINK = 22, V9FS_RREADLINK, V9FS_TGETATTR = 24, V9FS_RGETATTR, V9FS_TSETATTR = 26, V9FS_RSETATTR, V9FS_TXATTRWALK = 30, V9FS_RXATTRWALK, V9FS_TXATTRCREATE = 32, V9FS_RXATTRCREATE, V9FS_TREADDIR = 40, V9FS_RREADDIR, V9FS_TFSYNC = 50, V9FS_RFSYNC, V9FS_TLOCK = 52, V9FS_RLOCK, V9FS_TGETLOCK = 54, V9FS_RGETLOCK, V9FS_TLINK = 70, V9FS_RLINK, V9FS_TMKDIR = 72, V9FS_RMKDIR, V9FS_TRENAMEAT = 74, V9FS_RRENAMEAT, V9FS_TUNLINKAT = 76, V9FS_RUNLINKAT, }; /* 1 - u8 * 2 - u16le * 4 - u32le * 8 - u16le * d - data (u32le `n`, then `n` bytes of data) * s - string (u16le `n`, then `n` bytes of UTF-8) * q - qid (13 bytes, idk) */ static const char const *msgfmt[255] = { /* All messages start with a "size[4] type[1] tag[2]" * prefix; that is not included in this table. */ [V9FS_Tversion] = "max_msg_size[4] s", [V9FS_Rversion] = "4s", [V9FS_Tauth] = "4ss", [V9FS_Rauth] = "q", [V9FS_Rerror] = "s", [V9FS_Tflush] = "2", [V9FS_Rflush] = "", [V9FS_Tattach] = "44ss", [V9FS_Rattach] = "q", [V9FS_Twalk] = "TODO", [V9FS_Rwalk] = "TODO", [V9FS_Topen] = "41", [V9FS_Ropen] = "q4", [V9FS_Tcreate] = "4s41", [V9FS_Rcreate] = "q4", [V9FS_Tread] = "484", [V9FS_Rread] = "d", [V9FS_Twrite] = "48d", [V9FS_Rwrite] = "4", [V9FS_Tclunk] = "4", [V9FS_Rclunk] = "", [V9FS_Tremove] = "4", [V9FS_Rremove] = "", [V9FS_Tstat] = "4", [V9FS_Rstat] = "TODO", [V9FS_Twstat] = "TODO", [V9FS_Rwstat] = "", }; void net9p_listen_cr(void *_arg) { (void)_arg; cr_begin(); union { struct sockaddr_in in; struct sockaddr gen; } addr; memset(&addr, 0, sizeof addr); addr.in.sin_family = AF_INET; addr.in.sin_port = htons(9001); int fd = socket(AF_INET, SOCK_STREAM|SOCK_NONBLOCK, 0); if (fd < 0) error(1, errno, "socket"); if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) < 0) error(1, errno, "setsockopt"); if (bind(fd, &addr.gen, sizeof addr) < 0) error(1, errno, "bind"); if (listen(fd, 5) < 0) error(1, errno, "listen"); for (;;) { int conn = accept(fd, NULL, NULL); if (conn < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) { cr_yield(); continue; } error(1, errno, "accept"); } if (!coroutine_add(net9p_worker_cr, &conn)) error(1, 0, "coroutine_add(net9p_worker_cr, &%d)", conn); } cr_end(); } void net9p_worker_cr(void *_arg) { int fd = *((int *)_arg); cr_begin(); close(fd); cr_end(); }