diff --git a/Cargo.lock b/Cargo.lock index bd7dfe2..2e374ee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -238,460 +238,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" -[[package]] -name = "aws-config" -version = "1.8.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f156acdd2cf55f5aa53ee416c4ac851cf1222694506c0b1f78c85695e9ca9d" -dependencies = [ - "aws-credential-types", - "aws-runtime", - "aws-sdk-sso", - "aws-sdk-ssooidc", - "aws-sdk-sts", - "aws-smithy-async", - "aws-smithy-http", - "aws-smithy-json", - "aws-smithy-runtime", - "aws-smithy-runtime-api", - "aws-smithy-types", - "aws-types", - "bytes", - "fastrand", - "hex", - "http 1.4.0", - "sha1 0.10.6", - "time", - "tokio", - "tracing", - "url", - "zeroize", -] - -[[package]] -name = "aws-credential-types" -version = "1.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f20799b373a1be121fe3005fba0c2090af9411573878f224df44b42727fcaf7" -dependencies = [ - "aws-smithy-async", - "aws-smithy-runtime-api", - "aws-smithy-types", - "zeroize", -] - -[[package]] -name = "aws-lc-rs" -version = "1.16.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ec6fb3fe69024a75fa7e1bfb48aa6cf59706a101658ea01bfd33b2b248a038f" -dependencies = [ - "aws-lc-sys", - "zeroize", -] - -[[package]] -name = "aws-lc-sys" -version = "0.40.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f50037ee5e1e41e7b8f9d161680a725bd1626cb6f8c7e901f91f942850852fe7" -dependencies = [ - "cc", - "cmake", - "dunce", - "fs_extra", -] - -[[package]] -name = "aws-runtime" -version = "1.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dcd93c82209ac7413532388067dce79be5a8780c1786e5fae3df22e4dee2864" -dependencies = [ - "aws-credential-types", - "aws-sigv4", - "aws-smithy-async", - "aws-smithy-eventstream", - "aws-smithy-http", - "aws-smithy-runtime", - "aws-smithy-runtime-api", - "aws-smithy-types", - "aws-types", - "bytes", - "bytes-utils", - "fastrand", - "http 0.2.12", - "http 1.4.0", - "http-body 0.4.6", - "http-body 1.0.1", - "percent-encoding", - "pin-project-lite", - "tracing", - "uuid", -] - -[[package]] -name = "aws-sdk-s3" -version = "1.131.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe1b8c5282bf859170836045296b3cd710b7573aceb909498366bb508a41058e" -dependencies = [ - "aws-credential-types", - "aws-runtime", - "aws-sigv4", - "aws-smithy-async", - "aws-smithy-checksums", - "aws-smithy-eventstream", - "aws-smithy-http", - "aws-smithy-json", - "aws-smithy-observability", - "aws-smithy-runtime", - "aws-smithy-runtime-api", - "aws-smithy-types", - "aws-smithy-xml", - "aws-types", - "bytes", - "fastrand", - "hex", - "hmac 0.13.0", - "http 0.2.12", - "http 1.4.0", - "http-body 1.0.1", - "lru", - "percent-encoding", - "regex-lite", - "sha2 0.11.0", - "tracing", - "url", -] - -[[package]] -name = "aws-sdk-sso" -version = "1.98.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d69c77aafa20460c68b6b3213c84f6423b6e76dbf89accd3e1789a686ffd9489" -dependencies = [ - "aws-credential-types", - "aws-runtime", - "aws-smithy-async", - "aws-smithy-http", - "aws-smithy-json", - "aws-smithy-observability", - "aws-smithy-runtime", - "aws-smithy-runtime-api", - "aws-smithy-types", - "aws-types", - "bytes", - "fastrand", - "http 0.2.12", - "http 1.4.0", - "regex-lite", - "tracing", -] - -[[package]] -name = "aws-sdk-ssooidc" -version = "1.100.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c7e7b09346d5ca22a2a08267555843a6a0127fb20d8964cb6ecfb8fdb190225" -dependencies = [ - "aws-credential-types", - "aws-runtime", - "aws-smithy-async", - "aws-smithy-http", - "aws-smithy-json", - "aws-smithy-observability", - "aws-smithy-runtime", - "aws-smithy-runtime-api", - "aws-smithy-types", - "aws-types", - "bytes", - "fastrand", - "http 0.2.12", - "http 1.4.0", - "regex-lite", - "tracing", -] - -[[package]] -name = "aws-sdk-sts" -version = "1.103.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2249b81a2e73a8027c41c378463a81ec39b8510f184f2caab87de912af0f49b" -dependencies = [ - "aws-credential-types", - "aws-runtime", - "aws-smithy-async", - "aws-smithy-http", - "aws-smithy-json", - "aws-smithy-observability", - "aws-smithy-query", - "aws-smithy-runtime", - "aws-smithy-runtime-api", - "aws-smithy-types", - "aws-smithy-xml", - "aws-types", - "fastrand", - "http 0.2.12", - "http 1.4.0", - "regex-lite", - "tracing", -] - -[[package]] -name = "aws-sigv4" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68dc0b907359b120170613b5c09ccc61304eac3998ff6274b97d93ee6490115a" -dependencies = [ - "aws-credential-types", - "aws-smithy-eventstream", - "aws-smithy-http", - "aws-smithy-runtime-api", - "aws-smithy-types", - "bytes", - "crypto-bigint 0.5.5", - "form_urlencoded", - "hex", - "hmac 0.13.0", - "http 0.2.12", - "http 1.4.0", - "p256", - "percent-encoding", - "ring", - "sha2 0.11.0", - "subtle", - "time", - "tracing", - "zeroize", -] - -[[package]] -name = "aws-smithy-async" -version = "1.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffcaf626bdda484571968400c326a244598634dc75fd451325a54ad1a59acfc" -dependencies = [ - "futures-util", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "aws-smithy-checksums" -version = "0.64.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10efbbcec1e044b81600e2fc562a391951d291152d95b482d5b7e7132299d762" -dependencies = [ - "aws-smithy-http", - "aws-smithy-types", - "bytes", - "crc-fast", - "hex", - "http 1.4.0", - "http-body 1.0.1", - "http-body-util", - "md-5 0.11.0", - "pin-project-lite", - "sha1 0.11.0", - "sha2 0.11.0", - "tracing", -] - -[[package]] -name = "aws-smithy-eventstream" -version = "0.60.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faf09d74e5e32f76b8762da505a3cd59303e367a664ca67295387baa8c1d7548" -dependencies = [ - "aws-smithy-types", - "bytes", - "crc32fast", -] - -[[package]] -name = "aws-smithy-http" -version = "0.63.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba1ab2dc1c2c3749ead27180d333c42f11be8b0e934058fb4b2258ee8dbe5231" -dependencies = [ - "aws-smithy-eventstream", - "aws-smithy-runtime-api", - "aws-smithy-types", - "bytes", - "bytes-utils", - "futures-core", - "futures-util", - "http 1.4.0", - "http-body 1.0.1", - "http-body-util", - "percent-encoding", - "pin-project-lite", - "pin-utils", - "tracing", -] - -[[package]] -name = "aws-smithy-http-client" -version = "1.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a2f165a7feee6f263028b899d0a181987f4fa7179a6411a32a439fba7c5f769" -dependencies = [ - "aws-smithy-async", - "aws-smithy-runtime-api", - "aws-smithy-types", - "h2 0.3.27", - "h2 0.4.13", - "http 0.2.12", - "http 1.4.0", - "http-body 0.4.6", - "hyper 0.14.32", - "hyper 1.9.0", - "hyper-rustls 0.24.2", - "hyper-rustls 0.27.9", - "hyper-util", - "pin-project-lite", - "rustls 0.21.12", - "rustls 0.23.40", - "rustls-native-certs", - "rustls-pki-types", - "tokio", - "tokio-rustls 0.26.4", - "tower", - "tracing", -] - -[[package]] -name = "aws-smithy-json" -version = "0.62.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9648b0bb82a2eedd844052c6ad2a1a822d1f8e3adee5fbf668366717e428856a" -dependencies = [ - "aws-smithy-types", -] - -[[package]] -name = "aws-smithy-observability" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06c2315d173edbf1920da8ba3a7189695827002e4c0fc961973ab1c54abca9c" -dependencies = [ - "aws-smithy-runtime-api", -] - -[[package]] -name = "aws-smithy-query" -version = "0.60.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a56d79744fb3edb5d722ef79d86081e121d3b9422cb209eb03aea6aa4f21ebd" -dependencies = [ - "aws-smithy-types", - "urlencoding", -] - -[[package]] -name = "aws-smithy-runtime" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0504b1ab12debb5959e5165ee5fe97dd387e7aa7ea6a477bfd7635dfe769a4f5" -dependencies = [ - "aws-smithy-async", - "aws-smithy-http", - "aws-smithy-http-client", - "aws-smithy-observability", - "aws-smithy-runtime-api", - "aws-smithy-types", - "bytes", - "fastrand", - "http 0.2.12", - "http 1.4.0", - "http-body 0.4.6", - "http-body 1.0.1", - "http-body-util", - "pin-project-lite", - "pin-utils", - "tokio", - "tracing", -] - -[[package]] -name = "aws-smithy-runtime-api" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71a13df6ada0aafbf21a73bdfcdf9324cfa9df77d96b8446045be3cde61b42e" -dependencies = [ - "aws-smithy-async", - "aws-smithy-runtime-api-macros", - "aws-smithy-types", - "bytes", - "http 0.2.12", - "http 1.4.0", - "pin-project-lite", - "tokio", - "tracing", - "zeroize", -] - -[[package]] -name = "aws-smithy-runtime-api-macros" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d7396fd9500589e62e460e987ecb671bad374934e55ec3b5f498cc7a8a8a7b7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "aws-smithy-types" -version = "1.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d73dbfbaa8e4bc57b9045137680b958d274823509a360abfd8e1d514d40c95c" -dependencies = [ - "base64-simd", - "bytes", - "bytes-utils", - "futures-core", - "http 0.2.12", - "http 1.4.0", - "http-body 0.4.6", - "http-body 1.0.1", - "http-body-util", - "itoa", - "num-integer", - "pin-project-lite", - "pin-utils", - "ryu", - "serde", - "time", - "tokio", - "tokio-util", -] - -[[package]] -name = "aws-smithy-xml" -version = "0.60.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce02add1aa3677d022f8adf81dcbe3046a95f17a1b1e8979c145cd21d3d22b3" -dependencies = [ - "xmlparser", -] - -[[package]] -name = "aws-types" -version = "1.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f4bbcaa9304ea40902d3d5f42a0428d1bd895a2b0f6999436fb279ffddc58ac" -dependencies = [ - "aws-credential-types", - "aws-smithy-async", - "aws-smithy-runtime-api", - "aws-smithy-types", - "rustc_version", - "tracing", -] - [[package]] name = "axum" version = "0.8.9" @@ -702,7 +248,7 @@ dependencies = [ "bytes", "futures-util", "http 1.4.0", - "http-body 1.0.1", + "http-body", "http-body-util", "itoa", "matchit", @@ -726,7 +272,7 @@ dependencies = [ "bytes", "futures-core", "http 1.4.0", - "http-body 1.0.1", + "http-body", "http-body-util", "mime", "pin-project-lite", @@ -735,6 +281,16 @@ dependencies = [ "tower-service", ] +[[package]] +name = "backend-secure" +version = "0.1.0" +dependencies = [ + "rnex-base", + "rnex-mm", + "rnex-server", + "tokio", +] + [[package]] name = "backtrace" version = "0.3.76" @@ -750,28 +306,12 @@ dependencies = [ "windows-link", ] -[[package]] -name = "base16ct" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" - [[package]] name = "base64" version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" -[[package]] -name = "base64-simd" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "339abbe78e73178762e23bea9dfd08e697eb3f3301cd4be981c0f78ba5859195" -dependencies = [ - "outref", - "vsimd", -] - [[package]] name = "base64ct" version = "1.8.3" @@ -822,9 +362,9 @@ checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" [[package]] name = "bytemuck" -version = "1.25.0" +version = "1.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" +checksum = "d6aedf8ae72766347502cf3cb4f41cf5e9cc37d28bee90f1fdaaae15f9cf9424" dependencies = [ "bytemuck_derive", ] @@ -852,16 +392,6 @@ version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" -[[package]] -name = "bytes-utils" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dafe3a8757b027e2be6e4e5601ed563c55989fcf1546e933c66c8eb3a058d35" -dependencies = [ - "bytes", - "either", -] - [[package]] name = "bytestring" version = "1.5.1" @@ -878,8 +408,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d16d90359e986641506914ba71350897565610e87ce0ad9e6f28569db3dd5c6d" dependencies = [ "find-msvc-tools", - "jobserver", - "libc", "shlex", ] @@ -935,19 +463,11 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e34d8227fe1ba289043aeb13792056ff80fd6de1a9f49137a5f499de8e8c78ea" dependencies = [ + "block-buffer 0.12.0", "crypto-common 0.2.1", "inout 0.2.2", ] -[[package]] -name = "cmake" -version = "0.1.58" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" -dependencies = [ - "cc", -] - [[package]] name = "cmov" version = "0.5.3" @@ -963,12 +483,6 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "const-oid" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" - [[package]] name = "const-oid" version = "0.10.2" @@ -984,35 +498,6 @@ dependencies = [ "unicode-segmentation", ] -[[package]] -name = "cookie" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" -dependencies = [ - "percent-encoding", - "time", - "version_check", -] - -[[package]] -name = "cookie_store" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15b2c103cf610ec6cae3da84a766285b42fd16aad564758459e6ecf128c75206" -dependencies = [ - "cookie", - "document-features", - "idna", - "indexmap", - "log", - "serde", - "serde_derive", - "serde_json", - "time", - "url", -] - [[package]] name = "core-foundation" version = "0.10.1" @@ -1068,18 +553,6 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "217698eaf96b4a3f0bc4f3662aaa55bdf913cd54d7204591faa790070c6d0853" -[[package]] -name = "crc-fast" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd92aca2c6001b1bf5ba0ff84ee74ec8501b52bbef0cac80bf25a6c1d87a83d" -dependencies = [ - "crc", - "digest 0.10.7", - "rustversion", - "spin 0.10.0", -] - [[package]] name = "crc32fast" version = "1.5.0" @@ -1104,28 +577,6 @@ version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" -[[package]] -name = "crypto-bigint" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" -dependencies = [ - "generic-array", - "rand_core 0.6.4", - "subtle", - "zeroize", -] - -[[package]] -name = "crypto-bigint" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" -dependencies = [ - "rand_core 0.6.4", - "subtle", -] - [[package]] name = "crypto-common" version = "0.1.7" @@ -1147,9 +598,9 @@ dependencies = [ [[package]] name = "ctor" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01334b89b69ff726750c5ce5073fc8bd860e99aa9a8fc5ca11b04730e3aee97a" +checksum = "fb22e947478ccf9dc44d8922042c677a63fbb88f2cb468521d1145816e5087cb" dependencies = [ "link-section", "linktime-proc-macro", @@ -1164,12 +615,6 @@ dependencies = [ "cmov", ] -[[package]] -name = "data-encoding" -version = "2.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8" - [[package]] name = "debugid" version = "0.8.0" @@ -1182,19 +627,9 @@ dependencies = [ [[package]] name = "der" -version = "0.6.1" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" -dependencies = [ - "const-oid 0.9.6", - "zeroize", -] - -[[package]] -name = "der" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71fd89660b2dc699704064e59e9dba0147b903e85319429e131620d022be411b" +checksum = "a69dedd701da44b0536442edf09c81a64b0ab97a7a4a5e3d1971f00027cbc63d" dependencies = [ "pem-rfc7468", "zeroize", @@ -1250,7 +685,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" dependencies = [ "block-buffer 0.12.0", - "const-oid 0.10.2", + "const-oid", "crypto-common 0.2.1", "ctutils", ] @@ -1276,15 +711,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "document-features" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" -dependencies = [ - "litrs", -] - [[package]] name = "dotenv" version = "0.15.0" @@ -1297,24 +723,6 @@ version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" -[[package]] -name = "dunce" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" - -[[package]] -name = "ecdsa" -version = "0.14.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" -dependencies = [ - "der 0.6.1", - "elliptic-curve", - "rfc6979", - "signature", -] - [[package]] name = "either" version = "1.15.0" @@ -1324,26 +732,6 @@ dependencies = [ "serde", ] -[[package]] -name = "elliptic-curve" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" -dependencies = [ - "base16ct", - "crypto-bigint 0.4.9", - "der 0.6.1", - "digest 0.10.7", - "ff", - "generic-array", - "group", - "pkcs8", - "rand_core 0.6.4", - "sec1", - "subtle", - "zeroize", -] - [[package]] name = "encoding_rs" version = "0.8.35" @@ -1396,16 +784,6 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" -[[package]] -name = "ff" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" -dependencies = [ - "rand_core 0.6.4", - "subtle", -] - [[package]] name = "find-msvc-tools" version = "0.1.9" @@ -1448,7 +826,7 @@ checksum = "5e139bc46ca777eb5efaf62df0ab8cc5fd400866427e56c68b22e414e53bd3be" dependencies = [ "futures-core", "futures-sink", - "spin 0.9.8", + "spin", ] [[package]] @@ -1493,27 +871,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "fs_extra" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" - -[[package]] -name = "futures" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - [[package]] name = "futures-channel" version = "0.3.32" @@ -1558,17 +915,6 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" -[[package]] -name = "futures-macro" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - [[package]] name = "futures-sink" version = "0.3.32" @@ -1587,10 +933,8 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ - "futures-channel", "futures-core", "futures-io", - "futures-macro", "futures-sink", "futures-task", "memchr", @@ -1651,36 +995,6 @@ version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" -[[package]] -name = "group" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" -dependencies = [ - "ff", - "rand_core 0.6.4", - "subtle", -] - -[[package]] -name = "h2" -version = "0.3.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http 0.2.12", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - [[package]] name = "h2" version = "0.4.13" @@ -1806,17 +1120,6 @@ dependencies = [ "itoa", ] -[[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http 0.2.12", - "pin-project-lite", -] - [[package]] name = "http-body" version = "1.0.1" @@ -1836,7 +1139,7 @@ dependencies = [ "bytes", "futures-core", "http 1.4.0", - "http-body 1.0.1", + "http-body", "pin-project-lite", ] @@ -1862,30 +1165,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "hyper" -version = "0.14.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2 0.3.27", - "http 0.2.12", - "http-body 0.4.6", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2 0.5.10", - "tokio", - "tower-service", - "tracing", - "want", -] - [[package]] name = "hyper" version = "1.9.0" @@ -1896,9 +1175,9 @@ dependencies = [ "bytes", "futures-channel", "futures-core", - "h2 0.4.13", + "h2", "http 1.4.0", - "http-body 1.0.1", + "http-body", "httparse", "httpdate", "itoa", @@ -1908,21 +1187,6 @@ dependencies = [ "want", ] -[[package]] -name = "hyper-rustls" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" -dependencies = [ - "futures-util", - "http 0.2.12", - "hyper 0.14.32", - "log", - "rustls 0.21.12", - "tokio", - "tokio-rustls 0.24.1", -] - [[package]] name = "hyper-rustls" version = "0.27.9" @@ -1930,12 +1194,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" dependencies = [ "http 1.4.0", - "hyper 1.9.0", + "hyper", "hyper-util", - "rustls 0.23.40", - "rustls-native-certs", + "rustls", "tokio", - "tokio-rustls 0.26.4", + "tokio-rustls", "tower-service", ] @@ -1945,7 +1208,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" dependencies = [ - "hyper 1.9.0", + "hyper", "hyper-util", "pin-project-lite", "tokio", @@ -1960,7 +1223,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.9.0", + "hyper", "hyper-util", "native-tls", "tokio", @@ -1979,8 +1242,8 @@ dependencies = [ "futures-channel", "futures-util", "http 1.4.0", - "http-body 1.0.1", - "hyper 1.9.0", + "http-body", + "hyper", "ipnet", "libc", "percent-encoding", @@ -2181,16 +1444,6 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" -[[package]] -name = "jobserver" -version = "0.1.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" -dependencies = [ - "getrandom 0.3.4", - "libc", -] - [[package]] name = "js-sys" version = "0.3.97" @@ -2203,12 +1456,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "json" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd" - [[package]] name = "language-tags" version = "0.3.2" @@ -2245,9 +1492,9 @@ dependencies = [ [[package]] name = "link-section" -version = "0.18.2" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2b1dd6fe32e55c0fc0ea9493aa57459ca3cf4ff3c857c7d0302290150da6e4f" +checksum = "e333fe507b738576d6da5bb3f1a7d7a1c80307ed9ef31624c057d844c19c93e9" [[package]] name = "linktime-proc-macro" @@ -2267,12 +1514,6 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" -[[package]] -name = "litrs" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" - [[package]] name = "local-waker" version = "0.1.4" @@ -2294,24 +1535,6 @@ version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" -[[package]] -name = "lru" -version = "0.16.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f66e8d5d03f609abc3a39e6f08e4164ebf1447a732906d39eb9b99b7919ef39" -dependencies = [ - "hashbrown 0.16.1", -] - -[[package]] -name = "macros" -version = "0.0.0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - [[package]] name = "macros" version = "0.1.1" @@ -2407,9 +1630,9 @@ dependencies = [ [[package]] name = "nex-account" -version = "0.2.3" +version = "0.2.4" source = "sparse+https://crates.spbr.net/api/v1/crates/" -checksum = "2dd9e8b23a09bb5ab8aeb5f39ed5ed1861549e4294757c9be30eb281c4ad11d0" +checksum = "6f1cfe935e71c764dfd6bad9b23372396f785408536c0a23fba379ef405117d3" dependencies = [ "base64", "bytemuck", @@ -2439,6 +1662,16 @@ dependencies = [ "libc", ] +[[package]] +name = "node-holder-backend" +version = "0.1.0" +dependencies = [ + "rnex-node-holder", + "rnex-reggie-protos", + "rnex-server", + "tokio", +] + [[package]] name = "nu-ansi-term" version = "0.50.3" @@ -2454,15 +1687,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - [[package]] name = "num-traits" version = "0.2.19" @@ -2714,23 +1938,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "outref" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" - -[[package]] -name = "p256" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51f44edd08f51e2ade572f141051021c5af22677e42b7dd28a88155151c33594" -dependencies = [ - "ecdsa", - "elliptic-curve", - "sha2 0.10.9", -] - [[package]] name = "parking" version = "2.2.1" @@ -2818,22 +2025,6 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkcs8" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" -dependencies = [ - "der 0.6.1", - "spki", -] - [[package]] name = "pkg-config" version = "0.3.33" @@ -2941,12 +2132,10 @@ name = "proxy" version = "0.1.0" dependencies = [ "cfg-if", - "log", "proxy-common", - "prudplite", "prudpv0", "prudpv1", - "rnex-core", + "rnex-prudp", "tokio", ] @@ -2955,24 +2144,14 @@ name = "proxy-common" version = "0.1.0" dependencies = [ "hex", - "log", - "rnex-core", + "rnex-prudp", + "rnex-reggie-protos", + "rnex-rmc", + "rnex-server", + "rnex-util", "thiserror", "tokio", -] - -[[package]] -name = "prudplite" -version = "0.1.0" -dependencies = [ - "bytemuck", - "futures-util", - "log", - "proxy-common", - "rnex-core", - "tokio", - "tokio-tungstenite", - "v-byte-helpers", + "tracing", ] [[package]] @@ -2982,11 +2161,10 @@ dependencies = [ "bytemuck", "cfg-if", "hmac 0.12.1", - "log", "md-5 0.10.6", "proxy-common", - "rc4", - "rnex-core", + "rc4 0.1.0", + "rnex-prudp", "tokio", "typenum", ] @@ -2999,12 +2177,12 @@ dependencies = [ "bytemuck", "cfg-if", "hmac 0.12.1", - "log", "md-5 0.10.6", "once_cell", "proxy-common", - "rc4", - "rnex-core", + "rc4 0.1.0", + "rnex-prudp", + "rnex-util", "thiserror", "tokio", "typenum", @@ -3083,15 +2261,6 @@ dependencies = [ "rand_core 0.9.5", ] -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.17", -] - [[package]] name = "rand_core" version = "0.9.5" @@ -3116,6 +2285,15 @@ dependencies = [ "cipher 0.4.4", ] +[[package]] +name = "rc4" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "840038b674daa9f7a7957440d937951d15c0143c056e631e529141fd780e0c92" +dependencies = [ + "cipher 0.5.1", +] + [[package]] name = "redox_syscall" version = "0.5.18" @@ -3171,12 +2349,12 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2 0.4.13", + "h2", "http 1.4.0", - "http-body 1.0.1", + "http-body", "http-body-util", - "hyper 1.9.0", - "hyper-rustls 0.27.9", + "hyper", + "hyper-rustls", "hyper-tls", "hyper-util", "js-sys", @@ -3199,17 +2377,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "rfc6979" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" -dependencies = [ - "crypto-bigint 0.4.9", - "hmac 0.12.1", - "zeroize", -] - [[package]] name = "ring" version = "0.17.14" @@ -3225,49 +2392,232 @@ dependencies = [ ] [[package]] -name = "rnex-core" -version = "0.1.1" +name = "rnex-auth" +version = "0.1.0" dependencies = [ "anyhow", - "async-trait", - "aws-config", - "aws-sdk-s3", - "base64", - "bytemuck", "cfg-if", - "chrono", - "ctor", - "dotenv", - "futures", "hex", - "hmac 0.12.1", - "json", - "log", - "macros 0.0.0", - "md-5 0.10.6", "nex-account", - "once_cell", - "paste", "rand 0.10.2", - "rc4", - "sentry", - "sentry-tracing", - "serde", - "serde_json", - "sha2 0.10.9", - "simplelog", - "sqlx", - "thiserror", + "rnex-auth-protos", + "rnex-prudp", + "rnex-reggie-protos", + "rnex-rmc", + "rnex-server", "tokio", "tonic", "tracing", - "tracing-subscriber", - "typenum", +] + +[[package]] +name = "rnex-auth-protos" +version = "0.1.0" +dependencies = [ + "cfg-if", + "ctor", + "rnex-rmc", + "tokio", +] + +[[package]] +name = "rnex-base" +version = "0.1.0" +dependencies = [ + "cfg-if", + "rand 0.10.2", + "rnex-base-protos", + "rnex-rmc", + "rnex-server", + "rnex-util", + "tokio", + "tracing", +] + +[[package]] +name = "rnex-base-protos" +version = "0.1.0" +dependencies = [ + "ctor", + "rnex-rmc", +] + +[[package]] +name = "rnex-ds" +version = "0.1.0" + +[[package]] +name = "rnex-ds-protos" +version = "0.1.0" +dependencies = [ + "ctor", + "rnex-base-protos", + "rnex-rmc", +] + +[[package]] +name = "rnex-fpd" +version = "0.1.0" + +[[package]] +name = "rnex-fpd-protos" +version = "0.1.0" +dependencies = [ + "ctor", + "rnex-rmc", +] + +[[package]] +name = "rnex-mm" +version = "0.1.0" +dependencies = [ + "bytemuck", + "cfg-if", + "rand 0.10.2", + "rnex-base", + "rnex-base-protos", + "rnex-mm-protos", + "rnex-rmc", + "rnex-server", + "rnex-util", + "serde", + "tokio", + "tracing", "ureq", - "urlencoding", +] + +[[package]] +name = "rnex-mm-protos" +version = "0.1.0" +dependencies = [ + "cfg-if", + "ctor", + "rnex-base-protos", + "rnex-rmc", +] + +[[package]] +name = "rnex-msg" +version = "0.1.0" + +[[package]] +name = "rnex-msg-protos" +version = "0.1.0" +dependencies = [ + "ctor", + "rnex-rmc", +] + +[[package]] +name = "rnex-node-holder" +version = "0.1.0" +dependencies = [ + "rnex-reggie-protos", + "rnex-rmc", + "rnex-server", + "tokio", +] + +[[package]] +name = "rnex-prudp" +version = "0.1.0" +dependencies = [ + "bytemuck", + "cfg-if", + "hmac 0.13.0", + "md-5 0.11.0", + "rand 0.10.2", + "rc4 0.2.0", + "rnex-util", + "tracing", + "typenum", "v-byte-helpers", ] +[[package]] +name = "rnex-reggie-protos" +version = "0.1.0" +dependencies = [ + "ctor", + "rnex-rmc", +] + +[[package]] +name = "rnex-rk" +version = "0.1.0" + +[[package]] +name = "rnex-rk-protos" +version = "0.1.0" +dependencies = [ + "bytemuck", + "ctor", + "rnex-base-protos", + "rnex-rmc", +] + +[[package]] +name = "rnex-rmc" +version = "0.1.0" +dependencies = [ + "bytemuck", + "ctor", + "hex", + "paste", + "rand 0.10.2", + "rnex-rmc-macros", + "rnex-util", + "thiserror", + "tokio", + "tracing", + "v-byte-helpers", +] + +[[package]] +name = "rnex-rmc-macros" +version = "0.0.0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "rnex-server" +version = "0.1.0" +dependencies = [ + "anyhow", + "ctor", + "dotenv", + "paste", + "rnex-rmc", + "rnex-util", + "sentry", + "tokio", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "rnex-server-backend-auth" +version = "0.1.0" +dependencies = [ + "rnex-auth", + "rnex-server", + "tokio", +] + +[[package]] +name = "rnex-util" +version = "0.1.0" +dependencies = [ + "bytemuck", + "chrono", + "md-5 0.11.0", + "tokio", + "tracing", +] + [[package]] name = "rustc-demangle" version = "0.1.28" @@ -3298,70 +2648,34 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.12" +version = "0.23.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +checksum = "6b92b125634d9b795e7beca796cc790df15a7fb38323bf3196fda83292d06b1f" dependencies = [ - "log", - "ring", - "rustls-webpki 0.101.7", - "sct", -] - -[[package]] -name = "rustls" -version = "0.23.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b" -dependencies = [ - "aws-lc-rs", "log", "once_cell", "ring", "rustls-pki-types", - "rustls-webpki 0.103.13", + "rustls-webpki", "subtle", "zeroize", ] -[[package]] -name = "rustls-native-certs" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" -dependencies = [ - "openssl-probe", - "rustls-pki-types", - "schannel", - "security-framework", -] - [[package]] name = "rustls-pki-types" -version = "1.14.1" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9" +checksum = "764899a24af3980067ee14bc143654f297b22eaebfe3c7b6b211920a5a59b046" dependencies = [ "zeroize", ] -[[package]] -name = "rustls-webpki" -version = "0.101.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "rustls-webpki" version = "0.103.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" dependencies = [ - "aws-lc-rs", "ring", "rustls-pki-types", "untrusted", @@ -3394,30 +2708,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "sct" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "sec1" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" -dependencies = [ - "base16ct", - "der 0.6.1", - "generic-array", - "pkcs8", - "subtle", - "zeroize", -] - [[package]] name = "security-framework" version = "3.7.0" @@ -3624,17 +2914,6 @@ dependencies = [ "serde", ] -[[package]] -name = "sha1" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if", - "cpufeatures 0.2.17", - "digest 0.10.7", -] - [[package]] name = "sha1" version = "0.11.0" @@ -3693,16 +2972,6 @@ dependencies = [ "libc", ] -[[package]] -name = "signature" -version = "1.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" -dependencies = [ - "digest 0.10.7", - "rand_core 0.6.4", -] - [[package]] name = "simd-adler32" version = "0.3.9" @@ -3780,22 +3049,6 @@ dependencies = [ "lock_api", ] -[[package]] -name = "spin" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591" - -[[package]] -name = "spki" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" -dependencies = [ - "base64ct", - "der 0.6.1", -] - [[package]] name = "sqlx" version = "0.9.0" @@ -3818,7 +3071,6 @@ dependencies = [ "base64", "bytes", "cfg-if", - "chrono", "crc", "crossbeam-queue", "either", @@ -3892,7 +3144,6 @@ dependencies = [ "bitflags", "byteorder", "bytes", - "chrono", "crc", "digest 0.11.3", "dotenvy", @@ -3903,7 +3154,7 @@ dependencies = [ "log", "percent-encoding", "serde", - "sha1 0.11.0", + "sha1", "sha2 0.11.0", "sqlx-core", "thiserror", @@ -3920,7 +3171,6 @@ dependencies = [ "base64", "bitflags", "byteorder", - "chrono", "crc", "dotenvy", "etcetera", @@ -3953,7 +3203,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "488e99c397a62007e4229aec669a179816339afc6d2620ca6fa420dbee2e982c" dependencies = [ "atoi", - "chrono", "flume", "form_urlencoded", "futures-channel", @@ -4183,23 +3432,13 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-rustls" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" -dependencies = [ - "rustls 0.21.12", - "tokio", -] - [[package]] name = "tokio-rustls" version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ - "rustls 0.23.40", + "rustls", "tokio", ] @@ -4214,22 +3453,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-tungstenite" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f72a05e828585856dacd553fba484c242c46e391fb0e58917c942ee9202915c" -dependencies = [ - "futures-util", - "log", - "rustls 0.23.40", - "rustls-native-certs", - "rustls-pki-types", - "tokio", - "tokio-rustls 0.26.4", - "tungstenite", -] - [[package]] name = "tokio-util" version = "0.7.18" @@ -4253,11 +3476,11 @@ dependencies = [ "axum", "base64", "bytes", - "h2 0.4.13", + "h2", "http 1.4.0", - "http-body 1.0.1", + "http-body", "http-body-util", - "hyper 1.9.0", + "hyper", "hyper-timeout", "hyper-util", "percent-encoding", @@ -4340,7 +3563,7 @@ dependencies = [ "bytes", "futures-util", "http 1.4.0", - "http-body 1.0.1", + "http-body", "pin-project-lite", "tower", "tower-layer", @@ -4424,24 +3647,6 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" -[[package]] -name = "tungstenite" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c01152af293afb9c7c2a57e4b559c5620b421f6d133261c60dd2d0cdb38e6b8" -dependencies = [ - "bytes", - "data-encoding", - "http 1.4.0", - "httparse", - "log", - "rand 0.9.4", - "rustls 0.23.40", - "rustls-pki-types", - "sha1 0.10.6", - "thiserror", -] - [[package]] name = "typenum" version = "1.20.1" @@ -4515,16 +3720,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dea7109cdcd5864d4eeb1b58a1648dc9bf520360d7af16ec26d0a9354bafcfc0" dependencies = [ "base64", - "cookie_store", - "der 0.8.0", + "der", "flate2", "log", "native-tls", "percent-encoding", - "rustls 0.23.40", + "rustls", "rustls-pki-types", - "serde", - "serde_json", "ureq-proto", "utf8-zero", "webpki-root-certs", @@ -4556,12 +3758,6 @@ dependencies = [ "serde_derive", ] -[[package]] -name = "urlencoding" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" - [[package]] name = "utf8-zero" version = "0.8.1" @@ -4576,9 +3772,9 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "uuid" -version = "1.23.1" +version = "1.23.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76" +checksum = "bf80a72845275afea99e7f2b434723d3bc7e38470fcd1c7ed39a599c73319a53" dependencies = [ "js-sys", "serde_core", @@ -4591,7 +3787,7 @@ version = "0.1.1" source = "git+https://github.com/RusticMaple/VByteMacros#e2f31bded8c5591e847ba03faf79ae0351e43e69" dependencies = [ "bytemuck", - "macros 0.1.1", + "macros", ] [[package]] @@ -4612,12 +3808,6 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" -[[package]] -name = "vsimd" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64" - [[package]] name = "want" version = "0.3.1" @@ -4761,9 +3951,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52f5ee44c96cf55f1b349600768e3ece3a8f26010c05265ab73f945bb1a2eb9d" +checksum = "bf85cb06032201fa7c6f829d7db5a7e5aa45bcc0655327713065f6f0576731bf" dependencies = [ "rustls-pki-types", ] @@ -5046,12 +4236,6 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" -[[package]] -name = "xmlparser" -version = "0.13.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" - [[package]] name = "yoke" version = "0.8.2" @@ -5077,18 +4261,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.48" +version = "0.8.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" +checksum = "b7cbbc0a705a0fd05cc3676525980d2bf5a9bc4adac6d6475209a7887cf59d19" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.48" +version = "0.8.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" +checksum = "e2e817b7b52d0c7358d3246da9d69935ebb18116b2b102b4230dac079b4862f5" dependencies = [ "proc-macro2", "quote", @@ -5118,9 +4302,9 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.8.2" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" +checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" [[package]] name = "zerotrie" diff --git a/Cargo.toml b/Cargo.toml index 046a20f..6a360ad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,38 @@ [workspace] resolver = "3" members = [ - "macros", - "rnex-core", "prudpv1", - "prudpv0" -, "proxy", "proxy-common", "prudplite"] + "prudpv0", + "proxy", + "proxy-common", + "rnex-rmc", + "rnex-rmc/macros", + "rnex-util", + "rnex-protocols/mm-protos", + "rnex-protocols/ds-protos", + "rnex-protocols/rk-protos", + "rnex-protocols/base-protos", + "rnex-protocols/auth-protos", + "rnex-protocols/reggie-protos", + "rnex-protocols/msg-protos", + "rnex-protocols/fpd-protos", + "rnex-prudp", + "rnex-server", + "rnex-server/backend-auth", + "rnex-server/backend-secure", + "rnex-server/backend-node-holder", + "rnex-server-nex-modules/rnex-mm", + "rnex-server-nex-modules/rnex-ds", + "rnex-server-nex-modules/rnex-rk", + "rnex-server-nex-modules/rnex-fpd", + "rnex-server-nex-modules/rnex-node-holder", + "rnex-server-nex-modules/rnex-base", + "rnex-server-nex-modules/rnex-msg", + "rnex-server-nex-modules/rnex-auth" +] + + +[workspace.lints.clippy] +print_stdout = { level = "deny", priority = 1} +pedantic = { level = "warn", priority = 0 } +all = { level = "warn", priority = -1 } diff --git a/check-edition.sh b/check-edition.sh index 7494337..3193259 100755 --- a/check-edition.sh +++ b/check-edition.sh @@ -13,4 +13,6 @@ echo CHECKING $EDITION echo FEATURES: echo $EDITION_FEATURES -RUSTFLAGS="--deny warnings" cargo check --features "$EDITION_FEATURES" +#RUSTFLAGS="--deny warnings" cargo clippy --workspace --features "$EDITION_FEATURES" +# cargo check --workspace --features "$EDITION_FEATURES" +echo "edition checks are disabled right now due to being in" diff --git a/proxy-common/Cargo.toml b/proxy-common/Cargo.toml index bd13ffa..32ad8de 100644 --- a/proxy-common/Cargo.toml +++ b/proxy-common/Cargo.toml @@ -3,9 +3,16 @@ name = "proxy-common" version = "0.1.0" edition = "2024" +[lints] +workspace = true + [dependencies] thiserror = "2.0.12" -rnex-core = { path = "../rnex-core", version = "0.1.1" } +rnex-prudp = { path = "../rnex-prudp" } +rnex-server = { path = "../rnex-server" } +rnex-util = { path = "../rnex-util" } +rnex-reggie-protos = { path = "../rnex-protocols/reggie-protos" } +rnex-rmc = { path = "../rnex-rmc" } tokio = { version = "1.47.0", features = ["full"] } -log = "0.4.25" hex = "0.4.3" +tracing = "0.1.44" diff --git a/proxy-common/src/lib.rs b/proxy-common/src/lib.rs index d696c72..e1f3a02 100644 --- a/proxy-common/src/lib.rs +++ b/proxy-common/src/lib.rs @@ -1,21 +1,14 @@ -use log::{error, info}; -use rnex_core::{ - PID, - executables::common::try_get_ip, - prudp::{socket_addr::PRUDPSockAddr, virtual_port::VirtualPort}, - reggie::{RemoteEdgeNodeHolder, UnitPacketWrite}, - rmc::{ - protocols::{ - RemoteDisconnectable, RmcCallable, RmcConnection, RmcPureRemoteObject, - new_rmc_gateway_connection, - }, - structures::RmcSerialize, - }, - rnex_proxy_common::ConnectionInitData, - util::{SendingBufferConnection, SplittableBufferConnection}, +use rnex_prudp::{socket_addr::PRUDPSockAddr, virtual_port::VirtualPort}; +use rnex_reggie_protos::reggie::{EdgeNodeHolderConnectOption, RemoteEdgeNodeHolder}; +use rnex_rmc::{ + RemoteDisconnectable, RmcCallable, RmcConnection, RmcPureRemoteObject, + new_rmc_gateway_connection, serialization::RmcSerialize, }; +use rnex_server::{ConnectionInitData, try_get_ip}; +use rnex_util::{PID, SendingBufferConnection, SplittableBufferConnection, UnitPacketWrite}; use std::{ env::{self, VarError}, + fmt::Debug, net::{AddrParseError, Ipv4Addr, SocketAddr, SocketAddrV4}, ops::Deref, panic, @@ -24,6 +17,7 @@ use std::{ }; use thiserror::Error; use tokio::net::TcpStream; +use tracing::{error, info, instrument}; const RNEX_DEFAULT_PORT: u16 = match u16::from_str_radix(env!("RNEX_DEFAULT_PORT"), 10) { Ok(v) => v, @@ -104,6 +98,15 @@ impl ProxyStartupParam { } struct OnRemoteDrop(T, Option); +impl Debug + for OnRemoteDrop +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut tuple_builder = f.debug_tuple("OnRemoteDrop"); + tuple_builder.field(&self.0); + tuple_builder.finish_non_exhaustive() + } +} impl Deref for OnRemoteDrop { type Target = T; @@ -136,10 +139,10 @@ impl RmcCallable _protocol_id: u16, _method_id: u32, _call_id: u32, - _rest: Vec, - ) -> impl Future + Send { + _rest: &[u8], + ) -> impl Future + Send { // maybe respond with not implemented or something - async {} + async { false } } } @@ -160,7 +163,7 @@ pub async fn setup_edge_node_connection( let conn: SplittableBufferConnection = conn.into(); conn.send( - rnex_core::reggie::EdgeNodeHolderConnectOption::Register(param.self_public) + EdgeNodeHolderConnectOption::Register(param.self_public) .to_data() .unwrap(), ) @@ -168,7 +171,7 @@ pub async fn setup_edge_node_connection( println!("{:?}", param.self_public); //leave the inner object floating so that it gets destroyed once we disconnect - new_rmc_gateway_connection(conn, move |r| { + new_rmc_gateway_connection(conn, async move |r| { Arc::new(OnRemoteDrop::::new( r, shutdown_callback, @@ -191,7 +194,7 @@ pub async fn new_backend_connection( }; let data = ConnectionInitData { - prudpsock_addr: addr, + addr: addr.regular_socket_addr, pid: pid, } .to_data() diff --git a/proxy/Cargo.toml b/proxy/Cargo.toml index 98e8b2b..6e4500f 100644 --- a/proxy/Cargo.toml +++ b/proxy/Cargo.toml @@ -3,20 +3,20 @@ name = "proxy" version = "0.1.0" edition = "2024" +[lints] +workspace = true + [dependencies] tokio = { version = "1.47.0", features = ["full"] } prudpv0 = { path = "../prudpv0", optional = true } prudpv1 = { path = "../prudpv1", optional = true } -prudplite = { path = "../prudplite", optional = true } proxy-common = { path = "../proxy-common" } cfg-if = "1.0.4" -rnex-core = { path = "../rnex-core", version = "0.1.1" } -log = "0.4.25" +rnex-prudp = { path = "../rnex-prudp" } [features] prudpv0 = ["dep:prudpv0"] prudpv1 = ["dep:prudpv1"] -prudplite = ["dep:prudplite"] friends = ["prudpv0", "prudpv0/friends"] splatoon = ["prudpv1"] diff --git a/prudplite/Cargo.toml b/prudplite/Cargo.toml deleted file mode 100644 index 34720a5..0000000 --- a/prudplite/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "prudplite" -version = "0.1.0" -edition = "2024" - -[features] -nx = [] -v4-3-11 = [] - -[dependencies] -rnex-core = { path = "../rnex-core", version = "0.1.1" } -tokio = { version = "1.47.0", features = ["full"] } -bytemuck = { version = "1.23.1", features = ["derive"] } -proxy-common = {path = "../proxy-common"} -tokio-tungstenite = {version = "0.29.0", features = ["rustls", "rustls-tls-native-roots"]} -log = "0.4.25" -futures-util = "0.3.31" -v-byte-helpers = { git = "https://github.com/RusticMaple/VByteMacros", version = "0.1.1" } diff --git a/prudplite/src/crypto/insecure.rs b/prudplite/src/crypto/insecure.rs deleted file mode 100644 index a1beaf2..0000000 --- a/prudplite/src/crypto/insecure.rs +++ /dev/null @@ -1,14 +0,0 @@ -use rnex_core::PID; - -use crate::crypto::Crypto; - -pub struct Insecure; - -impl Crypto for Insecure { - fn new_connection(&self, _data: &[u8]) -> Option<(PID, Vec)> { - Some((100, vec![])) - } - fn new() -> Self { - Self - } -} diff --git a/prudplite/src/crypto/mod.rs b/prudplite/src/crypto/mod.rs deleted file mode 100644 index 38d8091..0000000 --- a/prudplite/src/crypto/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -use rnex_core::PID; - -pub mod insecure; -pub mod secure; - -pub trait Crypto: 'static + Send + Sync { - fn new_connection(&self, data: &[u8]) -> Option<(PID, Vec)>; - fn new() -> Self; -} diff --git a/prudplite/src/crypto/secure.rs b/prudplite/src/crypto/secure.rs deleted file mode 100644 index 4aff759..0000000 --- a/prudplite/src/crypto/secure.rs +++ /dev/null @@ -1,27 +0,0 @@ -use rnex_core::{ - PID, executables::common::SECURE_SERVER_ACCOUNT, nex::account::Account, - prudp::ticket::read_secure_connection_data, rmc::structures::RmcSerialize, -}; - -use crate::crypto::Crypto; - -pub struct Secure(&'static Account); - -impl Crypto for Secure { - fn new_connection(&self, data: &[u8]) -> Option<(PID, Vec)> { - let (_, pid, check_value) = read_secure_connection_data(data, &self.0)?; - - let check_value_response = check_value + 1; - - let data = bytemuck::bytes_of(&check_value_response); - - let mut response = Vec::new(); - - data.serialize(&mut response).ok()?; - - Some((pid, response)) - } - fn new() -> Self { - Self(&SECURE_SERVER_ACCOUNT) - } -} diff --git a/prudplite/src/executable.rs b/prudplite/src/executable.rs deleted file mode 100644 index b4d8a0e..0000000 --- a/prudplite/src/executable.rs +++ /dev/null @@ -1,45 +0,0 @@ -use futures_util::{SinkExt, StreamExt}; -use rnex_core::prudp::types_flags::{TypesFlags, flags::NEED_ACK, types::SYN}; -use tokio_tungstenite::tungstenite::{Message, client::IntoClientRequest, http::header}; - -use crate::packet::{LiteHeader, LitePacket, PacketSpecificData, StreamTypes, create_packet_from}; - -mod packet; - -const KEY: &str = "4eb18d39"; - -const URL: &str = "wss://g2DF33D01-lp1.s.n.srv.nintendo.net"; -#[tokio::main] -async fn main() { - let login = URL.into_client_request().unwrap(); - let (mut stream, response) = tokio_tungstenite::connect_async(login).await.unwrap(); - - println!("response: {:?}", response); - - let packet = create_packet_from( - LiteHeader { - stream_types: StreamTypes::new(10, 10), - source_port: 1, - destination_port: 1, - fragment_id: 0, - types_flags: TypesFlags::default().types(SYN).flags(NEED_ACK), - sequence_id: 0, - ..Default::default() - }, - &[PacketSpecificData::SupportedFunctions(0x8)], - &[], - ); - - println!("sending ack"); - stream.send(Message::Binary(packet.into())).await.unwrap(); - println!("waiting for response"); - let packet = stream.next().await.unwrap(); - let Message::Binary(packet) = packet.unwrap() else { - panic!() - }; - let packet = LitePacket::new(packet); - - let header = packet.header().unwrap(); - - println!("{:?}", header); -} diff --git a/prudplite/src/lib.rs b/prudplite/src/lib.rs deleted file mode 100644 index 0df7b2e..0000000 --- a/prudplite/src/lib.rs +++ /dev/null @@ -1,316 +0,0 @@ -pub mod crypto; -mod packet; - -use std::{collections::HashMap, net::SocketAddr, sync::Arc}; - -use crate::{ - crypto::{Crypto, insecure::Insecure, secure::Secure}, - packet::{LiteHeader, LitePacket, PacketSpecificData, StreamTypes, create_packet_from}, -}; -use futures_util::{SinkExt, StreamExt}; -use log::{error, info, warn}; -use proxy_common::{ProxyStartupParam, new_backend_connection}; -use rnex_core::{ - PID, - prudp::{ - socket_addr::PRUDPSockAddr, - types_flags::{ - TypesFlags, - flags::{ACK, NEED_ACK, RELIABLE}, - types::{CONNECT, DATA, DISCONNECT, PING, SYN}, - }, - virtual_port::VirtualPort, - }, - util::SplittableBufferConnection, -}; -use tokio::net::{TcpListener, TcpStream}; -use tokio_tungstenite::{ - WebSocketStream, - tungstenite::{Bytes, Message}, -}; - -struct ConnectionState { - param: Arc, - active: bool, - websocket: WebSocketStream, - #[allow(dead_code)] - pid: PID, - backend_conn: SplittableBufferConnection, - addr: PRUDPSockAddr, - incoming_reliable: HashMap>, - client_reliable_counter: u16, - #[allow(dead_code)] - server_reliable_counter: u16, -} - -impl ConnectionState { - pub async fn handle_incoming_prudp(&mut self, packet: LitePacket, sorted: bool) { - let Some(header) = packet.header() else { - warn!("invalid data on connection"); - return; - }; - - if (header.types_flags.get_flags() & NEED_ACK) != 0 { - let data = create_packet_from( - LiteHeader { - stream_types: StreamTypes::new( - self.param.virtual_port.get_stream_type(), - self.addr.virtual_port.get_stream_type(), - ), - source_port: self.param.virtual_port.get_port_number(), - destination_port: self.addr.virtual_port.get_port_number(), - fragment_id: header.fragment_id, - types_flags: TypesFlags::default() - .types(header.types_flags.get_types()) - .flags(ACK), - sequence_id: header.sequence_id, - ..Default::default() - }, - &[], - &[], - ); - let data: Bytes = data.into(); - if header.types_flags.get_types() == DISCONNECT { - self.websocket - .send(Message::Binary(data.clone())) - .await - .ok(); - self.websocket - .send(Message::Binary(data.clone())) - .await - .ok(); - } - self.websocket.send(Message::Binary(data)).await.ok(); - } - - if (header.types_flags.get_flags() & ACK) != 0 { - // we can just safely ignore acks, we ARE sending over tcp after all already guarantees that our packets will arrive - // we can however not guarantee the order of incoming client packets so we should still take care of that - // (the client might be doing some funny things which we dont know of) - return; - } - - if (header.types_flags.get_flags() & RELIABLE != 0) & !sorted { - self.incoming_reliable.insert(header.sequence_id, packet); - if self.incoming_reliable.len() > 5 { - self.active = false; - warn!("client is spamming out of order reliable packets, throwing out"); - } - return; - } - - match header.types_flags.get_types() { - DATA => { - if header.fragment_id != 0 { - warn!("fragmented packets arent yet supported"); - return; - } - - let Some(payload) = packet.payload() else { - return; - }; - self.backend_conn.send(payload.into()).await; - } - PING => {} - v => { - info!("unimplemented packet type: {}", v); - } - } - } - #[allow(dead_code)] - pub async fn process_reliable(&mut self) { - while let Some(v) = self.incoming_reliable.remove(&self.client_reliable_counter) { - self.handle_incoming_prudp(v, true).await; - self.client_reliable_counter += 1; - } - } - pub async fn handle_connection(&mut self) { - while self.active { - tokio::select! { - v = self.websocket.next() => { - match v { - Some(Ok(Message::Binary(v))) => { - self.handle_incoming_prudp(LitePacket::new(v), false).await; - } - _ => { - info!("client disconnected or errored out"); - return; - } - } - } - _ = self.backend_conn.recv() => { - - } - } - } - } -} - -pub async fn websocket_thread_unconnected( - param: Arc, - crypto: Arc, - conn: TcpStream, - addr: SocketAddr, -) { - let mut websocket = match tokio_tungstenite::accept_async(conn).await { - Ok(v) => v, - Err(e) => { - error!("error accepting websocket connection: {}", e); - return; - } - }; - - while let Some(Ok(v)) = websocket.next().await { - match v { - Message::Binary(b) => { - let packet = LitePacket::new(b); - - let Some(header) = packet.header() else { - error!("got malformed message, disconnecting"); - return; - }; - - match header.types_flags.get_types() { - SYN => { - let Some(supported) = packet.packet_specific_iter() else { - error!("got malformed message, disconnecting"); - return; - }; - - let Some(PacketSpecificData::SupportedFunctions(s)) = supported - .into_iter() - .find(|v| matches!(v, PacketSpecificData::SupportedFunctions(_))) - else { - error!("got malformed message, disconnecting"); - return; - }; - - let data = create_packet_from( - LiteHeader { - destination_port: header.source_port, - source_port: param.virtual_port.get_port_number(), - stream_types: StreamTypes::new( - param.virtual_port.get_stream_type(), - header.stream_types.source(), - ), - fragment_id: 0, - sequence_id: 0, - types_flags: TypesFlags::default().types(SYN).flags(ACK), - ..Default::default() - }, - &[ - PacketSpecificData::SupportedFunctions(s & 0xFF), - PacketSpecificData::ConnectionSignature([0; 16]), - ], - &[], - ); - websocket.send(Message::Binary(data.into())).await.ok(); - } - CONNECT => { - let Some(supported) = packet.packet_specific_iter() else { - error!("got malformed message, disconnecting"); - return; - }; - - let Some(PacketSpecificData::SupportedFunctions(s)) = supported - .into_iter() - .find(|v| matches!(v, PacketSpecificData::SupportedFunctions(_))) - else { - error!("got malformed message, disconnecting"); - return; - }; - - let Some(data) = packet.payload() else { - error!("got malformed message, disconnecting"); - return; - }; - - let Some((pid, data)) = crypto.new_connection(data) else { - error!("invalid login data"); - return; - }; - - let data = create_packet_from( - LiteHeader { - destination_port: header.source_port, - source_port: param.virtual_port.get_port_number(), - stream_types: StreamTypes::new( - param.virtual_port.get_stream_type(), - header.stream_types.source(), - ), - fragment_id: 0, - sequence_id: 0, - types_flags: TypesFlags::default().types(CONNECT).flags(ACK), - ..Default::default() - }, - &[ - PacketSpecificData::SupportedFunctions(s & 0xFF), - PacketSpecificData::ConnectionSignature([0; 16]), - ], - &data, - ); - websocket.send(Message::Binary(data.into())).await.ok(); - - let addr = PRUDPSockAddr::new( - addr, - VirtualPort::new(header.source_port, header.stream_types.source()), - ); - let Some(backend_conn) = new_backend_connection(¶m, addr, pid).await - else { - error!("unable to connect to backend"); - return; - }; - let mut connection = ConnectionState { - active: true, - addr, - pid, - backend_conn, - client_reliable_counter: 2, - server_reliable_counter: 1, - param, - incoming_reliable: HashMap::new(), - websocket, - }; - - connection.handle_connection().await; - break; - } - v => { - error!( - "invalid packet type for unconnected client {}, disconnecting", - v, - ); - } - } - } - v => { - error!("non binary message({:?}) , disconnecting", v); - return; - } - } - } -} - -pub async fn start_proxy(param: ProxyStartupParam) { - let param = Arc::new(param); - let crypto = Arc::new(C::new()); - let listener = TcpListener::bind(param.self_private) - .await - .expect("unable to bind to port"); - - while let Ok((connection, addr)) = listener.accept().await { - let param = param.clone(); - let crypto = crypto.clone(); - tokio::spawn(websocket_thread_unconnected( - param, crypto, connection, addr, - )); - } -} - -pub async fn start_secure(param: ProxyStartupParam) { - start_proxy::(param).await; -} - -pub async fn start_insecure(param: ProxyStartupParam) { - start_proxy::(param).await; -} diff --git a/prudplite/src/packet.rs b/prudplite/src/packet.rs deleted file mode 100644 index e75750b..0000000 --- a/prudplite/src/packet.rs +++ /dev/null @@ -1,222 +0,0 @@ -use std::{ - fmt::Debug, - io::{self, Cursor, Read, Write}, -}; - -use bytemuck::{Pod, Zeroable, bytes_of_mut}; -use rnex_core::prudp::types_flags::TypesFlags; -use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; - -#[derive(Pod, Zeroable, Copy, Clone, Default, Debug)] -#[repr(C)] -pub struct LiteHeader { - pub magic: u8, - pub packet_specific_length: u8, - pub payload_size: u16, - pub stream_types: StreamTypes, - pub source_port: u8, - pub destination_port: u8, - pub fragment_id: u8, - pub types_flags: TypesFlags, - pub sequence_id: u16, -} - -pub enum PacketSpecificData { - SupportedFunctions(u32), - ConnectionSignature([u8; 16]), - LiteSignature([u8; 16]), -} - -impl PacketSpecificData { - fn consume(reader: &mut impl Read) -> io::Result { - let mut option_id = 0u8; - reader.read_exact(bytes_of_mut(&mut option_id))?; - let mut size = 0u8; - reader.read_exact(bytes_of_mut(&mut size))?; - - match option_id { - 0 => { - if size != 4 { - Err(io::Error::other( - "invalid option size for supported functions", - )) - } else { - Ok(Self::SupportedFunctions(reader.read_le_u32()?)) - } - } - 1 => { - if size != 16 { - Err(io::Error::other( - "invalid option size for connection signature", - )) - } else { - Ok(Self::ConnectionSignature( - reader.read_struct(IS_BIG_ENDIAN)?, - )) - } - } - 0x80 => { - if size != 16 { - Err(io::Error::other("invalid option size for lite signature")) - } else { - Ok(Self::LiteSignature(reader.read_struct(IS_BIG_ENDIAN)?)) - } - } - _ => Err(io::Error::other("invalid option id")), - } - } - - fn write_size(&self) -> usize { - 2 + match self { - PacketSpecificData::SupportedFunctions(_) => 4, - Self::ConnectionSignature(_) => 16, - Self::LiteSignature(_) => 16, - } - } - - fn write_self(&self, writer: &mut impl Write) -> io::Result<()> { - match self { - PacketSpecificData::SupportedFunctions(v) => { - writer.write_all(&[0, 4])?; - writer.write_all(&v.to_le_bytes())?; - } - Self::ConnectionSignature(v) => { - writer.write_all(&[1, 16])?; - writer.write_all(&v[..])?; - } - Self::LiteSignature(v) => { - writer.write_all(&[0x80, 16])?; - writer.write_all(&v[..])?; - } - } - - Ok(()) - } -} - -pub struct LitePacket>(T); - -pub struct PacketSpecificIter<'a>(Cursor<&'a [u8]>); - -impl<'a> Iterator for PacketSpecificIter<'a> { - type Item = PacketSpecificData; - - fn next(&mut self) -> Option { - PacketSpecificData::consume(&mut self.0).ok() - } -} - -impl> LitePacket { - pub fn new(inner: T) -> Self { - Self(inner) - } - - pub fn header(&self) -> Option<&LiteHeader> { - bytemuck::try_from_bytes(self.0.as_ref().get(..size_of::())?).ok() - } - pub fn header_mut(&mut self) -> Option<&mut LiteHeader> - where - T: AsMut<[u8]>, - { - bytemuck::try_from_bytes_mut(self.0.as_mut().get_mut(..size_of::())?).ok() - } - - pub fn payload(&self) -> Option<&[u8]> { - let header = self.header()?; - self.0 - .as_ref() - .get(size_of::() + header.packet_specific_length as usize..) - } - - pub fn payload_mut(&mut self) -> Option<&mut [u8]> - where - T: AsMut<[u8]>, - { - let len = self.header()?.packet_specific_length; - self.0 - .as_mut() - .get_mut(size_of::() + len as usize..) - } - - pub fn packet_specific_raw(&self) -> Option<&[u8]> { - let header = self.header()?; - self.0.as_ref().get( - size_of::() - ..size_of::() + header.packet_specific_length as usize, - ) - } - pub fn packet_specific_raw_mut(&mut self) -> Option<&mut [u8]> - where - T: AsMut<[u8]>, - { - let len = self.header()?.packet_specific_length; - self.0 - .as_mut() - .get_mut(size_of::()..size_of::() + len as usize) - } - - pub fn packet_specific_iter<'a>(&'a self) -> Option> { - self.packet_specific_raw() - .map(Cursor::new) - .map(PacketSpecificIter) - } -} - -pub fn create_packet_from( - header: LiteHeader, - specific_data: &[PacketSpecificData], - data: &[u8], -) -> Vec { - let specific_size: usize = specific_data.iter().map(|v| v.write_size()).sum(); - let mut packet = LitePacket::new(vec![ - 0u8; - size_of::() + specific_size + data.len() - ]); - - *packet.header_mut().expect("packet malformed in creation") = LiteHeader { - magic: 0x80, - packet_specific_length: specific_size as u8, - payload_size: data.len() as u16, - ..header - }; - - let mut cursor = Cursor::new( - packet - .packet_specific_raw_mut() - .expect("packet malformed in creation"), - ); - - for specific in specific_data { - specific.write_self(&mut cursor).unwrap(); - } - - packet - .payload_mut() - .expect("packet malformed in creation") - .copy_from_slice(data); - - packet.0 -} - -#[derive(Pod, Zeroable, Copy, Clone, Default)] -#[repr(transparent)] -pub struct StreamTypes(u8); - -impl Debug for StreamTypes { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "({},{})", self.source(), self.destination()) - } -} - -impl StreamTypes { - pub fn new(source_stream: u8, dest_stream: u8) -> Self { - Self((source_stream & 0xF << 4) & dest_stream & 0xF) - } - - pub fn source(&self) -> u8 { - self.0 >> 4 - } - pub fn destination(&self) -> u8 { - self.0 & 0xF - } -} diff --git a/prudpv0/Cargo.toml b/prudpv0/Cargo.toml index 447436d..4429315 100644 --- a/prudpv0/Cargo.toml +++ b/prudpv0/Cargo.toml @@ -3,13 +3,15 @@ name = "prudpv0" version = "0.1.0" edition = "2024" +[lints] +workspace = true + [dependencies] -rnex-core = { path = "../rnex-core", version = "0.1.1" } +rnex-prudp = { path = "../rnex-prudp" } tokio = { version = "1.47.0", features = ["full"] } bytemuck = { version = "1.23.1", features = ["derive"] } typenum = "1.18.0" rc4 = "0.1.0" -log = "0.4.25" cfg-if = "1.0.4" proxy-common = {path = "../proxy-common"} hmac = "0.12.1" diff --git a/prudpv1/Cargo.toml b/prudpv1/Cargo.toml index b8346bf..a56d739 100644 --- a/prudpv1/Cargo.toml +++ b/prudpv1/Cargo.toml @@ -3,7 +3,11 @@ name = "prudpv1" version = "0.1.0" edition = "2024" +[lints] +workspace = true + [dependencies] + bytemuck = { version = "1.23.1", features = ["derive"] } tokio = { version = "1.47.0", features = ["full"] } hmac = "0.12.1" @@ -11,11 +15,11 @@ md-5 = "^0.10.6" rc4 = "0.1.0" v-byte-helpers = { git = "https://github.com/RusticMaple/VByteMacros", version = "0.1.1" } thiserror = "2.0.12" -log = "0.4.27" async-trait = "0.1.88" typenum = "1.18.0" once_cell = "1.21.3" -rnex-core = { path = "../rnex-core", version = "0.1.1" } +rnex-prudp = { path = "../rnex-prudp" } +rnex-util = { path = "../rnex-util" } proxy-common = {path = "../proxy-common"} cfg-if = "1.0.4" diff --git a/prudpv1/src/prudp/router.rs b/prudpv1/src/prudp/router.rs index 3d09123..180d90e 100644 --- a/prudpv1/src/prudp/router.rs +++ b/prudpv1/src/prudp/router.rs @@ -2,7 +2,6 @@ use crate::prudp::packet::PRUDPV1Packet; use crate::prudp::router::Error::VirtualPortTaken; use crate::prudp::socket::{AnyInternalSocket, CryptoHandler, ExternalSocket, new_socket_pair}; use log::{error, info}; -use rnex_core::prudp::virtual_port::VirtualPort; use std::io; use std::io::Cursor; use std::marker::PhantomData; diff --git a/prudpv1/src/prudp/secure.rs b/prudpv1/src/prudp/secure.rs index 2618b74..001680f 100644 --- a/prudpv1/src/prudp/secure.rs +++ b/prudpv1/src/prudp/secure.rs @@ -3,11 +3,6 @@ use crate::prudp::socket::{CryptoHandler, CryptoHandlerConnectionInstance}; use hmac::digest::consts::U32; use rc4::cipher::StreamCipherCoreWrapper; use rc4::{KeyInit, Rc4, Rc4Core, StreamCipher}; -use rnex_core::PID; -use rnex_core::nex::account::Account; -use rnex_core::prudp::encryption::EncryptionPair; -use rnex_core::prudp::ticket::read_secure_connection_data; -use rnex_core::rmc::structures::RmcSerialize; use typenum::U5; type Rc4U32 = StreamCipherCoreWrapper>; diff --git a/prudpv1/src/prudp/socket.rs b/prudpv1/src/prudp/socket.rs index 57f4ce4..b6def61 100644 --- a/prudpv1/src/prudp/socket.rs +++ b/prudpv1/src/prudp/socket.rs @@ -6,12 +6,6 @@ use async_trait::async_trait; use log::error; use log::{info, warn}; use rc4::StreamCipher; -use rnex_core::PID; -use rnex_core::prudp::socket_addr::PRUDPSockAddr; -use rnex_core::prudp::types_flags::TypesFlags; -use rnex_core::prudp::types_flags::flags::{ACK, HAS_SIZE, MULTI_ACK, NEED_ACK, RELIABLE}; -use rnex_core::prudp::types_flags::types::{CONNECT, DATA, DISCONNECT, PING, SYN}; -use rnex_core::prudp::virtual_port::VirtualPort; use std::collections::{BTreeMap, HashMap}; use std::io::Cursor; use std::marker::PhantomData; diff --git a/prudpv1/src/prudp/unsecure.rs b/prudpv1/src/prudp/unsecure.rs index f9a566a..939bfea 100644 --- a/prudpv1/src/prudp/unsecure.rs +++ b/prudpv1/src/prudp/unsecure.rs @@ -1,14 +1,14 @@ use crate::prudp::packet::PRUDPV1Packet; use crate::prudp::socket::{CryptoHandler, CryptoHandlerConnectionInstance}; use rc4::{KeyInit, Rc4, StreamCipher}; -use rnex_core::prudp::encryption::{DEFAULT_KEY, EncryptionPair}; +use rnex_prudp::encryption::{DEFAULT_KEY, EncryptionPair}; use typenum::U5; pub struct Unsecure(pub &'static str); pub struct UnsecureInstance { key: &'static str, - streams: Vec>>, + streams: Vec>, self_signature: [u8; 16], #[allow(dead_code)] remote_signature: [u8; 16], @@ -32,7 +32,11 @@ impl CryptoHandler for Unsecure { Vec::new(), UnsecureInstance { streams: (0..substream_count) - .map(|_| EncryptionPair::init_both(|| Rc4::new(&DEFAULT_KEY))) + .map(|_| { + EncryptionPair::init_both(|| { + Rc4::new_from_slice(DEFAULT_KEY).expect("invalid key length") + }) + }) .collect(), key: self.0, remote_signature, diff --git a/rnex-core/.sqlx/query-15b108cbdaaf3ebb99254330fdcf31c7038239be4c9e88e76653d36482f74379.json b/rnex-core-deprecated/.sqlx/query-15b108cbdaaf3ebb99254330fdcf31c7038239be4c9e88e76653d36482f74379.json similarity index 100% rename from rnex-core/.sqlx/query-15b108cbdaaf3ebb99254330fdcf31c7038239be4c9e88e76653d36482f74379.json rename to rnex-core-deprecated/.sqlx/query-15b108cbdaaf3ebb99254330fdcf31c7038239be4c9e88e76653d36482f74379.json diff --git a/rnex-core/.sqlx/query-164708b549c483a041d2e54065ed3ffbd9f8d5304f6aa6d785dbddbb1626c0e9.json b/rnex-core-deprecated/.sqlx/query-164708b549c483a041d2e54065ed3ffbd9f8d5304f6aa6d785dbddbb1626c0e9.json similarity index 100% rename from rnex-core/.sqlx/query-164708b549c483a041d2e54065ed3ffbd9f8d5304f6aa6d785dbddbb1626c0e9.json rename to rnex-core-deprecated/.sqlx/query-164708b549c483a041d2e54065ed3ffbd9f8d5304f6aa6d785dbddbb1626c0e9.json diff --git a/rnex-core/.sqlx/query-1c2be699b4bfc7e5e6d3a74d7badf67d1812b99e1ec952a044fc03e1a5c63703.json b/rnex-core-deprecated/.sqlx/query-1c2be699b4bfc7e5e6d3a74d7badf67d1812b99e1ec952a044fc03e1a5c63703.json similarity index 100% rename from rnex-core/.sqlx/query-1c2be699b4bfc7e5e6d3a74d7badf67d1812b99e1ec952a044fc03e1a5c63703.json rename to rnex-core-deprecated/.sqlx/query-1c2be699b4bfc7e5e6d3a74d7badf67d1812b99e1ec952a044fc03e1a5c63703.json diff --git a/rnex-core/.sqlx/query-219fec3fc852f36de99e5f00ca7a1675439bb44c91158f8b8a696e326c45447c.json b/rnex-core-deprecated/.sqlx/query-219fec3fc852f36de99e5f00ca7a1675439bb44c91158f8b8a696e326c45447c.json similarity index 100% rename from rnex-core/.sqlx/query-219fec3fc852f36de99e5f00ca7a1675439bb44c91158f8b8a696e326c45447c.json rename to rnex-core-deprecated/.sqlx/query-219fec3fc852f36de99e5f00ca7a1675439bb44c91158f8b8a696e326c45447c.json diff --git a/rnex-core/.sqlx/query-29d4f5c07b36c3d3b6b54a86a1757f27247530878b7f82feeb65802d995a38c4.json b/rnex-core-deprecated/.sqlx/query-29d4f5c07b36c3d3b6b54a86a1757f27247530878b7f82feeb65802d995a38c4.json similarity index 100% rename from rnex-core/.sqlx/query-29d4f5c07b36c3d3b6b54a86a1757f27247530878b7f82feeb65802d995a38c4.json rename to rnex-core-deprecated/.sqlx/query-29d4f5c07b36c3d3b6b54a86a1757f27247530878b7f82feeb65802d995a38c4.json diff --git a/rnex-core/.sqlx/query-2c8f6740e719d786ed05d2d9cdb29a786ff7b34579938258b73504f7971b3849.json b/rnex-core-deprecated/.sqlx/query-2c8f6740e719d786ed05d2d9cdb29a786ff7b34579938258b73504f7971b3849.json similarity index 100% rename from rnex-core/.sqlx/query-2c8f6740e719d786ed05d2d9cdb29a786ff7b34579938258b73504f7971b3849.json rename to rnex-core-deprecated/.sqlx/query-2c8f6740e719d786ed05d2d9cdb29a786ff7b34579938258b73504f7971b3849.json diff --git a/rnex-core/.sqlx/query-2d025ae36b11518c43a0531c58f58e6c97c3f4726bae21e0cfaa8cc0ff218692.json b/rnex-core-deprecated/.sqlx/query-2d025ae36b11518c43a0531c58f58e6c97c3f4726bae21e0cfaa8cc0ff218692.json similarity index 100% rename from rnex-core/.sqlx/query-2d025ae36b11518c43a0531c58f58e6c97c3f4726bae21e0cfaa8cc0ff218692.json rename to rnex-core-deprecated/.sqlx/query-2d025ae36b11518c43a0531c58f58e6c97c3f4726bae21e0cfaa8cc0ff218692.json diff --git a/rnex-core/.sqlx/query-2ff34379bbc32276c3b78ef1283b8158ea907d36588e1e59f6cbe752d89361bb.json b/rnex-core-deprecated/.sqlx/query-2ff34379bbc32276c3b78ef1283b8158ea907d36588e1e59f6cbe752d89361bb.json similarity index 100% rename from rnex-core/.sqlx/query-2ff34379bbc32276c3b78ef1283b8158ea907d36588e1e59f6cbe752d89361bb.json rename to rnex-core-deprecated/.sqlx/query-2ff34379bbc32276c3b78ef1283b8158ea907d36588e1e59f6cbe752d89361bb.json diff --git a/rnex-core/.sqlx/query-31e36bb378bcf8e665391d9cd2c5282fea9540a0673456d58f8142cafc330240.json b/rnex-core-deprecated/.sqlx/query-31e36bb378bcf8e665391d9cd2c5282fea9540a0673456d58f8142cafc330240.json similarity index 100% rename from rnex-core/.sqlx/query-31e36bb378bcf8e665391d9cd2c5282fea9540a0673456d58f8142cafc330240.json rename to rnex-core-deprecated/.sqlx/query-31e36bb378bcf8e665391d9cd2c5282fea9540a0673456d58f8142cafc330240.json diff --git a/rnex-core/.sqlx/query-37d449b81e2aa3abdbdaf38587ae1a6a6c5c38acb06d91c5b0924c3f0a5d2e92.json b/rnex-core-deprecated/.sqlx/query-37d449b81e2aa3abdbdaf38587ae1a6a6c5c38acb06d91c5b0924c3f0a5d2e92.json similarity index 100% rename from rnex-core/.sqlx/query-37d449b81e2aa3abdbdaf38587ae1a6a6c5c38acb06d91c5b0924c3f0a5d2e92.json rename to rnex-core-deprecated/.sqlx/query-37d449b81e2aa3abdbdaf38587ae1a6a6c5c38acb06d91c5b0924c3f0a5d2e92.json diff --git a/rnex-core/.sqlx/query-3d06238fddc72d1ba452602e1a8002e9186ce1dfc6c68b52d9d2a8a38f5c3a1f.json b/rnex-core-deprecated/.sqlx/query-3d06238fddc72d1ba452602e1a8002e9186ce1dfc6c68b52d9d2a8a38f5c3a1f.json similarity index 100% rename from rnex-core/.sqlx/query-3d06238fddc72d1ba452602e1a8002e9186ce1dfc6c68b52d9d2a8a38f5c3a1f.json rename to rnex-core-deprecated/.sqlx/query-3d06238fddc72d1ba452602e1a8002e9186ce1dfc6c68b52d9d2a8a38f5c3a1f.json diff --git a/rnex-core/.sqlx/query-433b8cbd7320b5463391b08545c09b11255b363112c3379319b9e69ed003f2eb.json b/rnex-core-deprecated/.sqlx/query-433b8cbd7320b5463391b08545c09b11255b363112c3379319b9e69ed003f2eb.json similarity index 100% rename from rnex-core/.sqlx/query-433b8cbd7320b5463391b08545c09b11255b363112c3379319b9e69ed003f2eb.json rename to rnex-core-deprecated/.sqlx/query-433b8cbd7320b5463391b08545c09b11255b363112c3379319b9e69ed003f2eb.json diff --git a/rnex-core/.sqlx/query-502f3f0fbb3739ddcffa2938680b2399e0b204b25631e14cac0d61fcff8e29c3.json b/rnex-core-deprecated/.sqlx/query-502f3f0fbb3739ddcffa2938680b2399e0b204b25631e14cac0d61fcff8e29c3.json similarity index 100% rename from rnex-core/.sqlx/query-502f3f0fbb3739ddcffa2938680b2399e0b204b25631e14cac0d61fcff8e29c3.json rename to rnex-core-deprecated/.sqlx/query-502f3f0fbb3739ddcffa2938680b2399e0b204b25631e14cac0d61fcff8e29c3.json diff --git a/rnex-core/.sqlx/query-555c438210f49e3a8fd279bf3d493cfdef21c64fd31d1b2bd7a7605f97d550ee.json b/rnex-core-deprecated/.sqlx/query-555c438210f49e3a8fd279bf3d493cfdef21c64fd31d1b2bd7a7605f97d550ee.json similarity index 100% rename from rnex-core/.sqlx/query-555c438210f49e3a8fd279bf3d493cfdef21c64fd31d1b2bd7a7605f97d550ee.json rename to rnex-core-deprecated/.sqlx/query-555c438210f49e3a8fd279bf3d493cfdef21c64fd31d1b2bd7a7605f97d550ee.json diff --git a/rnex-core/.sqlx/query-5cea63e5c1d279af23ef56d7ba02f49ac8c4cb5668559a92daebea815a2d64ec.json b/rnex-core-deprecated/.sqlx/query-5cea63e5c1d279af23ef56d7ba02f49ac8c4cb5668559a92daebea815a2d64ec.json similarity index 100% rename from rnex-core/.sqlx/query-5cea63e5c1d279af23ef56d7ba02f49ac8c4cb5668559a92daebea815a2d64ec.json rename to rnex-core-deprecated/.sqlx/query-5cea63e5c1d279af23ef56d7ba02f49ac8c4cb5668559a92daebea815a2d64ec.json diff --git a/rnex-core/.sqlx/query-720b2a71163a0d3907e847d874cf230267f8241bcc261ca968d143d4ab6b5ab8.json b/rnex-core-deprecated/.sqlx/query-720b2a71163a0d3907e847d874cf230267f8241bcc261ca968d143d4ab6b5ab8.json similarity index 100% rename from rnex-core/.sqlx/query-720b2a71163a0d3907e847d874cf230267f8241bcc261ca968d143d4ab6b5ab8.json rename to rnex-core-deprecated/.sqlx/query-720b2a71163a0d3907e847d874cf230267f8241bcc261ca968d143d4ab6b5ab8.json diff --git a/rnex-core/.sqlx/query-744047264f63b5eac396d8c0606824f43eb87c2739404d423b2d94bb727ed1c9.json b/rnex-core-deprecated/.sqlx/query-744047264f63b5eac396d8c0606824f43eb87c2739404d423b2d94bb727ed1c9.json similarity index 100% rename from rnex-core/.sqlx/query-744047264f63b5eac396d8c0606824f43eb87c2739404d423b2d94bb727ed1c9.json rename to rnex-core-deprecated/.sqlx/query-744047264f63b5eac396d8c0606824f43eb87c2739404d423b2d94bb727ed1c9.json diff --git a/rnex-core/.sqlx/query-75f4e823a82add9c1608a43a0dff6633db4cd635037622fd61d7a3a6a872db2e.json b/rnex-core-deprecated/.sqlx/query-75f4e823a82add9c1608a43a0dff6633db4cd635037622fd61d7a3a6a872db2e.json similarity index 100% rename from rnex-core/.sqlx/query-75f4e823a82add9c1608a43a0dff6633db4cd635037622fd61d7a3a6a872db2e.json rename to rnex-core-deprecated/.sqlx/query-75f4e823a82add9c1608a43a0dff6633db4cd635037622fd61d7a3a6a872db2e.json diff --git a/rnex-core/.sqlx/query-8605011b998a4608c739bf5ab388a7a9bf551126712c1d1089a4263453090e79.json b/rnex-core-deprecated/.sqlx/query-8605011b998a4608c739bf5ab388a7a9bf551126712c1d1089a4263453090e79.json similarity index 100% rename from rnex-core/.sqlx/query-8605011b998a4608c739bf5ab388a7a9bf551126712c1d1089a4263453090e79.json rename to rnex-core-deprecated/.sqlx/query-8605011b998a4608c739bf5ab388a7a9bf551126712c1d1089a4263453090e79.json diff --git a/rnex-core/.sqlx/query-8706ac06d78ffaa2a45418be7ae71340561031d8e5c91f46c041f83e54c31a7d.json b/rnex-core-deprecated/.sqlx/query-8706ac06d78ffaa2a45418be7ae71340561031d8e5c91f46c041f83e54c31a7d.json similarity index 100% rename from rnex-core/.sqlx/query-8706ac06d78ffaa2a45418be7ae71340561031d8e5c91f46c041f83e54c31a7d.json rename to rnex-core-deprecated/.sqlx/query-8706ac06d78ffaa2a45418be7ae71340561031d8e5c91f46c041f83e54c31a7d.json diff --git a/rnex-core/.sqlx/query-8df96ce41787673f9fd03aadf142f3a77f61ff0d3fbe54cf34e967fbb852cbb8.json b/rnex-core-deprecated/.sqlx/query-8df96ce41787673f9fd03aadf142f3a77f61ff0d3fbe54cf34e967fbb852cbb8.json similarity index 100% rename from rnex-core/.sqlx/query-8df96ce41787673f9fd03aadf142f3a77f61ff0d3fbe54cf34e967fbb852cbb8.json rename to rnex-core-deprecated/.sqlx/query-8df96ce41787673f9fd03aadf142f3a77f61ff0d3fbe54cf34e967fbb852cbb8.json diff --git a/rnex-core/.sqlx/query-93be6b6b0ac5d85881e6e223a7d48f5eb4a3761dd71129ba6939cdd0d62569fb.json b/rnex-core-deprecated/.sqlx/query-93be6b6b0ac5d85881e6e223a7d48f5eb4a3761dd71129ba6939cdd0d62569fb.json similarity index 100% rename from rnex-core/.sqlx/query-93be6b6b0ac5d85881e6e223a7d48f5eb4a3761dd71129ba6939cdd0d62569fb.json rename to rnex-core-deprecated/.sqlx/query-93be6b6b0ac5d85881e6e223a7d48f5eb4a3761dd71129ba6939cdd0d62569fb.json diff --git a/rnex-core/.sqlx/query-c27439038dc25c17738b4a9cc37f94f83f23239a0c37c7adbccaef571e0128da.json b/rnex-core-deprecated/.sqlx/query-c27439038dc25c17738b4a9cc37f94f83f23239a0c37c7adbccaef571e0128da.json similarity index 100% rename from rnex-core/.sqlx/query-c27439038dc25c17738b4a9cc37f94f83f23239a0c37c7adbccaef571e0128da.json rename to rnex-core-deprecated/.sqlx/query-c27439038dc25c17738b4a9cc37f94f83f23239a0c37c7adbccaef571e0128da.json diff --git a/rnex-core/.sqlx/query-daac203a168b0aab9550176524d0741da291e8861fd7c6ac4838d7fe20a871f8.json b/rnex-core-deprecated/.sqlx/query-daac203a168b0aab9550176524d0741da291e8861fd7c6ac4838d7fe20a871f8.json similarity index 100% rename from rnex-core/.sqlx/query-daac203a168b0aab9550176524d0741da291e8861fd7c6ac4838d7fe20a871f8.json rename to rnex-core-deprecated/.sqlx/query-daac203a168b0aab9550176524d0741da291e8861fd7c6ac4838d7fe20a871f8.json diff --git a/rnex-core/.sqlx/query-e28d8776cc49b55fe76cf33ac12fe18e500d243f1b55fd18e7d96d281605bcf9.json b/rnex-core-deprecated/.sqlx/query-e28d8776cc49b55fe76cf33ac12fe18e500d243f1b55fd18e7d96d281605bcf9.json similarity index 100% rename from rnex-core/.sqlx/query-e28d8776cc49b55fe76cf33ac12fe18e500d243f1b55fd18e7d96d281605bcf9.json rename to rnex-core-deprecated/.sqlx/query-e28d8776cc49b55fe76cf33ac12fe18e500d243f1b55fd18e7d96d281605bcf9.json diff --git a/rnex-core/.sqlx/query-efe4bf3602782a0d521274956e0fcecccf8f0f8dd20d890a76acf85265b2192c.json b/rnex-core-deprecated/.sqlx/query-efe4bf3602782a0d521274956e0fcecccf8f0f8dd20d890a76acf85265b2192c.json similarity index 100% rename from rnex-core/.sqlx/query-efe4bf3602782a0d521274956e0fcecccf8f0f8dd20d890a76acf85265b2192c.json rename to rnex-core-deprecated/.sqlx/query-efe4bf3602782a0d521274956e0fcecccf8f0f8dd20d890a76acf85265b2192c.json diff --git a/rnex-core/.sqlx/query-f66ad3f63457ee6b256d909dbbe9269ec6b63387a44b9beaa0da2e11c73d2680.json b/rnex-core-deprecated/.sqlx/query-f66ad3f63457ee6b256d909dbbe9269ec6b63387a44b9beaa0da2e11c73d2680.json similarity index 100% rename from rnex-core/.sqlx/query-f66ad3f63457ee6b256d909dbbe9269ec6b63387a44b9beaa0da2e11c73d2680.json rename to rnex-core-deprecated/.sqlx/query-f66ad3f63457ee6b256d909dbbe9269ec6b63387a44b9beaa0da2e11c73d2680.json diff --git a/rnex-core/.sqlx/query-f7c6fdbd098c8c6f3e5520794c115a39af3e23d1acd523118088cf6f1b9dab92.json b/rnex-core-deprecated/.sqlx/query-f7c6fdbd098c8c6f3e5520794c115a39af3e23d1acd523118088cf6f1b9dab92.json similarity index 100% rename from rnex-core/.sqlx/query-f7c6fdbd098c8c6f3e5520794c115a39af3e23d1acd523118088cf6f1b9dab92.json rename to rnex-core-deprecated/.sqlx/query-f7c6fdbd098c8c6f3e5520794c115a39af3e23d1acd523118088cf6f1b9dab92.json diff --git a/rnex-core/Cargo.toml b/rnex-core-deprecated/Cargo.toml similarity index 93% rename from rnex-core/Cargo.toml rename to rnex-core-deprecated/Cargo.toml index c4cd3aa..2545c9b 100644 --- a/rnex-core/Cargo.toml +++ b/rnex-core-deprecated/Cargo.toml @@ -3,16 +3,16 @@ name = "rnex-core" version = "0.1.1" edition = "2024" +[lints] +workspace = true + [dependencies] bytemuck = { version = "1.21.0", features = ["derive"] } dotenv = "0.15.0" -once_cell = "1.20.2" rc4 = "0.1.0" thiserror = "2.0.11" v-byte-helpers = { git = "https://github.com/RusticMaple/VByteMacros", version = "0.1.1" } -simplelog = "0.12.2" chrono = "0.4.39" -log = "0.4.25" rand = "0.10.0" cfg-if = "1.0.4" hmac = "0.12.1" @@ -20,7 +20,7 @@ md-5 = "^0.10.6" tokio = { version = "1.43.0", features = ["full"] } hex = "0.4.3" -macros = { path = "../macros" } +rnex-rmc = { path = "../rnex-rmc" } paste = "1.0.15" typenum = "1.18.0" json = "0.12.4" @@ -39,7 +39,7 @@ async-trait = "0.1.89" ctor = "1.0.7" nex-account = { version = "0.2.1", registry = "spbr" } tonic = "0.14.6" -tracing = { version = "0.1.44", features = ["log"] } +tracing = { version = "0.1.44" } tracing-subscriber = "0.3.23" sentry-tracing = "0.48.4" sentry = { version = "0.48.4", features = ["tracing"] } @@ -52,8 +52,8 @@ rmc_struct_header = [] guest_login = [] friends = ["guest_login", "database-support"] big_pid = [] -v3-3-2 = [] third-notif-param = [] +v3-3-2 = [] v3-4-0 = ["v3-3-2", "third-notif-param", "rmc_struct_header"] v3-5-0 = ["v3-4-0"] v3-8-15 = ["v3-5-0"] diff --git a/rnex-core/benches/rmc_serialization.rs b/rnex-core-deprecated/benches/rmc_serialization.rs similarity index 100% rename from rnex-core/benches/rmc_serialization.rs rename to rnex-core-deprecated/benches/rmc_serialization.rs diff --git a/rnex-core/src/executables/backend_server_insecure.rs b/rnex-core-deprecated/src/executables/backend_server_insecure.rs similarity index 100% rename from rnex-core/src/executables/backend_server_insecure.rs rename to rnex-core-deprecated/src/executables/backend_server_insecure.rs diff --git a/rnex-core/src/executables/backend_server_secure.rs b/rnex-core-deprecated/src/executables/backend_server_secure.rs similarity index 100% rename from rnex-core/src/executables/backend_server_secure.rs rename to rnex-core-deprecated/src/executables/backend_server_secure.rs diff --git a/rnex-core/src/executables/common.rs b/rnex-core-deprecated/src/executables/common.rs similarity index 88% rename from rnex-core/src/executables/common.rs rename to rnex-core-deprecated/src/executables/common.rs index 1f96446..2cfe351 100644 --- a/rnex-core/src/executables/common.rs +++ b/rnex-core-deprecated/src/executables/common.rs @@ -1,7 +1,5 @@ use crate::reggie::UnitPacketRead; use cfg_if::cfg_if; -use log::error; -use once_cell::sync::Lazy; use rnex_core::nex::account::Account; use rnex_core::rmc::protocols::{RmcCallable, RmcConnection, new_rmc_gateway_connection}; use rnex_core::rmc::structures::RmcSerialize; @@ -13,6 +11,7 @@ use std::io::{Cursor, Read, Write}; use std::net::{Ipv4Addr, SocketAddrV4, TcpStream}; use std::sync::Arc; use tokio::net::TcpListener; +use tracing::error; const IP_REQ_SERVICE_URLS: &[(&str, &str, &str)] = &[ ("ipinfo.io:80", "ipinfo.io", "/ip"), @@ -70,12 +69,12 @@ pub fn try_get_ip() -> Option { let mut stream = TcpStream::connect(url.0)?; stream.write_all( format!( - r#"GET {} HTTP/1.0 + "GET {} HTTP/1.0 Host: {} User-Agent: RNEX Accept: */* -"#, +", url.2, url.1 ) .as_str() @@ -95,37 +94,37 @@ Accept: */* None } -pub static OWN_IP_PRIVATE: Lazy = Lazy::new(|| { +pub static OWN_IP_PRIVATE: LazyLock = LazyLock::new(|| { env::var("SERVER_IP") .ok() .map(|s| s.parse().expect("invalid ip address")) .unwrap_or(Ipv4Addr::UNSPECIFIED) }); -pub static OWN_IP_PUBLIC: Lazy = Lazy::new(|| { +pub static OWN_IP_PUBLIC: LazyLock = LazyLock::new(|| { env::var("SERVER_IP_PUBLIC") .ok() .map(|s| s.parse().expect("invalid ip address")) .unwrap_or_else(|| try_get_ip().unwrap()) }); -pub static SERVER_PORT: Lazy = Lazy::new(|| { +pub static SERVER_PORT: LazyLock = LazyLock::new(|| { env::var("SERVER_PORT") .ok() .and_then(|s| s.parse().ok()) .unwrap_or(10000) }); -pub static KERBEROS_SERVER_PASSWORD: Lazy = Lazy::new(|| { +pub static KERBEROS_SERVER_PASSWORD: LazyLock = LazyLock::new(|| { env::var("AUTH_SERVER_PASSWORD") .ok() .unwrap_or("password".to_owned()) }); -pub static AUTH_SERVER_ACCOUNT: Lazy = - Lazy::new(|| Account::new(1, "Quazal Authentication", &KERBEROS_SERVER_PASSWORD)); -pub static SECURE_SERVER_ACCOUNT: Lazy = - Lazy::new(|| Account::new(2, "Quazal Rendez-Vous", &KERBEROS_SERVER_PASSWORD)); +pub static AUTH_SERVER_ACCOUNT: LazyLock = + LazyLock::new(|| Account::new(1, "Quazal Authentication", &KERBEROS_SERVER_PASSWORD)); +pub static SECURE_SERVER_ACCOUNT: LazyLock = + LazyLock::new(|| Account::new(2, "Quazal Rendez-Vous", &KERBEROS_SERVER_PASSWORD)); pub async fn new_simple_backend(mut creation_function: F) where diff --git a/rnex-core/src/executables/edge_node_holder_server.rs b/rnex-core-deprecated/src/executables/edge_node_holder_server.rs similarity index 100% rename from rnex-core/src/executables/edge_node_holder_server.rs rename to rnex-core-deprecated/src/executables/edge_node_holder_server.rs diff --git a/rnex-core/src/executables/friends_backend.rs b/rnex-core-deprecated/src/executables/friends_backend.rs similarity index 99% rename from rnex-core/src/executables/friends_backend.rs rename to rnex-core-deprecated/src/executables/friends_backend.rs index 58a6e7d..11bf3b9 100644 --- a/rnex-core/src/executables/friends_backend.rs +++ b/rnex-core-deprecated/src/executables/friends_backend.rs @@ -4,8 +4,8 @@ use std::{ sync::{Arc, atomic::AtomicU32}, }; -use log::error; use tokio::net::TcpListener; +use tracing::error; use crate::{ executables::common::{OWN_IP_PRIVATE, SERVER_PORT}, diff --git a/rnex-core/src/executables/mod.rs b/rnex-core-deprecated/src/executables/mod.rs similarity index 100% rename from rnex-core/src/executables/mod.rs rename to rnex-core-deprecated/src/executables/mod.rs diff --git a/rnex-core/src/executables/regular_backend.rs b/rnex-core-deprecated/src/executables/regular_backend.rs similarity index 100% rename from rnex-core/src/executables/regular_backend.rs rename to rnex-core-deprecated/src/executables/regular_backend.rs diff --git a/rnex-core/src/lib.rs b/rnex-core-deprecated/src/lib.rs similarity index 76% rename from rnex-core/src/lib.rs rename to rnex-core-deprecated/src/lib.rs index c382964..89dcfb7 100644 --- a/rnex-core/src/lib.rs +++ b/rnex-core-deprecated/src/lib.rs @@ -11,8 +11,6 @@ pub type PID = i32; pub use ctor::ctor; -extern crate self as rnex_core; - pub mod prudp; pub mod rmc; //mod protocols; @@ -23,12 +21,6 @@ pub mod grpc; pub mod kerberos; pub mod nex; pub mod reggie; -pub mod result; pub mod rnex_proxy_common; pub mod util; pub mod versions; -pub use macros::*; - -pub mod config { - pub const FEATURE_HAS_STRUCT_HEADER: bool = cfg!(feature = "rmc_struct_header"); -} diff --git a/rnex-core/src/nex/common.rs b/rnex-core-deprecated/src/nex/common.rs similarity index 81% rename from rnex-core/src/nex/common.rs rename to rnex-core-deprecated/src/nex/common.rs index 19fce1b..75e2000 100644 --- a/rnex-core/src/nex/common.rs +++ b/rnex-core-deprecated/src/nex/common.rs @@ -23,10 +23,10 @@ pub async fn get_station_urls( for station in station_urls { let is_public = station.options.iter().any(|v| { - if let NatType(v) = v { - if *v & PUBLIC != 0 { - return true; - } + if let NatType(v) = v + && *v & PUBLIC != 0 + { + return true; } false }); @@ -63,14 +63,16 @@ pub async fn get_station_urls( } else { let mut public_station = private_station.clone(); - public_station.options.retain(|v| match v { - Address(_) | Port(_) | NatFiltering(_) | NatMapping(_) | NatType(_) => false, - _ => true, + public_station.options.retain(|v| { + !matches!( + v, + Address(_) | Port(_) | NatFiltering(_) | NatMapping(_) | NatType(_) + ) }); public_station .options - .push(Address(addr.regular_socket_addr.ip().clone())); + .push(Address(addr.regular_socket_addr.ip())); public_station .options .push(Port(addr.regular_socket_addr.port())); @@ -84,10 +86,9 @@ pub async fn get_station_urls( let both = [&mut public_station, &mut private_station]; for station in both { - station.options.retain(|v| match v { - PrincipalID(_) | RVConnectionID(_) => false, - _ => true, - }); + station + .options + .retain(|v| !matches!(v, PrincipalID(_) | RVConnectionID(_))); station.options.push(PrincipalID(pid)); station.options.push(RVConnectionID(cid)); @@ -96,3 +97,7 @@ pub async fn get_station_urls( Ok(vec![public_station]) } + +#[track_caller] +#[cfg(feature = "database-support")] +fn test() {} diff --git a/rnex-core/src/nex/datastore.rs b/rnex-core-deprecated/src/nex/datastore.rs similarity index 94% rename from rnex-core/src/nex/datastore.rs rename to rnex-core-deprecated/src/nex/datastore.rs index 7d0d7cd..6a095a3 100644 --- a/rnex-core/src/nex/datastore.rs +++ b/rnex-core-deprecated/src/nex/datastore.rs @@ -1,5 +1,5 @@ -use std::convert; -use chrono::{NaiveDateTime, Utc}; +use crate::rmc::protocols::datastore::DataStoreGetCustomRankingParam; +use chrono::Utc; use futures::TryStreamExt; use futures::future::join_all; use rnex_core::PID; @@ -15,16 +15,17 @@ use rnex_core::rmc::protocols::datastore::{ }; use rnex_core::rmc::protocols::datastore::{ BufferQueueParam, CompletePostParam, DataStoreChangeMetaParam, DataStoreCustomRankingResult, - DataStoreGetCustomRankingByDataIDParam, DataStorePrepareGetParam, DataStoreReqGetInfo, - DataStoreSearchParam, GetMetaInfo, GetMetaParam, KeyValue, Permission, PersistenceTarget, - RateCustomRankingParam, RatingInfo, RatingInfoWithSlot, RatingInitParamWithSlot, DataStoreDeleteParam, DataStoreFileServerObjectInfo, DataStoreGetCourseRecordParam, - DataStoreGetCourseRecordResult, DataStoreReportCourseParam, DataStoreUploadCourseRecordParam + DataStoreGetCourseRecordResult, DataStoreGetCustomRankingByDataIDParam, + DataStorePrepareGetParam, DataStoreReportCourseParam, DataStoreReqGetInfo, + DataStoreSearchParam, DataStoreUploadCourseRecordParam, GetMetaInfo, GetMetaParam, KeyValue, + Permission, PersistenceTarget, RateCustomRankingParam, RatingInfo, RatingInfoWithSlot, + RatingInitParamWithSlot, }; use rnex_core::rmc::response::ErrorCode; use rnex_core::rmc::structures::qbuffer::QBuffer; use rnex_core::rmc::structures::qresult::QResult; -use crate::rmc::protocols::datastore::DataStoreGetCustomRankingParam; +use std::convert; fn map_row_to_meta_info( row_data_id: i64, @@ -324,7 +325,7 @@ fn filter_properties_by_result_option(meta_info: &mut GetMetaInfo, result_option async fn init_object_rating_slot(data_id: i64, rating_param: RatingInitParamWithSlot) { log::info!("running init object rating slot"); - let row = sqlx::query!( + sqlx::query!( r#" INSERT INTO datastore.object_ratings ( data_id, @@ -610,7 +611,7 @@ async fn rate_object( let rating = RatingInfo::default(); - let row = sqlx::query!( + sqlx::query!( r#" UPDATE datastore.object_ratings SET total_value=total_value+$1, count=count+1 @@ -690,7 +691,7 @@ async fn get_rating_with_slot_data_id(dataid: i64) -> Result vec![ - 0x00000001, - 0x00000032, - 0x00000096, - 0x0000012c, - 0x000001f4, - 0x00000320, - 0x00000514, - 0x000007d0, - 0x00000bb8, - 0x00001388, + 0x0000_0001, + 0x0000_0032, + 0x0000_0096, + 0x0000_012c, + 0x0000_01f4, + 0x0000_0320, + 0x0000_0514, + 0x0000_07d0, + 0x0000_0bb8, + 0x0000_1388, MAX_COURSE_UPLOADS, - 0x00000014, - 0x0000001e, - 0x00000028, - 0x00000032, - 0x0000003c, - 0x00000046, - 0x00000050, - 0x0000005a, - 0x00000064, - 0x00000023, - 0x0000004b, - 0x00000023, - 0x0000004b, - 0x00000032, - 0x00000000, - 0x00000003, - 0x00000003, - 0x00000064, - 0x00000006, - 0x00000001, - 0x00000060, - 0x00000005, - 0x00000060, - 0x00000000, - 0x000007e4, - 0x00000001, - 0x00000001, - 0x0000000c, - 0x00000000, + 0x0000_0014, + 0x0000_001e, + 0x0000_0028, + 0x0000_0032, + 0x0000_003c, + 0x0000_0046, + 0x0000_0050, + 0x0000_005a, + 0x0000_0064, + 0x0000_0023, + 0x0000_004b, + 0x0000_0023, + 0x0000_004b, + 0x0000_0032, + 0x0000_0000, + 0x0000_0003, + 0x0000_0003, + 0x0000_0064, + 0x0000_0006, + 0x0000_0001, + 0x0000_0060, + 0x0000_0005, + 0x0000_0060, + 0x0000_0000, + 0x0000_07e4, + 0x0000_0001, + 0x0000_0001, + 0x0000_000c, + 0x0000_0000, ], 1 => vec![ - 2, 1770179696, 1770179664, 1770179640, 1770180827, 1770180777, 1770180745, - 1770177625, 1770177590, + 2, + 1_770_179_696, + 1_770_179_664, + 1_770_179_640, + 1_770_180_827, + 1_770_180_777, + 1_770_180_745, + 1_770_177_625, + 1_770_177_590, + ], + 2 => vec![ + 0x0000_07df, + 0x0000_000c, + 0x0000_0016, + 0x0000_0005, + 0x0000_0000, ], - 2 => vec![0x000007df, 0x0000000c, 0x00000016, 0x00000005, 0x00000000], 10 => vec![35, 75, 96, 40, 5, 6], _ => { log::error!("unknown SMM app id: {}", appid); @@ -1489,7 +1503,7 @@ impl DataStore for User { .map(KerberosDateTime::from_naive) .unwrap_or_default(); - let mut meta_info = GetMetaInfo { + let meta_info = GetMetaInfo { dataid: row.data_id, owner: row.owner.unwrap_or(0), size: row.size.unwrap_or(0) as u32, @@ -1529,7 +1543,7 @@ impl DataStore for User { ) -> Result<(), ErrorCode> { let now = Utc::now().naive_utc(); - let row = sqlx::query!( + sqlx::query!( r#" INSERT INTO datastore.course_records ( data_id, @@ -1667,12 +1681,18 @@ impl DataStore for User { &self, application_id: u32, ) -> Result { - // official servers always return true? application ID is always 0 as far as i know. maybe a check is warranted for the app id? - Ok(true) + if application_id == 0 { + Ok(true) + } else { + Err(ErrorCode::Core_Unknown) + } } - async fn report_course(&self, report_course_param: DataStoreReportCourseParam) -> Result<(), ErrorCode> { - let row = sqlx::query!( + async fn report_course( + &self, + report_course_param: DataStoreReportCourseParam, + ) -> Result<(), ErrorCode> { + sqlx::query!( r#" INSERT INTO datastore.reports ( data_id, @@ -1688,12 +1708,12 @@ impl DataStore for User { report_course_param.report_category as i16, report_course_param.report_reason ) - .execute(get_db()) - .await - .map_err(|e| { - log::error!("DB Error: {:?}", e); - ErrorCode::Core_NotImplemented // i don't know why, but returning this makes the game show "Report sent OK" so i'll use it - })?; + .execute(get_db()) + .await + .map_err(|e| { + log::error!("DB Error: {:?}", e); + ErrorCode::Core_NotImplemented // i don't know why, but returning this makes the game show "Report sent OK" so i'll use it + })?; Ok(()) } @@ -1707,12 +1727,12 @@ impl DataStore for User { "#, param.dataid ) - .fetch_one(get_db()) - .await - .map_err(|e| { - log::error!("DB Error: {:?}", e); - ErrorCode::DataStore_NotFound - })?; + .fetch_one(get_db()) + .await + .map_err(|e| { + log::error!("DB Error: {:?}", e); + ErrorCode::DataStore_NotFound + })?; let passwd = row.update_password; @@ -1722,23 +1742,23 @@ impl DataStore for User { log::info!("update password check passed"); - let deletequery = sqlx::query!( + sqlx::query!( "UPDATE datastore.objects SET deleted=true WHERE data_id=$1", param.dataid ) - .execute(get_db()) - .await - .map_err(|e| { - log::error!("DB Error: {:?}", e); - ErrorCode::DataStore_NotFound - })?; + .execute(get_db()) + .await + .map_err(|e| { + log::error!("DB Error: {:?}", e); + ErrorCode::DataStore_NotFound + })?; Ok(()) } async fn get_custom_ranking( &self, - param: DataStoreGetCustomRankingParam + param: DataStoreGetCustomRankingParam, ) -> Result<(Vec, Vec), ErrorCode> { let mut ranking_results = Vec::new(); @@ -1760,12 +1780,12 @@ impl DataStore for User { param.result_range.size as i64, param.result_range.offset as i64, ) - .fetch_all(get_db()) - .await - .map_err(|e| { - log::error!("DB Error: {:?}", e); - ErrorCode::DataStore_NotFound - })?; + .fetch_all(get_db()) + .await + .map_err(|e| { + log::error!("DB Error: {:?}", e); + ErrorCode::DataStore_NotFound + })?; let mut current_order = param.result_range.offset + 1; @@ -1811,7 +1831,12 @@ impl DataStore for User { Ok((ranking_results, q_results)) } - async fn ctr_pickup_course_search_object(&self, course_search_param: DataStoreSearchParam, extra_data: Vec) -> Result, ErrorCode> { + // todo: respect the search parameters and extra data + async fn ctr_pickup_course_search_object( + &self, + _course_search_param: DataStoreSearchParam, + _extra_data: Vec, + ) -> Result, ErrorCode> { let mut courses = Vec::new(); let mut stream = sqlx::query!( @@ -1852,7 +1877,7 @@ impl DataStore for User { LIMIT 100 "# ) - .fetch(get_db()); + .fetch(get_db()); while let Some(row) = stream.try_next().await.map_err(|e| { eprintln!("stream error: {:?}", e); @@ -1885,7 +1910,7 @@ impl DataStore for User { .map(KerberosDateTime::from_naive) .unwrap_or_default(); - let mut meta_info = GetMetaInfo { + let meta_info = GetMetaInfo { dataid: row.data_id, owner: row.owner.unwrap_or(0), size: row.size.unwrap_or(0) as u32, diff --git a/rnex-core/src/nex/friends_handler.rs b/rnex-core-deprecated/src/nex/friends_handler.rs similarity index 91% rename from rnex-core/src/nex/friends_handler.rs rename to rnex-core-deprecated/src/nex/friends_handler.rs index e0c5d22..4ded520 100644 --- a/rnex-core/src/nex/friends_handler.rs +++ b/rnex-core-deprecated/src/nex/friends_handler.rs @@ -4,26 +4,22 @@ use std::sync::{LazyLock, Weak}; use std::time::Duration; use std::{env, mem}; -use bytemuck::{Pod, Zeroable}; -use chrono::{TimeZone, Utc}; -use log::info; -use macros::rmc_struct; -use rnex_core::rmc::protocols::account_management::{ +use crate::rmc::protocols::account_management::{ AccountExtraInfo, AccountManagement, RawAccountManagement, RawAccountManagementInfo, RemoteAccountManagement, }; -use rnex_core::rmc::protocols::friends_3ds::{ +use crate::rmc::protocols::friends_3ds::{ Friends3DS, RawFriends3DS, RawFriends3DSInfo, RemoteFriends3DS, }; -use rnex_core::rmc::protocols::friends_wiiu::{ +use crate::rmc::protocols::friends_wiiu::{ FriendsWiiU, RawFriendsWiiU, RawFriendsWiiUInfo, RemoteFriendsWiiU, }; -use rnex_core::rmc::protocols::nintendo_notification::{ +use crate::rmc::protocols::nintendo_notification::{ NintendoNotification, RawNintendoNotification, RawNintendoNotificationInfo, RemoteNintendoNotification, }; -use rnex_core::rmc::protocols::secure::{RawSecure, RawSecureInfo, RemoteSecure, Secure}; -use rnex_core::{ +use crate::rmc::protocols::secure::{RawSecure, RawSecureInfo, RemoteSecure, Secure}; +use crate::{ define_rmc_proto, kerberos::KerberosDateTime, nex::common::get_station_urls, @@ -37,20 +33,25 @@ use rnex_core::{ structures::{any::Any, qresult::QResult}, }, }; +use bytemuck::{Pod, Zeroable}; +use chrono::{TimeZone, Utc}; +use rnex_rmc::rmc_struct; use sqlx::query; use std::sync::atomic::Ordering::Relaxed; use tokio::spawn; use tokio::sync::RwLock; use tokio::time::sleep; +use tracing::warn; +use tracing::{error, info}; -use rnex_core::rmc::protocols::friends_wiiu::{GameKey, MiiV2, PrincipalBasicInfo}; +use crate::rmc::protocols::friends_wiiu::{GameKey, MiiV2, PrincipalBasicInfo}; -use rnex_core::PID; +use crate::PID; -use rnex_core::rmc::protocols::account_management::NintendoCreateAccountData; -use rnex_core::rmc::protocols::nintendo_notification::NintendoNotificationEvent; +use crate::rmc::protocols::account_management::NintendoCreateAccountData; +use crate::rmc::protocols::nintendo_notification::NintendoNotificationEvent; -use rnex_core::rmc::structures::data::Data; +use crate::rmc::structures::data::Data; use crate::executables::common::get_db; @@ -61,9 +62,9 @@ use crate::rmc::protocols::friends_3ds::{ use crate::rmc::protocols::friends_wiiu::FriendRequestMessage; use crate::rmc::protocols::nintendo_notification::NintendoNotificationEventGeneral; use crate::rmc::response::ErrorCode::FPD_InvalidArgument; +use crate::rmc::structures::qbuffer::QBuffer; use nex_account::grpc::ActCreateInfo; use nex_account::{derive_pid_hmac, grpc_client}; -use rnex_core::rmc::structures::qbuffer::QBuffer; define_rmc_proto!( proto FriendsUser{ @@ -223,7 +224,7 @@ impl Friends3DS for FriendsUser { let dummy = FriendRelationship { data: Data {}, pid: 69, - local_friend_code: 3268487429723707977, + local_friend_code: 3_268_487_429_723_707_977, relationship_type: 1, }; @@ -258,7 +259,7 @@ impl Friends3DS for FriendsUser { let dummy = FriendRelationship { data: Data {}, pid: 69, - local_friend_code: 3268487429723707977, + local_friend_code: 3_268_487_429_723_707_977, relationship_type: 1, }; @@ -275,12 +276,12 @@ impl Friends3DS for FriendsUser { unk2: Vec, unk3: Vec, ) -> Result, ErrorCode> { - log::info!("params: {:?}, {:?}, {:?}", unk1, unk2, unk3); + info!("params: {:?}, {:?}, {:?}", unk1, unk2, unk3); let dummy = FriendRelationship { data: Data {}, pid: 69, - local_friend_code: 3268487429723707977, + local_friend_code: 3_268_487_429_723_707_977, relationship_type: 1, }; @@ -320,10 +321,10 @@ impl Friends3DS for FriendsUser { pid: 69, presence: NintendoPresence { data: Data {}, - changed_bit_flag: 0xFFFFFFFF, + changed_bit_flag: 0xFFFF_FFFF, game_key: rnex_core::rmc::protocols::friends_3ds::GameKey { data: Data {}, - title_id: 1125899907457280, + title_id: 1_125_899_907_457_280, version: 2064, }, game_mode_desctiption: "".to_string(), @@ -365,7 +366,7 @@ impl Friends3DS for FriendsUser { platform: 0, game_key: rnex_core::rmc::protocols::friends_3ds::GameKey { data: Data {}, - title_id: 1125899907457280, + title_id: 1_125_899_907_457_280, version: 2064, }, message: "yo whats up".to_string(), @@ -603,24 +604,24 @@ impl FriendsWiiU for FriendsUser { let users = self.fm.users.read().await; let user = users.get(&friend.pid).cloned(); drop(users); - if let Some(user) = user { - if let Some(user) = user.upgrade() { - let online_presence = user.presence.read().await; - if let Some(online_presence) = online_presence.as_ref() { - presence = online_presence.clone(); - } else { - println!( - "internal server error, user is somehow online and in the friends manager yet has not set their presence yet..." - ); - } - drop(online_presence); - let mut other_friend_remotes = user.maybe_remote_friend.write().await; - other_friend_remotes.insert(self.pid, self.this.clone()); - drop(other_friend_remotes); - let mut remo_friends = self.maybe_remote_friend.write().await; - remo_friends.insert(friend.pid, Arc::downgrade(&user)); - drop(remo_friends); + if let Some(user) = user + && let Some(user) = user.upgrade() + { + let online_presence = user.presence.read().await; + if let Some(online_presence) = online_presence.as_ref() { + presence = online_presence.clone(); + } else { + println!( + "internal server error, user is somehow online and in the friends manager yet has not set their presence yet..." + ); } + drop(online_presence); + let mut other_friend_remotes = user.maybe_remote_friend.write().await; + other_friend_remotes.insert(self.pid, self.this.clone()); + drop(other_friend_remotes); + let mut remo_friends = self.maybe_remote_friend.write().await; + remo_friends.insert(friend.pid, Arc::downgrade(&user)); + drop(remo_friends); } friends.push(FriendInfo { @@ -852,7 +853,7 @@ impl FriendsWiiU for FriendsUser { .process_nintendo_notification_event_1(NintendoNotificationEvent { event_type: 30, sender: pid, - data: data, + data, }) .await; }); @@ -865,7 +866,7 @@ impl FriendsWiiU for FriendsUser { friend_request_id: i64::MAX, is_recieved: true, unk: 0, - message: message, + message, unk2: 1, unk3: "Dummy".into(), game_key, @@ -976,10 +977,9 @@ impl FriendsWiiU for FriendsUser { return Err(ErrorCode::Core_Exception); } } - } else { - println!("unknown db error occurred"); - return Err(ErrorCode::Core_Exception); } + println!("unknown db error occurred"); + return Err(ErrorCode::Core_Exception); } }; @@ -1100,57 +1100,57 @@ impl FriendsWiiU for FriendsUser { let users = self.fm.users.read().await; let user = users.get(&sender).cloned(); drop(users); - if let Some(user) = user { - if let Some(user) = user.upgrade() { - let mut friends = user.friend_pids.write().await; - friends.push(self.pid); - drop(friends); - let mut friends = user.maybe_remote_friend.write().await; - friends.insert(self.pid, self.this.clone()); - drop(friends); + if let Some(user) = user + && let Some(user) = user.upgrade() + { + let mut friends = user.friend_pids.write().await; + friends.push(self.pid); + drop(friends); + let mut friends = user.maybe_remote_friend.write().await; + friends.insert(self.pid, self.this.clone()); + drop(friends); - let Ok(r) = query!( - "select * from nintendo_network_accounts where pid = $1", - self.pid - ) - .fetch_one(&mut *tx) - .await - else { - println!("internal server error whilest getting nna info"); - return Err(ErrorCode::Core_Exception); - }; - let data = Any::new(&FriendInfo { + let Ok(r) = query!( + "select * from nintendo_network_accounts where pid = $1", + self.pid + ) + .fetch_one(&mut *tx) + .await + else { + println!("internal server error whilest getting nna info"); + return Err(ErrorCode::Core_Exception); + }; + let data = Any::new(&FriendInfo { + data: Data {}, + nna_info: nna_info_from_record!(r), + became_friends: KerberosDateTime::now(), + comment: Comment { data: Data {}, - nna_info: nna_info_from_record!(r), - became_friends: KerberosDateTime::now(), - comment: Comment { - data: Data {}, - last_changed: KerberosDateTime::from_naive(r.comment_lastchanged), - message: r.comment_message, - unk: (bytemuck::cast::<_, u16>(r.comment_unk) & 0xFF) as u8, - }, - last_online: KerberosDateTime::now(), - presence: self.presence.read().await.clone().unwrap_or_default(), - unk: 0, + last_changed: KerberosDateTime::from_naive(r.comment_lastchanged), + message: r.comment_message, + unk: (bytemuck::cast::<_, u16>(r.comment_unk) & 0xFF) as u8, + }, + last_online: KerberosDateTime::now(), + presence: self.presence.read().await.clone().unwrap_or_default(), + unk: 0, + }) + .expect("type error"); + user.remote + .process_nintendo_notification_event_1(NintendoNotificationEvent { + event_type: 30, + sender: self.pid, + data, }) - .expect("type error"); - user.remote - .process_nintendo_notification_event_1(NintendoNotificationEvent { - event_type: 30, - sender: self.pid, - data: data, - }) - .await; - let online_presence = user.presence.read().await; - if let Some(online_presence) = online_presence.as_ref() { - presence = online_presence.clone(); - } else { - println!( - "internal server error, user is somehow online and in the friends manager yet has not set their presence yet..." - ); - } - drop(online_presence); + .await; + let online_presence = user.presence.read().await; + if let Some(online_presence) = online_presence.as_ref() { + presence = online_presence.clone(); + } else { + println!( + "internal server error, user is somehow online and in the friends manager yet has not set their presence yet..." + ); } + drop(online_presence); } tx.commit().await.ok(); @@ -1483,7 +1483,7 @@ impl FriendsWiiU for FriendsUser { .execute(get_db()) .await { - println!("internal server error whilest updating mii: {}", e); + println!("internal server error whilest updating mii: {e}"); return Err(ErrorCode::Core_Exception); } @@ -1546,7 +1546,7 @@ impl FriendsWiiU for FriendsUser { let mut principal_infos = Vec::with_capacity(pids.len()); for pid in pids { - println!("looking up pid: {}", pid); + println!("looking up pid: {pid}"); let Ok(user) = query!( "select * from nintendo_network_accounts where pid = $1", pid @@ -1594,8 +1594,8 @@ impl FriendsWiiU for FriendsUser { .fetch_optional(get_db()) .await else { - println!("error whilest getting friend requests"); - return Err(ErrorCode::Core_SystemError); + warn!("user requested request setting of invalid user"); + continue; }; if denylist.is_some() { @@ -1712,8 +1712,6 @@ impl AccountManagement for FriendsGuest { email: String, auth_data: Any, ) -> Result<(PID, String), ErrorCode> { - println!("{}, {}, {}, {}", principal_name, key, groups, email); - let nex_token = if let Ok(extra_info) = auth_data.try_get_as::() { extra_info.nex_token } else if let Ok(data) = auth_data.try_get_as::() { @@ -1722,15 +1720,15 @@ impl AccountManagement for FriendsGuest { return Err(ErrorCode::Authentication_InvalidParam); }; let (pid, nex_key) = nex_account::decode_nexact_token(&nex_token).map_err(|e| { - log::error!("failed to decode token: {}", e); - log::info!("{:?}", nex_token); + error!("failed to decode token: {e}"); + info!("{nex_token:?}"); ErrorCode::Authentication_InvalidParam })?; //let mac = derive_pid_hmac(data.nna_info.principal_basic_info.pid, &nexkey); let mut client = grpc_client().await.map_err(|e| { - eprintln!("error occurred: {:?}", e); + eprintln!("error occurred: {e:?}"); ErrorCode::Core_Unknown })?; @@ -1741,23 +1739,23 @@ impl AccountManagement for FriendsGuest { pid, }; - let nexkey = client + let nex_key = client .create_new_sequential_or_update_and_get_account(new_account) .await .map_err(|_| ErrorCode::Core_Unknown)? .into_inner(); - if nexkey.key.len() != 16 { - log::error!("nex key was not 16 bytes long"); + if nex_key.key.len() != 16 { + error!("nex key was not 16 bytes long"); return Err(ErrorCode::Authentication_InvalidParam); } - let nexkeyarray: [u8; 16] = nexkey.key.try_into().expect("how...?"); + let nexkeyarray: [u8; 16] = nex_key.key.try_into().expect("how...?"); let mac = derive_pid_hmac(pid, &nexkeyarray); let hex_str = hex::encode(mac); - return Ok((pid, hex_str)); + Ok((pid, hex_str)) } } diff --git a/rnex-core/src/nex/mod.rs b/rnex-core-deprecated/src/nex/mod.rs similarity index 100% rename from rnex-core/src/nex/mod.rs rename to rnex-core-deprecated/src/nex/mod.rs diff --git a/rnex-core/src/nex/remote_console.rs b/rnex-core-deprecated/src/nex/remote_console.rs similarity index 100% rename from rnex-core/src/nex/remote_console.rs rename to rnex-core-deprecated/src/nex/remote_console.rs diff --git a/rnex-core/src/nex/s3presigner.rs b/rnex-core-deprecated/src/nex/s3presigner.rs similarity index 100% rename from rnex-core/src/nex/s3presigner.rs rename to rnex-core-deprecated/src/nex/s3presigner.rs diff --git a/rnex-core/src/common.rs b/rnex-core/src/common.rs deleted file mode 100644 index c1894f3..0000000 --- a/rnex-core/src/common.rs +++ /dev/null @@ -1,48 +0,0 @@ -use std::borrow::Cow; -use tracing_subscriber::layer::SubscriberExt; -use tracing_subscriber::util::SubscriberInitExt; - -pub fn rnex_release() -> String { - let edition_piece = if let Some(e) = option_env!("EDITION") { - format!("{}", e) - } else { - env!("FEATURESET").into() - }; - - format!( - "rnex {} v{}({})", - edition_piece, - env!("CARGO_PKG_VERSION"), - env!("GIT_HASH") - ) -} - -pub async fn with_setup(f: impl AsyncFnOnce()) { - println!("setting up logger and dotenv"); - dotenv::dotenv().ok(); - let _maybe_sentry = if let Ok(sentry_url) = std::env::var("SENTRY_URL") { - Some(sentry::init(( - sentry_url, - sentry::ClientOptions { - release: Some(Cow::Owned(rnex_release())), - send_default_pii: true, - ..Default::default() - }, - ))) - } else { - None - }; - tracing_subscriber::registry() - .with(tracing_subscriber::fmt::layer()) - .with(sentry::integrations::tracing::layer()) - .try_init() - .expect("failed to init tracing subscriber"); - - f().await; - - /*ctrlc::set_handler(||{ - FORCE_EXIT.call_once_force(|_|{ - println!("attempting exit"); - }); - }).unwrap();*/ -} diff --git a/rnex-core/src/grpc/account.rs b/rnex-core/src/grpc/account.rs deleted file mode 100644 index 40f3647..0000000 --- a/rnex-core/src/grpc/account.rs +++ /dev/null @@ -1,189 +0,0 @@ -use nex_account::grpc::Pid; -use nex_account::grpc::nex_account_service_client::NexAccountServiceClient; -use once_cell::sync::Lazy; -use rnex_core::PID; -use std::array::TryFromSliceError; -use std::sync::LazyLock; -use std::{env, result}; -use thiserror::Error; -use tokio::task::JoinError; -use tonic::transport::Channel; - -static API_KEY: Lazy = Lazy::new(|| { - let key = env::var("ACCOUNT_GQL_API_KEY").expect("no graphql ip specified"); - - key -}); - -static CLIENT_URI: Lazy = Lazy::new(|| { - env::var("ACCOUNT_GQL_URL") - .ok() - .and_then(|s| s.parse().ok()) - .expect("no graphql ip specified") -}); - -#[derive(Error, Debug)] -pub enum Error { - #[error(transparent)] - RequestError(#[from] ureq::Error), - #[error(transparent)] - Json(#[from] json::Error), - #[error(transparent)] - Status(#[from] tonic::Status), - #[error(transparent)] - Transport(#[from] tonic::transport::Error), - #[error("invalid password size: {0}")] - PasswordConversion(#[from] TryFromSliceError), - #[error("something happened")] - SomethingHappened, - #[error("error joining blocking task: {0}")] - Join(#[from] JoinError), -} - -pub type Result = result::Result; - -static NEX_ACCOUNT_URL: LazyLock = - LazyLock::new(|| env::var("NEX_ACCOUNT_ENDPOINT").expect("NEX_ACCOUNT_ENDPOINT not set")); - -pub struct Client(NexAccountServiceClient); //(reqwest::Client); - -impl Client { - pub async fn new() -> Result { - let client = nex_account::grpc_client().await.unwrap(); - Ok(Self(client)) - } - - pub async fn get_nex_key(&mut self, pid: PID) -> Result<[u8; 16]> { - let prekey = self.0.get_nex_key_by_pid(Pid { pid }).await?.into_inner(); - - log::warn!("prekey is {:?}", prekey); - - let nexkey: [u8; 16] = prekey - .key - .try_into() - .map_err(|_| Error::SomethingHappened)?; - - Ok(nexkey) - } - - pub async fn get_user_level(&mut self, _pid: PID) -> Result { - // let req = self - // .do_request(object! { - // "query": r"query($pid: Int!){ - // userByPid(pid: $pid){ - // accountLevel - // } - // }", - // "variables": { - // "pid": pid - // } - // }) - // .await?; - // - // let Some(val) = req - // .entries() - // .find(|v| v.0 == "data") - // .ok_or(SomethingHappened)? - // .1 - // .entries() - // .find(|v| v.0 == "userByPid") - // .ok_or(SomethingHappened)? - // .1 - // .entries() - // .find(|v| v.0 == "accountLevel") - // .ok_or(SomethingHappened)? - // .1 - // .as_i32() - // else { - // return Err(SomethingHappened); - // }; - - // everyone is tester until this is implemented - Ok(0) - } - - // pub async fn get_pid_from_token(&mut self, token: String) -> Result { - // let req = self - // .do_request(object! { - // "query": - // r"query($token: String!){ - // token(tokenData: $token){ - // pid - // } - // }", - // "variables": { - // "token": token - // } - // }) - // .await?; - // // this breaks switch nex servers and should be fixed eventually - // let Some(val) = req - // .entries() - // .find(|v| v.0 == "data") - // .ok_or(SomethingHappened)? - // .1 - // .entries() - // .find(|v| v.0 == "token") - // .ok_or(SomethingHappened)? - // .1 - // .entries() - // .find(|v| v.0 == "pid") - // .ok_or(SomethingHappened)? - // .1 - // .as_i32() - // else { - // return Err(SomethingHappened); - // }; - // - // Ok(val) - // } - - /*pub async fn get_user_data(&mut self , pid: u32) -> Result{ - let req = Request::new(GetUserDataRequest{ - pid - }); - - let response = self.0.get_user_data(req).await?.into_inner(); - - Ok(response) - }*/ -} - -/* - -pub struct Client(AccountClient>); - -impl Client{ - pub async fn new() -> Result{ - let channel = Channel::from_static(&*CLIENT_URI).connect().await?; - - let func = Box::new(&|mut req: Request<()>|{ - req.metadata_mut().insert("x-api-key", API_KEY.clone()); - Ok(req) - }) as InterceptorFunc; - - let client = AccountClient::with_interceptor(channel, func); - Ok(Self(client)) - } - - pub async fn get_nex_password(&mut self , pid: u32) -> Result<[u8; 16]>{ - let req = Request::new(GetNexPasswordRequest{ - pid - }); - - let response = self.0.get_nex_password(req).await?.into_inner(); - - Ok(response.password.as_bytes().try_into()?) - } - - pub async fn get_user_data(&mut self , pid: u32) -> Result{ - let req = Request::new(GetUserDataRequest{ - pid - }); - - let response = self.0.get_user_data(req).await?.into_inner(); - - Ok(response) - } -} -*/ diff --git a/rnex-core/src/grpc/mod.rs b/rnex-core/src/grpc/mod.rs deleted file mode 100644 index c96ccfe..0000000 --- a/rnex-core/src/grpc/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -//! Legacy grpc communication server for being able to use this with pretendos infrastructure -//! before account rs is finished. -//! -//! This WILL be deprecated as soon as account rs is in a stable state. -//use tonic::{Request, Status}; - -//type InterceptorFunc = Box) -> Result, Status> + Send>; -pub mod account; \ No newline at end of file diff --git a/rnex-core/src/kerberos/mod.rs b/rnex-core/src/kerberos/mod.rs deleted file mode 100644 index 42e8575..0000000 --- a/rnex-core/src/kerberos/mod.rs +++ /dev/null @@ -1,240 +0,0 @@ -use bytemuck::{Pod, Zeroable, bytes_of}; -use cfg_if::cfg_if; -use chrono::{Datelike, NaiveDate, NaiveDateTime, NaiveTime, Timelike, Utc}; -use hmac::Hmac; -use hmac::Mac; -use rc4::KeyInit; -use rc4::cipher::StreamCipherCoreWrapper; -use rc4::{Rc4, Rc4Core, StreamCipher}; -use rnex_core::rmc::structures::RmcSerialize; -use std::fmt::Display; -use std::io::{Read, Write}; -use typenum::U16; -use typenum::Unsigned; - -use rnex_core::rmc::structures::Result; - -use rnex_core::PID; - -cfg_if! { - if #[cfg(feature = "friends")]{ - pub type SessionLengthTy = U16; - } else { - use rc4::consts::U32; - pub type SessionLengthTy = U32; - } -} -pub const SESSION_KEY_LENGTH: usize = SessionLengthTy::USIZE; - -type Md5Hmac = Hmac; - -#[derive(Pod, Zeroable, Copy, Clone, Debug, Eq, PartialEq)] -#[repr(transparent)] -pub struct KerberosDateTime(pub u64); - -impl Display for KerberosDateTime { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "{}.{}.{} {}:{}:{}", - self.get_year(), - self.get_month(), - self.get_days(), - self.get_hours(), - self.get_minutes(), - self.get_seconds() - ) - } -} - -impl KerberosDateTime { - // this is the time which smm returned as the expriy date, we use it as a - // date so far into the future that it might as well just be never more generally - pub const PRACTICALLY_NEVER: Self = Self::new(0, 0, 0, 31, 12, 9999); - pub fn from_naive(dt: chrono::NaiveDateTime) -> Self { - use chrono::Datelike; - use chrono::Timelike; - Self::new( - dt.second() as u64, - dt.minute() as u64, - dt.hour() as u64, - dt.day() as u64, - dt.month() as u64, - dt.year() as u64, - ) - } - - pub const fn new(second: u64, minute: u64, hour: u64, day: u64, month: u64, year: u64) -> Self { - Self(second | (minute << 6) | (hour << 12) | (day << 17) | (month << 22) | (year << 26)) - } - - pub fn now() -> Self { - let now = chrono::Utc::now(); - Self::new( - now.second() as u64, - now.minute() as u64, - now.hour() as u64, - now.day() as u64, - now.month() as u64, - now.year() as u64, - ) - } - - pub const fn get_seconds(&self) -> u8 { - (self.0 & 0b111111) as u8 - } - - pub const fn get_minutes(&self) -> u8 { - ((self.0 >> 6) & 0b111111) as u8 - } - pub const fn get_hours(&self) -> u8 { - ((self.0 >> 12) & 0b11111) as u8 - } - pub const fn get_days(&self) -> u8 { - ((self.0 >> 17) & 0b111111) as u8 - } - pub const fn get_month(&self) -> u8 { - ((self.0 >> 22) & 0b1111) as u8 - } - pub const fn get_year(&self) -> u64 { - (self.0 >> 26) & 0xFFFFFFFF - } - pub fn to_regular_time(&self) -> chrono::DateTime { - let date = match NaiveDate::from_ymd_opt( - self.get_year() as i32, - self.get_month() as u32, - self.get_days() as u32, - ) { - Some(v) => v, - None => { - println!("invalid datetime...: {}", self); - Default::default() - } - }; - - NaiveDateTime::new( - date, - NaiveTime::from_hms_opt( - self.get_hours() as u32, - self.get_minutes() as u32, - self.get_seconds() as u32, - ) - .unwrap_or_default(), - ) - .and_utc() - } -} - -impl Default for KerberosDateTime { - fn default() -> Self { - KerberosDateTime(0) - } -} - -impl RmcSerialize for KerberosDateTime { - fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> Result<()> { - Ok(self.0.serialize(writer)?) - } - - fn deserialize(reader: &mut (impl Read + ?Sized)) -> Result { - Ok(Self(u64::deserialize(reader)?)) - } -} - -#[derive(Pod, Zeroable, Copy, Clone)] -#[repr(C, packed)] -pub struct TicketInternalData { - pub issued_time: KerberosDateTime, - pub pid: PID, - pub session_key: [u8; SESSION_KEY_LENGTH], -} - -impl TicketInternalData { - pub(crate) fn new(pid: PID) -> Self { - Self { - issued_time: KerberosDateTime::now(), - pid, - session_key: rand::random(), - } - } - - pub(crate) fn encrypt(&self, key: [u8; 16]) -> Box<[u8]> { - let mut data = bytes_of(self).to_vec(); - - let mut rc4: StreamCipherCoreWrapper> = Rc4::new_from_slice(&key).unwrap(); - rc4.apply_keystream(&mut data); - - let mut hmac = ::new_from_slice(&key).unwrap(); - - hmac.write_all(&data[..]) - .expect("failed to write data to hmac"); - - let hmac_result = &hmac.finalize().into_bytes()[..]; - - data.write_all(&hmac_result) - .expect("failed to write data to vec"); - - data.into_boxed_slice() - } -} - -#[derive(Pod, Zeroable, Debug, Copy, Clone)] -#[repr(C, packed)] -pub struct Ticket { - pub session_key: [u8; SESSION_KEY_LENGTH], - pub pid: PID, -} - -impl Ticket { - pub fn encrypt(&self, key: [u8; 16], internal_data: &[u8]) -> Box<[u8]> { - let mut data = bytes_of(self).to_vec(); - - internal_data - .serialize(&mut data) - .expect("unable to write to vec"); - - let mut rc4: StreamCipherCoreWrapper> = Rc4::new_from_slice(&key).unwrap(); - rc4.apply_keystream(&mut data); - - let mut hmac = ::new_from_slice(&key).unwrap(); - - hmac.write_all(&data[..]) - .expect("failed to write data to hmac"); - - let hmac_result = &hmac.finalize().into_bytes()[..]; - - data.write_all(&hmac_result) - .expect("failed to write data to vec"); - - data.into_boxed_slice() - } -} - -#[cfg(test)] -mod test { - use crate::kerberos::KerberosDateTime; - - #[test] - fn kerberos_time_convert_test() { - let time = KerberosDateTime(135904948834); - - println!("{}", time.to_regular_time().to_rfc2822()); - - let time = KerberosDateTime(0x9C3F3E0000); - - println!( - "{}.{}.{} {}:{}:{}", - time.get_year(), - time.get_month(), - time.get_days(), - time.get_hours(), - time.get_minutes(), - time.get_seconds() - ); - println!("{}", time.to_regular_time().to_rfc2822()); - - assert_eq!(KerberosDateTime::PRACTICALLY_NEVER, time); - - println!("{}", KerberosDateTime(134222053376)); - } -} diff --git a/rnex-core/src/prudp/mod.rs b/rnex-core/src/prudp/mod.rs deleted file mode 100644 index 501463a..0000000 --- a/rnex-core/src/prudp/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -pub mod encryption; -pub mod socket_addr; -pub mod station_url; -pub mod ticket; -pub mod types_flags; -pub mod virtual_port; diff --git a/rnex-core/src/reggie.rs b/rnex-core/src/reggie.rs deleted file mode 100644 index 39f12de..0000000 --- a/rnex-core/src/reggie.rs +++ /dev/null @@ -1,60 +0,0 @@ -use crate::define_rmc_proto; -use crate::rmc::structures::RmcSerialize; -use macros::{RmcSerialize, method_id, rmc_proto}; -use rnex_core::rmc::response::ErrorCode; -use std::io; -use std::net::SocketAddrV4; -use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; - -pub trait UnitPacketRead: AsyncRead + Unpin { - async fn read_buffer(&mut self) -> Result, io::Error> { - let mut len_raw: [u8; 4] = [0; 4]; - - self.read_exact(&mut len_raw).await?; - - let len = u32::from_le_bytes(len_raw); - - let mut vec = vec![0u8; len as _]; - - self.read_exact(&mut vec).await?; - - Ok(vec) - } -} - -impl UnitPacketRead for T {} -pub trait UnitPacketWrite: AsyncWrite + Unpin { - async fn send_buffer(&mut self, data: &[u8]) -> Result<(), io::Error> { - let mut dest_data = Vec::new(); - - data.serialize(&mut dest_data) - .expect("ran out of memory or something"); - - self.write_all(&dest_data[..]).await?; - - self.flush().await?; - - Ok(()) - } -} - -impl UnitPacketWrite for T {} - -#[rmc_proto(1)] -pub trait EdgeNodeManagement { - #[method_id(1)] - async fn get_url(&self, seed: u64) -> Result; -} - -define_rmc_proto!( - proto EdgeNodeHolder{ - EdgeNodeManagement - } -); - -#[derive(RmcSerialize, Debug)] -#[repr(u32)] -pub enum EdgeNodeHolderConnectOption { - DontRegister = 0, - Register(SocketAddrV4) = 1, -} diff --git a/rnex-core/src/rmc/mod.rs b/rnex-core/src/rmc/mod.rs deleted file mode 100644 index 23458f6..0000000 --- a/rnex-core/src/rmc/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub mod message; -pub mod structures; -pub mod response; -pub mod protocols; - - - diff --git a/rnex-core/src/rmc/protocols/matchmake.rs b/rnex-core/src/rmc/protocols/matchmake.rs deleted file mode 100644 index d0f98af..0000000 --- a/rnex-core/src/rmc/protocols/matchmake.rs +++ /dev/null @@ -1,27 +0,0 @@ -use macros::{method_id, rmc_proto}; -use rnex_core::prudp::station_url::StationUrl; -use rnex_core::rmc::response::ErrorCode; - -use rnex_core::PID; - -use crate::rmc::structures::any::Any; -use crate::rmc::structures::matchmake::Gathering; - -#[rmc_proto(21)] -pub trait Matchmake { - #[method_id(2)] - async fn unregister_gathering(&self, gid: u32) -> Result; - #[method_id(21)] - async fn find_by_single_id(&self, gid: u32) -> Result<(bool, Any), ErrorCode>; - #[method_id(41)] - async fn get_session_urls(&self, gid: u32) -> Result, ErrorCode>; - #[method_id(42)] - async fn update_session_host(&self, gid: u32, change_owner: bool) -> Result<(), ErrorCode>; - #[method_id(44)] - async fn migrate_gathering_ownership( - &self, - gid: u32, - candidates: Vec, - participants_only: bool, - ) -> Result<(), ErrorCode>; -} diff --git a/rnex-core/src/rmc/protocols/mod.rs b/rnex-core/src/rmc/protocols/mod.rs deleted file mode 100644 index bf4d80f..0000000 --- a/rnex-core/src/rmc/protocols/mod.rs +++ /dev/null @@ -1,371 +0,0 @@ -#![allow(async_fn_in_trait)] - -pub mod account_management; -pub mod auth; -pub mod datastore; -pub mod friends_3ds; -pub mod friends_wiiu; -pub mod matchmake; -pub mod matchmake_ext; -pub mod matchmake_extension; -pub mod message_delivery; -pub mod messaging; -pub mod nat_traversal; -pub mod nintendo_notification; -pub mod notifications; -pub mod ranking; -pub mod secure; -pub mod util; - -use crate::result::ResultExtension; -use crate::rmc::message::RMCMessage; -use crate::rmc::protocols::RemoteCallError::ConnectionBroke; -use crate::rmc::response::{ErrorCode, RMCResponse, RMCResponseResult}; -use crate::rmc::structures; -use crate::rmc::structures::RmcSerialize; -use crate::util::{SendingBufferConnection, SplittableBufferConnection}; -use log::{error, info}; -use std::collections::HashMap; -use std::future::Future; -use std::io::Cursor; -use std::ops::Deref; -use std::sync::Arc; -use std::time::Duration; -use thiserror::Error; -use tokio::sync::{Mutex, Notify}; -use tokio::time::{Instant, sleep, sleep_until}; - -#[derive(Error, Debug)] -pub enum RemoteCallError { - #[error("Call to remote timed out whilst waiting on response.")] - Timeout, - #[error("A server side rmc error occurred: {0:?}")] - ServerError(ErrorCode), - #[error("Connection broke")] - ConnectionBroke, - #[error("Error reading response data: {0}")] - InvalidResponse(#[from] structures::Error), -} - -pub struct RmcConnection(pub SendingBufferConnection, pub RmcResponseReceiver); - -pub struct RmcResponseReceiver(Arc, Arc>>); - -impl RmcConnection { - pub async fn make_raw_call( - &self, - message: &RMCMessage, - ) -> Result { - self.make_raw_call_no_response(message).await?; - - let data = self.1.get_response_data(message.call_id).await?; - - let out = ::deserialize(&mut Cursor::new(data))?; - - Ok(out) - } - - pub async fn make_raw_call_no_response( - &self, - message: &RMCMessage, - ) -> Result<(), RemoteCallError> { - let message_data = message.to_data(); - - self.0.send(message_data).await.ok_or(ConnectionBroke)?; - - Ok(()) - } - - pub async fn disconnect(&self) { - self.0.disconnect().await; - } -} - -impl RmcResponseReceiver { - // returns none if timed out - pub async fn get_response_data(&self, call_id: u32) -> Result, RemoteCallError> { - let mut end_wait_time = Instant::now(); - end_wait_time += Duration::from_secs(5); - - let sleep_fut = sleep_until(end_wait_time); - tokio::pin!(sleep_fut); - - let mut sleep_manual_unlock_fut = Instant::now(); - sleep_manual_unlock_fut += Duration::from_secs(4); - - let sleep_manual_unlock_fut = sleep_until(sleep_manual_unlock_fut); - tokio::pin!(sleep_manual_unlock_fut); - - loop { - let mut locked = self.1.lock().await; - - if let Some(v) = locked.remove(&call_id) { - match v.response_result { - RMCResponseResult::Success { data, .. } => return Ok(data), - RMCResponseResult::Error { error_code, .. } => { - return Err(RemoteCallError::ServerError(error_code)); - } - } - } - - drop(locked); - - let notif_fut = self.0.notified(); - - tokio::select! { - _ = &mut sleep_manual_unlock_fut => { - continue; - } - _ = &mut sleep_fut => { - return Err(RemoteCallError::Timeout); - } - _ = notif_fut => { - continue; - } - } - } - } -} - -pub trait HasRmcConnection { - fn get_connection(&self) -> &RmcConnection; -} - -pub trait RemoteObject { - fn new(conn: RmcConnection) -> Self; -} - -impl RemoteObject for () { - fn new(_: RmcConnection) -> Self {} -} - -pub trait RmcCallable { - //type Remote: RemoteObject; - fn rmc_call( - &self, - responder: &SendingBufferConnection, - protocol_id: u16, - method_id: u32, - call_id: u32, - rest: Vec, - ) -> impl std::future::Future + Send; -} - -#[macro_export] -macro_rules! define_rmc_proto { - (proto $name:ident{ - $($protocol:path),* - }) => { - paste::paste!{ - #[allow(unused_variables)] - pub trait []: std::any::Any $( + [] + $protocol)* { - async fn rmc_call(&self, remote_response_connection: &rnex_core::util::SendingBufferConnection, protocol_id: u16, method_id: u32, call_id: u32, rest: Vec){ - match protocol_id{ - $( - []::PROTOCOL_ID => ]>::rmc_call_proto(self, remote_response_connection, method_id, call_id, rest).await, - )* - v => log::error!("invalid protocol called on rmc object {}", v) - } - } - } - - pub struct [](rnex_core::rmc::protocols::RmcConnection); - - impl rnex_core::rmc::protocols::RmcPureRemoteObject for []{ - fn new(conn: rnex_core::rmc::protocols::RmcConnection) -> Self{ - Self(conn) - } - } - - impl rnex_core::rmc::protocols::RemoteDisconnectable for []{ - - async fn disconnect(&self){ - self.0.disconnect().await; - } - } - - impl rnex_core::rmc::protocols::HasRmcConnection for []{ - fn get_connection(&self) -> &rnex_core::rmc::protocols::RmcConnection{ - &self.0 - } - } - - $( - impl [] for []{} - )* - } - }; -} - -/// This is a special case to allow unit to represent the fact that no object is represented. -impl RmcCallable for () { - async fn rmc_call( - &self, - _remote_response_connection: &SendingBufferConnection, - _protocol_id: u16, - _method_id: u32, - _call_id: u32, - _rest: Vec, - ) { - //todo: maybe reply with not implemented(?) - } -} - -pub trait RmcPureRemoteObject { - fn new(conn: RmcConnection) -> Self; -} - -pub trait RemoteDisconnectable { - async fn disconnect(&self); -} - -pub struct OnlyRemote(T); - -impl OnlyRemote { - pub fn new(conn: RmcConnection) -> Self { - Self(T::new(conn)) - } -} - -impl Deref for OnlyRemote { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl OnlyRemote { - pub async fn disconnect(&self) { - self.0.disconnect().await; - } -} - -impl RmcCallable for OnlyRemote { - fn rmc_call( - &self, - _responder: &SendingBufferConnection, - _protocol_id: u16, - _method_id: u32, - _call_id: u32, - _rest: Vec, - ) -> impl Future + Send { - // maybe respond with not implemented or something - async {} - } -} - -async fn handle_incoming( - mut connection: SplittableBufferConnection, - remote: Arc, - notify: Arc, - incoming: Arc>>, -) { - let sending_conn = connection.duplicate_sender(); - - while let Some(v) = connection.recv().await { - let Some(proto_id) = v.get(4) else { - error!("received too small rmc message."); - error!("ending rmc gateway."); - return; - }; - - // protocol 0 is hardcoded to be the no protocol protocol aka keepalive protocol - if *proto_id == 0 { - println!("got keepalive"); - continue; - } - - if (proto_id & 0x80) == 0 { - let Some(response) = RMCResponse::new(&mut Cursor::new(v)).display_err_or_some() else { - error!("ending rmc gateway."); - return; - }; - - info!("got rmc response"); - - let mut locked = incoming.lock().await; - - locked.insert(response.get_call_id(), response); - notify.notify_waiters(); - } else { - let Some(message) = RMCMessage::new(&mut Cursor::new(v)).display_err_or_some() else { - error!("ending rmc gateway."); - return; - }; - - let RMCMessage { - protocol_id, - method_id, - call_id, - rest_of_data, - } = message; - - info!( - "RMC REQUEST: Proto: {}; Method: {}; cid: {}", - protocol_id, method_id, call_id - ); - - remote - .rmc_call(&sending_conn, protocol_id, method_id, call_id, rest_of_data) - .await; - } - } - - info!("rmc disconnected") -} - -pub fn new_rmc_gateway_connection( - conn: SplittableBufferConnection, - create_internal: F, -) -> Arc -where - F: FnOnce(RmcConnection) -> Arc, -{ - let notify = Arc::new(Notify::new()); - let incoming: Arc>> = Default::default(); - - let response_recv = RmcResponseReceiver(notify.clone(), incoming.clone()); - - let sending_conn = conn.duplicate_sender(); - - let rmc_conn = RmcConnection(sending_conn, response_recv); - - let sending_conn = conn.duplicate_sender(); - - let exposed_object = (create_internal)(rmc_conn); - - { - let exposed_object = exposed_object.clone(); - tokio::spawn(async move { - handle_incoming(conn, exposed_object, notify, incoming).await; - }); - - tokio::spawn(async move { - while sending_conn.is_alive() { - sending_conn.send([0, 0, 0, 0, 0].to_vec()).await; - sleep(Duration::from_secs(10)).await; - } - }); - } - - exposed_object -} - -impl RmcCallable for Arc { - fn rmc_call( - &self, - responder: &SendingBufferConnection, - protocol_id: u16, - method_id: u32, - call_id: u32, - rest: Vec, - ) -> impl Future + Send { - self.as_ref() - .rmc_call(responder, protocol_id, method_id, call_id, rest) - } -} - -define_rmc_proto! { - proto NoProto{} -} diff --git a/rnex-core/src/rmc/protocols/nat_traversal.rs b/rnex-core/src/rmc/protocols/nat_traversal.rs deleted file mode 100644 index c0862a8..0000000 --- a/rnex-core/src/rmc/protocols/nat_traversal.rs +++ /dev/null @@ -1,23 +0,0 @@ -use macros::{method_id, rmc_proto}; -use rnex_core::rmc::response::ErrorCode; - -#[rmc_proto(3)] -pub trait NatTraversal{ - #[method_id(2)] - async fn request_probe_initiation(&self, station_to_probe: String) -> Result<(),ErrorCode>; - - #[method_id(3)] - async fn request_probe_initialization_ext(&self, target_list: Vec, station_to_probe: String) -> Result<(),ErrorCode>; - - #[method_id(4)] - async fn report_nat_traversal_result(&self, cid: u32, result: bool, rtt: u32) -> Result<(),ErrorCode>; - - #[method_id(5)] - async fn report_nat_properties(&self, nat_mapping: u32, nat_filtering: u32, rtt: u32) -> Result<(),ErrorCode>; -} - -#[rmc_proto(3, NoReturn)] -pub trait NatTraversalConsole{ - #[method_id(2)] - async fn request_probe_initiation(&self, station_to_probe: String); -} \ No newline at end of file diff --git a/rnex-core/src/rmc/protocols/notifications.rs b/rnex-core/src/rmc/protocols/notifications.rs deleted file mode 100644 index e66f8fe..0000000 --- a/rnex-core/src/rmc/protocols/notifications.rs +++ /dev/null @@ -1,41 +0,0 @@ -use macros::{RmcSerialize, method_id, rmc_proto}; - -use rnex_core::PID; - -pub mod notification_types { - pub const OWNERSHIP_CHANGED: u32 = 4000; - pub const HOST_CHANGED: u32 = 110000; - pub const REQUEST_JOIN_GATHERING: u32 = 101; - pub const END_GATHERING: u32 = 102; -} - -cfg_if::cfg_if! { - if #[cfg(feature = "third-notif-param")]{ - #[derive(RmcSerialize, Debug, Default, Clone)] - #[rmc_struct(0)] - pub struct NotificationEvent { - pub pid_source: PID, - pub notif_type: u32, - pub param_1: PID, - pub param_2: PID, - pub str_param: String, - pub param_3: PID, - } - } else { - #[derive(RmcSerialize, Debug, Default, Clone)] - #[rmc_struct(0)] - pub struct NotificationEvent { - pub pid_source: PID, - pub notif_type: u32, - pub param_1: PID, - pub param_2: PID, - pub str_param: String, - } - } -} - -#[rmc_proto(14, NoReturn)] -pub trait Notification { - #[method_id(1)] - async fn process_notification_event(&self, event: NotificationEvent); -} diff --git a/rnex-core/src/rmc/response.rs b/rnex-core/src/rmc/response.rs deleted file mode 100644 index db093fb..0000000 --- a/rnex-core/src/rmc/response.rs +++ /dev/null @@ -1,502 +0,0 @@ -// i seriously dont know why the compiler is complaining about unused parentheses in the repr -// attributes but this gets it to not complain anymore -#![allow(unused_parens)] - -use crate::rmc::response::ErrorCode::Core_Exception; -use crate::rmc::structures::qresult::ERROR_MASK; -use crate::util::SendingBufferConnection; -use bytemuck::bytes_of; -use log::{error, warn}; -use std::io; -use std::io::{Read, Seek, Write}; -use std::mem::transmute; -use v_byte_helpers::EnumTryInto; -use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; - -#[derive(Debug, Clone)] -pub enum RMCResponseResult { - Success { - call_id: u32, - method_id: u32, - data: Vec, - }, - Error { - error_code: ErrorCode, - call_id: u32, - }, -} - -#[derive(Debug, Clone)] -pub struct RMCResponse { - pub protocol_id: u8, - pub response_result: RMCResponseResult, -} - -impl RMCResponse { - pub fn new(stream: &mut (impl Seek + Read)) -> io::Result { - // ignore the size for now this will only be used for checking - let size: u32 = stream.read_struct(IS_BIG_ENDIAN)?; - - let protocol_id: u8 = stream.read_struct(IS_BIG_ENDIAN)?; - - /*let protocol_id: u16 = match protocol_id{ - 0x7F => { - stream.read_struct(IS_BIG_ENDIAN)? - }, - _ => protocol_id as u16 - };*/ - - let is_success: u8 = stream.read_struct(IS_BIG_ENDIAN)?; - - let response_result = if is_success == 0x01 { - let call_id: u32 = stream.read_struct(IS_BIG_ENDIAN)?; - let method_id: u32 = stream.read_struct(IS_BIG_ENDIAN)?; - let method_id = method_id & (!0x8000); - - let mut data: Vec = vec![0u8; (size - 2 - 4 - 4) as _]; - - stream.read(&mut data)?; - - RMCResponseResult::Success { - call_id, - method_id, - data, - } - } else { - let error_code: u32 = stream.read_struct(IS_BIG_ENDIAN)?; - let error_code = error_code & (!0x80000000); - let call_id: u32 = stream.read_struct(IS_BIG_ENDIAN)?; - - RMCResponseResult::Error { - error_code: { - match ErrorCode::try_from(error_code) { - Ok(v) => v, - Err(()) => { - error!("invalid error code {:#010x}", error_code); - Core_Exception - } - } - }, - call_id, - } - }; - - Ok(Self { - protocol_id, - response_result, - }) - } - - pub fn get_call_id(&self) -> u32 { - match &self.response_result { - RMCResponseResult::Success { call_id, .. } => *call_id, - RMCResponseResult::Error { call_id, .. } => *call_id, - } - } - - pub fn to_data(self) -> Vec { - generate_response(self.protocol_id, self.response_result) - .expect("failed to generate response") - } -} - -pub fn generate_response(protocol_id: u8, response: RMCResponseResult) -> io::Result> { - let size = 1 - + 1 - + match &response { - RMCResponseResult::Success { data, .. } => 4 + 4 + data.len(), - RMCResponseResult::Error { .. } => 4 + 4, - }; - - let mut data_out = Vec::with_capacity(size + 4); - - let u32_size: u32 = size as _; - - data_out.write_all(bytes_of(&u32_size))?; - data_out.push(protocol_id); - - match response { - RMCResponseResult::Success { - call_id, - method_id, - data, - } => { - data_out.push(1); - data_out.write_all(bytes_of(&call_id))?; - let ored_method_id = method_id | 0x8000; - data_out.write_all(bytes_of(&ored_method_id))?; - data_out.write_all(&data)?; - } - RMCResponseResult::Error { - call_id, - error_code, - } => { - data_out.push(0); - let error_code_val: u32 = error_code.into(); - let error_code_val = error_code_val | ERROR_MASK; - data_out.write_all(bytes_of(&error_code_val))?; - data_out.write_all(bytes_of(&call_id))?; - } - } - - assert_eq!(data_out.len(), size + 4); - - Ok(data_out) -} - -pub async fn send_result( - connection: &SendingBufferConnection, - result: Result, ErrorCode>, - protocol_id: u8, - method_id: u32, - call_id: u32, -) { - let response_result = match result { - Ok(v) => RMCResponseResult::Success { - call_id, - method_id, - data: v, - }, - Err(e) => { - warn!("error occurred during call: {:?}", e); - RMCResponseResult::Error { - call_id, - error_code: e.into(), - } - } - }; - - let response = RMCResponse { - response_result, - protocol_id, - }; - - send_response(connection, response).await -} - -pub async fn send_response(connection: &SendingBufferConnection, rmcresponse: RMCResponse) { - connection.send(rmcresponse.to_data()).await; -} - -//taken from kinnays error list directly -#[allow(nonstandard_style)] -#[repr(u32)] -#[derive(Debug, EnumTryInto, Clone, Copy)] -pub enum ErrorCode { - Core_Unknown = 0x00010001, - Core_NotImplemented = 0x00010002, - Core_InvalidPointer = 0x00010003, - Core_OperationAborted = 0x00010004, - Core_Exception = 0x00010005, - Core_AccessDenied = 0x00010006, - Core_InvalidHandle = 0x00010007, - Core_InvalidIndex = 0x00010008, - Core_OutOfMemory = 0x00010009, - Core_InvalidArgument = 0x0001000A, - Core_Timeout = 0x0001000B, - Core_InitializationFailure = 0x0001000C, - Core_CallInitiationFailure = 0x0001000D, - Core_RegistrationError = 0x0001000E, - Core_BufferOverflow = 0x0001000F, - Core_InvalidLockState = 0x00010010, - Core_InvalidSequence = 0x00010011, - Core_SystemError = 0x00010012, - Core_Cancelled = 0x00010013, - DDL_InvalidSignature = 0x00020001, - DDL_IncorrectVersion = 0x00020002, - RendezVous_ConnectionFailure = 0x00030001, - RendezVous_NotAuthenticated = 0x00030002, - RendezVous_InvalidUsername = 0x00030064, - RendezVous_InvalidPassword = 0x00030065, - RendezVous_UsernameAlreadyExists = 0x00030066, - RendezVous_AccountDisabled = 0x00030067, - RendezVous_AccountExpired = 0x00030068, - RendezVous_ConcurrentLoginDenied = 0x00030069, - RendezVous_EncryptionFailure = 0x0003006A, - RendezVous_InvalidPID = 0x0003006B, - RendezVous_MaxConnectionsReached = 0x0003006C, - RendezVous_InvalidGID = 0x0003006D, - RendezVous_InvalidControlScriptID = 0x0003006E, - RendezVous_InvalidOperationInLiveEnvironment = 0x0003006F, - RendezVous_DuplicateEntry = 0x00030070, - RendezVous_ControlScriptFailure = 0x00030071, - RendezVous_ClassNotFound = 0x00030072, - RendezVous_SessionVoid = 0x00030073, - RendezVous_DDLMismatch = 0x00030075, - RendezVous_InvalidConfiguration = 0x00030076, - RendezVous_SessionFull = 0x000300C8, - RendezVous_InvalidGatheringPassword = 0x000300C9, - RendezVous_WithoutParticipationPeriod = 0x000300CA, - RendezVous_PersistentGatheringCreationMax = 0x000300CB, - RendezVous_PersistentGatheringParticipationMax = 0x000300CC, - RendezVous_DeniedByParticipants = 0x000300CD, - RendezVous_ParticipantInBlackList = 0x000300CE, - RendezVous_GameServerMaintenance = 0x000300CF, - RendezVous_OperationPostpone = 0x000300D0, - RendezVous_OutOfRatingRange = 0x000300D1, - RendezVous_ConnectionDisconnected = 0x000300D2, - RendezVous_InvalidOperation = 0x000300D3, - RendezVous_NotParticipatedGathering = 0x000300D4, - RendezVous_MatchmakeSessionUserPasswordUnmatch = 0x000300D5, - RendezVous_MatchmakeSessionSystemPasswordUnmatch = 0x000300D6, - RendezVous_UserIsOffline = 0x000300D7, - RendezVous_AlreadyParticipatedGathering = 0x000300D8, - RendezVous_PermissionDenied = 0x000300D9, - RendezVous_NotFriend = 0x000300DA, - RendezVous_SessionClosed = 0x000300DB, - RendezVous_DatabaseTemporarilyUnavailable = 0x000300DC, - RendezVous_InvalidUniqueId = 0x000300DD, - RendezVous_MatchmakingWithdrawn = 0x000300DE, - RendezVous_LimitExceeded = 0x000300DF, - RendezVous_AccountTemporarilyDisabled = 0x000300E0, - RendezVous_PartiallyServiceClosed = 0x000300E1, - RendezVous_ConnectionDisconnectedForConcurrentLogin = 0x000300E2, - PythonCore_Exception = 0x00040001, - PythonCore_TypeError = 0x00040002, - PythonCore_IndexError = 0x00040003, - PythonCore_InvalidReference = 0x00040004, - PythonCore_CallFailure = 0x00040005, - PythonCore_MemoryError = 0x00040006, - PythonCore_KeyError = 0x00040007, - PythonCore_OperationError = 0x00040008, - PythonCore_ConversionError = 0x00040009, - PythonCore_ValidationError = 0x0004000A, - Transport_Unknown = 0x00050001, - Transport_ConnectionFailure = 0x00050002, - Transport_InvalidUrl = 0x00050003, - Transport_InvalidKey = 0x00050004, - Transport_InvalidURLType = 0x00050005, - Transport_DuplicateEndpoint = 0x00050006, - Transport_IOError = 0x00050007, - Transport_Timeout = 0x00050008, - Transport_ConnectionReset = 0x00050009, - Transport_IncorrectRemoteAuthentication = 0x0005000A, - Transport_ServerRequestError = 0x0005000B, - Transport_DecompressionFailure = 0x0005000C, - Transport_ReliableSendBufferFullFatal = 0x0005000D, - Transport_UPnPCannotInit = 0x0005000E, - Transport_UPnPCannotAddMapping = 0x0005000F, - Transport_NatPMPCannotInit = 0x00050010, - Transport_NatPMPCannotAddMapping = 0x00050011, - Transport_UnsupportedNAT = 0x00050013, - Transport_DnsError = 0x00050014, - Transport_ProxyError = 0x00050015, - Transport_DataRemaining = 0x00050016, - Transport_NoBuffer = 0x00050017, - Transport_NotFound = 0x00050018, - Transport_TemporaryServerError = 0x00050019, - Transport_PermanentServerError = 0x0005001A, - Transport_ServiceUnavailable = 0x0005001B, - Transport_ReliableSendBufferFull = 0x0005001C, - Transport_InvalidStation = 0x0005001D, - Transport_InvalidSubStreamID = 0x0005001E, - Transport_PacketBufferFull = 0x0005001F, - Transport_NatTraversalError = 0x00050020, - Transport_NatCheckError = 0x00050021, - DOCore_StationNotReached = 0x00060001, - DOCore_TargetStationDisconnect = 0x00060002, - DOCore_LocalStationLeaving = 0x00060003, - DOCore_ObjectNotFound = 0x00060004, - DOCore_InvalidRole = 0x00060005, - DOCore_CallTimeout = 0x00060006, - DOCore_RMCDispatchFailed = 0x00060007, - DOCore_MigrationInProgress = 0x00060008, - DOCore_NoAuthority = 0x00060009, - DOCore_NoTargetStationSpecified = 0x0006000A, - DOCore_JoinFailed = 0x0006000B, - DOCore_JoinDenied = 0x0006000C, - DOCore_ConnectivityTestFailed = 0x0006000D, - DOCore_Unknown = 0x0006000E, - DOCore_UnfreedReferences = 0x0006000F, - DOCore_JobTerminationFailed = 0x00060010, - DOCore_InvalidState = 0x00060011, - DOCore_FaultRecoveryFatal = 0x00060012, - DOCore_FaultRecoveryJobProcessFailed = 0x00060013, - DOCore_StationInconsitency = 0x00060014, - DOCore_AbnormalMasterState = 0x00060015, - DOCore_VersionMismatch = 0x00060016, - FPD_NotInitialized = 0x00650000, - FPD_AlreadyInitialized = 0x00650001, - FPD_NotConnected = 0x00650002, - FPD_Connected = 0x00650003, - FPD_InitializationFailure = 0x00650004, - FPD_OutOfMemory = 0x00650005, - FPD_RmcFailed = 0x00650006, - FPD_InvalidArgument = 0x00650007, - FPD_InvalidLocalAccountID = 0x00650008, - FPD_InvalidPrincipalID = 0x00650009, - FPD_InvalidLocalFriendCode = 0x0065000A, - FPD_LocalAccountNotExists = 0x0065000B, - FPD_LocalAccountNotLoaded = 0x0065000C, - FPD_LocalAccountAlreadyLoaded = 0x0065000D, - FPD_FriendAlreadyExists = 0x0065000E, - FPD_FriendNotExists = 0x0065000F, - FPD_FriendNumMax = 0x00650010, - FPD_NotFriend = 0x00650011, - FPD_FileIO = 0x00650012, - FPD_P2PInternetProhibited = 0x00650013, - FPD_Unknown = 0x00650014, - FPD_InvalidState = 0x00650015, - FPD_AddFriendProhibited = 0x00650017, - FPD_InvalidAccount = 0x00650019, - FPD_BlacklistedByMe = 0x0065001A, - FPD_FriendAlreadyAdded = 0x0065001C, - FPD_MyFriendListLimitExceed = 0x0065001D, - FPD_RequestLimitExceed = 0x0065001E, - FPD_InvalidMessageID = 0x0065001F, - FPD_MessageIsNotMine = 0x00650020, - FPD_MessageIsNotForMe = 0x00650021, - FPD_FriendRequestBlocked = 0x00650022, - FPD_NotInMyFriendList = 0x00650023, - FPD_FriendListedByMe = 0x00650024, - FPD_NotInMyBlacklist = 0x00650025, - FPD_IncompatibleAccount = 0x00650026, - FPD_BlockSettingChangeNotAllowed = 0x00650027, - FPD_SizeLimitExceeded = 0x00650028, - FPD_OperationNotAllowed = 0x00650029, - FPD_NotNetworkAccount = 0x0065002A, - FPD_NotificationNotFound = 0x0065002B, - FPD_PreferenceNotInitialized = 0x0065002C, - FPD_FriendRequestNotAllowed = 0x0065002D, - Ranking_NotInitialized = 0x00670001, - Ranking_InvalidArgument = 0x00670002, - Ranking_RegistrationError = 0x00670003, - Ranking_NotFound = 0x00670005, - Ranking_InvalidScore = 0x00670006, - Ranking_InvalidDataSize = 0x00670007, - Ranking_PermissionDenied = 0x00670009, - Ranking_Unknown = 0x0067000A, - Ranking_NotImplemented = 0x0067000B, - Authentication_NASAuthenticateError = 0x00680001, - Authentication_TokenParseError = 0x00680002, - Authentication_HttpConnectionError = 0x00680003, - Authentication_HttpDNSError = 0x00680004, - Authentication_HttpGetProxySetting = 0x00680005, - Authentication_TokenExpired = 0x00680006, - Authentication_ValidationFailed = 0x00680007, - Authentication_InvalidParam = 0x00680008, - Authentication_PrincipalIdUnmatched = 0x00680009, - Authentication_MoveCountUnmatch = 0x0068000A, - Authentication_UnderMaintenance = 0x0068000B, - Authentication_UnsupportedVersion = 0x0068000C, - Authentication_ServerVersionIsOld = 0x0068000D, - Authentication_Unknown = 0x0068000E, - Authentication_ClientVersionIsOld = 0x0068000F, - Authentication_AccountLibraryError = 0x00680010, - Authentication_ServiceNoLongerAvailable = 0x00680011, - Authentication_UnknownApplication = 0x00680012, - Authentication_ApplicationVersionIsOld = 0x00680013, - Authentication_OutOfService = 0x00680014, - Authentication_NetworkServiceLicenseRequired = 0x00680015, - Authentication_NetworkServiceLicenseSystemError = 0x00680016, - Authentication_NetworkServiceLicenseError3 = 0x00680017, - Authentication_NetworkServiceLicenseError4 = 0x00680018, - DataStore_Unknown = 0x00690001, - DataStore_InvalidArgument = 0x00690002, - DataStore_PermissionDenied = 0x00690003, - DataStore_NotFound = 0x00690004, - DataStore_AlreadyLocked = 0x00690005, - DataStore_UnderReviewing = 0x00690006, - DataStore_Expired = 0x00690007, - DataStore_InvalidCheckToken = 0x00690008, - DataStore_SystemFileError = 0x00690009, - DataStore_OverCapacity = 0x0069000A, - DataStore_OperationNotAllowed = 0x0069000B, - DataStore_InvalidPassword = 0x0069000C, - DataStore_ValueNotEqual = 0x0069000D, - ServiceItem_Unknown = 0x006C0001, - ServiceItem_InvalidArgument = 0x006C0002, - ServiceItem_EShopUnknownHttpError = 0x006C0003, - ServiceItem_EShopResponseParseError = 0x006C0004, - ServiceItem_NotOwned = 0x006C0005, - ServiceItem_InvalidLimitationType = 0x006C0006, - ServiceItem_ConsumptionRightShortage = 0x006C0007, - MatchmakeReferee_Unknown = 0x006F0001, - MatchmakeReferee_InvalidArgument = 0x006F0002, - MatchmakeReferee_AlreadyExists = 0x006F0003, - MatchmakeReferee_NotParticipatedGathering = 0x006F0004, - MatchmakeReferee_NotParticipatedRound = 0x006F0005, - MatchmakeReferee_StatsNotFound = 0x006F0006, - MatchmakeReferee_RoundNotFound = 0x006F0007, - MatchmakeReferee_RoundArbitrated = 0x006F0008, - MatchmakeReferee_RoundNotArbitrated = 0x006F0009, - Subscriber_Unknown = 0x00700001, - Subscriber_InvalidArgument = 0x00700002, - Subscriber_OverLimit = 0x00700003, - Subscriber_PermissionDenied = 0x00700004, - Ranking2_Unknown = 0x00710001, - Ranking2_InvalidArgument = 0x00710002, - Ranking2_InvalidScore = 0x00710003, - SmartDeviceVoiceChat_Unknown = 0x00720001, - SmartDeviceVoiceChat_InvalidArgument = 0x00720002, - SmartDeviceVoiceChat_InvalidResponse = 0x00720003, - SmartDeviceVoiceChat_InvalidAccessToken = 0x00720004, - SmartDeviceVoiceChat_Unauthorized = 0x00720005, - SmartDeviceVoiceChat_AccessError = 0x00720006, - SmartDeviceVoiceChat_UserNotFound = 0x00720007, - SmartDeviceVoiceChat_RoomNotFound = 0x00720008, - SmartDeviceVoiceChat_RoomNotActivated = 0x00720009, - SmartDeviceVoiceChat_ApplicationNotSupported = 0x0072000A, - SmartDeviceVoiceChat_InternalServerError = 0x0072000B, - SmartDeviceVoiceChat_ServiceUnavailable = 0x0072000C, - SmartDeviceVoiceChat_UnexpectedError = 0x0072000D, - SmartDeviceVoiceChat_UnderMaintenance = 0x0072000E, - SmartDeviceVoiceChat_ServiceNoLongerAvailable = 0x0072000F, - SmartDeviceVoiceChat_AccountTemporarilyDisabled = 0x00720010, - SmartDeviceVoiceChat_PermissionDenied = 0x00720011, - SmartDeviceVoiceChat_NetworkServiceLicenseRequired = 0x00720012, - SmartDeviceVoiceChat_AccountLibraryError = 0x00720013, - SmartDeviceVoiceChat_GameModeNotFound = 0x00720014, - Screening_Unknown = 0x00730001, - Screening_InvalidArgument = 0x00730002, - Screening_NotFound = 0x00730003, - Custom_Unknown = 0x00740001, - Ess_Unknown = 0x00750001, - Ess_GameSessionError = 0x00750002, - Ess_GameSessionMaintenance = 0x00750003, -} - -impl From for ErrorCode { - fn from(value: super::structures::Error) -> Self { - error!("rmc error occurred during method runtime: {}", value); - Self::Core_InvalidArgument - } -} - -impl Into for ErrorCode { - fn into(self) -> u32 { - unsafe { transmute(self) } - } -} - -#[cfg(test)] -mod test { - use crate::rmc::response::ErrorCode; - use hmac::digest::KeyInit; - use hmac::digest::consts::U5; - use rc4::{Rc4, StreamCipher}; - - #[test] - fn test() { - let data_orig = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 69, 4, 20]; - let mut data = data_orig; - - let mut rc4: Rc4 = Rc4::new_from_slice("FUCKE".as_bytes().into()).expect("invalid key"); - - rc4.apply_keystream(&mut data); - - assert_ne!(data_orig, data); - - let mut rc4: Rc4 = Rc4::new_from_slice("FUCKE".as_bytes().into()).expect("invalid key"); - - rc4.apply_keystream(&mut data); - - assert_eq!(data_orig, data); - } - - #[test] - fn test_enum_equivilance() { - let val: u32 = ErrorCode::Core_Unknown.into(); - assert_eq!(val, 0x00010001) - } -} diff --git a/rnex-core/src/rmc/structures/connection_data.rs b/rnex-core/src/rmc/structures/connection_data.rs deleted file mode 100644 index d134e85..0000000 --- a/rnex-core/src/rmc/structures/connection_data.rs +++ /dev/null @@ -1,19 +0,0 @@ -use macros::RmcSerialize; -use rnex_core::kerberos::KerberosDateTime; - -#[derive(Debug, RmcSerialize)] -#[rmc_struct(1)] -pub struct ConnectionData { - pub station_url: String, - pub special_protocols: Vec, - pub special_station_url: String, - pub date_time: KerberosDateTime, -} - -#[derive(Debug, RmcSerialize)] -#[rmc_struct(1)] -pub struct ConnectionDataOld { - pub station_url: String, - pub special_protocols: Vec, - pub special_station_url: String, -} diff --git a/rnex-core/src/rmc/structures/data.rs b/rnex-core/src/rmc/structures/data.rs deleted file mode 100644 index 26d4a0d..0000000 --- a/rnex-core/src/rmc/structures/data.rs +++ /dev/null @@ -1,5 +0,0 @@ -use macros::RmcSerialize; - -#[derive(RmcSerialize, Debug, Clone, Copy, Default)] -#[rmc_struct(0)] -pub struct Data {} diff --git a/rnex-core/src/rmc/structures/ranking.rs b/rnex-core/src/rmc/structures/ranking.rs deleted file mode 100644 index 773889d..0000000 --- a/rnex-core/src/rmc/structures/ranking.rs +++ /dev/null @@ -1,22 +0,0 @@ -use bytemuck::{Pod, Zeroable}; -use macros::RmcSerialize; -use rnex_core::rmc::structures::qbuffer::QBuffer; - -#[derive(RmcSerialize, Debug)] -#[rmc_struct(0)] -pub struct UploadCompetitionData{ - pub unk_1/*?*/: u32, - pub splatfest_id: u32, - pub unk_2/*?*/: u32, - pub score: u32, - pub team_id: u8, - pub team_win: u8, - pub is_first_upload: bool, - pub appdata: QBuffer, -} - -#[derive(Copy, Clone, Pod, Zeroable)] -#[repr(C)] -struct UserData { - name: [u16; 0x10], -} diff --git a/rnex-core/src/rnex_proxy_common.rs b/rnex-core/src/rnex_proxy_common.rs deleted file mode 100644 index adaac28..0000000 --- a/rnex-core/src/rnex_proxy_common.rs +++ /dev/null @@ -1,40 +0,0 @@ -use crate::{PID, prudp::socket_addr::PRUDPSockAddr}; -use macros::RmcSerialize; - -#[derive(Debug, PartialEq, Eq, RmcSerialize)] -#[rmc_struct(0)] -pub struct ConnectionInitData { - pub prudpsock_addr: PRUDPSockAddr, - pub pid: PID, -} - -#[cfg(test)] -mod test { - use std::{ - io::Cursor, - net::{Ipv4Addr, SocketAddr, SocketAddrV4}, - }; - - use crate::{ - prudp::{socket_addr::PRUDPSockAddr, virtual_port::VirtualPort}, - rmc::structures::RmcSerialize, - rnex_proxy_common::ConnectionInitData, - }; - - #[test] - fn test() { - let data = ConnectionInitData { - prudpsock_addr: PRUDPSockAddr { - regular_socket_addr: SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::BROADCAST, 19293)), - virtual_port: VirtualPort::new(10, 2), - }, - pid: 100, - }; - - let ser = data.to_data().unwrap(); - - let de = ConnectionInitData::deserialize(&mut Cursor::new(ser)).unwrap(); - - assert_eq!(data, de); - } -} diff --git a/rnex-core/src/server_api/gatherings.rs b/rnex-core/src/server_api/gatherings.rs deleted file mode 100644 index 735b34f..0000000 --- a/rnex-core/src/server_api/gatherings.rs +++ /dev/null @@ -1,88 +0,0 @@ -use std::{ - hash::{DefaultHasher, Hash, Hasher}, - sync::Arc, -}; - -use rnex_server_api::gatherings::{ - Gatherings, gathering_info_service_server::GatheringInfoService, -}; -use tonic::{Request, Response, Status, async_trait}; - -use crate::{ - nex::matchmake::{ExtendedMatchmakeSession, MatchmakeManager}, - rmc::structures::matchmake::{self, MatchmakeSession}, - server_api, -}; - -impl Into for &ExtendedMatchmakeSession { - fn into(self) -> rnex_server_api::gatherings::Gathering { - let players = self.get_active_players().map(|p| *p.pid as u64).collect(); - let ExtendedMatchmakeSession { - session: - MatchmakeSession { - gathering: - matchmake::Gathering { - state, - flags, - host_pid, - description, - maximum_participants, - minimum_participants, - owner_pid, - participant_policy, - policy_argument, - self_gid, - }, - application_buffer, - attributes, - gamemode, - matchmake_system_type, - open_participation, - participation_count, - session_key, - }, - connected_players, - } = self; - rnex_server_api::gatherings::Gathering { - players, - description: description.clone(), - flags: *flags, - host_pid: *host_pid as _, - maximum_participants: *maximum_participants as _, - minimum_participants: *minimum_participants as _, - owner_pid: *owner_pid as _, - participant_policy: *participant_policy, - policy_argument: *policy_argument, - self_gid: *self_gid, - state: *state, - application_buffer: application_buffer.clone(), - attributes: attributes.clone(), - ..Default::default() - } - } -} - -struct GatheringsApi(Arc); - -#[async_trait] -impl GatheringInfoService for GatheringsApi { - async fn get_gatherings( - &self, - request: Request<()>, - ) -> std::result::Result, Status> { - Ok(Response::new(Gatherings { - gatherings: self - .0 - .sessions - .read() - .await - .keys() - .map(|gid| { - let mut hasher = DefaultHasher::new(); - gid.hash(&mut hasher); - hasher.finish() - }) - .collect(), - })) - } -} diff --git a/rnex-core/src/server_api/meta.rs b/rnex-core/src/server_api/meta.rs deleted file mode 100644 index fb5b5ef..0000000 --- a/rnex-core/src/server_api/meta.rs +++ /dev/null @@ -1,36 +0,0 @@ -use rnex_server_api::meta::{ - ApiFeature, ApiFeatures, BuildInfo, server_meta_service_server::ServerMetaService, -}; -use tonic::{Request, Response, Status, async_trait, transport::Server}; - -pub struct ServerMeta; - -#[async_trait] -impl ServerMetaService for ServerMeta { - async fn get_build_info(&self, request: Request<()>) -> Result, Status> { - Ok(Response::new(BuildInfo { - version: env!("CARGO_PKG_VERSION").to_owned(), - edition: env!("EDITION").to_owned(), - build_hash: env!("GIT_HASH").to_owned(), - feature_set: env!("FEATURESET").to_owned(), - })) - } - async fn get_api_features( - &self, - request: Request<()>, - ) -> Result, Status> { - let mut api_features = vec![ApiFeature { - name: "meta".to_owned(), - needs_admin: false, - version: 0, - }]; - - #[cfg(not(feature = "friends"))] - api_features.push(ApiFeature { - name: "gatherings".to_owned(), - version: 0, - needs_admin: true, - }); - Ok(Response::new(ApiFeatures { api_features })) - } -} diff --git a/rnex-core/src/server_api/mod.rs b/rnex-core/src/server_api/mod.rs deleted file mode 100644 index b1389c8..0000000 --- a/rnex-core/src/server_api/mod.rs +++ /dev/null @@ -1,22 +0,0 @@ -use std::{net::SocketAddr, str::FromStr}; - -use rnex_server_api::meta::server_meta_service_server::ServerMetaServiceServer; -use tonic::transport::Server; - -#[cfg(not(feature = "friends"))] -use crate::nex::matchmake::MatchmakeManager; -use crate::server_api::meta::ServerMeta; -#[cfg(not(feature = "friends"))] -use std::sync::Arc; -#[cfg(not(feature = "friends"))] -mod gatherings; - -mod meta; - -pub async fn launch_server_api(#[cfg(not(feature = "friends"))] mmm: Arc) { - let mut server = Server::builder().add_service(ServerMetaServiceServer::new(ServerMeta)); - - server - .serve(SocketAddr::from_str("0.0.0.0:80").expect("unable to make sockaddr from ip")) - .await; -} diff --git a/rnex-core/src/versions.rs b/rnex-core/src/versions.rs deleted file mode 100644 index 03b71b5..0000000 --- a/rnex-core/src/versions.rs +++ /dev/null @@ -1,95 +0,0 @@ -use std::marker::PhantomData; -use std::ops::{BitAnd, BitOr}; -use typenum::{Cmp, IsEqual, IsLess, IsLessOrEqual, Unsigned}; - -/// This trait represents a version at compile time -trait Version { - type Major: Unsigned; - type Minor: Unsigned; -} - -/// This struct contains nothing and is used to represent specific versions as an instance of -/// [`Version`]. It is instances as `Ver` -struct Ver { - _phantom: PhantomData<(MAJ, MIN)>, -} - -impl Version for Ver { - type Major = MAJ; - type Minor = MIN; -} - -/// Represents two versions which can be compared -trait ComparableVersion: Version { - type IsAtLeast: SameOrUnit; -} - -impl ComparableVersion for U -where - ::Major: Cmp, - ::Minor: IsLessOrEqual, - ::Major: - IsEqual>>, - ::Major: IsLess< - Self::Major, - Output: BitOr< - typenum::And< - typenum::Eq, - typenum::LeEq, - >, - Output: SameOrUnit, - >, - >, -{ - type IsAtLeast = typenum::Or< - typenum::Le, - typenum::And, typenum::LeEq>, - >; -} - -/// Simple check for testing if the `TEST` version is at least `REQ` or higher. -type VersionAbove = >::IsAtLeast; - -trait VersionIsAtLeast {} - -impl> VersionIsAtLeast - for T -{ -} - -/// Trait for containing the result of elements which only conditionally exist -trait CondElemResult { - type Output; -} - -/// Empty helper struct which only servers to give a concrete type when creating fields in rmc -/// structs which have a version requirement. This is not meant to be used directly, use -/// [`MinVersion`] instead. -struct MinVersionElementHelper> { - _phantom: PhantomData<(T, REQUIRED, VER)>, -} - -/// This should be used either with [`typenum::True`] or [`typenum::False`]. When `True` the [`Self::Output`] -/// will be the same as the `T` you put into Output. When `False` it will always be `()` -trait SameOrUnit { - type Output; -} - -impl SameOrUnit for typenum::True { - type Output = T; -} - -impl SameOrUnit for typenum::False { - type Output = (); -} - -impl> CondElemResult - for MinVersionElementHelper -{ - type Output = <>::IsAtLeast as SameOrUnit>::Output; -} - -/// When the version condition is met the field will exist and will simply be `T` if not it will be -/// replaced by `()`. Use this when you need to add versioning to rmc structs. -type MinVersion = - as CondElemResult>::Output; diff --git a/rnex-protocols/auth-protos/Cargo.toml b/rnex-protocols/auth-protos/Cargo.toml new file mode 100644 index 0000000..7bc3cea --- /dev/null +++ b/rnex-protocols/auth-protos/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "rnex-auth-protos" +version = "0.1.0" +edition = "2024" + +[dependencies] +cfg-if = "1.0.4" +ctor = "1.0.8" +rnex-rmc = { path = "../../rnex-rmc" } +tokio = { version = "1.52.3", features = ["time", "sync"] } + +[features] +nx = [] + +[lints] +workspace = true diff --git a/rnex-core/src/rmc/protocols/auth.rs b/rnex-protocols/auth-protos/src/auth.rs similarity index 80% rename from rnex-core/src/rmc/protocols/auth.rs rename to rnex-protocols/auth-protos/src/auth.rs index fd1ec2e..f9d53b9 100644 --- a/rnex-core/src/rmc/protocols/auth.rs +++ b/rnex-protocols/auth-protos/src/auth.rs @@ -1,11 +1,31 @@ -use crate::rmc::structures::connection_data::{ConnectionData, ConnectionDataOld}; -use crate::rmc::structures::data::Data; use cfg_if::cfg_if; -use macros::{RmcSerialize, method_id, rmc_proto}; -use rnex_core::PID; -use rnex_core::rmc::response::ErrorCode; -use rnex_core::rmc::structures::any::Any; -use rnex_core::rmc::structures::qresult::QResult; +use rnex_rmc::{ + RmcSerialize, + any::Any, + data::Data, + method_id, + qresult::QResult, + response::ErrorCode, + rmc_proto, + util::{PID, date_time::DateTime}, +}; + +#[derive(Debug, RmcSerialize)] +#[rmc_struct(1)] +pub struct ConnectionData { + pub station_url: String, + pub special_protocols: Vec, + pub special_station_url: String, + pub date_time: DateTime, +} + +#[derive(Debug, RmcSerialize)] +#[rmc_struct(1)] +pub struct ConnectionDataOld { + pub station_url: String, + pub special_protocols: Vec, + pub special_station_url: String, +} cfg_if! { if #[cfg(feature = "nx")]{ @@ -34,6 +54,8 @@ pub trait Auth { #[method_id(2)] async fn login_ex(&self, name: String, extra_data: Any) -> Result; + /// representation of the `RequestTicket` method(for details see the + /// [kinnay wiki entry](https://github.com/kinnay/NintendoClients/wiki/Authentication-Protocol)) #[method_id(3)] async fn request_ticket( &self, @@ -41,9 +63,6 @@ pub trait Auth { destination_pid: PID, ) -> Result; - /// representation of the `RequestTicket` method(for details see the - /// [kinnay wiki entry](https://github.com/kinnay/NintendoClients/wiki/Authentication-Protocol)) - /// representation of the `GetPID` method(for details see the /// [kinnay wiki entry](https://github.com/kinnay/NintendoClients/wiki/Authentication-Protocol)) #[method_id(4)] diff --git a/rnex-protocols/auth-protos/src/lib.rs b/rnex-protocols/auth-protos/src/lib.rs new file mode 100644 index 0000000..9777108 --- /dev/null +++ b/rnex-protocols/auth-protos/src/lib.rs @@ -0,0 +1,11 @@ +#![allow(async_fn_in_trait)] + +use rnex_rmc::define_rmc_proto; +pub mod auth; +use auth::{Auth, RawAuth, RawAuthInfo, RemoteAuth}; + +define_rmc_proto!( + proto AuthProtocol{ + Auth + } +); diff --git a/rnex-protocols/base-protos/Cargo.toml b/rnex-protocols/base-protos/Cargo.toml new file mode 100644 index 0000000..55bb5e3 --- /dev/null +++ b/rnex-protocols/base-protos/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "rnex-base-protos" +version = "0.1.0" +edition = "2024" + +[dependencies] +ctor = "1.0.8" +rnex-rmc = { path = "../../rnex-rmc" } + +[lints] +workspace = true diff --git a/rnex-core/src/rmc/structures/resultsrange.rs b/rnex-protocols/base-protos/src/lib.rs similarity index 56% rename from rnex-core/src/rmc/structures/resultsrange.rs rename to rnex-protocols/base-protos/src/lib.rs index 0fbaced..c00c83e 100644 --- a/rnex-core/src/rmc/structures/resultsrange.rs +++ b/rnex-protocols/base-protos/src/lib.rs @@ -1,4 +1,10 @@ -use macros::RmcSerialize; +#![allow(async_fn_in_trait)] + +use rnex_rmc::{RmcSerialize, define_rmc_proto}; +pub mod secure; +pub mod util; +use secure::{RawSecure, RawSecureInfo, RemoteSecure, Secure}; +use util::{RawUtility, RawUtilityInfo, RemoteUtility, Utility}; #[derive(RmcSerialize, Debug, Default, Clone)] #[rmc_struct(0)] @@ -16,3 +22,10 @@ impl ResultsRange { .into() } } + +define_rmc_proto!( + proto BaseProtocol{ + Secure, + Utility, + } +); diff --git a/rnex-core/src/rmc/protocols/secure.rs b/rnex-protocols/base-protos/src/secure.rs similarity index 70% rename from rnex-core/src/rmc/protocols/secure.rs rename to rnex-protocols/base-protos/src/secure.rs index 7989b74..89cc85b 100644 --- a/rnex-core/src/rmc/protocols/secure.rs +++ b/rnex-protocols/base-protos/src/secure.rs @@ -1,10 +1,7 @@ -use macros::{RmcSerialize, method_id, rmc_proto}; -use rnex_core::prudp::station_url::StationUrl; -use rnex_core::rmc::response::ErrorCode; -use rnex_core::rmc::structures::qresult::QResult; - -use crate::rmc::structures::any::Any; -use crate::rmc::structures::data::Data; +use rnex_rmc::{ + RmcSerialize, any::Any, data::Data, method_id, qresult::QResult, response::ErrorCode, + rmc_proto, util::station_url::StationUrl, +}; #[derive(RmcSerialize)] #[rmc_struct(0)] @@ -34,7 +31,7 @@ pub trait Secure { async fn register_ex( &self, station_urls: Vec, - data: Any, + data: Any, ) -> Result<(QResult, u32, StationUrl), ErrorCode>; #[method_id(7)] async fn replace_url(&self, target: StationUrl, dest: StationUrl) -> Result<(), ErrorCode>; diff --git a/rnex-core/src/rmc/protocols/util.rs b/rnex-protocols/base-protos/src/util.rs similarity index 75% rename from rnex-core/src/rmc/protocols/util.rs rename to rnex-protocols/base-protos/src/util.rs index 3d0c2c1..8882694 100644 --- a/rnex-core/src/rmc/protocols/util.rs +++ b/rnex-protocols/base-protos/src/util.rs @@ -1,6 +1,4 @@ -use macros::{method_id, rmc_proto}; - -use rnex_core::rmc::response::ErrorCode; +use rnex_rmc::{method_id, response::ErrorCode, rmc_proto}; #[rmc_proto(110)] pub trait Utility { diff --git a/rnex-protocols/ds-protos/Cargo.toml b/rnex-protocols/ds-protos/Cargo.toml new file mode 100644 index 0000000..42d535b --- /dev/null +++ b/rnex-protocols/ds-protos/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "rnex-ds-protos" +version = "0.1.0" +edition = "2024" + +[dependencies] +ctor = "1.0.8" +rnex-rmc = { path = "../../rnex-rmc" } +rnex-base-protos = { path = "../base-protos" } + +[lints] +workspace = true diff --git a/rnex-core/src/rmc/protocols/datastore.rs b/rnex-protocols/ds-protos/src/datastore.rs similarity index 94% rename from rnex-core/src/rmc/protocols/datastore.rs rename to rnex-protocols/ds-protos/src/datastore.rs index f850a90..f26852e 100644 --- a/rnex-core/src/rmc/protocols/datastore.rs +++ b/rnex-protocols/ds-protos/src/datastore.rs @@ -1,10 +1,12 @@ -use macros::{RmcSerialize, method_id, rmc_proto}; -use rnex_core::PID; -use rnex_core::kerberos::KerberosDateTime; -use rnex_core::rmc::response::ErrorCode; -use rnex_core::rmc::structures::qbuffer::QBuffer; -use rnex_core::rmc::structures::qresult::QResult; -use rnex_core::rmc::structures::resultsrange::ResultsRange; +use rnex_base_protos::ResultsRange; +use rnex_rmc::{ + RmcSerialize, method_id, + qbuffer::QBuffer, + qresult::QResult, + response::ErrorCode, + rmc_proto, + util::{PID, date_time::DateTime}, +}; #[derive(RmcSerialize, Clone, Debug, Default)] #[rmc_struct(0)] @@ -55,15 +57,15 @@ pub struct GetMetaInfo { pub meta_binary: QBuffer, pub permission: Permission, pub del_permission: Permission, - pub created_time: KerberosDateTime, - pub updated_time: KerberosDateTime, + pub created_time: DateTime, + pub updated_time: DateTime, pub period: u16, pub status: u8, pub referred_count: u32, pub refer_dat_id: u32, pub flag: u32, - pub referred_time: KerberosDateTime, - pub expire_time: KerberosDateTime, + pub referred_time: DateTime, + pub expire_time: DateTime, pub tags: Vec, pub ratings: Vec, } @@ -199,10 +201,10 @@ pub struct DataStoreSearchParam { pub owner_type: u8, pub destination_ids: Vec, pub data_type: u16, - pub created_after: KerberosDateTime, - pub created_before: KerberosDateTime, - pub updated_after: KerberosDateTime, - pub updated_before: KerberosDateTime, + pub created_after: DateTime, + pub created_before: DateTime, + pub updated_after: DateTime, + pub updated_before: DateTime, pub refer_dat_id: u32, pub tags: Vec, pub result_order_column: u8, @@ -291,8 +293,8 @@ pub struct DataStoreGetCourseRecordResult { pub first_pid: u32, pub best_pid: u32, pub best_score: i32, - pub created_time: KerberosDateTime, - pub updated_time: KerberosDateTime, + pub created_time: DateTime, + pub updated_time: DateTime, } #[derive(RmcSerialize, Clone)] diff --git a/rnex-protocols/ds-protos/src/lib.rs b/rnex-protocols/ds-protos/src/lib.rs new file mode 100644 index 0000000..3a90e51 --- /dev/null +++ b/rnex-protocols/ds-protos/src/lib.rs @@ -0,0 +1,11 @@ +#![allow(async_fn_in_trait)] + +pub mod datastore; +use datastore::{DataStore, RawDataStore, RawDataStoreInfo, RemoteDataStore}; +use rnex_rmc::define_rmc_proto; + +define_rmc_proto!( + proto DatastoreProtocol{ + DataStore + } +); diff --git a/rnex-protocols/fpd-protos/Cargo.toml b/rnex-protocols/fpd-protos/Cargo.toml new file mode 100644 index 0000000..1e28cf2 --- /dev/null +++ b/rnex-protocols/fpd-protos/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "rnex-fpd-protos" +version = "0.1.0" +edition = "2024" + +[dependencies] +ctor = "1.0.8" +rnex-rmc = { path = "../../rnex-rmc" } + +[lints] +workspace = true diff --git a/rnex-core/src/rmc/protocols/account_management.rs b/rnex-protocols/fpd-protos/src/account_management.rs similarity index 70% rename from rnex-core/src/rmc/protocols/account_management.rs rename to rnex-protocols/fpd-protos/src/account_management.rs index c17ff86..8fcdd75 100644 --- a/rnex-core/src/rmc/protocols/account_management.rs +++ b/rnex-protocols/fpd-protos/src/account_management.rs @@ -1,14 +1,14 @@ -use macros::{RmcSerialize, method_id, rmc_proto}; - -use rnex_core::{ - PID, - rmc::{response::ErrorCode, structures::any::Any}, +use rnex_rmc::{ + RmcSerialize, + any::Any, + data::Data, + method_id, + response::ErrorCode, + rmc_proto, + util::{PID, date_time::DateTime}, }; -use crate::{ - kerberos::KerberosDateTime, - rmc::{protocols::friends_wiiu::NNAInfo, structures::data::Data}, -}; +use crate::friends_wiiu::NNAInfo; #[derive(RmcSerialize, Debug, Clone)] #[rmc_struct(0)] @@ -17,7 +17,7 @@ pub struct NintendoCreateAccountData { pub data: Data, pub nna_info: NNAInfo, pub nex_token: String, - pub birthday: KerberosDateTime, + pub birthday: DateTime, pub unk: u64, } diff --git a/rnex-core/src/rmc/protocols/friends_3ds.rs b/rnex-protocols/fpd-protos/src/friends_3ds.rs similarity index 91% rename from rnex-core/src/rmc/protocols/friends_3ds.rs rename to rnex-protocols/fpd-protos/src/friends_3ds.rs index ec2bec6..c2bdc72 100644 --- a/rnex-core/src/rmc/protocols/friends_3ds.rs +++ b/rnex-protocols/fpd-protos/src/friends_3ds.rs @@ -1,8 +1,12 @@ -use macros::{RmcSerialize, method_id, rmc_proto}; - -use rnex_core::rmc::{response::ErrorCode, structures::data::Data}; - -use crate::{PID, kerberos::KerberosDateTime}; +use rnex_rmc::{ + RmcSerialize, + data::Data, + list::Buffer, + method_id, + response::ErrorCode, + rmc_proto, + util::{PID, date_time::DateTime}, +}; #[derive(RmcSerialize)] #[rmc_struct(0)] @@ -38,7 +42,7 @@ pub struct MiiList { pub unk1: String, pub unk2: bool, pub unk3: u8, - pub mii_data: Vec>, + pub mii_data: Vec, } #[derive(RmcSerialize, Debug)] @@ -56,14 +60,14 @@ pub struct PlayedGame { #[extends] pub data: Data, pub game_key: GameKey, - pub date_time: KerberosDateTime, + pub date_time: DateTime, } #[derive(RmcSerialize)] #[rmc_struct(0)] pub struct FriendInfo { pub pid: u32, - pub unk2: KerberosDateTime, + pub unk2: DateTime, } #[derive(RmcSerialize)] @@ -73,7 +77,7 @@ pub struct FriendMii { pub data: Data, pub pid: PID, pub mii: Mii, - pub modified_at: KerberosDateTime, + pub modified_at: DateTime, } #[derive(RmcSerialize)] @@ -83,7 +87,7 @@ pub struct FriendMiiList { pub data: Data, pub unk1: u32, pub mii_list: MiiList, - pub unk2: KerberosDateTime, + pub unk2: DateTime, } #[derive(RmcSerialize)] @@ -110,7 +114,7 @@ pub struct NintendoPresence { pub join_game_mode: u32, pub owner_pid: PID, pub join_group_id: u32, - pub application_arg: Vec, + pub application_arg: Buffer, } #[derive(RmcSerialize)] #[rmc_struct(0)] @@ -127,7 +131,7 @@ pub struct FriendComment { pub data: Data, pub pid: PID, pub comment: String, - pub modified_at: KerberosDateTime, + pub modified_at: DateTime, } #[derive(RmcSerialize)] #[rmc_struct(0)] @@ -136,7 +140,7 @@ pub struct FriendPicture { pub data: Data, pub unk1: u32, pub pic_data: Vec, - pub date_time: KerberosDateTime, + pub date_time: DateTime, } #[derive(RmcSerialize)] @@ -152,9 +156,9 @@ pub struct FriendPersistentInfo { pub platform: u8, pub game_key: GameKey, pub message: String, - pub msg_updated_at: KerberosDateTime, - pub friended_at: KerberosDateTime, - pub last_online: KerberosDateTime, + pub msg_updated_at: DateTime, + pub friended_at: DateTime, + pub last_online: DateTime, } #[rmc_proto(101)] diff --git a/rnex-core/src/rmc/protocols/friends_wiiu.rs b/rnex-protocols/fpd-protos/src/friends_wiiu.rs similarity index 88% rename from rnex-core/src/rmc/protocols/friends_wiiu.rs rename to rnex-protocols/fpd-protos/src/friends_wiiu.rs index ff16ac5..6cab4f0 100644 --- a/rnex-core/src/rmc/protocols/friends_wiiu.rs +++ b/rnex-protocols/fpd-protos/src/friends_wiiu.rs @@ -1,12 +1,12 @@ -use macros::{RmcSerialize, method_id, rmc_proto}; - -use rnex_core::{kerberos::KerberosDateTime, rmc::response::ErrorCode}; - -use rnex_core::rmc::structures::data::Data; - -use rnex_core::PID; - -use crate::rmc::structures::qbuffer::QBuffer; +use rnex_rmc::{ + RmcSerialize, + data::Data, + method_id, + qbuffer::QBuffer, + response::ErrorCode, + rmc_proto, + util::{PID, date_time::DateTime}, +}; #[derive(RmcSerialize, Debug, Clone, Default)] #[rmc_struct(0)] @@ -17,7 +17,7 @@ pub struct MiiV2 { pub unk: u8, pub unk2: u8, pub mii_data: Vec, - pub date_time: KerberosDateTime, + pub date_time: DateTime, } #[derive(RmcSerialize, Debug, Clone, Default)] @@ -88,7 +88,7 @@ pub struct Comment { pub data: Data, pub unk: u8, pub message: String, - pub last_changed: KerberosDateTime, + pub last_changed: DateTime, } #[derive(RmcSerialize, Default, Debug)] @@ -99,8 +99,8 @@ pub struct FriendInfo { pub nna_info: NNAInfo, pub presence: NintendoPresenceV2, pub comment: Comment, - pub became_friends: KerberosDateTime, - pub last_online: KerberosDateTime, + pub became_friends: DateTime, + pub last_online: DateTime, pub unk: u64, } @@ -116,8 +116,8 @@ pub struct FriendRequestMessage { pub unk2: u8, pub unk3: String, pub game_key: GameKey, - pub unk4: KerberosDateTime, - pub expires_on: KerberosDateTime, + pub unk4: DateTime, + pub expires_on: DateTime, } #[derive(RmcSerialize, Debug, Clone)] @@ -127,7 +127,7 @@ pub struct FriendRequest { pub data: Data, pub basic_info: PrincipalBasicInfo, pub request_message: FriendRequestMessage, - pub sent_on: KerberosDateTime, + pub sent_on: DateTime, } #[derive(RmcSerialize, Debug, Default)] @@ -137,7 +137,7 @@ pub struct BlacklistedPrincipal { pub data: Data, pub basic_info: PrincipalBasicInfo, pub game_key: GameKey, - pub since: KerberosDateTime, + pub since: DateTime, } #[derive(RmcSerialize, Debug)] #[rmc_struct(0)] @@ -167,7 +167,7 @@ pub trait FriendsWiiU { &self, info: NNAInfo, presence: NintendoPresenceV2, - date_time: KerberosDateTime, + date_time: DateTime, ) -> Result< ( PrincipalPreference, @@ -200,7 +200,7 @@ pub trait FriendsWiiU { unk2: u8, unk3: String, game_key: GameKey, - unk4: KerberosDateTime, + unk4: DateTime, ) -> Result<(FriendRequest, FriendInfo), ErrorCode>; #[method_id(6)] async fn cancel_friend_request(&self, id: u64) -> Result<(), ErrorCode>; @@ -222,9 +222,9 @@ pub trait FriendsWiiU { #[method_id(13)] async fn update_presence(&self, presence: NintendoPresenceV2) -> Result<(), ErrorCode>; #[method_id(14)] - async fn update_mii(&self, presence: MiiV2) -> Result; + async fn update_mii(&self, presence: MiiV2) -> Result; #[method_id(15)] - async fn update_comment(&self, presence: Comment) -> Result; + async fn update_comment(&self, presence: Comment) -> Result; #[method_id(16)] async fn update_preference(&self, preference: PrincipalPreference) -> Result<(), ErrorCode>; #[method_id(17)] diff --git a/rnex-protocols/fpd-protos/src/lib.rs b/rnex-protocols/fpd-protos/src/lib.rs new file mode 100644 index 0000000..c8373b5 --- /dev/null +++ b/rnex-protocols/fpd-protos/src/lib.rs @@ -0,0 +1,33 @@ +#![allow(async_fn_in_trait)] + +use rnex_rmc::define_rmc_proto; +pub mod account_management; +pub mod friends_3ds; +pub mod friends_wiiu; +pub mod nintendo_notification; +use account_management::{ + AccountManagement, RawAccountManagement, RawAccountManagementInfo, RemoteAccountManagement, +}; +use friends_3ds::{Friends3DS, RawFriends3DS, RawFriends3DSInfo, RemoteFriends3DS}; +use friends_wiiu::{FriendsWiiU, RawFriendsWiiU, RawFriendsWiiUInfo, RemoteFriendsWiiU}; +use nintendo_notification::{ + NintendoNotification, RawNintendoNotification, RawNintendoNotificationInfo, + RemoteNintendoNotification, +}; + +define_rmc_proto!( + proto FriendsUser{ + FriendsWiiU, + Friends3DS + } +); +define_rmc_proto!( + proto FriendRemote{ + NintendoNotification + } +); +define_rmc_proto!( + proto FriendsGuest{ + AccountManagement + } +); diff --git a/rnex-core/src/rmc/protocols/nintendo_notification.rs b/rnex-protocols/fpd-protos/src/nintendo_notification.rs similarity index 85% rename from rnex-core/src/rmc/protocols/nintendo_notification.rs rename to rnex-protocols/fpd-protos/src/nintendo_notification.rs index 0142cee..afdb866 100644 --- a/rnex-core/src/rmc/protocols/nintendo_notification.rs +++ b/rnex-protocols/fpd-protos/src/nintendo_notification.rs @@ -1,9 +1,4 @@ -use macros::{RmcSerialize, method_id, rmc_proto}; - -use rnex_core::PID; -use rnex_core::rmc::structures::any::Any; - -use crate::rmc::structures::data::Data; +use rnex_rmc::{RmcSerialize, any::Any, data::Data, method_id, rmc_proto, util::PID}; #[derive(RmcSerialize)] #[rmc_struct(0)] diff --git a/rnex-protocols/mm-protos/Cargo.toml b/rnex-protocols/mm-protos/Cargo.toml new file mode 100644 index 0000000..0113842 --- /dev/null +++ b/rnex-protocols/mm-protos/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "rnex-mm-protos" +version = "0.1.0" +edition = "2024" + +[dependencies] +ctor = "1.0.8" +rnex-rmc = { path = "../../rnex-rmc" } +cfg-if = "1.0.4" +rnex-base-protos = { path = "../base-protos" } + +[features] +third-notif-param = [] +v3-3-2 = [] +v3-4-0 = ["v3-3-2", "third-notif-param"] +v3-5-0 = ["v3-4-0"] +v3-8-15 = ["v3-5-0"] +v3-10-22 = ["v3-8-15"] +v4-3-11 = ["v3-8-15"] + +[lints] +workspace = true diff --git a/rnex-protocols/mm-protos/src/lib.rs b/rnex-protocols/mm-protos/src/lib.rs new file mode 100644 index 0000000..4b2a593 --- /dev/null +++ b/rnex-protocols/mm-protos/src/lib.rs @@ -0,0 +1,34 @@ +#![allow(async_fn_in_trait)] + +use rnex_rmc::define_rmc_proto; + +pub mod matchmake; +pub mod matchmake_ext; +pub mod matchmake_extension; +pub mod nat_traversal; +pub mod notifications; +use matchmake::{Matchmake, RawMatchmake, RawMatchmakeInfo, RemoteMatchmake}; +use matchmake_ext::{MatchmakeExt, RawMatchmakeExt, RawMatchmakeExtInfo, RemoteMatchmakeExt}; +use matchmake_extension::{ + MatchmakeExtension, RawMatchmakeExtension, RawMatchmakeExtensionInfo, RemoteMatchmakeExtension, +}; +use nat_traversal::{ + NatTraversal, NatTraversalConsole, RawNatTraversal, RawNatTraversalConsole, + RawNatTraversalConsoleInfo, RawNatTraversalInfo, RemoteNatTraversal, RemoteNatTraversalConsole, +}; +use notifications::{Notification, RawNotification, RawNotificationInfo, RemoteNotification}; + +define_rmc_proto!( + proto MatchMakingProtocol{ + MatchmakeExtension, + MatchmakeExt, + Matchmake, + NatTraversal + } +); +define_rmc_proto!( + proto MatchMakingClientProtocol{ + Notification, + NatTraversalConsole, + } +); diff --git a/rnex-core/src/rmc/structures/matchmake.rs b/rnex-protocols/mm-protos/src/matchmake.rs similarity index 85% rename from rnex-core/src/rmc/structures/matchmake.rs rename to rnex-protocols/mm-protos/src/matchmake.rs index 0890365..c9d25d9 100644 --- a/rnex-core/src/rmc/structures/matchmake.rs +++ b/rnex-protocols/mm-protos/src/matchmake.rs @@ -1,12 +1,15 @@ use cfg_if::cfg_if; -use macros::RmcSerialize; -use rnex_core::rmc::structures::variant::Variant; +use rnex_rmc::{ + RmcSerialize, + any::Any, + method_id, + response::ErrorCode, + rmc_proto, + string_set::StringSet, + util::{PID, station_url::StationUrl}, + variant::Variant, +}; -use rnex_core::PID; - -use crate::rmc::structures::string_set::StringSet; - -// rmc structure #[derive(RmcSerialize, Debug, Clone, Default, PartialEq)] #[rmc_struct(0)] pub struct Gathering { @@ -168,3 +171,22 @@ pub mod gathering_flags { pub const VERBOSE_PARTICIPANTS: u32 = 0x400; pub const VERBOSE_PARTICIPANTS_EX: u32 = 0x800; } + +#[rmc_proto(21)] +pub trait Matchmake { + #[method_id(2)] + async fn unregister_gathering(&self, gid: u32) -> Result; + #[method_id(21)] + async fn find_by_single_id(&self, gid: u32) -> Result<(bool, Any), ErrorCode>; + #[method_id(41)] + async fn get_session_urls(&self, gid: u32) -> Result, ErrorCode>; + #[method_id(42)] + async fn update_session_host(&self, gid: u32, change_owner: bool) -> Result<(), ErrorCode>; + #[method_id(44)] + async fn migrate_gathering_ownership( + &self, + gid: u32, + candidates: Vec, + participants_only: bool, + ) -> Result<(), ErrorCode>; +} diff --git a/rnex-core/src/rmc/protocols/matchmake_ext.rs b/rnex-protocols/mm-protos/src/matchmake_ext.rs similarity index 56% rename from rnex-core/src/rmc/protocols/matchmake_ext.rs rename to rnex-protocols/mm-protos/src/matchmake_ext.rs index 46c1c09..97bff1f 100644 --- a/rnex-core/src/rmc/protocols/matchmake_ext.rs +++ b/rnex-protocols/mm-protos/src/matchmake_ext.rs @@ -1,8 +1,7 @@ -use macros::{method_id, rmc_proto}; -use rnex_core::rmc::response::ErrorCode; +use rnex_rmc::{method_id, response::ErrorCode, rmc_proto}; #[rmc_proto(50)] -pub trait MatchmakeExt{ +pub trait MatchmakeExt { #[method_id(1)] async fn end_participation(&self, gid: u32, message: String) -> Result; -} \ No newline at end of file +} diff --git a/rnex-core/src/rmc/protocols/matchmake_extension.rs b/rnex-protocols/mm-protos/src/matchmake_extension.rs similarity index 85% rename from rnex-core/src/rmc/protocols/matchmake_extension.rs rename to rnex-protocols/mm-protos/src/matchmake_extension.rs index effb0a7..3f05f37 100644 --- a/rnex-core/src/rmc/protocols/matchmake_extension.rs +++ b/rnex-protocols/mm-protos/src/matchmake_extension.rs @@ -1,13 +1,13 @@ -use macros::{method_id, rmc_proto}; -use rnex_core::rmc::response::ErrorCode; -use rnex_core::rmc::structures::matchmake::{ - AutoMatchmakeParam, CreateMatchmakeSessionParam, JoinMatchmakeSessionParam, MatchmakeSession, -}; +use rnex_base_protos::ResultsRange; +use rnex_rmc::{any::Any, method_id, response::ErrorCode, rmc_proto}; -use crate::rmc::protocols::notifications::NotificationEvent; -use crate::rmc::structures::any::Any; -use crate::rmc::structures::matchmake::{Gathering, MatchmakeSessionSearchCriteria}; -use crate::rmc::structures::resultsrange::ResultsRange; +use crate::{ + matchmake::{ + AutoMatchmakeParam, CreateMatchmakeSessionParam, Gathering, JoinMatchmakeSessionParam, + MatchmakeSession, MatchmakeSessionSearchCriteria, + }, + notifications::NotificationEvent, +}; #[rmc_proto(109)] pub trait MatchmakeExtension { diff --git a/rnex-protocols/mm-protos/src/nat_traversal.rs b/rnex-protocols/mm-protos/src/nat_traversal.rs new file mode 100644 index 0000000..e8bb9fa --- /dev/null +++ b/rnex-protocols/mm-protos/src/nat_traversal.rs @@ -0,0 +1,36 @@ +use rnex_rmc::{method_id, response::ErrorCode, rmc_proto, util::station_url::StationUrl}; + +#[rmc_proto(3)] +pub trait NatTraversal { + #[method_id(2)] + async fn request_probe_initiation(&self, station_to_probe: String) -> Result<(), ErrorCode>; + + #[method_id(3)] + async fn request_probe_initialization_ext( + &self, + target_list: Vec, + station_to_probe: String, + ) -> Result<(), ErrorCode>; + + #[method_id(4)] + async fn report_nat_traversal_result( + &self, + cid: u32, + result: bool, + rtt: u32, + ) -> Result<(), ErrorCode>; + + #[method_id(5)] + async fn report_nat_properties( + &self, + nat_mapping: u32, + nat_filtering: u32, + rtt: u32, + ) -> Result<(), ErrorCode>; +} + +#[rmc_proto(3, NoReturn)] +pub trait NatTraversalConsole { + #[method_id(2)] + async fn request_probe_initiation(&self, station_to_probe: String); +} diff --git a/rnex-protocols/mm-protos/src/notifications.rs b/rnex-protocols/mm-protos/src/notifications.rs new file mode 100644 index 0000000..d4018a2 --- /dev/null +++ b/rnex-protocols/mm-protos/src/notifications.rs @@ -0,0 +1,26 @@ +use rnex_rmc::{RmcSerialize, method_id, rmc_proto, util::PID}; + +pub mod notification_types { + pub const OWNERSHIP_CHANGED: u32 = 4_000; + pub const HOST_CHANGED: u32 = 110_000; + pub const REQUEST_JOIN_GATHERING: u32 = 101; + pub const END_GATHERING: u32 = 102; +} + +#[derive(RmcSerialize, Debug, Default, Clone)] +#[rmc_struct(0)] +pub struct NotificationEvent { + pub pid_source: PID, + pub notif_type: u32, + pub param_1: PID, + pub param_2: PID, + pub str_param: String, + #[cfg(feature = "third-notif-param")] + pub param_3: PID, +} + +#[rmc_proto(14, NoReturn)] +pub trait Notification { + #[method_id(1)] + async fn process_notification_event(&self, event: NotificationEvent); +} diff --git a/rnex-protocols/msg-protos/Cargo.toml b/rnex-protocols/msg-protos/Cargo.toml new file mode 100644 index 0000000..cf45459 --- /dev/null +++ b/rnex-protocols/msg-protos/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "rnex-msg-protos" +version = "0.1.0" +edition = "2024" + +[dependencies] +ctor = "1.0.8" +rnex-rmc = { path = "../../rnex-rmc" } + +[features] +v3-3-2 = [] +v3-4-0 = ["v3-3-2"] +v3-5-0 = ["v3-4-0"] +v3-8-15 = ["v3-5-0"] +v3-10-22 = ["v3-8-15"] +v4-3-11 = ["v3-8-15"] + +[lints] +workspace = true diff --git a/rnex-protocols/msg-protos/src/lib.rs b/rnex-protocols/msg-protos/src/lib.rs new file mode 100644 index 0000000..0b27492 --- /dev/null +++ b/rnex-protocols/msg-protos/src/lib.rs @@ -0,0 +1,22 @@ +#![allow(async_fn_in_trait)] + +pub mod message_delivery; +pub mod messaging; +use message_delivery::{ + MessageDelivery, MessageDeliveryNoResponse, RawMessageDelivery, RawMessageDeliveryInfo, + RawMessageDeliveryNoResponse, RawMessageDeliveryNoResponseInfo, RemoteMessageDelivery, + RemoteMessageDeliveryNoResponse, +}; +use rnex_rmc::define_rmc_proto; + +define_rmc_proto!( + proto MessagingProtocol{ + MessageDelivery + } +); + +define_rmc_proto!( + proto MessagingClient{ + MessageDeliveryNoResponse + } +); diff --git a/rnex-core/src/rmc/protocols/message_delivery.rs b/rnex-protocols/msg-protos/src/message_delivery.rs similarity index 70% rename from rnex-core/src/rmc/protocols/message_delivery.rs rename to rnex-protocols/msg-protos/src/message_delivery.rs index e0d5cf1..053b5ad 100644 --- a/rnex-core/src/rmc/protocols/message_delivery.rs +++ b/rnex-protocols/msg-protos/src/message_delivery.rs @@ -1,6 +1,6 @@ -use macros::{method_id, rmc_proto}; +use rnex_rmc::{any::Any, method_id, response::ErrorCode, rmc_proto}; -use crate::rmc::{protocols::messaging::UserMessage, response::ErrorCode, structures::any::Any}; +use crate::messaging::UserMessage; #[rmc_proto(27)] pub trait MessageDelivery { diff --git a/rnex-core/src/rmc/protocols/messaging.rs b/rnex-protocols/msg-protos/src/messaging.rs similarity index 79% rename from rnex-core/src/rmc/protocols/messaging.rs rename to rnex-protocols/msg-protos/src/messaging.rs index 9849865..1b949d3 100644 --- a/rnex-core/src/rmc/protocols/messaging.rs +++ b/rnex-protocols/msg-protos/src/messaging.rs @@ -1,9 +1,4 @@ -use macros::RmcSerialize; - -use crate::{ - kerberos::KerberosDateTime, - rmc::structures::{data::Data, qbuffer::QBuffer}, -}; +use rnex_rmc::{RmcSerialize, data::Data, qbuffer::QBuffer, util::date_time::DateTime}; #[derive(RmcSerialize, Debug, Clone)] #[rmc_struct(0)] @@ -15,7 +10,7 @@ pub struct UserMessage { pub recipient_type: u32, pub parent_id: u32, pub pid_sender: u32, - pub receptiontime: KerberosDateTime, + pub receptiontime: DateTime, pub life_time: u32, pub flags: u32, pub subject: String, diff --git a/rnex-protocols/reggie-protos/Cargo.toml b/rnex-protocols/reggie-protos/Cargo.toml new file mode 100644 index 0000000..99b2089 --- /dev/null +++ b/rnex-protocols/reggie-protos/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "rnex-reggie-protos" +version = "0.1.0" +edition = "2024" + +[dependencies] +ctor = "1.0.8" +rnex-rmc = { path = "../../rnex-rmc" } + +[lints] +workspace = true diff --git a/rnex-protocols/reggie-protos/src/lib.rs b/rnex-protocols/reggie-protos/src/lib.rs new file mode 100644 index 0000000..62f02a1 --- /dev/null +++ b/rnex-protocols/reggie-protos/src/lib.rs @@ -0,0 +1,3 @@ +#![allow(async_fn_in_trait)] + +pub mod reggie; diff --git a/rnex-protocols/reggie-protos/src/reggie.rs b/rnex-protocols/reggie-protos/src/reggie.rs new file mode 100644 index 0000000..85a9565 --- /dev/null +++ b/rnex-protocols/reggie-protos/src/reggie.rs @@ -0,0 +1,22 @@ +use std::net::SocketAddrV4; + +use rnex_rmc::{RmcSerialize, define_rmc_proto, method_id, response::ErrorCode, rmc_proto}; + +#[rmc_proto(1)] +pub trait EdgeNodeManagement { + #[method_id(1)] + async fn get_url(&self, seed: u64) -> Result; +} + +define_rmc_proto!( + proto EdgeNodeHolder{ + EdgeNodeManagement + } +); + +#[derive(RmcSerialize, Debug)] +#[repr(u32)] +pub enum EdgeNodeHolderConnectOption { + DontRegister = 0, + Register(SocketAddrV4) = 1, +} diff --git a/rnex-protocols/rk-protos/Cargo.toml b/rnex-protocols/rk-protos/Cargo.toml new file mode 100644 index 0000000..f77ce64 --- /dev/null +++ b/rnex-protocols/rk-protos/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "rnex-rk-protos" +version = "0.1.0" +edition = "2024" + +[dependencies] +bytemuck = { version = "1.25.0", features = ["derive"] } +ctor = "1.0.8" +rnex-rmc = { path = "../../rnex-rmc" } +rnex-base-protos = { path = "../base-protos" } + +[lints] +workspace = true diff --git a/rnex-protocols/rk-protos/src/lib.rs b/rnex-protocols/rk-protos/src/lib.rs new file mode 100644 index 0000000..71afcf4 --- /dev/null +++ b/rnex-protocols/rk-protos/src/lib.rs @@ -0,0 +1,12 @@ +#![allow(async_fn_in_trait)] + +use rnex_rmc::define_rmc_proto; + +pub mod ranking; +use ranking::{Ranking, RawRanking, RawRankingInfo, RemoteRanking}; + +define_rmc_proto!( + proto RankingProtocol{ + Ranking, + } +); diff --git a/rnex-core/src/rmc/protocols/ranking.rs b/rnex-protocols/rk-protos/src/ranking.rs similarity index 62% rename from rnex-core/src/rmc/protocols/ranking.rs rename to rnex-protocols/rk-protos/src/ranking.rs index 9a9ca09..ed54d86 100644 --- a/rnex-core/src/rmc/protocols/ranking.rs +++ b/rnex-protocols/rk-protos/src/ranking.rs @@ -1,12 +1,31 @@ -use macros::{RmcSerialize, method_id, rmc_proto}; +use bytemuck::{Pod, Zeroable}; +use rnex_base_protos::ResultsRange; +use rnex_rmc::{ + RmcSerialize, method_id, + qbuffer::QBuffer, + response::ErrorCode, + rmc_proto, + util::{PID, date_time::DateTime}, +}; -use rnex_core::kerberos::KerberosDateTime; -use rnex_core::rmc::response::ErrorCode; -use rnex_core::rmc::structures::qbuffer::QBuffer; -use rnex_core::rmc::structures::ranking::UploadCompetitionData; -use rnex_core::rmc::structures::resultsrange::ResultsRange; +#[derive(RmcSerialize, Debug)] +#[rmc_struct(0)] +pub struct UploadCompetitionData { + pub unk_1: u32, + pub splatfest_id: u32, + pub unk_2: u32, + pub score: u32, + pub team_id: u8, + pub team_win: u8, + pub is_first_upload: bool, + pub appdata: QBuffer, +} -use crate::PID; +#[derive(Copy, Clone, Pod, Zeroable)] +#[repr(C)] +struct UserData { + name: [u16; 0x10], +} #[derive(RmcSerialize, Debug, Default, Clone)] #[rmc_struct(1)] @@ -32,7 +51,7 @@ pub struct CompetitionRankingScoreData { pub unk: u32, pub pid: PID, pub score: u32, - pub modified: KerberosDateTime, + pub modified: DateTime, pub unk2: u8, pub appdata: QBuffer, } diff --git a/rnex-prudp/Cargo.toml b/rnex-prudp/Cargo.toml new file mode 100644 index 0000000..17fe068 --- /dev/null +++ b/rnex-prudp/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "rnex-prudp" +version = "0.1.0" +edition = "2024" + +[dependencies] +hmac = "0.13.0" +md-5 = "0.11.0" +rc4 = "0.2.0" +typenum = "1.20.1" +cfg-if = "1.0.4" +rnex-util = { path = "../rnex-util" } +bytemuck = { version = "1.25.0", features = ["derive"] } +rand = "0.10.2" +tracing = "0.1.44" +v-byte-helpers = { git = "https://github.com/RusticMaple/VByteMacros", version = "0.1.1" } + +[features] +friends = [] + +[lints] +workspace = true diff --git a/rnex-core/src/prudp/encryption.rs b/rnex-prudp/src/encryption.rs similarity index 63% rename from rnex-core/src/prudp/encryption.rs rename to rnex-prudp/src/encryption.rs index aef3739..2aa1d3c 100644 --- a/rnex-core/src/prudp/encryption.rs +++ b/rnex-prudp/src/encryption.rs @@ -1,7 +1,4 @@ -use std::sync::LazyLock; - -use rc4::{Key, StreamCipher}; -use typenum::U5; +use rc4::StreamCipher; pub struct EncryptionPair { pub send: T, @@ -17,4 +14,4 @@ impl EncryptionPair { } } -pub static DEFAULT_KEY: LazyLock> = LazyLock::new(|| Key::from(*b"CD&ML")); +pub const DEFAULT_KEY: &[u8; 5] = b"CD&ML"; diff --git a/rnex-prudp/src/kerberos.rs b/rnex-prudp/src/kerberos.rs new file mode 100644 index 0000000..98fa8d5 --- /dev/null +++ b/rnex-prudp/src/kerberos.rs @@ -0,0 +1,87 @@ +use std::io::Write; + +use bytemuck::{Pod, Zeroable, bytes_of}; +use cfg_if::cfg_if; +use hmac::{Hmac, Mac}; +use rc4::{KeyInit, Rc4, StreamCipher}; +use rnex_util::{PID, date_time::DateTime}; +use typenum::Unsigned; + +cfg_if! { + if #[cfg(feature = "friends")]{ + use typenum::U16; + pub type SessionLengthTy = U16; + } else { + use rc4::consts::U32; + pub type SessionLengthTy = U32; + } +} +pub const SESSION_KEY_LENGTH: usize = SessionLengthTy::USIZE; + +type Md5Hmac = Hmac; + +#[derive(Pod, Zeroable, Copy, Clone)] +#[repr(C, packed)] +pub struct TicketInternalData { + pub issued_time: DateTime, + pub pid: PID, + pub session_key: [u8; SESSION_KEY_LENGTH], +} + +impl TicketInternalData { + pub fn new(pid: PID) -> Self { + Self { + issued_time: DateTime::now(), + pid, + session_key: rand::random(), + } + } + + pub fn encrypt(&self, key: [u8; 16]) -> Box<[u8]> { + let mut data = bytes_of(self).to_vec(); + + let mut rc4 = Rc4::new_from_slice(&key).unwrap(); + rc4.apply_keystream(&mut data); + + let mut hmac = ::new_from_slice(&key).unwrap(); + + hmac.update(&data[..]); + + let hmac_result = &hmac.finalize().into_bytes()[..]; + + data.write_all(hmac_result) + .expect("failed to write data to vec"); + + data.into_boxed_slice() + } +} + +#[derive(Pod, Zeroable, Debug, Copy, Clone)] +#[repr(C, packed)] +pub struct Ticket { + pub session_key: [u8; SESSION_KEY_LENGTH], + pub pid: PID, +} + +impl Ticket { + pub fn encrypt(&self, key: [u8; 16], internal_data: &[u8]) -> Box<[u8]> { + let mut data = bytes_of(self).to_vec(); + + data.extend_from_slice(bytes_of(&(internal_data.len() as u32))); + data.extend_from_slice(internal_data); + + let mut rc4 = Rc4::new_from_slice(&key).unwrap(); + rc4.apply_keystream(&mut data); + + let mut hmac = ::new_from_slice(&key).unwrap(); + + hmac.update(&data[..]); + + let hmac_result = &hmac.finalize().into_bytes()[..]; + + data.write_all(hmac_result) + .expect("failed to write data to vec"); + + data.into_boxed_slice() + } +} diff --git a/rnex-prudp/src/lib.rs b/rnex-prudp/src/lib.rs new file mode 100644 index 0000000..cc85442 --- /dev/null +++ b/rnex-prudp/src/lib.rs @@ -0,0 +1,16 @@ +use bytemuck::from_bytes; + +pub mod encryption; +pub mod kerberos; +pub mod socket_addr; +pub mod ticket; +pub mod types_flags; +pub mod virtual_port; + +fn read_buffer(data: &[u8]) -> Option<(Vec, &[u8])> { + let len: u32 = *from_bytes(data.get(..4)?); + + let buf = data.get(4..4 + len as usize)?; + + Some((buf.into(), data.get(4 + len as usize..).unwrap_or_default())) +} diff --git a/rnex-core/src/prudp/socket_addr.rs b/rnex-prudp/src/socket_addr.rs similarity index 82% rename from rnex-core/src/prudp/socket_addr.rs rename to rnex-prudp/src/socket_addr.rs index e7cdf94..09c22af 100644 --- a/rnex-core/src/prudp/socket_addr.rs +++ b/rnex-prudp/src/socket_addr.rs @@ -1,14 +1,13 @@ use hmac::Hmac; -use macros::RmcSerialize; use md5::digest::Mac; -use rnex_core::prudp::virtual_port::VirtualPort; -use std::io::Write; +use rc4::KeyInit; use std::net::{IpAddr, SocketAddr}; +use crate::virtual_port::VirtualPort; + type Md5Hmac = Hmac; -#[derive(Eq, PartialEq, Hash, Debug, Copy, Clone, Ord, PartialOrd, RmcSerialize)] -#[rmc_struct(0)] +#[derive(Eq, PartialEq, Hash, Debug, Copy, Clone, Ord, PartialOrd)] pub struct PRUDPSockAddr { pub regular_socket_addr: SocketAddr, pub virtual_port: VirtualPort, @@ -31,8 +30,7 @@ impl PRUDPSockAddr { }; //data.extend_from_slice(&self.regular_socket_addr.port().to_be_bytes()); - hmac.write_all(&data) - .expect("figuring this out was complete ass"); + hmac.update(&data); let result: [u8; 16] = hmac.finalize().into_bytes()[0..16] .try_into() .expect("fuck"); diff --git a/rnex-core/src/prudp/ticket.rs b/rnex-prudp/src/ticket.rs similarity index 67% rename from rnex-core/src/prudp/ticket.rs rename to rnex-prudp/src/ticket.rs index 35a4708..dc81c46 100644 --- a/rnex-core/src/prudp/ticket.rs +++ b/rnex-prudp/src/ticket.rs @@ -1,26 +1,22 @@ use std::io::Cursor; -use log::{error, info}; -use rc4::{KeyInit, Rc4, Rc4Core, StreamCipher, cipher::StreamCipherCoreWrapper}; -use typenum::U16; +use rc4::{KeyInit, Rc4, StreamCipher}; +use rnex_util::{PID, account::Account}; +use tracing::error; use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; use crate::{ - kerberos::{SESSION_KEY_LENGTH, SessionLengthTy, TicketInternalData}, - nex::account::Account, - rmc::structures::RmcSerialize, + kerberos::{SESSION_KEY_LENGTH, TicketInternalData}, + read_buffer, }; -use rnex_core::PID; pub fn read_secure_connection_data( data: &[u8], act: &Account, ) -> Option<([u8; SESSION_KEY_LENGTH], PID, u32)> { - let mut cursor = Cursor::new(data); - - let mut ticket_data: Vec = Vec::deserialize(&mut cursor).ok()?; - let mut request_data: Vec = Vec::deserialize(&mut cursor).ok()?; - info!("done request data {}", SESSION_KEY_LENGTH); + let (mut ticket_data, remainder) = read_buffer(data)?; + let (mut request_data, _) = read_buffer(remainder)?; + tracing::info!("done request data {}", SESSION_KEY_LENGTH); let ticket_data_size = ticket_data.len(); @@ -28,8 +24,7 @@ pub fn read_secure_connection_data( let server_key = act.nex_key; - let mut rc4: StreamCipherCoreWrapper> = - Rc4::new_from_slice(&server_key).expect("unable to init rc4 keystream"); + let mut rc4 = Rc4::new_from_slice(&server_key).expect("unable to init rc4 keystream"); rc4.apply_keystream(ticket_data); @@ -53,8 +48,7 @@ pub fn read_secure_connection_data( let request_data_length = request_data.len(); let request_data = &mut request_data[0..request_data_length - 0x10]; - let mut rc4: StreamCipherCoreWrapper> = - Rc4::new_from_slice(&session_key).expect("unable to init rc4 keystream"); + let mut rc4: Rc4 = Rc4::new_from_slice(&session_key).expect("unable to init rc4 keystream"); rc4.apply_keystream(request_data); diff --git a/rnex-core/src/prudp/types_flags.rs b/rnex-prudp/src/types_flags.rs similarity index 100% rename from rnex-core/src/prudp/types_flags.rs rename to rnex-prudp/src/types_flags.rs diff --git a/rnex-core/src/prudp/virtual_port.rs b/rnex-prudp/src/virtual_port.rs similarity index 100% rename from rnex-core/src/prudp/virtual_port.rs rename to rnex-prudp/src/virtual_port.rs diff --git a/rnex-rmc/Cargo.toml b/rnex-rmc/Cargo.toml new file mode 100644 index 0000000..a9d8758 --- /dev/null +++ b/rnex-rmc/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "rnex-rmc" +version = "0.1.0" +edition = "2024" + +[dependencies] +bytemuck = { version = "1.25.0", features = ["derive"] } +thiserror = "2.0.18" +tracing = "0.1.44" +v-byte-helpers = { git = "https://github.com/RusticMaple/VByteMacros", version = "0.1.1" } +rnex-util = { path = "../rnex-util" } +tokio = { version = "1.52.3", features = ["sync", "io-util", "rt", "macros", "time"] } +ctor = "1.0.8" +rnex-rmc-macros = { path = "./macros" } +paste = "1.0.15" +rand = "0.10.2" +hex = "0.4.3" + +[features] +rmc_struct_header = [] +big_pid = [] + +v3-3-2 = [] +v3-4-0 = ["v3-3-2", "rmc_struct_header"] +v3-5-0 = ["v3-4-0"] +v3-8-15 = ["v3-5-0"] +v3-10-22 = ["v3-8-15"] +v4-3-11 = ["v3-8-15"] + +[lints] +workspace = true diff --git a/macros/Cargo.lock b/rnex-rmc/macros/Cargo.lock similarity index 100% rename from macros/Cargo.lock rename to rnex-rmc/macros/Cargo.lock diff --git a/macros/Cargo.toml b/rnex-rmc/macros/Cargo.toml similarity index 84% rename from macros/Cargo.toml rename to rnex-rmc/macros/Cargo.toml index f748300..34de59d 100644 --- a/macros/Cargo.toml +++ b/rnex-rmc/macros/Cargo.toml @@ -1,10 +1,13 @@ [package] -name = "macros" +name = "rnex-rmc-macros" version = "0.0.0" authors = ["RusticMaple "] description = "A `cargo generate` template for quick-starting a procedural macro crate" keywords = ["template", "proc_macro", "procmacro"] -edition = "2018" +edition = "2024" + +[lints] +workspace = true [lib] proc-macro = true diff --git a/macros/src/lib.rs b/rnex-rmc/macros/src/lib.rs similarity index 87% rename from macros/src/lib.rs rename to rnex-rmc/macros/src/lib.rs index dc42aa3..a764226 100644 --- a/macros/src/lib.rs +++ b/rnex-rmc/macros/src/lib.rs @@ -1,4 +1,5 @@ #![allow(dead_code)] +#![allow(clippy::pedantic)] mod protos; mod rmc_struct; mod util; @@ -11,7 +12,7 @@ use proc_macro::TokenStream; use proc_macro2::Ident; use quote::quote; use syn::spanned::Spanned; -use syn::{parse_macro_input, Data, DeriveInput}; +use syn::{Data, DeriveInput, parse_macro_input}; #[proc_macro_derive(RmcSerialize, attributes(extends, rmc_struct))] pub fn rmc_serialize(input: TokenStream) -> TokenStream { @@ -31,7 +32,7 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream { let write_size = if let Some(v) = write_size { quote! { - fn serialize_write_size(&self) -> rnex_core::rmc::structures::Result{ + fn serialize_write_size(&self) -> ::rnex_rmc::serialization::Result{ #v } } @@ -51,13 +52,14 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream { let rmc_struct_impl = rmc_struct_impl.unwrap_or_default(); let tokens = quote! { - impl rnex_core::rmc::structures::RmcSerialize for #ident{ + #[automatically_derived] + impl ::rnex_rmc::serialization::RmcSerialize for #ident{ #[inline(always)] - fn serialize(&self, writer: &mut (impl ::std::io::Write + ?::std::marker::Sized)) -> rnex_core::rmc::structures::Result<()>{ + fn serialize(&self, writer: &mut (impl ::std::io::Write + ?::std::marker::Sized)) -> ::rnex_rmc::serialization::Result<()>{ #serialize } #[inline(always)] - fn deserialize(reader: &mut (impl ::std::io::Read + ?::std::marker::Sized)) -> rnex_core::rmc::structures::Result{ + fn deserialize(reader: &mut (impl ::std::io::Read + ?::std::marker::Sized)) -> ::rnex_rmc::serialization::Result{ #deserialize } @@ -140,9 +142,9 @@ pub fn rmc_struct(attr: TokenStream, input: TokenStream) -> TokenStream { } - impl rnex_core::rmc::protocols::RmcCallable for #struct_name{ - async fn rmc_call(&self, remote_response_connection: &rnex_core::util::SendingBufferConnection, protocol_id: u16, method_id: u32, call_id: u32, rest: Vec){ - ::rmc_call(self, remote_response_connection, protocol_id, method_id, call_id, rest).await; + impl ::rnex_rmc::RmcCallable for #struct_name{ + async fn rmc_call(&self, remote_response_connection: &::rnex_rmc::util::SendingBufferConnection, protocol_id: u16, method_id: u32, call_id: u32, rest: &[u8]) -> bool{ + ::rmc_call(self, remote_response_connection, protocol_id, method_id, call_id, rest).await } } }; diff --git a/macros/src/protos.rs b/rnex-rmc/macros/src/protos.rs similarity index 84% rename from macros/src/protos.rs rename to rnex-rmc/macros/src/protos.rs index 9b7604f..671bee3 100644 --- a/macros/src/protos.rs +++ b/rnex-rmc/macros/src/protos.rs @@ -1,9 +1,9 @@ use proc_macro2::{Ident, Span, TokenStream}; -use quote::{quote, ToTokens}; +use quote::{ToTokens, quote}; use syn::{ + Attribute, FnArg, ItemTrait, LitInt, LitStr, Meta, Pat, ReturnType, Token, TraitItem, Type, parse::{Parse, ParseStream}, punctuated::Punctuated, - Attribute, FnArg, ItemTrait, LitInt, LitStr, Meta, Pat, ReturnType, Token, TraitItem, Type, }; use crate::util::fold_tokenable; @@ -65,8 +65,7 @@ impl RmcProtocolData { properties, } = params; - let no_return_data = - properties.is_some_and(|p| p.1.iter().any(|i| i.to_string() == "NoReturn")); + let no_return_data = properties.is_some_and(|p| p.1.iter().any(|i| i == "NoReturn")); // gigantic ass struct initializer (to summarize this gets all of the data) RmcProtocolData { @@ -85,7 +84,7 @@ impl RmcProtocolData { a.path() .segments .last() - .is_some_and(|s| s.ident.to_string() == "method_id") + .is_some_and(|s| s.ident == "method_id") }) else { panic!("every function inside of an rmc protocol must have a method id"); }; @@ -124,14 +123,14 @@ impl RmcProtocolData { .filter(|a| match &a.meta { Meta::NameValue(v) => { if let Some(i) = v.path.get_ident() { - i.to_string() != "doc" + i != "doc" } else { true } } Meta::List(l) => { if let Some(seg) = l.path.segments.last() { - seg.ident.to_string() != "method_id" + seg.ident != "method_id" } else { true } @@ -167,7 +166,7 @@ impl RmcProtocolData { let optional_return = if self.has_returns { quote! { - -> ::core::result::Result, ::rnex_core::rmc::response::ErrorCode> + -> ::core::result::Result, ::rnex_rmc::response::ErrorCode> } } else { quote! {} @@ -182,7 +181,7 @@ impl RmcProtocolData { ); let return_from_deser_error = if self.has_returns { quote! { - return Err(::rnex_core::rmc::response::ErrorCode::Core_InvalidArgument); + return Err(::rnex_rmc::response::ErrorCode::Core_InvalidArgument); } } else { quote! { @@ -193,10 +192,10 @@ impl RmcProtocolData { quote! { #attribs let Ok(#param_name) = - <#param_type as rnex_core::rmc::structures::RmcSerialize>::deserialize( + <#param_type as ::rnex_rmc::serialization::RmcSerialize>::deserialize( &mut cursor ) else{ - log::error!(#error_msg); + ::rnex_rmc::tracing::error!(#error_msg); #return_from_deser_error }; } @@ -214,7 +213,7 @@ impl RmcProtocolData { quote! { let retval = retval?; let mut vec = Vec::new(); - rnex_core::rmc::structures::RmcSerialize::serialize(&retval, &mut vec).ok(); + ::rnex_rmc::serialization::RmcSerialize::serialize(&retval, &mut vec).ok(); Ok(vec) } } else { @@ -224,7 +223,7 @@ impl RmcProtocolData { quote! { #[inline(always)] #attribs - async fn #raw_name (&self, data: ::std::vec::Vec) #optional_return{ + async fn #raw_name (&self, data: &[u8]) #optional_return{ let mut cursor = ::std::io::Cursor::new(data); #deser_params let retval = self.#name(#call_params).await; @@ -254,7 +253,7 @@ impl RmcProtocolData { let optional_notimpl_return = if self.has_returns { quote! { - Err(rnex_core::rmc::response::ErrorCode::Core_NotImplemented) + Err(::rnex_rmc::response::ErrorCode::Core_NotImplemented) } } else { quote! {} @@ -262,7 +261,7 @@ impl RmcProtocolData { let optional_result_sendback = if *has_returns { quote! { - rnex_core::rmc::response::send_result( + ::rnex_rmc::response::send_result( remote_response_connection, ret, #id, @@ -278,15 +277,15 @@ impl RmcProtocolData { #[inline(always)] async fn rmc_call_proto( &self, - remote_response_connection: &rnex_core::util::SendingBufferConnection, + remote_response_connection: &::rnex_rmc::util::SendingBufferConnection, method_id: u32, call_id: u32, - data: Vec, + data: &[u8], ){ let ret = match method_id{ #method_entries v => { - log::error!("(protocol {})unimplemented method id called on protocol: {}", #id, v); + ::rnex_rmc::tracing::error!("(protocol {})unimplemented method id called on protocol: {}", #id, v); #optional_notimpl_return } }; @@ -297,17 +296,18 @@ impl RmcProtocolData { // this gives us the name which the identifier of the corresponding Raw trait let raw_name = Ident::new(&format!("Raw{}", name), name.span()); - let proto_raw_methods = fold_tokenable(self.methods.iter().map(|m| generate_raw_method(m))); + let proto_raw_methods = fold_tokenable(self.methods.iter().map(generate_raw_method)); let rmc_call_proto = generate_rmc_call_proto(); // boilerplate tokens which all raw traits need quote! { - #[doc(hidden)] #[allow(unused_must_use)] + #[automatically_derived] pub trait #raw_name: #name{ #proto_raw_methods #rmc_call_proto } + #[automatically_derived] impl #raw_name for T{} } .to_token_stream() @@ -350,24 +350,24 @@ impl RmcProtocolData { let attrs = fold_tokenable(attrs.iter()); quote!{ #attrs - rnex_core::result::ResultExtension::display_err_or_some( - <#ty as rnex_core::rmc::structures::RmcSerialize>::serialize( + ::rnex_rmc::util::result::ResultExtension::display_err_or_some( + <#ty as ::rnex_rmc::serialization::RmcSerialize>::serialize( &#name, &mut cursor ) - ).ok_or(rnex_core::rmc::response::ErrorCode::Core_InvalidArgument)#optional_questionmark_operator ; + ).ok_or(::rnex_rmc::response::ErrorCode::Core_InvalidArgument)#optional_questionmark_operator ; } })); let make_call = if *has_returns { quote! { - rnex_core::result::ResultExtension::display_err_or_some( + ::rnex_rmc::util::result::ResultExtension::display_err_or_some( rmc_conn.make_raw_call(&message).await - ).ok_or(rnex_core::rmc::response::ErrorCode::Core_Exception) + ).ok_or(::rnex_rmc::response::ErrorCode::Core_Exception) } } else { quote! { - rnex_core::result::ResultExtension::display_err_or_some( + ::rnex_rmc::util::result::ResultExtension::display_err_or_some( rmc_conn.make_raw_call_no_response(&message).await ); } @@ -382,28 +382,29 @@ impl RmcProtocolData { let mut cursor = ::std::io::Cursor::new(&mut send_data); #param_serialize - let call_id = rand::random(); + let call_id = ::rnex_rmc::rand::random(); - let message = rnex_core::rmc::message::RMCMessage{ + let message = ::rnex_rmc::message::RMCMessage{ call_id, method_id: #method_id, protocol_id: #proto_id, rest_of_data: send_data }; - let rmc_conn = ::get_connection(self); + let rmc_conn = ::get_connection(self); #make_call } } }; - let remote_methods = fold_tokenable(methods.iter().map(|m| generate_remote_method(m))); + let remote_methods = fold_tokenable(methods.iter().map(generate_remote_method)); quote! { #[doc(hidden)] #[allow(unused_must_use)] - pub trait #remote_name: rnex_core::rmc::protocols::HasRmcConnection{ + #[automatically_derived] + pub trait #remote_name: ::rnex_rmc::HasRmcConnection{ #remote_methods } } @@ -416,8 +417,10 @@ impl RmcProtocolData { quote! { #[doc(hidden)] + #[automatically_derived] pub struct #raw_info_name; + #[automatically_derived] impl #raw_info_name { pub const PROTOCOL_ID: u16 = #id; } diff --git a/macros/src/rmc_struct.rs b/rnex-rmc/macros/src/rmc_struct.rs similarity index 82% rename from macros/src/rmc_struct.rs rename to rnex-rmc/macros/src/rmc_struct.rs index de93949..31ee83d 100644 --- a/macros/src/rmc_struct.rs +++ b/rnex-rmc/macros/src/rmc_struct.rs @@ -78,18 +78,18 @@ pub fn generate_write_size_struct( let ident = f.ident.as_ref().unwrap(); let attrs = fold_tokenable(f.attrs.iter().filter(|a| { if let Some(i) = a.meta.path().get_ident() { - i.to_string() != "extends" + i != "extends" } else { true } })); quote! { #attrs - sum += rnex_core::rmc::structures::RmcSerialize::serialize_write_size(&self.#ident)?; + sum += ::rnex_rmc::serialization::RmcSerialize::serialize_write_size(&self.#ident)?; } })); let optional_struct_header_calc = if with_potential_header { - quote! { sum += (if rnex_core::config::FEATURE_HAS_STRUCT_HEADER{ 5 } else { 0 }); } + quote! { sum += (if ::rnex_rmc::config::FEATURE_HAS_STRUCT_HEADER{ 5 } else { 0 }); } } else { quote! {} }; @@ -109,14 +109,14 @@ pub fn generate_serialize_struct( let ident = f.ident.as_ref().unwrap(); let attrs = fold_tokenable(f.attrs.iter().filter(|a| { if let Some(i) = a.meta.path().get_ident() { - i.to_string() != "extends" + i != "extends" } else { true } })); quote! { #attrs - rnex_core::rmc::structures::RmcSerialize::serialize(&self.#ident, writer)?; + ::rnex_rmc::serialization::RmcSerialize::serialize(&self.#ident, writer)?; } } let optional_extended_struct = if let Some(f) = extended_struct { @@ -127,10 +127,10 @@ pub fn generate_serialize_struct( let elems = fold_tokenable(elems.iter().map(|e| gen_elem_serialize(e))); let ser_body = if with_header { quote! { - rnex_core::rmc::structures::rmc_struct::write_struct( + ::rnex_rmc::rmc_struct::write_struct( writer, Self::version().unwrap(), - rnex_core::rmc::structures::helpers::len_of_write( + ::rnex_rmc::helpers::len_of_write( |writer|{ #elems Ok(()) @@ -163,14 +163,14 @@ pub fn generate_deserialize_struct( let ty = &f.ty; let attrs = fold_tokenable(f.attrs.iter().filter(|a| { if let Some(i) = a.meta.path().get_ident() { - i.to_string() != "extends" + i != "extends" } else { true } })); quote! { #attrs - let #ident: #ty = rnex_core::rmc::structures::RmcSerialize::deserialize(reader)?; + let #ident: #ty = ::rnex_rmc::serialization::RmcSerialize::deserialize(reader)?; } } let optional_extended_struct = if let Some(f) = extended_struct { @@ -183,7 +183,7 @@ pub fn generate_deserialize_struct( let ident = f.ident.as_ref().unwrap(); let attrs = fold_tokenable(f.attrs.iter().filter(|a| { if let Some(i) = a.meta.path().get_ident() { - i.to_string() != "extends" + i != "extends" } else { true } @@ -198,9 +198,9 @@ pub fn generate_deserialize_struct( }; let de_body = if with_header { quote! { - Ok(rnex_core::rmc::structures::rmc_struct::read_struct(reader, Self::version().unwrap(), move |mut reader|{ + ::rnex_rmc::rmc_struct::read_struct(reader, Self::version().unwrap(), move |mut reader|{ #de_body_inner - })?) + }) } } else { de_body_inner @@ -247,15 +247,15 @@ fn gen_rmc_struct_impl( Span::call_site(), ); quote! { - #[::rnex_core::ctor(unsafe)] + #[::ctor::ctor(unsafe)] #[allow(nonstandard_style)] fn register_fun() { println!("registering {} as parent of {}", #self_name_str_lit, #ext_ty_name); - let mut wr = <#extended_struct_ty as ::rnex_core::rmc::structures::RmcStruct>::get_struct_info() + let mut wr = <#extended_struct_ty as ::rnex_rmc::serialization::RmcStruct>::get_struct_info() .inheritors .write() .expect("poisoned"); - wr.push(<#struct_ident as ::rnex_core::rmc::structures::RmcStruct>::get_struct_info()); + wr.push(<#struct_ident as ::rnex_rmc::serialization::RmcStruct>::get_struct_info()); } } } else { @@ -263,11 +263,11 @@ fn gen_rmc_struct_impl( }; quote! { - impl ::rnex_core::rmc::structures::RmcStruct for #struct_ident { - fn get_struct_info() -> &'static ::rnex_core::rmc::structures::RmcStructInfo { + impl ::rnex_rmc::serialization::RmcStruct for #struct_ident { + fn get_struct_info() -> &'static ::rnex_rmc::serialization::RmcStructInfo { #register - static STRUCT_DATA: ::rnex_core::rmc::structures::RmcStructInfo = - ::rnex_core::rmc::structures::RmcStructInfo { + static STRUCT_DATA: ::rnex_rmc::serialization::RmcStructInfo = + ::rnex_rmc::serialization::RmcStructInfo { inheritors: ::std::sync::RwLock::new(::std::vec::Vec::new()), name: #self_name_str_lit, }; @@ -295,7 +295,7 @@ pub fn rmc_serialize_struct( && a.path() .segments .first() - .is_some_and(|p| p.ident.to_string() == "rmc_struct") + .is_some_and(|p| p.ident == "rmc_struct") && matches!(a.meta, Meta::List(_)) }); @@ -308,7 +308,7 @@ pub fn rmc_serialize_struct( && a.path() .segments .first() - .is_some_and(|p| p.ident.to_string() == "extends") + .is_some_and(|p| p.ident == "extends") }) }); let elements: Vec<_> = s @@ -320,7 +320,7 @@ pub fn rmc_serialize_struct( && a.path() .segments .first() - .is_some_and(|p| p.ident.to_string() == "extends") + .is_some_and(|p| p.ident == "extends") }) }) .collect(); @@ -393,18 +393,22 @@ pub fn rmc_generate_serialize_enum( enum_data: &DataEnum, repr_ty: &Ident, ) -> proc_macro2::TokenStream { - let match_content = fold_tokenable(enum_data.variants.iter().map(|v|{ + let match_content = fold_tokenable(enum_data.variants.iter().map(|v| { let ident = &v.ident; - let descriminant = &v.discriminant.as_ref().expect("every variant must have a descriminant to be a valid rmc struct").1; + let descriminant = &v + .discriminant + .as_ref() + .expect("every variant must have a descriminant to be a valid rmc struct") + .1; let (pattern, fields) = variant_to_pattern_and_fields(v); - let inner = fold_tokenable(fields.iter().enumerate().map(|(i, f)|{ + let inner = fold_tokenable(fields.iter().enumerate().map(|(i, f)| { let ty = &f.ty; - let name = field_to_ident(&f, i); - quote! {<#ty as rnex_core::rmc::structures::RmcSerialize>::serialize(#name, writer)?;} + let name = field_to_ident(f, i); + quote! {<#ty as ::rnex_rmc::serialization::RmcSerialize>::serialize(#name, writer)?;} })); - quote!{ + quote! { Self::#ident #pattern => { - <#repr_ty as rnex_core::rmc::structures::RmcSerialize>::serialize(&#descriminant, writer)?; + <#repr_ty as ::rnex_rmc::serialization::RmcSerialize>::serialize(&#descriminant, writer)?; #inner } } @@ -430,8 +434,8 @@ pub fn rmc_generate_deserialize_enum( let (pattern, fields) = variant_to_pattern_and_fields(v); let inner = fold_tokenable(fields.iter().enumerate().map(|(i, f)| { let ty = &f.ty; - let name = field_to_ident(&f, i); - quote! {let #name = <#ty as rnex_core::rmc::structures::RmcSerialize>::deserialize(reader)?;} + let name = field_to_ident(f, i); + quote! {let #name = <#ty as ::rnex_rmc::serialization::RmcSerialize>::deserialize(reader)?;} })); quote! { #descriminant => { @@ -443,12 +447,12 @@ pub fn rmc_generate_deserialize_enum( })); quote! { - let discriminant = <#repr_ty as rnex_core::rmc::structures::RmcSerialize>::deserialize(reader)?; + let discriminant = <#repr_ty as ::rnex_rmc::serialization::RmcSerialize>::deserialize(reader)?; Ok(match discriminant{ #match_content v => { - return Err(rnex_core::rmc::structures::Error::UnexpectedValue(v as u64)) + return Err(::rnex_rmc::serialization::Error::UnexpectedValue(v as u64)) } }) } @@ -465,11 +469,7 @@ pub fn rmc_serialize_enum( Option, ) { let repr_attr = derive_input.attrs.iter().find(|a| { - a.path().segments.len() == 1 - && a.path() - .segments - .first() - .is_some_and(|p| p.ident.to_string() == "repr") + a.path().segments.len() == 1 && a.path().segments.first().is_some_and(|p| p.ident == "repr") }); let Some(repr_attr) = repr_attr else { panic!("missing repr attribute"); @@ -477,8 +477,8 @@ pub fn rmc_serialize_enum( let ty: Ident = repr_attr.parse_args().unwrap(); - let serialize = rmc_generate_serialize_enum(&enum_data, &ty); - let deserialize = rmc_generate_deserialize_enum(&enum_data, &ty); + let serialize = rmc_generate_serialize_enum(enum_data, &ty); + let deserialize = rmc_generate_deserialize_enum(enum_data, &ty); (serialize, deserialize, None, None, None) } diff --git a/macros/src/util.rs b/rnex-rmc/macros/src/util.rs similarity index 100% rename from macros/src/util.rs rename to rnex-rmc/macros/src/util.rs diff --git a/rnex-core/src/rmc/structures/any.rs b/rnex-rmc/src/any.rs similarity index 57% rename from rnex-core/src/rmc/structures/any.rs rename to rnex-rmc/src/any.rs index 439f2d6..0a9990b 100644 --- a/rnex-core/src/rmc/structures/any.rs +++ b/rnex-rmc/src/any.rs @@ -1,11 +1,14 @@ -use rnex_core::rmc::structures::{Result, RmcSerialize}; +use crate::{ + RmcSerialize, + serialization::{Error, Result, RmcStruct}, +}; use std::{ io::{Cursor, Read, Write}, marker::PhantomData, }; use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; -use crate::rmc::structures::{RmcStruct, data::Data}; +use crate::data::Data; #[derive(Clone, Debug)] pub struct Any { @@ -28,7 +31,7 @@ impl RmcSerialize for Any { let name = String::deserialize(reader)?; if !T::get_struct_info().is_inheritor(&name) { - return Err(super::Error::InheritanceError); + return Err(Error::InheritanceError); } // also length ? @@ -46,7 +49,7 @@ impl RmcSerialize for Any { impl Any { pub fn try_into(self) -> Result> { if !U::get_struct_info().is_inheritor(&self.name) { - return Err(super::Error::InheritanceError); + return Err(Error::InheritanceError); } Ok(Any { data: self.data, @@ -56,13 +59,13 @@ impl Any { } pub fn try_get_as(&self) -> Result { if !U::get_struct_info().is_inheritor(&self.name) { - return Err(super::Error::InheritanceError); + return Err(Error::InheritanceError); } return U::deserialize(&mut Cursor::new(&self.data[..])); } pub fn new(val: &U) -> Result { if !T::get_struct_info().is_inheritor(U::get_struct_info().name) { - return Err(super::Error::InheritanceError); + return Err(Error::InheritanceError); } return Ok(Self { name: U::get_struct_info().name.to_owned(), @@ -78,7 +81,7 @@ impl Any { pub fn emplace_parent(&mut self, parent: &E) -> Result<()> { // validate if E is actually a parent of the contained struct if !E::get_struct_info().is_inheritor(&self.name) { - return Err(super::Error::InheritanceError); + return Err(Error::InheritanceError); } let mut cur = Cursor::new(&self.data[..]); @@ -88,7 +91,7 @@ impl Any { let rest_of_struct = &self .data .get(end_of_parent_pos as usize..) - .ok_or(super::Error::OOB)?; + .ok_or(Error::OOB)?; let mut new_data = parent.to_data()?; new_data.extend_from_slice(&rest_of_struct); @@ -98,60 +101,3 @@ impl Any { Ok(()) } } - -#[cfg(test)] -mod test { - use std::io::Cursor; - - use macros::RmcSerialize; - - use crate::rmc::structures::RmcSerialize; - use crate::rmc::structures::any::Any; - #[derive(RmcSerialize)] - #[rmc_struct(0)] - struct StructB { - valb: u32, - } - #[derive(RmcSerialize)] - #[rmc_struct(0)] - struct StructA { - #[extends] - base: StructB, - vala: u32, - } - #[derive(RmcSerialize)] - #[rmc_struct(0)] - struct Unrelated { - vala: u32, - } - - #[test] - fn test() { - let initial: Any = Any::new(&StructA { - base: StructB { valb: 10 }, - vala: 11, - }) - .unwrap(); - - let encoded = initial.to_data().unwrap(); - - let mut reser_b: Any = Any::deserialize(&mut Cursor::new(&encoded[..])).unwrap(); - - let mut data_b: StructB = reser_b.get().unwrap(); - assert_eq!(data_b.valb, 10); - data_b.valb = 20; - - reser_b.emplace_parent(&data_b).unwrap(); - - let data_a: StructA = reser_b.try_get_as().unwrap(); - assert_eq!(data_a.vala, 11); - assert_eq!(data_a.base.valb, 20); - - let data: Any = reser_b.try_into().unwrap(); - let data: Any = data.try_into().unwrap(); - let fail: Result, _> = data.try_into(); - assert!(fail.is_err()); - let fail: Result, _> = Any::deserialize(&mut Cursor::new(&encoded[..])); - assert!(fail.is_err()); - } -} diff --git a/rnex-core/src/rmc/structures/buffer.rs b/rnex-rmc/src/buffer.rs similarity index 93% rename from rnex-core/src/rmc/structures/buffer.rs rename to rnex-rmc/src/buffer.rs index cb82160..1e80941 100644 --- a/rnex-core/src/rmc/structures/buffer.rs +++ b/rnex-rmc/src/buffer.rs @@ -1,7 +1,7 @@ -use crate::rmc::structures::Result; -use crate::rmc::structures::RmcSerialize; use std::io::{Read, Write}; +use crate::serialization::{Result, RmcSerialize}; + impl<'a> RmcSerialize for &'a [u8] { fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> Result<()> { let u32_size = self.len() as u32; diff --git a/rnex-rmc/src/data.rs b/rnex-rmc/src/data.rs new file mode 100644 index 0000000..b0383f0 --- /dev/null +++ b/rnex-rmc/src/data.rs @@ -0,0 +1,41 @@ +use std::io::{Read, Write}; + +use crate::{ + config::FEATURE_HAS_STRUCT_HEADER, + helpers, rmc_struct, + serialization::{Result, RmcSerialize, RmcStruct, RmcStructInfo}, +}; + +#[derive(Debug, Clone, Copy, Default)] +pub struct Data {} +impl RmcSerialize for Data { + #[inline(always)] + fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> Result<()> { + rmc_struct::write_struct( + writer, + Self::version().unwrap(), + helpers::len_of_write(|_| Ok(())), + |_| Ok(()), + ) + } + #[inline(always)] + fn deserialize(reader: &mut (impl Read + ?Sized)) -> Result { + rmc_struct::read_struct(reader, Self::version().unwrap(), move |_| Ok(Self {})) + } + fn serialize_write_size(&self) -> Result { + Ok(if FEATURE_HAS_STRUCT_HEADER { 5 } else { 0 }) + } + fn version() -> Option { + Some(0) + } +} + +impl RmcStruct for Data { + fn get_struct_info() -> &'static RmcStructInfo { + static STRUCT_DATA: RmcStructInfo = RmcStructInfo { + inheritors: ::std::sync::RwLock::new(::std::vec::Vec::new()), + name: "Data", + }; + &STRUCT_DATA + } +} diff --git a/rnex-rmc/src/date_time.rs b/rnex-rmc/src/date_time.rs new file mode 100644 index 0000000..39f2a72 --- /dev/null +++ b/rnex-rmc/src/date_time.rs @@ -0,0 +1,15 @@ +use std::io::{Read, Write}; + +use rnex_util::date_time::DateTime; + +use crate::serialization::{Result, RmcSerialize}; + +impl RmcSerialize for DateTime { + fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> Result<()> { + self.0.serialize(writer) + } + + fn deserialize(reader: &mut (impl Read + ?Sized)) -> Result { + Ok(Self(u64::deserialize(reader)?)) + } +} diff --git a/rnex-core/src/rmc/structures/helpers.rs b/rnex-rmc/src/helpers.rs similarity index 64% rename from rnex-core/src/rmc/structures/helpers.rs rename to rnex-rmc/src/helpers.rs index eeadbd6..093680d 100644 --- a/rnex-core/src/rmc/structures/helpers.rs +++ b/rnex-rmc/src/helpers.rs @@ -1,16 +1,20 @@ use std::{fmt, io}; +use crate::serialization::Result; + pub struct DummyFormatWriter(u32); -impl fmt::Write for DummyFormatWriter{ +impl fmt::Write for DummyFormatWriter { fn write_str(&mut self, s: &str) -> fmt::Result { self.0 += s.as_bytes().len() as u32; Ok(()) } } -impl DummyFormatWriter{ - pub const fn new() -> Self{ Self(0) } +impl DummyFormatWriter { + pub const fn new() -> Self { + Self(0) + } pub const fn serialize_str_len(&self) -> u32 { 2 + self.0 + 1 } @@ -18,7 +22,7 @@ impl DummyFormatWriter{ pub struct DummyWriter(u32); -impl io::Write for DummyWriter{ +impl io::Write for DummyWriter { fn write(&mut self, buf: &[u8]) -> io::Result { self.0 += buf.len() as u32; Ok(buf.len()) @@ -33,16 +37,17 @@ impl io::Write for DummyWriter{ } } -impl DummyWriter{ - pub const fn new() -> Self{ Self(0) } - pub const fn get_total_len(&self) -> u32{ +impl DummyWriter { + pub const fn new() -> Self { + Self(0) + } + pub const fn get_total_len(&self) -> u32 { self.0 } } - -pub fn len_of_write(f: impl FnOnce(&mut DummyWriter) -> anyhow::Result<()>) -> u32{ +pub fn len_of_write(f: impl FnOnce(&mut DummyWriter) -> Result<()>) -> u32 { let mut dummy = DummyWriter::new(); f(&mut dummy).ok(); dummy.get_total_len() -} \ No newline at end of file +} diff --git a/rnex-rmc/src/lib.rs b/rnex-rmc/src/lib.rs new file mode 100644 index 0000000..4d034b2 --- /dev/null +++ b/rnex-rmc/src/lib.rs @@ -0,0 +1,473 @@ +#![allow(async_fn_in_trait)] + +pub mod helpers; +pub mod message; +pub mod primitives; +pub mod qresult; +pub mod response; +pub mod rmc_struct; +pub mod station_url; +use std::{collections::HashMap, fmt::Debug, io::Cursor, ops::Deref, sync::Arc, time::Duration}; + +pub use rand; +pub use rnex_rmc_macros::*; +use rnex_util::{SendingBufferConnection, SplittableBufferConnection, result::ResultExtension}; +use tokio::{ + sync::{Mutex, Notify}, + task, + time::{Instant, sleep, sleep_until}, +}; +pub use tracing; +pub mod any; +pub mod buffer; +pub mod data; +pub mod date_time; +pub mod list; +pub mod networking; +pub mod qbuffer; +pub mod serialization; +pub mod string; +pub mod string_set; +pub mod variant; + +use thiserror::Error; + +pub mod config { + pub const FEATURE_HAS_STRUCT_HEADER: bool = cfg!(feature = "rmc_struct_header"); +} + +pub use paste; +pub use rnex_util as util; +use tracing::{Instrument, error, info, info_span, instrument}; + +use crate::{ + RemoteCallError::ConnectionBroke, + message::RMCMessage, + response::{ErrorCode, RMCResponse, RMCResponseResult}, + serialization::RmcSerialize, +}; + +#[derive(Error, Debug)] +pub enum RemoteCallError { + #[error("Call to remote timed out whilst waiting on response.")] + Timeout, + #[error("A server side rmc error occurred: {0:?}")] + ServerError(ErrorCode), + #[error("Connection broke")] + ConnectionBroke, + #[error("Error reading response data: {0}")] + InvalidResponse(#[from] serialization::Error), +} + +#[derive(Clone, Debug)] +pub struct RmcConnection(pub SendingBufferConnection, pub RmcResponseReceiver); + +#[derive(Clone, Debug)] +pub struct RmcResponseReceiver(Arc, Arc>>); + +impl RmcConnection { + pub async fn make_raw_call( + &self, + message: &RMCMessage, + ) -> Result { + self.make_raw_call_no_response(message).await?; + + let data = self.1.get_response_data(message.call_id).await?; + + let out = ::deserialize(&mut Cursor::new(data))?; + + Ok(out) + } + + pub async fn make_raw_call_no_response( + &self, + message: &RMCMessage, + ) -> Result<(), RemoteCallError> { + let message_data = message.to_data(); + + self.0.send(message_data).await.ok_or(ConnectionBroke)?; + + Ok(()) + } + + pub async fn disconnect(&self) { + self.0.disconnect().await; + } +} + +pub trait HasProtoId {} + +impl RmcResponseReceiver { + // returns none if timed out + pub async fn get_response_data(&self, call_id: u32) -> Result, RemoteCallError> { + let mut end_wait_time = Instant::now(); + end_wait_time += Duration::from_secs(5); + + let sleep_fut = sleep_until(end_wait_time); + tokio::pin!(sleep_fut); + + let mut sleep_manual_unlock_fut = Instant::now(); + sleep_manual_unlock_fut += Duration::from_secs(4); + + let sleep_manual_unlock_fut = sleep_until(sleep_manual_unlock_fut); + tokio::pin!(sleep_manual_unlock_fut); + + loop { + let mut locked = self.1.lock().await; + + if let Some(v) = locked.remove(&call_id) { + match v.response_result { + RMCResponseResult::Success { data, .. } => return Ok(data), + RMCResponseResult::Error { error_code, .. } => { + return Err(RemoteCallError::ServerError(error_code)); + } + } + } + + drop(locked); + + let notif_fut = self.0.notified(); + + tokio::select! { + _ = &mut sleep_manual_unlock_fut => { + continue; + } + _ = &mut sleep_fut => { + return Err(RemoteCallError::Timeout); + } + _ = notif_fut => { + continue; + } + } + } + } +} + +pub trait HasRmcConnection { + fn get_connection(&self) -> &RmcConnection; +} + +pub trait RemoteObject { + fn new(conn: RmcConnection) -> Self; +} + +impl RemoteObject for () { + fn new(_: RmcConnection) -> Self {} +} + +pub trait RmcCallable { + //type Remote: RemoteObject; + // returns false on fail to match protocol to an implementation + fn rmc_call( + &self, + responder: &SendingBufferConnection, + protocol_id: u16, + method_id: u32, + call_id: u32, + rest: &[u8], + ) -> impl std::future::Future + Send; +} + +impl RmcCallable for Arc { + async fn rmc_call( + &self, + responder: &SendingBufferConnection, + protocol_id: u16, + method_id: u32, + call_id: u32, + rest: &[u8], + ) -> bool { + self.as_ref() + .rmc_call(responder, protocol_id, method_id, call_id, rest) + .await + } +} + +impl RmcCallable for Option { + async fn rmc_call( + &self, + responder: &SendingBufferConnection, + protocol_id: u16, + method_id: u32, + call_id: u32, + rest: &[u8], + ) -> bool { + if let Some(callable) = self.as_ref() { + return callable + .rmc_call(responder, protocol_id, method_id, call_id, rest) + .await; + } + false + } +} + +impl RmcCallable for Box { + async fn rmc_call( + &self, + responder: &SendingBufferConnection, + protocol_id: u16, + method_id: u32, + call_id: u32, + rest: &[u8], + ) -> bool { + self.as_ref() + .rmc_call(responder, protocol_id, method_id, call_id, rest) + .await + } +} + +#[macro_export] +macro_rules! define_rmc_proto { + (proto $name:ident{ + $($protocol:path),* $(,)? + }) => { + $crate::paste::paste!{ + #[allow(unused_variables)] + pub trait []: std::any::Any $( + [] + $protocol)* { + async fn rmc_call(&self, remote_response_connection: &$crate::util::SendingBufferConnection, protocol_id: u16, method_id: u32, call_id: u32, rest: &[u8]) -> bool{ + match protocol_id{ + $( + []::PROTOCOL_ID => {]>::rmc_call_proto(self, remote_response_connection, method_id, call_id, rest).await; true}, + )* + v => false + } + } + } + + #[derive(Debug)] + pub struct []($crate::RmcConnection); + + impl $crate::RmcPureRemoteObject for []{ + fn new(conn: $crate::RmcConnection) -> Self{ + Self(conn) + } + } + + impl $crate::RemoteDisconnectable for []{ + + async fn disconnect(&self){ + self.0.disconnect().await; + } + } + + impl $crate::HasRmcConnection for []{ + fn get_connection(&self) -> &$crate::RmcConnection{ + &self.0 + } + } + + $( + impl [] for []{} + )* + } + }; +} + +/// This is a special case to allow unit to represent the fact that no object is represented. +impl RmcCallable for () { + async fn rmc_call( + &self, + _remote_response_connection: &SendingBufferConnection, + _protocol_id: u16, + _method_id: u32, + _call_id: u32, + _rest: &[u8], + ) -> bool { + false + } +} + +pub trait RmcPureRemoteObject { + fn new(conn: RmcConnection) -> Self; +} + +pub trait RemoteDisconnectable { + async fn disconnect(&self); +} + +#[derive(Debug)] +pub struct OnlyRemote(T); + +impl OnlyRemote { + pub fn new(conn: RmcConnection) -> Self { + Self(T::new(conn)) + } +} + +impl Deref for OnlyRemote { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl OnlyRemote { + pub async fn disconnect(&self) { + self.0.disconnect().await; + } +} + +impl RmcCallable for OnlyRemote { + fn rmc_call( + &self, + _responder: &SendingBufferConnection, + _protocol_id: u16, + _method_id: u32, + _call_id: u32, + _rest: &[u8], + ) -> impl Future + Send { + // maybe respond with not implemented or something + async { false } + } +} + +async fn handle_incoming( + sending_conn: SendingBufferConnection, + remote: Arc, + notify: Arc, + incoming: Arc>>, + data: Vec, +) { + let Some(proto_id) = data.get(4) else { + error!("received too small rmc message."); + error!("ending rmc gateway."); + sending_conn.disconnect().await; + return; + }; + + // protocol 0 is hardcoded to be the no protocol protocol aka keepalive protocol + if *proto_id == 0 { + println!("got keepalive"); + return; + } + + if (proto_id & 0x80) == 0 { + let Some(response) = RMCResponse::new(&mut Cursor::new(data)).display_err_or_some() else { + error!("invalid rmc response."); + error!("ending rmc gateway."); + sending_conn.disconnect().await; + return; + }; + + info!("got rmc response"); + + let mut locked = incoming.lock().await; + + locked.insert(response.get_call_id(), response); + notify.notify_waiters(); + } else { + let Some(message) = RMCMessage::new(&mut Cursor::new(data)).display_err_or_some() else { + error!("invalid rmc message."); + error!("ending rmc gateway."); + sending_conn.disconnect().await; + return; + }; + + let RMCMessage { + protocol_id, + method_id, + call_id, + rest_of_data, + } = message; + + async { + if !remote + .rmc_call( + &sending_conn, + protocol_id, + method_id, + call_id, + &rest_of_data[..], + ) + .await + { + error!( + protocol_id, + method_id, + arguments = hex::encode(&rest_of_data), + "rmc call on unimplemented protocol" + ) + } + } + .instrument(info_span!( + "rmc call", + protocol_id, + method_id, + call_id, + raw_arguments = hex::encode(&rest_of_data), + )) + .await; + } +} + +#[instrument] +async fn handle_incoming_loop( + mut connection: SplittableBufferConnection, + remote: Arc, + notify: Arc, + incoming: Arc>>, +) { + while let Some(data) = connection.recv().await { + let sending_conn = connection.duplicate_sender(); + let remote = remote.clone(); + let notify = notify.clone(); + let incoming = incoming.clone(); + task::spawn( + handle_incoming(sending_conn, remote, notify, incoming, data).in_current_span(), + ); + } + + info!("rmc disconnected") +} + +pub async fn new_rmc_gateway_connection( + conn: SplittableBufferConnection, + create_internal: F, +) -> Arc +where + F: AsyncFnOnce(RmcConnection) -> Arc, +{ + async move { + let notify = Arc::new(Notify::new()); + let incoming: Arc>> = Default::default(); + + let response_recv = RmcResponseReceiver(notify.clone(), incoming.clone()); + + let sending_conn = conn.duplicate_sender(); + + let rmc_conn = RmcConnection(sending_conn, response_recv); + + let sending_conn = conn.duplicate_sender(); + + let exposed_object = (create_internal)(rmc_conn) + .instrument(info_span!("initializing inner object")) + .await; + + { + let exposed_object = exposed_object.clone(); + tokio::spawn(async move { + handle_incoming_loop(conn, exposed_object, notify, incoming).await; + }); + + tokio::spawn( + async move { + while sending_conn.is_alive() { + sending_conn.send([0, 0, 0, 0, 0].to_vec()).await; + sleep(Duration::from_secs(10)).await; + } + } + .instrument(info_span!("timeout sender")), + ); + } + + exposed_object + } + // todo: maybe add info on who we're creating the gateway to somehow + .instrument(info_span!("create new rmc gateway connection")) + .await +} + +define_rmc_proto! { + proto NoProto{} +} diff --git a/rnex-core/src/rmc/structures/list.rs b/rnex-rmc/src/list.rs similarity index 74% rename from rnex-core/src/rmc/structures/list.rs rename to rnex-rmc/src/list.rs index 29b809c..28456b2 100644 --- a/rnex-core/src/rmc/structures/list.rs +++ b/rnex-rmc/src/list.rs @@ -1,13 +1,17 @@ -use crate::rmc::structures::RmcSerialize; use bytemuck::bytes_of; use std::io::{Read, Write}; use std::mem::MaybeUninit; use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; +use crate::serialization::{Result, RmcSerialize}; + +pub type Buffer = Vec; +pub type List = Vec; + // this is also for implementing `Buffer` this is tecnically not the same as its handled internaly // probably but as it has the same mapping it doesn't matter and simplifies things impl RmcSerialize for Vec { - fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> Result<()> { let u32_len = self.len() as u32; writer.write_all(bytes_of(&u32_len))?; @@ -18,7 +22,7 @@ impl RmcSerialize for Vec { Ok(()) } - fn deserialize(mut reader: &mut (impl Read + ?Sized)) -> crate::rmc::structures::Result { + fn deserialize(mut reader: &mut (impl Read + ?Sized)) -> Result { println!("reading list"); let len: u32 = reader.read_struct(IS_BIG_ENDIAN)?; @@ -32,7 +36,7 @@ impl RmcSerialize for Vec { Ok(vec) } - fn serialize_write_size(&self) -> crate::rmc::structures::Result { + fn serialize_write_size(&self) -> Result { let mut val = 0u32; for i in self { val += i.serialize_write_size()?; @@ -42,7 +46,7 @@ impl RmcSerialize for Vec { } impl RmcSerialize for [T; LEN] { - fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> Result<()> { for i in 0..LEN { self[i].serialize(writer)?; } @@ -50,7 +54,7 @@ impl RmcSerialize for [T; LEN] { Ok(()) } - fn deserialize(reader: &mut (impl Read + ?Sized)) -> crate::rmc::structures::Result { + fn deserialize(reader: &mut (impl Read + ?Sized)) -> Result { let mut arr = [const { MaybeUninit::::uninit() }; LEN]; for i in 0..LEN { @@ -64,7 +68,7 @@ impl RmcSerialize for [T; LEN] { Ok(arr) } #[inline(always)] - fn serialize_write_size(&self) -> crate::rmc::structures::Result { + fn serialize_write_size(&self) -> Result { let mut val = 0u32; for i in self { val += i.serialize_write_size()?; diff --git a/rnex-core/src/rmc/message.rs b/rnex-rmc/src/message.rs similarity index 58% rename from rnex-core/src/rmc/message.rs rename to rnex-rmc/src/message.rs index 4fcdfbe..a67454b 100644 --- a/rnex-core/src/rmc/message.rs +++ b/rnex-rmc/src/message.rs @@ -1,34 +1,35 @@ +use bytemuck::bytes_of; use std::io; use std::io::{Read, Seek, Write}; -use bytemuck::bytes_of; -use log::error; +use tracing::error; use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; -use crate::rmc::response::{ErrorCode, RMCResponseResult}; + +use crate::response::{ErrorCode, RMCResponseResult}; #[derive(Debug, Clone, PartialEq, Eq)] -pub struct RMCMessage{ +pub struct RMCMessage { pub protocol_id: u16, pub call_id: u32, pub method_id: u32, - pub rest_of_data: Vec + pub rest_of_data: Vec, } -impl RMCMessage{ - pub fn new(stream: &mut (impl Seek + Read)) -> io::Result{ +impl RMCMessage { + pub fn new(stream: &mut (impl Seek + Read)) -> io::Result { let size: u32 = stream.read_struct(IS_BIG_ENDIAN)?; let mut header_size = 1 + 4 + 4; let protocol_id: u8 = stream.read_struct(IS_BIG_ENDIAN)?; - let protocol_id= protocol_id & (!0x80); + let protocol_id = protocol_id & (!0x80); - let protocol_id: u16 = match protocol_id{ + let protocol_id: u16 = match protocol_id { 0x7F => { header_size += 2; stream.read_struct(IS_BIG_ENDIAN)? - }, - _ => protocol_id as u16 + } + _ => protocol_id as u16, }; let call_id = stream.read_struct(IS_BIG_ENDIAN)?; @@ -39,52 +40,66 @@ impl RMCMessage{ stream.read_to_end(&mut rest_of_data)?; if header_size + rest_of_data.len() != size as usize { - error!("received incorrect rmc packet: expected size {} but found {}", size, header_size + rest_of_data.len()); + error!( + "received incorrect rmc packet: expected size {} but found {}", + size, + header_size + rest_of_data.len() + ); } // println!("rmc packet: protoid: {}, method id: {}", protocol_id, method_id); // println!("{}", hex::encode(&rest_of_data)); //stream. - Ok(Self{ + Ok(Self { protocol_id, method_id, call_id, - rest_of_data + rest_of_data, }) } - pub fn to_data(&self) -> Vec{ + pub fn to_data(&self) -> Vec { let size = (1 + 4 + 4 + self.rest_of_data.len()) as u32; let mut output = Vec::new(); - output.write_all(bytes_of(&size)).expect("unable to write size"); + output + .write_all(bytes_of(&size)) + .expect("unable to write size"); let proto_id = self.protocol_id as u8 | 0x80; - output.write_all(bytes_of(&proto_id)).expect("unable to write size"); + output + .write_all(bytes_of(&proto_id)) + .expect("unable to write size"); - output.write_all(bytes_of(&self.call_id)).expect("unable to write size"); - output.write_all(bytes_of(&self.method_id)).expect("unable to write size"); + output + .write_all(bytes_of(&self.call_id)) + .expect("unable to write size"); + output + .write_all(bytes_of(&self.method_id)) + .expect("unable to write size"); - output.write_all(&self.rest_of_data).expect("unable to write data"); + output + .write_all(&self.rest_of_data) + .expect("unable to write data"); output } - pub fn error_result_with_code(&self, error_code: ErrorCode) -> RMCResponseResult{ + pub fn error_result_with_code(&self, error_code: ErrorCode) -> RMCResponseResult { RMCResponseResult::Error { call_id: self.call_id, - error_code + error_code, } } - pub fn success_with_data(&self, data: Vec) -> RMCResponseResult{ + pub fn success_with_data(&self, data: Vec) -> RMCResponseResult { RMCResponseResult::Success { call_id: self.call_id, method_id: self.method_id, - data + data, } } -} \ No newline at end of file +} diff --git a/rnex-core/src/rmc/structures/networking.rs b/rnex-rmc/src/networking.rs similarity index 70% rename from rnex-core/src/rmc/structures/networking.rs rename to rnex-rmc/src/networking.rs index 86e0acb..cb65e3b 100644 --- a/rnex-core/src/rmc/structures/networking.rs +++ b/rnex-rmc/src/networking.rs @@ -1,9 +1,9 @@ -use crate::rmc::structures::{Error, Result, RmcSerialize}; -use rnex_core::prudp::virtual_port::VirtualPort; use std::io::{Read, Write}; use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; +use crate::serialization::{Error, Result, RmcSerialize}; + impl RmcSerialize for SocketAddr { fn deserialize(mut reader: &mut (impl Read + ?Sized)) -> Result where @@ -32,25 +32,25 @@ impl RmcSerialize for SocketAddr { } impl RmcSerialize for SocketAddrV4 { - fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> Result<()> { self.ip().to_bits().serialize(writer)?; self.port().serialize(writer)?; Ok(()) } - fn deserialize(reader: &mut (impl Read + ?Sized)) -> crate::rmc::structures::Result { + fn deserialize(reader: &mut (impl Read + ?Sized)) -> Result { let ip = u32::deserialize(reader)?; let port = u16::deserialize(reader)?; Ok(SocketAddrV4::new(Ipv4Addr::from_bits(ip), port)) } - fn serialize_write_size(&self) -> crate::rmc::structures::Result { + fn serialize_write_size(&self) -> Result { Ok(6) } } impl RmcSerialize for SocketAddrV6 { - fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> Result<()> { self.ip().to_bits().serialize(writer)?; self.port().serialize(writer)?; self.flowinfo().serialize(writer)?; @@ -59,7 +59,7 @@ impl RmcSerialize for SocketAddrV6 { Ok(()) } - fn deserialize(reader: &mut (impl Read + ?Sized)) -> crate::rmc::structures::Result { + fn deserialize(reader: &mut (impl Read + ?Sized)) -> Result { let ip = u128::deserialize(reader)?; let port = u16::deserialize(reader)?; let flowinfo = u32::deserialize(reader)?; @@ -72,22 +72,23 @@ impl RmcSerialize for SocketAddrV6 { scope_id, )) } - fn serialize_write_size(&self) -> crate::rmc::structures::Result { + fn serialize_write_size(&self) -> Result { Ok(6) } } - +/* +use rnex_core::prudp::virtual_port::VirtualPort; impl RmcSerialize for VirtualPort { - fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> Result<()> { self.0.serialize(writer)?; Ok(()) } - fn deserialize(reader: &mut (impl Read + ?Sized)) -> crate::rmc::structures::Result { + fn deserialize(reader: &mut (impl Read + ?Sized)) -> Result { Ok(Self(u8::deserialize(reader)?)) } - fn serialize_write_size(&self) -> crate::rmc::structures::Result { + fn serialize_write_size(&self) -> Result { Ok(1) } -} +}*/ diff --git a/rnex-core/src/rmc/structures/primitives.rs b/rnex-rmc/src/primitives.rs similarity index 66% rename from rnex-core/src/rmc/structures/primitives.rs rename to rnex-rmc/src/primitives.rs index a925165..d0e3f3a 100644 --- a/rnex-core/src/rmc/structures/primitives.rs +++ b/rnex-rmc/src/primitives.rs @@ -1,166 +1,167 @@ -use crate::rmc::structures::RmcSerialize; use bytemuck::{bytes_of, bytes_of_mut}; use std::io::{Read, Write}; use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; +use crate::serialization::{Result, RmcSerialize}; + impl RmcSerialize for u8 { #[inline(always)] - fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> Result<()> { Ok(writer.write_all(bytes_of(self))?) } #[inline(always)] - fn deserialize(mut reader: &mut (impl Read + ?Sized)) -> crate::rmc::structures::Result { + fn deserialize(mut reader: &mut (impl Read + ?Sized)) -> Result { Ok(reader.read_struct(IS_BIG_ENDIAN)?) } #[inline(always)] - fn serialize_write_size(&self) -> crate::rmc::structures::Result { + fn serialize_write_size(&self) -> Result { Ok(1) } } impl RmcSerialize for i8 { #[inline(always)] - fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> Result<()> { Ok(writer.write_all(bytes_of(self))?) } #[inline(always)] - fn deserialize(mut reader: &mut (impl Read + ?Sized)) -> crate::rmc::structures::Result { + fn deserialize(mut reader: &mut (impl Read + ?Sized)) -> Result { Ok(reader.read_struct(IS_BIG_ENDIAN)?) } #[inline(always)] - fn serialize_write_size(&self) -> crate::rmc::structures::Result { + fn serialize_write_size(&self) -> Result { Ok(1) } } impl RmcSerialize for u16 { #[inline(always)] - fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> Result<()> { Ok(writer.write_all(bytes_of(self))?) } #[inline(always)] - fn deserialize(mut reader: &mut (impl Read + ?Sized)) -> crate::rmc::structures::Result { + fn deserialize(mut reader: &mut (impl Read + ?Sized)) -> Result { Ok(reader.read_struct(IS_BIG_ENDIAN)?) } #[inline(always)] - fn serialize_write_size(&self) -> crate::rmc::structures::Result { + fn serialize_write_size(&self) -> Result { Ok(2) } } impl RmcSerialize for i16 { #[inline(always)] - fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> Result<()> { Ok(writer.write_all(bytes_of(self))?) } #[inline(always)] - fn deserialize(mut reader: &mut (impl Read + ?Sized)) -> crate::rmc::structures::Result { + fn deserialize(mut reader: &mut (impl Read + ?Sized)) -> Result { Ok(reader.read_struct(IS_BIG_ENDIAN)?) } #[inline(always)] - fn serialize_write_size(&self) -> crate::rmc::structures::Result { + fn serialize_write_size(&self) -> Result { Ok(2) } } impl RmcSerialize for u32 { #[inline(always)] - fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> Result<()> { Ok(writer.write_all(bytes_of(self))?) } #[inline(always)] - fn deserialize(mut reader: &mut (impl Read + ?Sized)) -> crate::rmc::structures::Result { + fn deserialize(mut reader: &mut (impl Read + ?Sized)) -> Result { Ok(reader.read_struct(IS_BIG_ENDIAN)?) } #[inline(always)] - fn serialize_write_size(&self) -> crate::rmc::structures::Result { + fn serialize_write_size(&self) -> Result { Ok(4) } } impl RmcSerialize for i32 { #[inline(always)] - fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> Result<()> { Ok(writer.write_all(bytes_of(self))?) } #[inline(always)] - fn deserialize(mut reader: &mut (impl Read + ?Sized)) -> crate::rmc::structures::Result { + fn deserialize(mut reader: &mut (impl Read + ?Sized)) -> Result { Ok(reader.read_struct(IS_BIG_ENDIAN)?) } #[inline(always)] - fn serialize_write_size(&self) -> crate::rmc::structures::Result { + fn serialize_write_size(&self) -> Result { Ok(4) } } impl RmcSerialize for u64 { #[inline(always)] - fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> Result<()> { Ok(writer.write_all(bytes_of(self))?) } #[inline(always)] - fn deserialize(mut reader: &mut (impl Read + ?Sized)) -> crate::rmc::structures::Result { + fn deserialize(mut reader: &mut (impl Read + ?Sized)) -> Result { Ok(reader.read_struct(IS_BIG_ENDIAN)?) } #[inline(always)] - fn serialize_write_size(&self) -> crate::rmc::structures::Result { + fn serialize_write_size(&self) -> Result { Ok(8) } } impl RmcSerialize for u128 { #[inline(always)] - fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> Result<()> { Ok(writer.write_all(bytes_of(self))?) } #[inline(always)] - fn deserialize(reader: &mut (impl Read + ?Sized)) -> crate::rmc::structures::Result { + fn deserialize(reader: &mut (impl Read + ?Sized)) -> Result { let mut data = 0u128; reader.read_exact(&mut bytes_of_mut(&mut data))?; Ok(data) } #[inline(always)] - fn serialize_write_size(&self) -> crate::rmc::structures::Result { + fn serialize_write_size(&self) -> Result { Ok(8) } } impl RmcSerialize for i64 { #[inline(always)] - fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> Result<()> { Ok(writer.write_all(bytes_of(self))?) } #[inline(always)] - fn deserialize(mut reader: &mut (impl Read + ?Sized)) -> crate::rmc::structures::Result { + fn deserialize(mut reader: &mut (impl Read + ?Sized)) -> Result { Ok(reader.read_struct(IS_BIG_ENDIAN)?) } #[inline(always)] - fn serialize_write_size(&self) -> crate::rmc::structures::Result { + fn serialize_write_size(&self) -> Result { Ok(8) } } impl RmcSerialize for f64 { #[inline(always)] - fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> Result<()> { Ok(writer.write_all(bytes_of(self))?) } #[inline(always)] - fn deserialize(mut reader: &mut (impl Read + ?Sized)) -> crate::rmc::structures::Result { + fn deserialize(mut reader: &mut (impl Read + ?Sized)) -> Result { Ok(reader.read_struct(IS_BIG_ENDIAN)?) } #[inline(always)] - fn serialize_write_size(&self) -> crate::rmc::structures::Result { + fn serialize_write_size(&self) -> Result { Ok(8) } } impl RmcSerialize for bool { #[inline(always)] - fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> Result<()> { match self { true => writer.write_all(&[1])?, false => writer.write_all(&[0])?, @@ -169,45 +170,45 @@ impl RmcSerialize for bool { } #[inline(always)] - fn deserialize(reader: &mut (impl Read + ?Sized)) -> crate::rmc::structures::Result { + fn deserialize(reader: &mut (impl Read + ?Sized)) -> Result { Ok(u8::deserialize(reader)? != 0) } #[inline(always)] - fn serialize_write_size(&self) -> crate::rmc::structures::Result { + fn serialize_write_size(&self) -> Result { Ok(1) } } impl RmcSerialize for (T, U) { #[inline(always)] - fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> Result<()> { self.0.serialize(writer)?; self.1.serialize(writer)?; Ok(()) } #[inline(always)] - fn deserialize(reader: &mut (impl Read + ?Sized)) -> crate::rmc::structures::Result { + fn deserialize(reader: &mut (impl Read + ?Sized)) -> Result { let first = T::deserialize(reader)?; let second = U::deserialize(reader)?; Ok((first, second)) } #[inline(always)] - fn serialize_write_size(&self) -> crate::rmc::structures::Result { + fn serialize_write_size(&self) -> Result { Ok(self.0.serialize_write_size()? + self.1.serialize_write_size()?) } } impl RmcSerialize for (T, U, V) { #[inline(always)] - fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> Result<()> { self.0.serialize(writer)?; self.1.serialize(writer)?; self.2.serialize(writer)?; Ok(()) } #[inline(always)] - fn deserialize(reader: &mut (impl Read + ?Sized)) -> crate::rmc::structures::Result { + fn deserialize(reader: &mut (impl Read + ?Sized)) -> Result { let first = T::deserialize(reader)?; let second = U::deserialize(reader)?; let third = V::deserialize(reader)?; @@ -215,7 +216,7 @@ impl RmcSerialize for (T, U, Ok((first, second, third)) } #[inline(always)] - fn serialize_write_size(&self) -> crate::rmc::structures::Result { + fn serialize_write_size(&self) -> Result { Ok(self.0.serialize_write_size()? + self.1.serialize_write_size()? + self.2.serialize_write_size()?) @@ -226,7 +227,7 @@ impl RmcSeri for (T, U, V, W) { #[inline(always)] - fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> Result<()> { self.0.serialize(writer)?; self.1.serialize(writer)?; self.2.serialize(writer)?; @@ -234,7 +235,7 @@ impl RmcSeri Ok(()) } #[inline(always)] - fn deserialize(reader: &mut (impl Read + ?Sized)) -> crate::rmc::structures::Result { + fn deserialize(reader: &mut (impl Read + ?Sized)) -> Result { let first = T::deserialize(reader)?; let second = U::deserialize(reader)?; let third = V::deserialize(reader)?; @@ -243,7 +244,7 @@ impl RmcSeri Ok((first, second, third, fourth)) } #[inline(always)] - fn serialize_write_size(&self) -> crate::rmc::structures::Result { + fn serialize_write_size(&self) -> Result { Ok(self.0.serialize_write_size()? + self.1.serialize_write_size()? + self.2.serialize_write_size()? @@ -255,7 +256,7 @@ impl crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> Result<()> { self.0.serialize(writer)?; self.1.serialize(writer)?; self.2.serialize(writer)?; @@ -266,7 +267,7 @@ impl crate::rmc::structures::Result { + fn deserialize(reader: &mut (impl Read + ?Sized)) -> Result { let first = T::deserialize(reader)?; let second = U::deserialize(reader)?; let third = V::deserialize(reader)?; @@ -276,7 +277,7 @@ impl crate::rmc::structures::Result { + fn serialize_write_size(&self) -> Result { Ok(self.0.serialize_write_size()? + self.1.serialize_write_size()? + self.2.serialize_write_size()? @@ -295,7 +296,7 @@ impl< > RmcSerialize for (T, U, V, W, X, Y) { #[inline(always)] - fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> Result<()> { self.0.serialize(writer)?; self.1.serialize(writer)?; self.2.serialize(writer)?; @@ -307,7 +308,7 @@ impl< } #[inline(always)] - fn deserialize(reader: &mut (impl Read + ?Sized)) -> crate::rmc::structures::Result { + fn deserialize(reader: &mut (impl Read + ?Sized)) -> Result { let first = T::deserialize(reader)?; let second = U::deserialize(reader)?; let third = V::deserialize(reader)?; @@ -318,7 +319,7 @@ impl< Ok((first, second, third, fourth, fifth, sixth)) } #[inline(always)] - fn serialize_write_size(&self) -> crate::rmc::structures::Result { + fn serialize_write_size(&self) -> Result { Ok(self.0.serialize_write_size()? + self.1.serialize_write_size()? + self.2.serialize_write_size()? @@ -339,7 +340,7 @@ impl< > RmcSerialize for (T, U, V, W, X, Y, Z) { #[inline(always)] - fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> Result<()> { self.0.serialize(writer)?; self.1.serialize(writer)?; self.2.serialize(writer)?; @@ -351,7 +352,7 @@ impl< Ok(()) } #[inline(always)] - fn deserialize(reader: &mut (impl Read + ?Sized)) -> crate::rmc::structures::Result { + fn deserialize(reader: &mut (impl Read + ?Sized)) -> Result { let first = T::deserialize(reader)?; let second = U::deserialize(reader)?; let third = V::deserialize(reader)?; @@ -363,7 +364,7 @@ impl< Ok((first, second, third, fourth, fifth, sixth, seventh)) } #[inline(always)] - fn serialize_write_size(&self) -> crate::rmc::structures::Result { + fn serialize_write_size(&self) -> Result { Ok(self.0.serialize_write_size()? + self.1.serialize_write_size()? + self.2.serialize_write_size()? @@ -386,7 +387,7 @@ impl< > RmcSerialize for (T, U, V, W, X, Y, Z, A) { #[inline(always)] - fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> Result<()> { self.0.serialize(writer)?; self.1.serialize(writer)?; self.2.serialize(writer)?; @@ -399,7 +400,7 @@ impl< Ok(()) } #[inline(always)] - fn deserialize(reader: &mut (impl Read + ?Sized)) -> crate::rmc::structures::Result { + fn deserialize(reader: &mut (impl Read + ?Sized)) -> Result { let first = T::deserialize(reader)?; let second = U::deserialize(reader)?; let third = V::deserialize(reader)?; @@ -412,7 +413,7 @@ impl< Ok((first, second, third, fourth, fifth, sixth, seventh, eighth)) } #[inline(always)] - fn serialize_write_size(&self) -> crate::rmc::structures::Result { + fn serialize_write_size(&self) -> Result { Ok(self.0.serialize_write_size()? + self.1.serialize_write_size()? + self.2.serialize_write_size()? @@ -437,7 +438,7 @@ impl< > RmcSerialize for (T, U, V, W, X, Y, Z, A, B) { #[inline(always)] - fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> Result<()> { self.0.serialize(writer)?; self.1.serialize(writer)?; self.2.serialize(writer)?; @@ -451,7 +452,7 @@ impl< Ok(()) } #[inline(always)] - fn deserialize(reader: &mut (impl Read + ?Sized)) -> crate::rmc::structures::Result { + fn deserialize(reader: &mut (impl Read + ?Sized)) -> Result { let first = T::deserialize(reader)?; let second = U::deserialize(reader)?; let third = V::deserialize(reader)?; @@ -467,7 +468,7 @@ impl< )) } #[inline(always)] - fn serialize_write_size(&self) -> crate::rmc::structures::Result { + fn serialize_write_size(&self) -> Result { Ok(self.0.serialize_write_size()? + self.1.serialize_write_size()? + self.2.serialize_write_size()? @@ -482,15 +483,15 @@ impl< impl RmcSerialize for Box { #[inline(always)] - fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> Result<()> { self.as_ref().serialize(writer) } #[inline(always)] - fn deserialize(reader: &mut (impl Read + ?Sized)) -> crate::rmc::structures::Result { + fn deserialize(reader: &mut (impl Read + ?Sized)) -> Result { T::deserialize(reader).map(Box::new) } #[inline(always)] - fn serialize_write_size(&self) -> crate::rmc::structures::Result { + fn serialize_write_size(&self) -> Result { T::serialize_write_size(self.as_ref()) } } diff --git a/rnex-core/src/rmc/structures/qbuffer.rs b/rnex-rmc/src/qbuffer.rs similarity index 92% rename from rnex-core/src/rmc/structures/qbuffer.rs rename to rnex-rmc/src/qbuffer.rs index 171f749..4b1125d 100644 --- a/rnex-core/src/rmc/structures/qbuffer.rs +++ b/rnex-rmc/src/qbuffer.rs @@ -1,8 +1,9 @@ -use crate::rmc::structures::{Result, RmcSerialize}; use bytemuck::bytes_of; use std::io::{Read, Write}; use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; +use crate::serialization::{Result, RmcSerialize}; + #[derive(Clone, Debug, Default)] pub struct QBuffer(pub Vec); diff --git a/rnex-core/src/rmc/structures/qresult.rs b/rnex-rmc/src/qresult.rs similarity index 52% rename from rnex-core/src/rmc/structures/qresult.rs rename to rnex-rmc/src/qresult.rs index 7048495..bbc0757 100644 --- a/rnex-core/src/rmc/structures/qresult.rs +++ b/rnex-rmc/src/qresult.rs @@ -1,13 +1,14 @@ -use crate::rmc::response::ErrorCode; -use crate::rmc::structures::{Result, RmcSerialize}; -use bytemuck::{Pod, Zeroable, bytes_of}; +use bytemuck::{Pod, Zeroable}; use std::io::{Read, Write}; -use v_byte_helpers::SwapEndian; -use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; + +use crate::{ + response::ErrorCode, + serialization::{Result, RmcSerialize}, +}; pub const ERROR_MASK: u32 = 1 << 31; -#[derive(Pod, Zeroable, Copy, Clone, SwapEndian, Debug)] +#[derive(Pod, Zeroable, Copy, Clone, Debug)] #[repr(transparent)] pub struct QResult(u32); @@ -27,14 +28,11 @@ impl QResult { impl RmcSerialize for QResult { fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> Result<()> { - writer.write(bytes_of(self))?; - Ok(()) + self.0.serialize(writer) } - fn deserialize(mut reader: &mut (impl Read + ?Sized)) -> Result { - let result: Self = reader.read_struct(IS_BIG_ENDIAN)?; - println!("reading qresult: {:x}", result.0); - Ok(result) + fn deserialize(reader: &mut (impl Read + ?Sized)) -> Result { + RmcSerialize::deserialize(reader).map(Self) } fn serialize_write_size(&self) -> Result { Ok(4) diff --git a/rnex-rmc/src/response.rs b/rnex-rmc/src/response.rs new file mode 100644 index 0000000..7f71f6e --- /dev/null +++ b/rnex-rmc/src/response.rs @@ -0,0 +1,470 @@ +// i seriously dont know why the compiler is complaining about unused parentheses in the repr +// attributes but this gets it to not complain anymore +#![allow(unused_parens)] + +use crate::qresult::ERROR_MASK; +use crate::serialization::Error; +use bytemuck::bytes_of; +use rnex_util::SendingBufferConnection; +use std::io; +use std::io::{Read, Seek, Write}; +use std::mem::transmute; +use tracing::{error, warn}; +use v_byte_helpers::EnumTryInto; +use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; + +#[derive(Debug, Clone)] +pub enum RMCResponseResult { + Success { + call_id: u32, + method_id: u32, + data: Vec, + }, + Error { + error_code: ErrorCode, + call_id: u32, + }, +} + +#[derive(Debug, Clone)] +pub struct RMCResponse { + pub protocol_id: u8, + pub response_result: RMCResponseResult, +} + +impl RMCResponse { + pub fn new(stream: &mut (impl Seek + Read)) -> io::Result { + // ignore the size for now this will only be used for checking + let size: u32 = stream.read_struct(IS_BIG_ENDIAN)?; + + let protocol_id: u8 = stream.read_struct(IS_BIG_ENDIAN)?; + + /*let protocol_id: u16 = match protocol_id{ + 0x7F => { + stream.read_struct(IS_BIG_ENDIAN)? + }, + _ => protocol_id as u16 + };*/ + + let is_success: u8 = stream.read_struct(IS_BIG_ENDIAN)?; + + let response_result = if is_success == 0x01 { + let call_id: u32 = stream.read_struct(IS_BIG_ENDIAN)?; + let method_id: u32 = stream.read_struct(IS_BIG_ENDIAN)?; + let method_id = method_id & (!0x8000); + + let mut data: Vec = vec![0u8; (size - 2 - 4 - 4) as _]; + + stream.read(&mut data)?; + + RMCResponseResult::Success { + call_id, + method_id, + data, + } + } else { + let error_code: u32 = stream.read_struct(IS_BIG_ENDIAN)?; + let error_code = error_code & (!0x8000_0000); + let call_id: u32 = stream.read_struct(IS_BIG_ENDIAN)?; + + RMCResponseResult::Error { + error_code: { + match ErrorCode::try_from(error_code) { + Ok(v) => v, + Err(_) => { + error!("invalid error code {:#010x}", error_code); + ErrorCode::Core_Exception + } + } + }, + call_id, + } + }; + + Ok(Self { + protocol_id, + response_result, + }) + } + + pub fn get_call_id(&self) -> u32 { + match &self.response_result { + RMCResponseResult::Success { call_id, .. } => *call_id, + RMCResponseResult::Error { call_id, .. } => *call_id, + } + } + + pub fn to_data(self) -> Vec { + generate_response(self.protocol_id, self.response_result) + .expect("failed to generate response") + } +} + +pub fn generate_response(protocol_id: u8, response: RMCResponseResult) -> io::Result> { + let size = 1 + + 1 + + match &response { + RMCResponseResult::Success { data, .. } => 4 + 4 + data.len(), + RMCResponseResult::Error { .. } => 4 + 4, + }; + + let mut data_out = Vec::with_capacity(size + 4); + + let u32_size: u32 = size as _; + + data_out.write_all(bytes_of(&u32_size))?; + data_out.push(protocol_id); + + match response { + RMCResponseResult::Success { + call_id, + method_id, + data, + } => { + data_out.push(1); + data_out.write_all(bytes_of(&call_id))?; + let ored_method_id = method_id | 0x8000; + data_out.write_all(bytes_of(&ored_method_id))?; + data_out.write_all(&data)?; + } + RMCResponseResult::Error { + call_id, + error_code, + } => { + data_out.push(0); + let error_code_val: u32 = error_code.into(); + let error_code_val = error_code_val | ERROR_MASK; + data_out.write_all(bytes_of(&error_code_val))?; + data_out.write_all(bytes_of(&call_id))?; + } + } + + assert_eq!(data_out.len(), size + 4); + + Ok(data_out) +} + +pub async fn send_result( + connection: &SendingBufferConnection, + result: Result, ErrorCode>, + protocol_id: u8, + method_id: u32, + call_id: u32, +) { + let response_result = match result { + Ok(v) => RMCResponseResult::Success { + call_id, + method_id, + data: v, + }, + Err(e) => { + warn!("error occurred during call: {:?}", e); + RMCResponseResult::Error { + call_id, + error_code: e.into(), + } + } + }; + + let response = RMCResponse { + response_result, + protocol_id, + }; + + send_response(connection, response).await +} + +pub async fn send_response(connection: &SendingBufferConnection, rmcresponse: RMCResponse) { + connection.send(rmcresponse.to_data()).await; +} + +//taken from kinnays error list directly +#[allow(nonstandard_style)] +#[repr(u32)] +#[derive(Debug, EnumTryInto, Clone, Copy)] +pub enum ErrorCode { + Core_Unknown = 0x0001_0001, + Core_NotImplemented = 0x0001_0002, + Core_InvalidPointer = 0x0001_0003, + Core_OperationAborted = 0x0001_0004, + Core_Exception = 0x0001_0005, + Core_AccessDenied = 0x0001_0006, + Core_InvalidHandle = 0x0001_0007, + Core_InvalidIndex = 0x0001_0008, + Core_OutOfMemory = 0x0001_0009, + Core_InvalidArgument = 0x0001_000A, + Core_Timeout = 0x0001_000B, + Core_InitializationFailure = 0x0001_000C, + Core_CallInitiationFailure = 0x0001_000D, + Core_RegistrationError = 0x0001_000E, + Core_BufferOverflow = 0x0001_000F, + Core_InvalidLockState = 0x0001_0010, + Core_InvalidSequence = 0x0001_0011, + Core_SystemError = 0x0001_0012, + Core_Cancelled = 0x0001_0013, + DDL_InvalidSignature = 0x0002_0001, + DDL_IncorrectVersion = 0x0002_0002, + RendezVous_ConnectionFailure = 0x0003_0001, + RendezVous_NotAuthenticated = 0x0003_0002, + RendezVous_InvalidUsername = 0x0003_0064, + RendezVous_InvalidPassword = 0x0003_0065, + RendezVous_UsernameAlreadyExists = 0x0003_0066, + RendezVous_AccountDisabled = 0x0003_0067, + RendezVous_AccountExpired = 0x0003_0068, + RendezVous_ConcurrentLoginDenied = 0x0003_0069, + RendezVous_EncryptionFailure = 0x0003_006A, + RendezVous_InvalidPID = 0x0003_006B, + RendezVous_MaxConnectionsReached = 0x0003_006C, + RendezVous_InvalidGID = 0x0003_006D, + RendezVous_InvalidControlScriptID = 0x0003_006E, + RendezVous_InvalidOperationInLiveEnvironment = 0x0003_006F, + RendezVous_DuplicateEntry = 0x0003_0070, + RendezVous_ControlScriptFailure = 0x0003_0071, + RendezVous_ClassNotFound = 0x0003_0072, + RendezVous_SessionVoid = 0x0003_0073, + RendezVous_DDLMismatch = 0x0003_0075, + RendezVous_InvalidConfiguration = 0x0003_0076, + RendezVous_SessionFull = 0x0003_00C8, + RendezVous_InvalidGatheringPassword = 0x0003_00C9, + RendezVous_WithoutParticipationPeriod = 0x0003_00CA, + RendezVous_PersistentGatheringCreationMax = 0x0003_00CB, + RendezVous_PersistentGatheringParticipationMax = 0x0003_00CC, + RendezVous_DeniedByParticipants = 0x0003_00CD, + RendezVous_ParticipantInBlackList = 0x0003_00CE, + RendezVous_GameServerMaintenance = 0x0003_00CF, + RendezVous_OperationPostpone = 0x0003_00D0, + RendezVous_OutOfRatingRange = 0x0003_00D1, + RendezVous_ConnectionDisconnected = 0x0003_00D2, + RendezVous_InvalidOperation = 0x0003_00D3, + RendezVous_NotParticipatedGathering = 0x0003_00D4, + RendezVous_MatchmakeSessionUserPasswordUnmatch = 0x0003_00D5, + RendezVous_MatchmakeSessionSystemPasswordUnmatch = 0x0003_00D6, + RendezVous_UserIsOffline = 0x0003_00D7, + RendezVous_AlreadyParticipatedGathering = 0x0003_00D8, + RendezVous_PermissionDenied = 0x0003_00D9, + RendezVous_NotFriend = 0x0003_00DA, + RendezVous_SessionClosed = 0x0003_00DB, + RendezVous_DatabaseTemporarilyUnavailable = 0x0003_00DC, + RendezVous_InvalidUniqueId = 0x0003_00DD, + RendezVous_MatchmakingWithdrawn = 0x0003_00DE, + RendezVous_LimitExceeded = 0x0003_00DF, + RendezVous_AccountTemporarilyDisabled = 0x0003_00E0, + RendezVous_PartiallyServiceClosed = 0x0003_00E1, + RendezVous_ConnectionDisconnectedForConcurrentLogin = 0x0003_00E2, + PythonCore_Exception = 0x0004_0001, + PythonCore_TypeError = 0x0004_0002, + PythonCore_IndexError = 0x0004_0003, + PythonCore_InvalidReference = 0x0004_0004, + PythonCore_CallFailure = 0x0004_0005, + PythonCore_MemoryError = 0x0004_0006, + PythonCore_KeyError = 0x0004_0007, + PythonCore_OperationError = 0x0004_0008, + PythonCore_ConversionError = 0x0004_0009, + PythonCore_ValidationError = 0x0004_000A, + Transport_Unknown = 0x0005_0001, + Transport_ConnectionFailure = 0x0005_0002, + Transport_InvalidUrl = 0x0005_0003, + Transport_InvalidKey = 0x0005_0004, + Transport_InvalidURLType = 0x0005_0005, + Transport_DuplicateEndpoint = 0x0005_0006, + Transport_IOError = 0x0005_0007, + Transport_Timeout = 0x0005_0008, + Transport_ConnectionReset = 0x0005_0009, + Transport_IncorrectRemoteAuthentication = 0x0005_000A, + Transport_ServerRequestError = 0x0005_000B, + Transport_DecompressionFailure = 0x0005_000C, + Transport_ReliableSendBufferFullFatal = 0x0005_000D, + Transport_UPnPCannotInit = 0x0005_000E, + Transport_UPnPCannotAddMapping = 0x0005_000F, + Transport_NatPMPCannotInit = 0x0005_0010, + Transport_NatPMPCannotAddMapping = 0x0005_0011, + Transport_UnsupportedNAT = 0x0005_0013, + Transport_DnsError = 0x0005_0014, + Transport_ProxyError = 0x0005_0015, + Transport_DataRemaining = 0x0005_0016, + Transport_NoBuffer = 0x0005_0017, + Transport_NotFound = 0x0005_0018, + Transport_TemporaryServerError = 0x0005_0019, + Transport_PermanentServerError = 0x0005_001A, + Transport_ServiceUnavailable = 0x0005_001B, + Transport_ReliableSendBufferFull = 0x0005_001C, + Transport_InvalidStation = 0x0005_001D, + Transport_InvalidSubStreamID = 0x0005_001E, + Transport_PacketBufferFull = 0x0005_001F, + Transport_NatTraversalError = 0x0005_0020, + Transport_NatCheckError = 0x0005_0021, + DOCore_StationNotReached = 0x0006_0001, + DOCore_TargetStationDisconnect = 0x0006_0002, + DOCore_LocalStationLeaving = 0x0006_0003, + DOCore_ObjectNotFound = 0x0006_0004, + DOCore_InvalidRole = 0x0006_0005, + DOCore_CallTimeout = 0x0006_0006, + DOCore_RMCDispatchFailed = 0x0006_0007, + DOCore_MigrationInProgress = 0x0006_0008, + DOCore_NoAuthority = 0x0006_0009, + DOCore_NoTargetStationSpecified = 0x0006_000A, + DOCore_JoinFailed = 0x0006_000B, + DOCore_JoinDenied = 0x0006_000C, + DOCore_ConnectivityTestFailed = 0x0006_000D, + DOCore_Unknown = 0x0006_000E, + DOCore_UnfreedReferences = 0x0006_000F, + DOCore_JobTerminationFailed = 0x0006_0010, + DOCore_InvalidState = 0x0006_0011, + DOCore_FaultRecoveryFatal = 0x0006_0012, + DOCore_FaultRecoveryJobProcessFailed = 0x0006_0013, + DOCore_StationInconsitency = 0x0006_0014, + DOCore_AbnormalMasterState = 0x0006_0015, + DOCore_VersionMismatch = 0x0006_0016, + FPD_NotInitialized = 0x0065_0000, + FPD_AlreadyInitialized = 0x0065_0001, + FPD_NotConnected = 0x0065_0002, + FPD_Connected = 0x0065_0003, + FPD_InitializationFailure = 0x0065_0004, + FPD_OutOfMemory = 0x0065_0005, + FPD_RmcFailed = 0x0065_0006, + FPD_InvalidArgument = 0x0065_0007, + FPD_InvalidLocalAccountID = 0x0065_0008, + FPD_InvalidPrincipalID = 0x0065_0009, + FPD_InvalidLocalFriendCode = 0x0065_000A, + FPD_LocalAccountNotExists = 0x0065_000B, + FPD_LocalAccountNotLoaded = 0x0065_000C, + FPD_LocalAccountAlreadyLoaded = 0x0065_000D, + FPD_FriendAlreadyExists = 0x0065_000E, + FPD_FriendNotExists = 0x0065_000F, + FPD_FriendNumMax = 0x0065_0010, + FPD_NotFriend = 0x0065_0011, + FPD_FileIO = 0x0065_0012, + FPD_P2PInternetProhibited = 0x0065_0013, + FPD_Unknown = 0x0065_0014, + FPD_InvalidState = 0x0065_0015, + FPD_AddFriendProhibited = 0x0065_0017, + FPD_InvalidAccount = 0x0065_0019, + FPD_BlacklistedByMe = 0x0065_001A, + FPD_FriendAlreadyAdded = 0x0065_001C, + FPD_MyFriendListLimitExceed = 0x0065_001D, + FPD_RequestLimitExceed = 0x0065_001E, + FPD_InvalidMessageID = 0x0065_001F, + FPD_MessageIsNotMine = 0x0065_0020, + FPD_MessageIsNotForMe = 0x0065_0021, + FPD_FriendRequestBlocked = 0x0065_0022, + FPD_NotInMyFriendList = 0x0065_0023, + FPD_FriendListedByMe = 0x0065_0024, + FPD_NotInMyBlacklist = 0x0065_0025, + FPD_IncompatibleAccount = 0x0065_0026, + FPD_BlockSettingChangeNotAllowed = 0x0065_0027, + FPD_SizeLimitExceeded = 0x0065_0028, + FPD_OperationNotAllowed = 0x0065_0029, + FPD_NotNetworkAccount = 0x0065_002A, + FPD_NotificationNotFound = 0x0065_002B, + FPD_PreferenceNotInitialized = 0x0065_002C, + FPD_FriendRequestNotAllowed = 0x0065_002D, + Ranking_NotInitialized = 0x0067_0001, + Ranking_InvalidArgument = 0x0067_0002, + Ranking_RegistrationError = 0x0067_0003, + Ranking_NotFound = 0x0067_0005, + Ranking_InvalidScore = 0x0067_0006, + Ranking_InvalidDataSize = 0x0067_0007, + Ranking_PermissionDenied = 0x0067_0009, + Ranking_Unknown = 0x0067_000A, + Ranking_NotImplemented = 0x0067_000B, + Authentication_NASAuthenticateError = 0x0068_0001, + Authentication_TokenParseError = 0x0068_0002, + Authentication_HttpConnectionError = 0x0068_0003, + Authentication_HttpDNSError = 0x0068_0004, + Authentication_HttpGetProxySetting = 0x0068_0005, + Authentication_TokenExpired = 0x0068_0006, + Authentication_ValidationFailed = 0x0068_0007, + Authentication_InvalidParam = 0x0068_0008, + Authentication_PrincipalIdUnmatched = 0x0068_0009, + Authentication_MoveCountUnmatch = 0x0068_000A, + Authentication_UnderMaintenance = 0x0068_000B, + Authentication_UnsupportedVersion = 0x0068_000C, + Authentication_ServerVersionIsOld = 0x0068_000D, + Authentication_Unknown = 0x0068_000E, + Authentication_ClientVersionIsOld = 0x0068_000F, + Authentication_AccountLibraryError = 0x0068_0010, + Authentication_ServiceNoLongerAvailable = 0x0068_0011, + Authentication_UnknownApplication = 0x0068_0012, + Authentication_ApplicationVersionIsOld = 0x0068_0013, + Authentication_OutOfService = 0x0068_0014, + Authentication_NetworkServiceLicenseRequired = 0x0068_0015, + Authentication_NetworkServiceLicenseSystemError = 0x0068_0016, + Authentication_NetworkServiceLicenseError3 = 0x0068_0017, + Authentication_NetworkServiceLicenseError4 = 0x0068_0018, + DataStore_Unknown = 0x0069_0001, + DataStore_InvalidArgument = 0x0069_0002, + DataStore_PermissionDenied = 0x0069_0003, + DataStore_NotFound = 0x0069_0004, + DataStore_AlreadyLocked = 0x0069_0005, + DataStore_UnderReviewing = 0x0069_0006, + DataStore_Expired = 0x0069_0007, + DataStore_InvalidCheckToken = 0x0069_0008, + DataStore_SystemFileError = 0x0069_0009, + DataStore_OverCapacity = 0x0069_000A, + DataStore_OperationNotAllowed = 0x0069_000B, + DataStore_InvalidPassword = 0x0069_000C, + DataStore_ValueNotEqual = 0x0069_000D, + ServiceItem_Unknown = 0x006C_0001, + ServiceItem_InvalidArgument = 0x006C_0002, + ServiceItem_EShopUnknownHttpError = 0x006C_0003, + ServiceItem_EShopResponseParseError = 0x006C_0004, + ServiceItem_NotOwned = 0x006C_0005, + ServiceItem_InvalidLimitationType = 0x006C_0006, + ServiceItem_ConsumptionRightShortage = 0x006C_0007, + MatchmakeReferee_Unknown = 0x006F_0001, + MatchmakeReferee_InvalidArgument = 0x006F_0002, + MatchmakeReferee_AlreadyExists = 0x006F_0003, + MatchmakeReferee_NotParticipatedGathering = 0x006F_0004, + MatchmakeReferee_NotParticipatedRound = 0x006F_0005, + MatchmakeReferee_StatsNotFound = 0x006F_0006, + MatchmakeReferee_RoundNotFound = 0x006F_0007, + MatchmakeReferee_RoundArbitrated = 0x006F_0008, + MatchmakeReferee_RoundNotArbitrated = 0x006F_0009, + Subscriber_Unknown = 0x0070_0001, + Subscriber_InvalidArgument = 0x0070_0002, + Subscriber_OverLimit = 0x0070_0003, + Subscriber_PermissionDenied = 0x0070_0004, + Ranking2_Unknown = 0x0071_0001, + Ranking2_InvalidArgument = 0x0071_0002, + Ranking2_InvalidScore = 0x0071_0003, + SmartDeviceVoiceChat_Unknown = 0x0072_0001, + SmartDeviceVoiceChat_InvalidArgument = 0x0072_0002, + SmartDeviceVoiceChat_InvalidResponse = 0x0072_0003, + SmartDeviceVoiceChat_InvalidAccessToken = 0x0072_0004, + SmartDeviceVoiceChat_Unauthorized = 0x0072_0005, + SmartDeviceVoiceChat_AccessError = 0x0072_0006, + SmartDeviceVoiceChat_UserNotFound = 0x0072_0007, + SmartDeviceVoiceChat_RoomNotFound = 0x0072_0008, + SmartDeviceVoiceChat_RoomNotActivated = 0x0072_0009, + SmartDeviceVoiceChat_ApplicationNotSupported = 0x0072_000A, + SmartDeviceVoiceChat_InternalServerError = 0x0072_000B, + SmartDeviceVoiceChat_ServiceUnavailable = 0x0072_000C, + SmartDeviceVoiceChat_UnexpectedError = 0x0072_000D, + SmartDeviceVoiceChat_UnderMaintenance = 0x0072_000E, + SmartDeviceVoiceChat_ServiceNoLongerAvailable = 0x0072_000F, + SmartDeviceVoiceChat_AccountTemporarilyDisabled = 0x0072_0010, + SmartDeviceVoiceChat_PermissionDenied = 0x0072_0011, + SmartDeviceVoiceChat_NetworkServiceLicenseRequired = 0x0072_0012, + SmartDeviceVoiceChat_AccountLibraryError = 0x0072_0013, + SmartDeviceVoiceChat_GameModeNotFound = 0x0072_0014, + Screening_Unknown = 0x0073_0001, + Screening_InvalidArgument = 0x0073_0002, + Screening_NotFound = 0x0073_0003, + Custom_Unknown = 0x0074_0001, + Ess_Unknown = 0x0075_0001, + Ess_GameSessionError = 0x0075_0002, + Ess_GameSessionMaintenance = 0x0075_0003, +} + +impl From for ErrorCode { + fn from(value: Error) -> Self { + error!("rmc error occurred during method runtime: {}", value); + Self::Core_InvalidArgument + } +} + +impl Into for ErrorCode { + fn into(self) -> u32 { + unsafe { transmute(self) } + } +} diff --git a/rnex-core/src/rmc/structures/rmc_struct.rs b/rnex-rmc/src/rmc_struct.rs similarity index 91% rename from rnex-core/src/rmc/structures/rmc_struct.rs rename to rnex-rmc/src/rmc_struct.rs index 92cdff1..2a12bbf 100644 --- a/rnex-core/src/rmc/structures/rmc_struct.rs +++ b/rnex-rmc/src/rmc_struct.rs @@ -1,14 +1,11 @@ -use crate::rmc::structures::Result; -use std::cmp::max; -use std::fmt::Arguments; -use std::io; -use std::io::{ErrorKind, IoSlice, Read, Write}; +#[cfg(not(feature = "rmc_struct_header"))] +use std::io::Read; +use std::{ + fmt::Arguments, + io::{self, ErrorKind, IoSlice, Write}, +}; -#[repr(C, packed)] -struct StructureHeader { - version: u8, - length: u32, -} +use crate::serialization::Result; #[cfg(feature = "rmc_struct_header")] pub const HEADER_SIZE: u32 = 0; @@ -80,7 +77,7 @@ impl<'a, T: Read + ?Sized> SubRead<'a, T> { impl Read for SubRead<'_, T> { #[inline(always)] fn read(&mut self, buf: &mut [u8]) -> io::Result { - let max_read = max(self.left_to_read, buf.len()); + let max_read = usize::max(self.left_to_read, buf.len()); let read = self.origin.read(&mut buf[..max_read])?; self.left_to_read -= read; Ok(read) diff --git a/rnex-core/src/rmc/structures/mod.rs b/rnex-rmc/src/serialization.rs similarity index 76% rename from rnex-core/src/rmc/structures/mod.rs rename to rnex-rmc/src/serialization.rs index 1a44ffe..ee3ce15 100644 --- a/rnex-core/src/rmc/structures/mod.rs +++ b/rnex-rmc/src/serialization.rs @@ -1,10 +1,11 @@ -use crate::rmc::structures::helpers::DummyWriter; -use std::io::{Read, Write}; -use std::string::FromUtf8Error; -use std::sync::RwLock; -use std::{fmt, io}; +use std::{ + fmt, + io::{self, Read, Write}, + string::FromUtf8Error, +}; + +use crate::helpers::DummyWriter; use thiserror::Error; -//ideas for the future: make a proc macro library which allows generation of struct reads #[derive(Error, Debug)] pub enum Error { @@ -31,24 +32,6 @@ pub enum Error { pub type Result = std::result::Result; -pub mod any; -pub mod buffer; -pub mod connection_data; -pub mod data; -pub mod helpers; -pub mod list; -pub mod matchmake; -pub mod networking; -pub mod primitives; -pub mod qbuffer; -pub mod qresult; -pub mod ranking; -pub mod resultsrange; -pub mod rmc_struct; -pub mod string; -pub mod string_set; -pub mod variant; - pub trait RmcSerialize { fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> Result<()>; fn serialize_write_size(&self) -> Result { @@ -77,9 +60,6 @@ pub trait RmcSerialize { } } -trait SendWrite: Send + Write {} -impl SendWrite for T {} - impl RmcSerialize for () { fn serialize(&self, _writer: &mut (impl Write + ?Sized)) -> Result<()> { Ok(()) @@ -94,12 +74,12 @@ impl RmcSerialize for () { pub struct RmcStructInfo { // this may never be locked after initialization - pub inheritors: RwLock>, + pub inheritors: std::sync::RwLock>, pub name: &'static str, } impl RmcStructInfo { - fn is_inheritor(&self, name: &str) -> bool { + pub fn is_inheritor(&self, name: &str) -> bool { if name == self.name { return true; } diff --git a/rnex-rmc/src/station_url.rs b/rnex-rmc/src/station_url.rs new file mode 100644 index 0000000..6d2a6af --- /dev/null +++ b/rnex-rmc/src/station_url.rs @@ -0,0 +1,30 @@ +use std::fmt::Write; +use std::io::{self, Read}; + +use rnex_util::station_url::StationUrl; + +use crate::{ + helpers::DummyFormatWriter, + serialization::{Error::StationUrlInvalid, Result, RmcSerialize}, +}; + +impl RmcSerialize for StationUrl { + fn deserialize(reader: &mut (impl Read + ?Sized)) -> Result { + let str = String::deserialize(reader)?; + + Self::try_from(str.as_str()).map_err(|_| StationUrlInvalid) + } + fn serialize(&self, writer: &mut (impl io::Write + ?Sized)) -> Result<()> { + let str: String = self.into(); + + str.serialize(writer) + } + + fn serialize_write_size(&self) -> Result { + let mut dummy = DummyFormatWriter::new(); + + write!(&mut dummy, "{}", self)?; + + Ok(dummy.serialize_str_len()) + } +} diff --git a/rnex-core/src/rmc/structures/string.rs b/rnex-rmc/src/string.rs similarity index 95% rename from rnex-core/src/rmc/structures/string.rs rename to rnex-rmc/src/string.rs index 59474cc..011cd66 100644 --- a/rnex-core/src/rmc/structures/string.rs +++ b/rnex-rmc/src/string.rs @@ -1,9 +1,10 @@ -use super::{Result, RmcSerialize}; use bytemuck::bytes_of; -use log::error; use std::io::{Read, Write}; +use tracing::error; use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; +use crate::serialization::{Result, RmcSerialize}; + impl RmcSerialize for String { fn deserialize(mut reader: &mut (impl Read + ?Sized)) -> Result { let len: u16 = reader.read_struct(IS_BIG_ENDIAN)?; diff --git a/rnex-core/src/rmc/structures/string_set.rs b/rnex-rmc/src/string_set.rs similarity index 85% rename from rnex-core/src/rmc/structures/string_set.rs rename to rnex-rmc/src/string_set.rs index 40ca258..7f71da5 100644 --- a/rnex-core/src/rmc/structures/string_set.rs +++ b/rnex-rmc/src/string_set.rs @@ -6,7 +6,7 @@ use std::{ string::ToString, }; -use rnex_core::rmc::structures::RmcSerialize; +use crate::serialization::{Error, Result, RmcSerialize}; #[derive(Debug, Clone)] pub struct StringSet(pub HashSet) @@ -61,26 +61,25 @@ impl RmcSerialize for StringSet where ::Err: std::error::Error + Send + Sync + 'static, { - fn deserialize(reader: &mut (impl Read + ?Sized)) -> super::Result + fn deserialize(reader: &mut (impl Read + ?Sized)) -> Result where Self: Sized, { - Self::from_str(&String::deserialize(reader)?).map_err(super::Error::Other) + Self::from_str(&String::deserialize(reader)?).map_err(Error::Other) } - fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> super::Result<()> { + fn serialize(&self, writer: &mut (impl Write + ?Sized)) -> Result<()> { self.to_string().serialize(writer) } - fn serialize_write_size(&self) -> super::Result { + fn serialize_write_size(&self) -> Result { self.to_string().serialize_write_size() } } #[cfg(test)] mod test { + use crate::string_set::StringSet; use std::str::FromStr; - use crate::rmc::structures::string_set::StringSet; - #[test] fn test() { let str_val = "0|100|200|10|110|210|20|120|220|30|130|230"; diff --git a/rnex-core/src/rmc/structures/variant.rs b/rnex-rmc/src/variant.rs similarity index 84% rename from rnex-core/src/rmc/structures/variant.rs rename to rnex-rmc/src/variant.rs index 45b29da..5ecb612 100644 --- a/rnex-core/src/rmc/structures/variant.rs +++ b/rnex-rmc/src/variant.rs @@ -1,8 +1,9 @@ -use rnex_core::kerberos::KerberosDateTime; -use rnex_core::rmc::structures; -use rnex_core::rmc::structures::{Result, RmcSerialize}; use std::io::{Read, Write}; +use rnex_util::date_time::DateTime; + +use crate::serialization::{Error, Result, RmcSerialize}; + #[derive(Debug, Clone, Default, PartialEq)] pub enum Variant { #[default] @@ -11,7 +12,7 @@ pub enum Variant { Double(f64), Bool(bool), String(String), - DateTime(KerberosDateTime), + DateTime(DateTime), UInt64(u64), } @@ -57,9 +58,9 @@ impl RmcSerialize for Variant { 2 => Ok(Variant::Double(f64::deserialize(reader)?)), 3 => Ok(Variant::Bool(bool::deserialize(reader)?)), 4 => Ok(Variant::String(String::deserialize(reader)?)), - 5 => Ok(Variant::DateTime(KerberosDateTime::deserialize(reader)?)), + 5 => Ok(Variant::DateTime(DateTime::deserialize(reader)?)), 6 => Ok(Variant::UInt64(u64::deserialize(reader)?)), - v => Err(structures::Error::UnexpectedValue(v as u64)), + v => Err(Error::UnexpectedValue(v as u64)), } } } diff --git a/rnex-server-nex-modules/rnex-auth/Cargo.toml b/rnex-server-nex-modules/rnex-auth/Cargo.toml new file mode 100644 index 0000000..a09095a --- /dev/null +++ b/rnex-server-nex-modules/rnex-auth/Cargo.toml @@ -0,0 +1,39 @@ +[package] +name = "rnex-auth" +version = "0.1.0" +edition = "2024" + +[dependencies] +rnex-rmc = { path = "../../rnex-rmc" } +rnex-auth-protos = { path = "../../rnex-protocols/auth-protos" } +rnex-reggie-protos = { path = "../../rnex-protocols/reggie-protos" } +rnex-server = { path = "../../rnex-server" } +rnex-prudp = { path = "../../rnex-prudp" } +hex = "0.4.3" +rand = "0.10.2" +nex-account = { version = "0.2.4", registry = "spbr" } +tonic = "0.14.6" +tracing = "0.1.44" +cfg-if = "1.0.4" +anyhow = "1.0.103" +tokio = { version = "1.52.3", features = ["net"] } + +[features] +rmc_struct_header = [] +guest_login = [] +friends = ["guest_login", "database-support"] +big_pid = [] +third-notif-param = [] +v3-3-2 = [] +v3-4-0 = ["v3-3-2", "third-notif-param", "rmc_struct_header"] +v3-5-0 = ["v3-4-0"] +v3-8-15 = ["v3-5-0"] +v3-10-22 = ["v3-8-15"] +v4-3-11 = ["v3-8-15"] +nx = ["big_pid"] +splatoon = ["v3-5-0"] +datastore = ["database-support", "v3-8-15"] +database-support = [] + +[lints] +workspace = true diff --git a/rnex-core/src/nex/auth_handler.rs b/rnex-server-nex-modules/rnex-auth/src/auth_handler.rs similarity index 75% rename from rnex-core/src/nex/auth_handler.rs rename to rnex-server-nex-modules/rnex-auth/src/auth_handler.rs index 2ba5486..c40b725 100644 --- a/rnex-core/src/nex/auth_handler.rs +++ b/rnex-server-nex-modules/rnex-auth/src/auth_handler.rs @@ -1,36 +1,39 @@ -use crate::grpc::account; -use crate::reggie::{RemoteEdgeNodeHolder, RemoteEdgeNodeManagement}; -use crate::{define_rmc_proto, kerberos}; +use std::{ + hash::{DefaultHasher, Hasher}, + net::SocketAddrV4, + sync::{Arc, LazyLock}, +}; + use cfg_if::cfg_if; -use log::{info, warn}; -use macros::rmc_struct; -use rnex_core::PID; -use rnex_core::kerberos::{KerberosDateTime, Ticket}; -use rnex_core::nex::account::Account; -use rnex_core::rmc::protocols::OnlyRemote; -use rnex_core::rmc::protocols::auth::{Auth, RawAuth, RawAuthInfo, RemoteAuth}; -use rnex_core::rmc::response::ErrorCode; -use rnex_core::rmc::response::ErrorCode::Core_Unknown; -use rnex_core::rmc::structures::any::Any; -use rnex_core::rmc::structures::connection_data::ConnectionData; -use rnex_core::rmc::structures::connection_data::ConnectionDataOld; -use rnex_core::rmc::structures::qresult::QResult; -use std::hash::{DefaultHasher, Hasher}; -use std::net::SocketAddrV4; -use std::sync::{Arc, LazyLock}; +use nex_account::{ + grpc::{self, nex_account_service_client}, + grpc_client, +}; +use rnex_auth_protos::{ + LocalAuthProtocol, + auth::{Auth, ConnectionData, ConnectionDataOld}, +}; +use rnex_prudp::kerberos::{Ticket, TicketInternalData}; +use rnex_reggie_protos::reggie::{RemoteEdgeNodeHolder, RemoteEdgeNodeManagement}; +use rnex_rmc::{ + OnlyRemote, + any::Any, + define_rmc_proto, + qresult::QResult, + rand, + response::ErrorCode, + rmc_struct, + util::{PID, account::Account, date_time::DateTime}, +}; +use rnex_server::PassthroughInitModule; +use tracing::{info, warn}; -define_rmc_proto!( - proto AuthClientProtocol{ - Auth - } -); +use crate::AuthManager; -#[rmc_struct(AuthClientProtocol)] +#[derive(Debug)] +#[rmc_struct(AuthProtocol)] pub struct AuthHandler { - pub destination_server_acct: &'static Account, - pub build_name: &'static str, - //pub station_url: &'static str, - pub control_server: Arc>, + pub(crate) am: PassthroughInitModule, } pub fn generate_ticket( @@ -40,16 +43,14 @@ pub fn generate_ticket( let source_key = source_act_login_data.1; let dest_key = dest_act_login_data.1; - let internal_data = kerberos::TicketInternalData::new(source_act_login_data.0); + let internal_data = TicketInternalData::new(source_act_login_data.0); let encrypted_inner = internal_data.encrypt(dest_key); - let encrypted_session_ticket = Ticket { + Ticket { pid: dest_act_login_data.0, session_key: internal_data.session_key, } - .encrypt(source_key, &encrypted_inner); - - encrypted_session_ticket + .encrypt(source_key, &encrypted_inner) } pub fn generate_ticket_with_string_user_key( source_act: PID, @@ -60,7 +61,7 @@ pub fn generate_ticket_with_string_user_key( let key_data: [u8; 16] = key_string.as_bytes().try_into().unwrap(); let dest_key = dest_act_login_data.1; - let internal_data = kerberos::TicketInternalData::new(source_act); + let internal_data = TicketInternalData::new(source_act); let encrypted_inner = internal_data.encrypt(dest_key); let encrypted_session_ticket = Ticket { @@ -79,14 +80,16 @@ async fn get_login_data_by_pid(pid: PID) -> Option<(PID, [u8; 16])> { return Some((source_login_data.0, source_login_data.1)); } - let Ok(mut client) = account::Client::new().await else { + let Ok(mut client) = nex_account::grpc_client().await else { return None; }; - let Ok(passwd) = client.get_nex_key(pid).await else { + let Ok(passwd) = client.get_nex_key_by_pid(grpc::Pid { pid }).await else { return None; }; + let passwd = passwd.into_inner().key.try_into().ok()?; + Some((pid, passwd)) } @@ -109,9 +112,9 @@ impl AuthHandler { #[cfg(feature = "guest_login")] { if name == GUEST_ACCOUNT.username { - log::info!("guest account login"); + info!("guest account login"); let source_login_data = GUEST_ACCOUNT.get_login_data(); - let destination_login_data = self.destination_server_acct.get_login_data(); + let destination_login_data = self.am.destination_server_acct.get_login_data(); return Ok(( source_login_data.0, @@ -120,44 +123,49 @@ impl AuthHandler { } } - log::info!("parsing pid"); + info!("parsing pid"); let Ok(pid) = name.parse() else { warn!("unable to connect to parse pid: {}", name); return Err(ErrorCode::Core_InvalidArgument); }; - log::info!("creating account grpc client"); - let Ok(mut client) = account::Client::new().await else { + info!("creating account grpc client"); + let Ok(mut client) = grpc_client().await else { warn!("unable to connect to grpc"); return Err(ErrorCode::Core_Exception); }; - log::info!("grabbing nex key"); - let Ok(passwd) = client.get_nex_key(pid).await else { + info!("grabbing nex key"); + let Ok(passwd) = client.get_nex_key_by_pid(grpc::Pid { pid }).await else { warn!("unable to get nex password for pid: {}:", pid); return Err(ErrorCode::Core_Exception); }; - log::info!("source login data"); + let passwd = passwd + .into_inner() + .key + .try_into() + .map_err(|_| ErrorCode::RendezVous_InvalidPassword)?; + info!("source login data"); let source_login_data = (pid, passwd); println!("{}, {:?}", pid, passwd); - let destination_login_data = self.destination_server_acct.get_login_data(); + let destination_login_data = self.am.destination_server_acct.get_login_data(); - log::info!("we are a-ok here"); + info!("we are a-ok here"); Ok(( pid, generate_ticket(source_login_data, destination_login_data), )) } - pub async fn generate_ticket_from_name_string_user_key( + pub fn generate_ticket_from_name_string_user_key( &self, name: &str, ) -> Result<(PID, String, Box<[u8]>), ErrorCode> { { if name == GUEST_ACCOUNT.username { let source_login_data = GUEST_ACCOUNT.get_login_data(); - let destination_login_data = self.destination_server_acct.get_login_data(); + let destination_login_data = self.am.destination_server_acct.get_login_data(); let ticket = generate_ticket_with_string_user_key( source_login_data.0, destination_login_data, @@ -170,7 +178,7 @@ impl AuthHandler { warn!("unable to connect to parse pid: {}", name); return Err(ErrorCode::Core_InvalidArgument); }; - let destination_login_data = self.destination_server_acct.get_login_data(); + let destination_login_data = self.am.destination_server_acct.get_login_data(); let data = generate_ticket_with_string_user_key(pid, destination_login_data); Ok((pid, data.0, data.1)) @@ -184,13 +192,13 @@ impl Auth for AuthHandler { ) -> Result<(QResult, PID, Vec, ConnectionDataOld, String), ErrorCode> { let (pid, ticket) = self.generate_ticket_from_name(&name).await?; - let result = QResult::success(Core_Unknown); + let result = QResult::success(ErrorCode::Core_Unknown); let mut hasher = DefaultHasher::new(); hasher.write(name.as_bytes()); - let Ok(addr) = self.control_server.get_url(hasher.finish()).await else { + let Ok(addr) = self.am.control_server.get_url(hasher.finish()).await else { warn!("no secure proxies"); return Err(ErrorCode::Core_Exception); }; @@ -206,7 +214,7 @@ impl Auth for AuthHandler { pid, ticket.into(), connection_data, - self.build_name.to_string(), + self.am.build_name.to_string(), ); info!("data: {:?}", ret); @@ -282,13 +290,13 @@ impl Auth for AuthHandler { ) -> Result<(QResult, PID, Vec, ConnectionData, String), ErrorCode> { let (pid, ticket) = self.generate_ticket_from_name(&name).await?; - let result = QResult::success(Core_Unknown); + let result = QResult::success(ErrorCode::Core_Unknown); let mut hasher = DefaultHasher::new(); hasher.write(name.as_bytes()); - let Ok(addr) = self.control_server.get_url(hasher.finish()).await else { + let Ok(addr) = self.am.control_server.get_url(hasher.finish()).await else { warn!("no secure proxies"); return Err(ErrorCode::Core_Exception); }; @@ -297,7 +305,7 @@ impl Auth for AuthHandler { station_url: station_url_from_sock_addr(addr), special_station_url: "".to_string(), //date_time: KerberosDateTime::new(1,1,1,1,1,1), - date_time: KerberosDateTime::now(), + date_time: DateTime::now(), special_protocols: Vec::new(), }; @@ -306,7 +314,7 @@ impl Auth for AuthHandler { pid, ticket.into(), connection_data, - self.build_name.to_string(), + self.am.build_name.to_string(), ); info!("data: {:?}", ret); @@ -321,13 +329,13 @@ impl Auth for AuthHandler { return Err(ErrorCode::Core_Exception); }; - let desgination_login_data = if destination_pid == self.destination_server_acct.pid { - self.destination_server_acct.get_login_data() + let desgination_login_data = if destination_pid == self.am.destination_server_acct.pid { + self.am.destination_server_acct.get_login_data() } else { return Err(ErrorCode::RendezVous_InvalidOperation); }; - let result = QResult::success(Core_Unknown); + let result = QResult::success(ErrorCode::Core_Unknown); let ticket = generate_ticket((pid, passwd), desgination_login_data); diff --git a/rnex-server-nex-modules/rnex-auth/src/lib.rs b/rnex-server-nex-modules/rnex-auth/src/lib.rs new file mode 100644 index 0000000..627e531 --- /dev/null +++ b/rnex-server-nex-modules/rnex-auth/src/lib.rs @@ -0,0 +1,87 @@ +#[allow(async_fn_in_trait)] +pub mod auth_handler; + +use std::{convert::Infallible, env, error::Error, net::SocketAddr, sync::Arc}; +use tokio::net::TcpStream; + +use nex_account::{grpc::Pid, grpc_client}; +use rnex_reggie_protos::reggie::{EdgeNodeHolderConnectOption::DontRegister, RemoteEdgeNodeHolder}; +use rnex_rmc::{ + OnlyRemote, new_rmc_gateway_connection, + serialization::RmcSerialize, + util::{SplittableBufferConnection, account::Account}, +}; +use rnex_server::{RnexManager, RnexModule, WeakPassthroughInitModule}; +use tracing::info; + +use crate::auth_handler::AuthHandler; + +#[derive(Debug)] +pub struct AuthManager { + pub destination_server_acct: Account, + pub build_name: &'static str, + pub control_server: Arc>, +} +#[derive(Debug)] +pub struct AuthModule; + +impl RnexManager for AuthManager { + type User = AuthHandler; + type InitData = SocketAddr; + async fn init_new_user( + this: rnex_server::PassthroughInitModule, + _: &rnex_server::ModuleHolder, + _: &rnex_rmc::RmcConnection, + init_data: &Self::InitData, + _: WeakPassthroughInitModule, + ) -> Self::User { + info!(target: "proxy_connections", address = ?init_data, "user connected"); + Self::User { am: this } + } +} + +/* +pub static FORWARD_EDGE_NODE_HOLDER: Lazy = Lazy::new(|| { + env::var("FORWARD_EDGE_NODE_HOLDER") + .ok() + .and_then(|s| Some(s.parse().unwrap())) + .expect("FORWARD_EDGE_NODE_HOLDER not set") +});*/ + +impl RnexModule for AuthModule { + type Manager = AuthManager; + type InitError = anyhow::Error; + async fn create_manager( + _: &rnex_server::ModuleHolder, + ) -> Result { + let conn = TcpStream::connect(env::var("FORWARD_EDGE_NODE_HOLDER")?) + .await + .unwrap(); + + let conn: SplittableBufferConnection = conn.into(); + + conn.send(DontRegister.to_data().unwrap()).await; + + let conn = new_rmc_gateway_connection(conn, async |r| { + Arc::new(OnlyRemote::::new(r)) + }) + .await; + Ok(AuthManager { + build_name: option_env!("AUTH_REPORT_VERSION").unwrap_or("no version specified"), + control_server: conn, + // todo: update nex-account to allow pulling the entire account info for rnex + destination_server_acct: Account::new_raw_key( + 2, + "Quazal Rendez-Vous", + grpc_client() + .await? + .get_nex_key_by_pid(Pid { pid: 2 }) + .await? + .into_inner() + .key + .try_into() + .map_err(|_| anyhow::Error::msg("invalid key size"))?, + ), + }) + } +} diff --git a/rnex-server-nex-modules/rnex-base/Cargo.toml b/rnex-server-nex-modules/rnex-base/Cargo.toml new file mode 100644 index 0000000..252e244 --- /dev/null +++ b/rnex-server-nex-modules/rnex-base/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "rnex-base" +version = "0.1.0" +edition = "2024" + +[dependencies] +rnex-rmc = { path = "../../rnex-rmc" } +rnex-util = { path = "../../rnex-util" } +rnex-base-protos = { path = "../../rnex-protocols/base-protos" } +rnex-server = { path = "../../rnex-server" } +tokio = { version = "1.52.3", features = ["sync"] } +rand = "0.10.2" +tracing = "0.1.44" +cfg-if = "1.0.4" + +[lints] +workspace = true diff --git a/rnex-server-nex-modules/rnex-base/src/lib.rs b/rnex-server-nex-modules/rnex-base/src/lib.rs new file mode 100644 index 0000000..700c63f --- /dev/null +++ b/rnex-server-nex-modules/rnex-base/src/lib.rs @@ -0,0 +1,52 @@ +use std::{ + convert::Infallible, + sync::atomic::{AtomicU32, Ordering::Relaxed}, +}; + +use rnex_server::{ConnectionInitData, RnexManager, RnexModule, WeakPassthroughInitModule}; + +use crate::user::BaseUser; + +pub mod user; + +#[derive(Default, Debug)] +pub struct BaseManager { + cid_counter: AtomicU32, +} + +#[derive(Debug, Default)] +pub struct BaseModule; + +impl RnexManager for BaseManager { + type User = BaseUser; + + type InitData = ConnectionInitData; + + async fn init_new_user( + this: rnex_server::PassthroughInitModule, + _mod_holder: &rnex_server::ModuleHolder, + _remote: &rnex_rmc::RmcConnection, + init_data: &Self::InitData, + _: WeakPassthroughInitModule, + ) -> Self::User { + BaseUser { + cid: this.cid_counter.fetch_add(1, Relaxed), + bm: this, + addr: init_data.addr, + pid: init_data.pid, + station_url: Default::default(), + } + } +} + +impl RnexModule for BaseModule { + type Manager = BaseManager; + + type InitError = Infallible; + + async fn create_manager( + _mod_holder: &rnex_server::ModuleHolder, + ) -> Result { + Ok(BaseManager::default()) + } +} diff --git a/rnex-server-nex-modules/rnex-base/src/user.rs b/rnex-server-nex-modules/rnex-base/src/user.rs new file mode 100644 index 0000000..46d7a80 --- /dev/null +++ b/rnex-server-nex-modules/rnex-base/src/user.rs @@ -0,0 +1,198 @@ +use std::net::SocketAddr; + +use rnex_base_protos::{LocalBaseProtocol, secure::Secure, util::Utility}; +use rnex_rmc::{any::Any, qresult::QResult, response::ErrorCode, rmc_struct}; +use rnex_server::PassthroughInitModule; +use rnex_util::{ + PID, + station_url::{StationUrl, UrlOptions, nat_types::PUBLIC}, +}; +use tokio::sync::{Mutex, RwLock}; +use tracing::info; + +use crate::BaseManager; + +pub async fn get_station_urls( + station_urls: &[StationUrl], + addr: SocketAddr, + pid: PID, + cid: u32, +) -> Result, ErrorCode> { + let mut public_station: Option = None; + let mut private_station: Option = None; + + for station in station_urls { + let is_public = station.options.iter().any(|v| { + if let UrlOptions::NatType(v) = v + && *v & PUBLIC != 0 + { + return true; + } + false + }); + + let Some(nat_filtering) = station.options.iter().find_map(|v| match v { + UrlOptions::NatFiltering(v) => Some(v), + _ => None, + }) else { + return Err(ErrorCode::Core_InvalidArgument); + }; + + let Some(nat_mapping) = station.options.iter().find_map(|v| match v { + UrlOptions::NatMapping(v) => Some(v), + _ => None, + }) else { + return Err(ErrorCode::Core_InvalidArgument); + }; + + if !is_public || (*nat_filtering == 0 && *nat_mapping == 0) { + private_station = Some(station.clone()); + } + + if is_public { + public_station = Some(station.clone()); + } + } + + let Some(mut private_station) = private_station else { + return Err(ErrorCode::Core_InvalidArgument); + }; + + let mut public_station = if let Some(public_station) = public_station { + public_station + } else { + let mut public_station = private_station.clone(); + + public_station.options.retain(|v| { + !matches!( + v, + UrlOptions::Address(_) + | UrlOptions::Port(_) + | UrlOptions::NatFiltering(_) + | UrlOptions::NatMapping(_) + | UrlOptions::NatType(_) + ) + }); + + public_station.options.push(UrlOptions::Address(addr.ip())); + public_station.options.push(UrlOptions::Port(addr.port())); + public_station.options.push(UrlOptions::NatFiltering(0)); + public_station.options.push(UrlOptions::NatMapping(0)); + public_station.options.push(UrlOptions::NatType(3)); + + public_station + }; + + let both = [&mut public_station, &mut private_station]; + + for station in both { + station.options.retain(|v| { + !matches!( + v, + UrlOptions::PrincipalID(_) + | UrlOptions::RVConnectionID(_) + | UrlOptions::ConnectionID(_) + ) + }); + + station.options.push(UrlOptions::PrincipalID(pid)); + station.options.push(UrlOptions::RVConnectionID(cid)); + station.options.push(UrlOptions::ConnectionID(cid)); + } + + Ok(vec![public_station]) +} + +#[rmc_struct(BaseProtocol)] +#[derive(Debug)] +pub struct BaseUser { + pub(crate) bm: PassthroughInitModule, + pub addr: SocketAddr, + pub station_url: RwLock>, + pub pid: PID, + pub cid: u32, +} + +impl Secure for BaseUser { + async fn register( + &self, + station_urls: Vec, + ) -> Result<(QResult, u32, StationUrl), ErrorCode> { + let cid = self.cid; + println!("{:?}", station_urls); + + /* + let mut users = self.matchmake_manager.users.write().await; + users.insert(cid, self.this.clone()); + drop(users); + let mut users = self.matchmake_manager.users_by_pid.write().await; + users.insert(self.pid, self.this.clone()); + drop(users); + */ + + let stations = get_station_urls(&station_urls, self.addr, self.pid, cid).await?; + + let first = stations.first().unwrap().clone(); + + let mut lock = self.station_url.write().await; + + *lock = stations; + + drop(lock); + + Ok((QResult::success(ErrorCode::Core_Unknown), self.cid, first)) + } + + async fn register_ex( + &self, + station_urls: Vec, + _data: Any, + ) -> Result<(QResult, u32, StationUrl), ErrorCode> { + self.register(station_urls).await + } + + async fn replace_url(&self, target_url: StationUrl, dest: StationUrl) -> Result<(), ErrorCode> { + let mut lock = self.station_url.write().await; + info!("target URL: {:?}", target_url); + info!("dest URL: {:?}", dest); + + let Some(target_addr) = target_url + .options + .iter() + .find(|v| matches!(v, UrlOptions::Address(_))) + else { + return Err(ErrorCode::Core_InvalidArgument); + }; + + let Some(target_port) = target_url + .options + .iter() + .find(|v| matches!(v, UrlOptions::Port(_))) + else { + return Err(ErrorCode::Core_InvalidArgument); + }; + + let Some(replacement_target) = lock.iter_mut().find(|url| { + url.options.iter().any(|o| o == target_addr) + && url.options.iter().any(|o| o == target_port) + }) else { + //probably internal ip + return Ok(()); + }; + *replacement_target = dest; + + drop(lock); + + Ok(()) + } +} + +impl Utility for BaseUser { + async fn acquire_nex_unique_id(&self) -> Result { + return Ok(rand::random()); + } + + async fn get_integer_settings(&self, _index: u32) -> Result, ErrorCode> { + Ok(vec![(0, 1), (1, 2), (2, 0), (3, 4)]) + } +} diff --git a/rnex-server-nex-modules/rnex-ds/Cargo.toml b/rnex-server-nex-modules/rnex-ds/Cargo.toml new file mode 100644 index 0000000..fbdbd11 --- /dev/null +++ b/rnex-server-nex-modules/rnex-ds/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "rnex-ds" +version = "0.1.0" +edition = "2024" + +[dependencies] + +[lints] +workspace = true diff --git a/rnex-server-nex-modules/rnex-ds/src/main.rs b/rnex-server-nex-modules/rnex-ds/src/main.rs new file mode 100644 index 0000000..e7a11a9 --- /dev/null +++ b/rnex-server-nex-modules/rnex-ds/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/rnex-server-nex-modules/rnex-fpd/Cargo.toml b/rnex-server-nex-modules/rnex-fpd/Cargo.toml new file mode 100644 index 0000000..cbdd650 --- /dev/null +++ b/rnex-server-nex-modules/rnex-fpd/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "rnex-fpd" +version = "0.1.0" +edition = "2024" + +[dependencies] + +[lints] +workspace = true diff --git a/rnex-server-nex-modules/rnex-fpd/src/main.rs b/rnex-server-nex-modules/rnex-fpd/src/main.rs new file mode 100644 index 0000000..e7a11a9 --- /dev/null +++ b/rnex-server-nex-modules/rnex-fpd/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/rnex-server-nex-modules/rnex-mm/Cargo.toml b/rnex-server-nex-modules/rnex-mm/Cargo.toml new file mode 100644 index 0000000..68d3ce1 --- /dev/null +++ b/rnex-server-nex-modules/rnex-mm/Cargo.toml @@ -0,0 +1,38 @@ +[package] +name = "rnex-mm" +version = "0.1.0" +edition = "2024" + +[dependencies] +rnex-rmc = { path = "../../rnex-rmc" } +rnex-util = { path = "../../rnex-util" } +rnex-mm-protos = { path = "../../rnex-protocols/mm-protos" } +rnex-base-protos = { path = "../../rnex-protocols/base-protos" } +rnex-server = { path = "../../rnex-server" } +rnex-base = { path = "../rnex-base" } +tokio = { version = "1.52.3", features = ["sync"] } +rand = "0.10.2" +tracing = "0.1.44" +cfg-if = "1.0.4" +bytemuck = "1.25.1" +serde = { version = "1.0.228", features = ["derive"] } +ureq = "3.3.0" + +[features] +rmc_struct_header = [] +guest_login = [] +friends = ["guest_login", "database-support"] +big_pid = [] +third-notif-param = [] +v3-3-2 = [] +v3-4-0 = ["v3-3-2", "third-notif-param", "rmc_struct_header"] +v3-5-0 = ["v3-4-0"] +v3-8-15 = ["v3-5-0"] +v3-10-22 = ["v3-8-15"] +v4-3-11 = ["v3-8-15"] +nx = ["big_pid"] +splatoon = ["v3-5-0"] +datastore = ["database-support", "v3-8-15"] +database-support = [] +[lints] +workspace = true diff --git a/rnex-server-nex-modules/rnex-mm/src/lib.rs b/rnex-server-nex-modules/rnex-mm/src/lib.rs new file mode 100644 index 0000000..fbfda2a --- /dev/null +++ b/rnex-server-nex-modules/rnex-mm/src/lib.rs @@ -0,0 +1,25 @@ +use std::{convert::Infallible, sync::atomic::AtomicU32}; + +use rnex_server::RnexModule; + +use crate::matchmake::MatchmakeManager; + +pub mod matchmake; +pub mod user; + +pub struct MatchMakeModule; +impl RnexModule for MatchMakeModule { + type Manager = MatchmakeManager; + type InitError = Infallible; + + async fn create_manager( + _: &rnex_server::ModuleHolder, + ) -> Result { + Ok(MatchmakeManager { + sessions: Default::default(), + rv_cid_counter: AtomicU32::new(1), + users: Default::default(), + users_by_pid: Default::default(), + }) + } +} diff --git a/rnex-core/src/nex/matchmake.rs b/rnex-server-nex-modules/rnex-mm/src/matchmake.rs similarity index 74% rename from rnex-core/src/nex/matchmake.rs rename to rnex-server-nex-modules/rnex-mm/src/matchmake.rs index c42e3c0..7b6e3fe 100644 --- a/rnex-core/src/nex/matchmake.rs +++ b/rnex-server-nex-modules/rnex-mm/src/matchmake.rs @@ -1,34 +1,46 @@ -use log::{info, warn}; +use rnex_mm_protos::{RemoteMatchMakingClientProtocol, notifications::RemoteNotification}; +use std::{ + collections::HashMap, + str::FromStr, + sync::{ + Arc, Weak, + atomic::{AtomicU32, Ordering}, + }, + time::Duration, +}; + +use cfg_if::cfg_if; use rand::random; -use rnex_core::PID; -use rnex_core::nex::user::User; -use rnex_core::rmc::protocols::notifications::notification_types::{ - HOST_CHANGED, OWNERSHIP_CHANGED, +use rnex_mm_protos::{ + matchmake::{ + Gathering, MatchmakeSession, MatchmakeSessionSearchCriteria, + gathering_flags::PERSISTENT_GATHERING, + }, + notifications::{ + NotificationEvent, + notification_types::{HOST_CHANGED, OWNERSHIP_CHANGED}, + }, }; -use rnex_core::rmc::protocols::notifications::{NotificationEvent, RemoteNotification}; -use rnex_core::rmc::response::ErrorCode; -use rnex_core::rmc::response::ErrorCode::{Core_InvalidArgument, RendezVous_SessionVoid}; -use rnex_core::rmc::structures::matchmake::gathering_flags::PERSISTENT_GATHERING; -use rnex_core::rmc::structures::matchmake::{ - Gathering, MatchmakeSession, MatchmakeSessionSearchCriteria, +use rnex_rmc::{RmcPureRemoteObject, response::ErrorCode}; +use rnex_server::{ + ConnectionInitData, PassthroughInitModule, RnexManager, WeakPassthroughInitModule, }; -use std::collections::HashMap; -use std::str::FromStr; -use std::sync::atomic::AtomicU32; -use std::sync::atomic::Ordering::Relaxed; -use std::sync::{Arc, Weak}; -use std::time::Duration; -use tokio::sync::{Mutex, RwLock}; -use tokio::time::{sleep, timeout}; +use rnex_util::PID; +use tokio::{ + sync::{Mutex, RwLock}, + time::sleep, +}; +use tracing::{info, instrument}; -use crate::rmc::protocols::nat_traversal::RemoteNatTraversalConsole; +use crate::user::MatchmakeUser; +#[derive(Debug)] pub struct MatchmakeManager { //pub gid_counter: AtomicU32, pub sessions: RwLock>>>, pub rv_cid_counter: AtomicU32, - pub users: RwLock>>, - pub users_by_pid: RwLock>>, + pub users: RwLock>>, + pub users_by_pid: RwLock>>, } impl MatchmakeManager { @@ -38,9 +50,10 @@ impl MatchmakeManager { } pub fn next_cid(&self) -> u32 { - self.rv_cid_counter.fetch_add(1, Relaxed) + self.rv_cid_counter.fetch_add(1, Ordering::Relaxed) } + #[instrument] pub async fn get_session( &self, gid: u32, @@ -48,7 +61,7 @@ impl MatchmakeManager { let sessions = self.sessions.read().await; let Some(session) = sessions.get(&gid) else { - return Err(RendezVous_SessionVoid); + return Err(ErrorCode::RendezVous_SessionVoid); }; let session = session.clone(); @@ -57,6 +70,7 @@ impl MatchmakeManager { Ok(session) } + #[instrument] async fn garbage_collect(&self) { info!("running rnex garbage collector over all sessions and users"); @@ -90,7 +104,8 @@ impl MatchmakeManager { } } - pub async fn initialize_garbage_collect_thread(this: Weak) { + #[instrument] + pub fn initialize_garbage_collect_thread(this: Weak) { tokio::spawn(async move { while let Some(this) = this.upgrade() { this.garbage_collect().await; @@ -103,6 +118,7 @@ impl MatchmakeManager { // this could be far more efficient but it is INCREDIBLY difficult to iterate over something // asyncronously propperly + #[instrument] pub async fn search_by_criteria( &self, criterias: &[MatchmakeSessionSearchCriteria], @@ -137,7 +153,7 @@ impl MatchmakeManager { #[derive(Default, Debug)] pub struct ExtendedMatchmakeSession { pub session: MatchmakeSession, - pub connected_players: Vec>, + pub connected_players: Vec>, } fn read_bounds_string(str: &str) -> Option<(T, T)> { @@ -159,7 +175,7 @@ fn check_bounds_str(compare: T, str: &str) -> Option>( +pub async fn broadcast_notification>( players: impl Iterator, notification_event: &NotificationEvent, ) { @@ -174,7 +190,7 @@ pub async fn broadcast_notification>( impl ExtendedMatchmakeSession { #[inline(always)] - pub fn get_active_players(&self) -> impl Iterator> { + pub fn get_active_players(&self) -> impl Iterator> { self.connected_players.iter().filter_map(|u| u.upgrade()) } @@ -186,21 +202,14 @@ impl ExtendedMatchmakeSession { pub async fn from_matchmake_session( gid: u32, session: MatchmakeSession, - host: &Weak, + host: &WeakPassthroughInitModule, ) -> Self { let Some(host) = host.upgrade() else { return Default::default(); }; - cfg_if::cfg_if! { + cfg_if! { if #[cfg(feature = "v3-5-0")]{ - use rnex_core::{ - rmc::structures::{ - variant::Variant, - matchmake::MatchmakeParam - }, - kerberos::KerberosDateTime - }; let mm_session = MatchmakeSession { gathering: Gathering { self_gid: gid, @@ -208,7 +217,7 @@ impl ExtendedMatchmakeSession { host_pid: host.pid, ..session.gathering.clone() }, - datetime: KerberosDateTime::now(), + datetime: DateTime::now(), session_key: (0..32).map(|_| random()).collect(), matchmake_param: MatchmakeParam { params: vec![ @@ -228,8 +237,8 @@ impl ExtendedMatchmakeSession { let mm_session = MatchmakeSession { gathering: Gathering { self_gid: gid, - owner_pid: host.pid, - host_pid: host.pid, + owner_pid: host.base.pid, + host_pid: host.base.pid, ..session.gathering.clone() }, session_key: (0..32).map(|_| random()).collect(), @@ -243,12 +252,16 @@ impl ExtendedMatchmakeSession { } } - pub async fn add_players(&mut self, conns: &[Weak], join_msg: String) { + pub async fn add_players( + &mut self, + conns: &[WeakPassthroughInitModule], + join_msg: String, + ) { let Some(initiating_user) = conns[0].upgrade() else { return; }; - let initiating_pid = initiating_user.pid; + let initiating_pid = initiating_user.base.pid; let old_particip = self.connected_players.clone(); for conn in conns { @@ -261,7 +274,7 @@ impl ExtendedMatchmakeSession { continue; }; - let other_pid = other_conn.pid; + let other_pid = other_conn.base.pid; /*if other_pid == self.session.gathering.owner_pid && joining_pid == self.session.gathering.owner_pid{ continue; @@ -271,7 +284,7 @@ impl ExtendedMatchmakeSession { .remote .process_notification_event(NotificationEvent { pid_source: initiating_pid, - notif_type: 122000, + notif_type: 122_000, param_1: self.session.gathering.self_gid as PID, param_2: other_pid, str_param: "".into(), @@ -285,7 +298,7 @@ impl ExtendedMatchmakeSession { .connected_players .iter() .filter_map(|p| p.upgrade()) - .map(|p| p.pid) + .map(|p| p.base.pid) .collect(); for other_connection in conns { @@ -322,7 +335,11 @@ impl ExtendedMatchmakeSession { /*if old_conns.pid != self.session.gathering.host_pid { continue; }*/ - for new_conn_pid in conns.iter().filter_map(Weak::upgrade).map(|c| c.pid) { + for new_conn_pid in conns + .iter() + .filter_map(WeakPassthroughInitModule::upgrade) + .map(|c| c.base.pid) + { old_conns .remote .process_notification_event(NotificationEvent { @@ -348,15 +365,15 @@ impl ExtendedMatchmakeSession { } #[inline] - pub fn get_host(&self) -> Option> { + pub fn get_host(&self) -> Option> { self.get_active_players() - .find(|v| v.pid == self.session.gathering.host_pid) + .find(|v| v.base.pid == self.session.gathering.host_pid) } #[inline] pub fn is_reachable(&self) -> bool { self.get_active_players() - .any(|v| v.pid == self.session.gathering.host_pid) + .any(|v| v.base.pid == self.session.gathering.host_pid) && (if self.session.gathering.flags & PERSISTENT_GATHERING != 0 { if self.has_min_active_players() { true @@ -380,89 +397,6 @@ impl ExtendedMatchmakeSession { self.is_reachable() && is_open } - pub async fn is_joinable_by(&self, user: Arc) -> bool { - let Some(host) = self.get_host() else { - return false; - }; - - let Some(user_station_url) = user.station_url.read().await.first().cloned() else { - return false; - }; - let Some(host_station_url) = host.station_url.read().await.first().cloned() else { - return false; - }; - - let mut tickets_requesters = host.remote_join_ticket_requesters.lock().await; - tickets_requesters.insert(user.cid, Arc::downgrade(&user)); - drop(tickets_requesters); - - host.remote - .request_probe_initiation(user_station_url.to_string()) - .await; - - let Some(_) = timeout(Duration::from_secs(5), async { - loop { - let mut stage1_recv = user.join_tickets_stage1_recv.lock().await; - - let Some(ticket) = stage1_recv.recv().await else { - return None; - }; - - if ticket.cid != host.cid { - user.join_tickets_stage1_sender.send(ticket).await.ok(); - drop(stage1_recv); - warn!("got incorrect ticket sleeping for 500 millis whilest leaving ticket reciever open for use"); - - sleep(Duration::from_millis(500)).await; - continue; - } - - return Some(ticket); - } - }) - .await - .ok() - .flatten() else { - return false; - }; - - let mut ticket_requesters = user.self_join_ticket_requesters.lock().await; - ticket_requesters.insert(host.cid); - drop(ticket_requesters); - - user.remote - .request_probe_initiation(host_station_url.to_string()) - .await; - - let Some(stage2_ticket) = timeout(Duration::from_secs(5), async { - loop { - let mut stage2_recv = user.join_tickets_stage2_recv.lock().await; - - let Some(ticket) = stage2_recv.recv().await else { - return None; - }; - - if ticket.cid != host.cid { - user.join_tickets_stage2_sender.send(ticket).await.ok(); - drop(stage2_recv); - warn!("got incorrect ticket sleeping for 500 millis whilest leaving ticket reciever open for use"); - - sleep(Duration::from_millis(500)).await; - continue; - } - - return Some(ticket); - } - }) - .await - .ok() - .flatten() else { - return false; - }; - - stage2_ticket.result - } - pub fn matches_criteria( &self, search_criteria: &MatchmakeSessionSearchCriteria, @@ -503,7 +437,7 @@ impl ExtendedMatchmakeSession { self.session.gathering.minimum_participants, &search_criteria.minimum_participants, ) - .ok_or(Core_InvalidArgument)? + .ok_or(ErrorCode::Core_InvalidArgument)? { return Ok(false); } @@ -512,7 +446,7 @@ impl ExtendedMatchmakeSession { self.session.gathering.maximum_participants, &search_criteria.maximum_participants, ) - .ok_or(Core_InvalidArgument)? + .ok_or(ErrorCode::Core_InvalidArgument)? { return Ok(false); } @@ -520,7 +454,7 @@ impl ExtendedMatchmakeSession { let game_mode: u32 = search_criteria .game_mode .parse() - .map_err(|_| Core_InvalidArgument)?; + .map_err(|_| ErrorCode::Core_InvalidArgument)?; if self.session.gamemode != game_mode { return Ok(false); @@ -529,7 +463,7 @@ impl ExtendedMatchmakeSession { let mm_sys_type: u32 = search_criteria .matchmake_system_type .parse() - .map_err(|_| Core_InvalidArgument)?; + .map_err(|_| ErrorCode::Core_InvalidArgument)?; if self.session.matchmake_system_type != mm_sys_type { return Ok(false); @@ -575,20 +509,20 @@ impl ExtendedMatchmakeSession { let Some(new_owner) = players .iter() - .find(|p| p.pid != self.session.gathering.owner_pid) + .find(|p| p.base.pid != self.session.gathering.owner_pid) else { self.session.gathering.owner_pid = 0; return Ok(()); }; - self.session.gathering.owner_pid = new_owner.pid; + self.session.gathering.owner_pid = new_owner.base.pid; self.broadcast_notification(&NotificationEvent { pid_source: initiator_pid, notif_type: OWNERSHIP_CHANGED, param_1: self.session.gathering.self_gid as PID, - param_2: new_owner.pid, + param_2: new_owner.base.pid, ..Default::default() }) .await; @@ -618,7 +552,7 @@ impl ExtendedMatchmakeSession { message: &str, ) -> Result<(), ErrorCode> { self.connected_players - .retain(|u| u.upgrade().is_some_and(|u| u.pid != pid)); + .retain(|u| u.upgrade().is_some_and(|u| u.base.pid != pid)); self.session.participation_count = (self.connected_players.len() & u32::MAX as usize) as u32; @@ -652,3 +586,34 @@ impl ExtendedMatchmakeSession { Ok(()) } } + +impl RnexManager for MatchmakeManager { + type User = MatchmakeUser; + + type InitData = ConnectionInitData; + + async fn init_new_user( + this: PassthroughInitModule, + mod_holder: &rnex_server::ModuleHolder, + remote: &rnex_rmc::RmcConnection, + _: &Self::InitData, + user: WeakPassthroughInitModule, + ) -> Self::User { + MatchmakeUser { + base: mod_holder + .get_ref_init_pt() + .expect("matchmaking module cannot work without the base module"), + matchmake_manager: this, + remote: RemoteMatchMakingClientProtocol::new(remote.clone()), + this: user, + } + } + async fn post_init(user: &Self::User) { + let mut users = user.matchmake_manager.users.write().await; + users.insert(user.base.cid, user.this.clone()); + drop(users); + let mut users = user.matchmake_manager.users_by_pid.write().await; + users.insert(user.base.pid, user.this.clone()); + drop(users); + } +} diff --git a/rnex-core/src/nex/user.rs b/rnex-server-nex-modules/rnex-mm/src/user.rs similarity index 55% rename from rnex-core/src/nex/user.rs rename to rnex-server-nex-modules/rnex-mm/src/user.rs index 7f17923..e7e0f5d 100644 --- a/rnex-core/src/nex/user.rs +++ b/rnex-server-nex-modules/rnex-mm/src/user.rs @@ -1,78 +1,34 @@ -use rnex_core::PID; -use rnex_core::define_rmc_proto; -use rnex_core::kerberos::KerberosDateTime; -use rnex_core::nex::common::get_station_urls; -use rnex_core::nex::matchmake::{ExtendedMatchmakeSession, MatchmakeManager}; -use rnex_core::nex::remote_console::RemoteConsole; -use rnex_core::prudp::station_url::StationUrl; -use rnex_core::prudp::station_url::UrlOptions::{ - Address, NatFiltering, NatMapping, Port, RVConnectionID, -}; -use rnex_core::rmc::protocols::matchmake::{ - Matchmake, RawMatchmake, RawMatchmakeInfo, RemoteMatchmake, -}; -use rnex_core::rmc::protocols::matchmake_ext::{ - MatchmakeExt, RawMatchmakeExt, RawMatchmakeExtInfo, RemoteMatchmakeExt, -}; -use rnex_core::rmc::protocols::matchmake_extension::{ - MatchmakeExtension, RawMatchmakeExtension, RawMatchmakeExtensionInfo, RemoteMatchmakeExtension, -}; -use rnex_core::rmc::protocols::nat_traversal::{ - NatTraversal, RawNatTraversal, RawNatTraversalInfo, RemoteNatTraversal, - RemoteNatTraversalConsole, -}; -use rnex_core::rmc::protocols::notifications::notification_types::{ - END_GATHERING, REQUEST_JOIN_GATHERING, -}; -use rnex_core::rmc::protocols::ranking::{Ranking, RawRanking, RawRankingInfo, RemoteRanking}; -use rnex_core::rmc::protocols::secure::{RawSecure, RawSecureInfo, RemoteSecure, Secure}; -use rnex_core::rmc::protocols::util::{RawUtility, RawUtilityInfo, RemoteUtility, Utility}; -use rnex_core::rmc::response::ErrorCode; -use rnex_core::rmc::structures::any::Any; -use rnex_core::rmc::structures::matchmake::{ - AutoMatchmakeParam, CreateMatchmakeSessionParam, JoinMatchmakeSessionParam, MatchmakeSession, -}; -use serde::{Deserialize, Serialize}; -use std::collections::HashMap; -use std::collections::HashSet; -use std::env; -use std::str::FromStr; -use tokio::sync::mpsc::Receiver; -use tokio::sync::mpsc::Sender; +use std::{env, sync::Arc}; -use cfg_if::cfg_if; -use log::{error, info}; -use macros::rmc_struct; -use rnex_core::{ - prudp::socket_addr::PRUDPSockAddr, - rmc::{ - protocols::{ - message_delivery::{ - MessageDelivery, RawMessageDelivery, RawMessageDeliveryInfo, RemoteMessageDelivery, - RemoteMessageDeliveryNoResponse, - }, - messaging::UserMessage, - notifications::{NotificationEvent, RemoteNotification}, - ranking::{ - CompetitionRankingGetParam, CompetitionRankingScoreData, - CompetitionRankingScoreInfo, - }, - }, - response::ErrorCode::{Core_InvalidArgument, RendezVous_AccountExpired}, - structures::{ - matchmake::{Gathering, MatchmakeSessionSearchCriteria}, - qbuffer::QBuffer, - qresult::QResult, - ranking::UploadCompetitionData, - }, +use rnex_base::user::BaseUser; +use rnex_base_protos::ResultsRange; +use rnex_mm_protos::{ + LocalMatchMakingProtocol, RemoteMatchMakingClientProtocol, + matchmake::{ + AutoMatchmakeParam, CreateMatchmakeSessionParam, Gathering, JoinMatchmakeSessionParam, + Matchmake, MatchmakeSession, MatchmakeSessionSearchCriteria, + }, + matchmake_ext::MatchmakeExt, + matchmake_extension::MatchmakeExtension, + nat_traversal::NatTraversal, + nat_traversal::RemoteNatTraversalConsole, + notifications::{ + NotificationEvent, RemoteNotification, + notification_types::{END_GATHERING, REQUEST_JOIN_GATHERING}, }, }; -use std::sync::{Arc, Weak}; -use tokio::sync::{Mutex, RwLock}; +use rnex_rmc::{any::Any, response::ErrorCode, rmc_struct}; +use rnex_server::{PassthroughInitModule, WeakPassthroughInitModule}; +use rnex_util::{ + PID, + station_url::{StationUrl, UrlOptions}, +}; +use tokio::sync::Mutex; +use tracing::{error, info}; -use crate::rmc::structures::resultsrange::ResultsRange; +use crate::matchmake::{ExtendedMatchmakeSession, MatchmakeManager}; -cfg_if! { +/*cfg_if! { if #[cfg(feature = "datastore")] { use rnex_core::rmc::protocols::datastore::{DataStore, RawDataStore, RawDataStoreInfo, RemoteDataStore}; define_rmc_proto!( @@ -102,7 +58,7 @@ cfg_if! { } ); } -} +}*/ /// Connection tickets are allowances to join a specific lobby, they are given out as soon as nat checks pass, /// there are 2 stages of tickets because both sides have to do nat checking before we let the player join @@ -112,90 +68,22 @@ pub struct ConnectionTicket { pub result: bool, } -#[rmc_struct(UserProtocol)] -pub struct User { +#[derive(Debug)] +#[rmc_struct(MatchMakingProtocol)] +pub struct MatchmakeUser { + pub base: PassthroughInitModule, + /* pub pid: PID, pub cid: u32, pub ip: PRUDPSockAddr, - pub this: Weak, - pub remote: RemoteConsole, - pub station_url: RwLock>, - pub matchmake_manager: Arc, - pub remote_join_ticket_requesters: Mutex>>, - pub self_join_ticket_requesters: Mutex>, - pub join_tickets_stage1_sender: Sender, - pub join_tickets_stage1_recv: Mutex>, - pub join_tickets_stage2_sender: Sender, - pub join_tickets_stage2_recv: Mutex>, + */ + pub this: WeakPassthroughInitModule, + pub remote: RemoteMatchMakingClientProtocol, + //pub station_url: RwLock>, + pub matchmake_manager: PassthroughInitModule, } -impl Secure for User { - async fn register( - &self, - station_urls: Vec, - ) -> Result<(QResult, u32, StationUrl), ErrorCode> { - let cid = self.cid; - println!("{:?}", station_urls); - - let mut users = self.matchmake_manager.users.write().await; - users.insert(cid, self.this.clone()); - drop(users); - let mut users = self.matchmake_manager.users_by_pid.write().await; - users.insert(self.pid, self.this.clone()); - drop(users); - - let stations = get_station_urls(&station_urls, self.ip, self.pid, cid).await?; - - let first = stations.first().unwrap().clone(); - - let mut lock = self.station_url.write().await; - - *lock = stations; - - drop(lock); - - let result = QResult::success(ErrorCode::Core_Unknown); - - Ok((result, cid, first)) - } - - async fn register_ex( - &self, - station_urls: Vec, - _data: Any, - ) -> Result<(QResult, u32, StationUrl), ErrorCode> { - self.register(station_urls).await - } - - async fn replace_url(&self, target_url: StationUrl, dest: StationUrl) -> Result<(), ErrorCode> { - let mut lock = self.station_url.write().await; - info!("target URL: {:?}", target_url); - info!("dest URL: {:?}", dest); - - let Some(target_addr) = target_url.options.iter().find(|v| matches!(v, Address(_))) else { - return Err(ErrorCode::Core_InvalidArgument); - }; - - let Some(target_port) = target_url.options.iter().find(|v| matches!(v, Port(_))) else { - return Err(ErrorCode::Core_InvalidArgument); - }; - - let Some(replacement_target) = lock.iter_mut().find(|url| { - url.options.iter().any(|o| o == target_addr) - && url.options.iter().any(|o| o == target_port) - }) else { - //probably internal ip - return Ok(()); - }; - *replacement_target = dest; - - drop(lock); - - Ok(()) - } -} - -impl MatchmakeExtension for User { +impl MatchmakeExtension for MatchmakeUser { async fn close_participation(&self, gid: u32) -> Result<(), ErrorCode> { let session = self.matchmake_manager.get_session(gid).await?; @@ -286,10 +174,10 @@ impl MatchmakeExtension for User { create_session_param .additional_participants .iter() - .any(|p| *p == u.pid) + .any(|p| *p == u.base.pid) }); for player in players { - joining_players.push(Arc::downgrade(&player)); + joining_players.push(PassthroughInitModule::downgrade(&player)); } } @@ -329,7 +217,7 @@ impl MatchmakeExtension for User { session .connected_players - .retain(|v| v.upgrade().is_some_and(|v| v.pid != self.pid)); + .retain(|v| v.upgrade().is_some_and(|v| v.base.pid != self.base.pid)); let mut joining_players = vec![self.this.clone()]; @@ -350,10 +238,10 @@ impl MatchmakeExtension for User { join_session_param .additional_participants .iter() - .any(|p| *p == u.pid) + .any(|p| *p == u.base.pid) }); for player in players { - joining_players.push(Arc::downgrade(&player)); + joining_players.push(PassthroughInitModule::downgrade(&player)); } } @@ -389,9 +277,14 @@ impl MatchmakeExtension for User { .connected_players .iter() .filter_map(|v| v.upgrade()) - .filter(|u| param.additional_participants.iter().any(|p| *p == u.pid)); + .filter(|u| { + param + .additional_participants + .iter() + .any(|p| *p == u.base.pid) + }); for player in players { - joining_players.push(Arc::downgrade(&player)); + joining_players.push(PassthroughInitModule::downgrade(&player)); } } @@ -510,7 +403,7 @@ impl MatchmakeExtension for User { REQUEST_JOIN_GATHERING => { user.remote .process_notification_event(NotificationEvent { - pid_source: self.pid, + pid_source: self.base.pid, notif_type: REQUEST_JOIN_GATHERING * 1000, param_1: bytemuck::cast(param_1), param_2: bytemuck::cast(param_2), @@ -523,7 +416,7 @@ impl MatchmakeExtension for User { END_GATHERING => { user.remote .process_notification_event(NotificationEvent { - pid_source: self.pid, + pid_source: self.base.pid, notif_type: END_GATHERING * 1000, param_1: bytemuck::cast(param_1), param_2: bytemuck::cast(param_2), @@ -549,10 +442,10 @@ impl MatchmakeExtension for User { let mut session = session.lock().await; - if session.session.gathering.host_pid == self.pid { + if session.session.gathering.host_pid == self.base.pid { return Err(ErrorCode::RendezVous_PermissionDenied); } - if session.session.gathering.owner_pid == self.pid { + if session.session.gathering.owner_pid == self.base.pid { return Err(ErrorCode::RendezVous_PermissionDenied); } @@ -604,7 +497,7 @@ impl MatchmakeExtension for User { } } -impl Matchmake for User { +impl Matchmake for MatchmakeUser { async fn find_by_single_id(&self, gid: u32) -> Result<(bool, Any), ErrorCode> { let s = self.matchmake_manager.get_session(gid).await?; let s = s.lock().await; @@ -626,8 +519,8 @@ impl Matchmake for User { .connected_players .iter() .filter_map(|v| v.upgrade()) - .filter(|u| u.pid == session.session.gathering.host_pid) - .map(|u| async move { u.station_url.read().await.clone() }) + .filter(|u| u.base.pid == session.session.gathering.host_pid) + .map(|u| async move { u.base.station_url.read().await.clone() }) .next() .ok_or(ErrorCode::RendezVous_SessionClosed)? .await; @@ -649,7 +542,7 @@ impl Matchmake for User { let session = self.matchmake_manager.get_session(gid).await?; let mut session = session.lock().await; - session.session.gathering.host_pid = self.pid; + session.session.gathering.host_pid = self.base.pid; for player in &session.connected_players { let Some(player) = player.upgrade() else { @@ -659,10 +552,10 @@ impl Matchmake for User { player .remote .process_notification_event(NotificationEvent { - notif_type: 110000, - pid_source: self.pid, + notif_type: 110_000, + pid_source: self.base.pid, param_1: gid as PID, - param_2: self.pid, + param_2: self.base.pid, #[cfg(feature = "third-notif-param")] param_3: 0, str_param: "".to_string(), @@ -671,7 +564,7 @@ impl Matchmake for User { } if change_session_owner { - session.session.gathering.owner_pid = self.pid; + session.session.gathering.owner_pid = self.base.pid; for player in &session.connected_players { let Some(player) = player.upgrade() else { @@ -682,9 +575,9 @@ impl Matchmake for User { .remote .process_notification_event(NotificationEvent { notif_type: 4000, - pid_source: self.pid, + pid_source: self.base.pid, param_1: gid as PID, - param_2: self.pid, + param_2: self.base.pid, #[cfg(feature = "third-notif-param")] param_3: 0, str_param: "".to_string(), @@ -705,7 +598,7 @@ impl Matchmake for User { let session = self.matchmake_manager.get_session(gid).await?; let mut session = session.lock().await; - let candidate = candidates.get(0).ok_or(Core_InvalidArgument)?; + let candidate = candidates.get(0).ok_or(ErrorCode::Core_InvalidArgument)?; session.session.gathering.owner_pid = *candidate; @@ -718,7 +611,7 @@ impl Matchmake for User { .remote .process_notification_event(NotificationEvent { notif_type: 4000, - pid_source: self.pid, + pid_source: self.base.pid, param_1: gid as PID, param_2: *candidate as PID, #[cfg(feature = "third-notif-param")] @@ -732,36 +625,40 @@ impl Matchmake for User { } } -impl MatchmakeExt for User { +impl MatchmakeExt for MatchmakeUser { async fn end_participation(&self, gid: u32, message: String) -> Result { let session = self.matchmake_manager.get_session(gid).await?; let mut session = session.lock().await; session - .remove_player_from_session(self.pid, &message) + .remove_player_from_session(self.base.pid, &message) .await?; Ok(true) } } -impl NatTraversal for User { +impl NatTraversal for MatchmakeUser { async fn report_nat_properties( &self, nat_mapping: u32, nat_filtering: u32, _rtt: u32, ) -> Result<(), ErrorCode> { - let mut urls = self.station_url.write().await; + let mut urls = self.base.station_url.write().await; for station_url in urls.iter_mut() { station_url.options.retain(|o| match o { - NatMapping(_) | NatFiltering(_) => false, + UrlOptions::NatMapping(_) | UrlOptions::NatFiltering(_) => false, _ => true, }); - station_url.options.push(NatMapping(nat_mapping as u8)); - station_url.options.push(NatFiltering(nat_filtering as u8)); + station_url + .options + .push(UrlOptions::NatMapping(nat_mapping as u8)); + station_url + .options + .push(UrlOptions::NatFiltering(nat_filtering as u8)); } Ok(()) @@ -773,40 +670,17 @@ impl NatTraversal for User { result: bool, _rtt: u32, ) -> Result<(), ErrorCode> { - if let Some(user) = self - .remote_join_ticket_requesters - .lock() - .await - .remove(&cid) - .map(|u| u.upgrade()) - .flatten() - { - user.join_tickets_stage1_sender - .send(ConnectionTicket { - cid: self.cid, - result, - }) - .await - .ok(); - } - if let Some(_user) = self.self_join_ticket_requesters.lock().await.take(&cid) { - self.join_tickets_stage2_sender - .send(ConnectionTicket { cid, result }) - .await - .ok(); - } - Ok(()) } async fn request_probe_initiation(&self, _station_to_probe: String) -> Result<(), ErrorCode> { info!("NO!"); - Err(RendezVous_AccountExpired) + Err(ErrorCode::RendezVous_AccountExpired) } async fn request_probe_initialization_ext( &self, - target_list: Vec, + target_list: Vec, station_to_probe: String, ) -> Result<(), ErrorCode> { let users = self.matchmake_manager.users.read().await; @@ -816,15 +690,11 @@ impl NatTraversal for User { target_list, station_to_probe ); - for target in target_list { - let Ok(url) = StationUrl::try_from(target.as_ref()) else { - continue; - }; - - let Some(RVConnectionID(v)) = url + for url in target_list { + let Some(UrlOptions::RVConnectionID(v)) = url .options .into_iter() - .find(|o| matches!(o, &RVConnectionID(_))) + .find(|o| matches!(o, &UrlOptions::RVConnectionID(_))) else { continue; }; @@ -847,204 +717,3 @@ impl NatTraversal for User { Ok(()) } } - -#[derive(Serialize, Deserialize)] -pub struct CompetitionPostResults { - pub splatfest_id: u32, - pub score: u32, - pub team_id: u8, - pub team_win: u8, - pub user: PID, -} - -// Seperate function because I cannot give a fuck right now -fn fetch_team_votes(fest_id: u32) -> Result, ErrorCode> { - let endpoint_votes = env::var("RNEX_SPLATOON_RESULTS_VOTES_GET").map_err(|_| { - error!("RNEX_SPLATOON_RESULTS_VOTES_GET not set"); - ErrorCode::RendezVous_InvalidConfiguration - })?; - - let url_votes = format!("{}?splatfest_id={}", endpoint_votes, fest_id); - let mut response = ureq::get(&url_votes).call().map_err(|e| { - error!("GET for votes failed: {:?}", e); - ErrorCode::RendezVous_InvalidConfiguration - })?; - - let body = response.body_mut().read_to_string().map_err(|e| { - error!("failed to read votes body: {:?}", e); - ErrorCode::RendezVous_InvalidConfiguration - })?; - - let body = body.trim().trim_start_matches('[').trim_end_matches(']'); - let votes: Result, _> = body.split(',').map(|s| u32::from_str(s.trim())).collect(); - - votes.map_err(|e| { - error!("failed to parse votes: {:?}", e); - ErrorCode::RendezVous_InvalidConfiguration - }) -} - -impl Utility for User { - async fn acquire_nex_unique_id(&self) -> Result { - return Ok(rand::random()); - } - - async fn get_integer_settings(&self, _index: u32) -> Result, ErrorCode> { - Ok(vec![(0, 1), (1, 2), (2, 0), (3, 4)]) - } -} - -impl Ranking for User { - async fn competition_ranking_get_param( - &self, - param: CompetitionRankingGetParam, - ) -> Result, ErrorCode> { - let fest_id = param.festival_ids.get(0).copied().unwrap_or(0); - - let endpoint_results = env::var("RNEX_SPLATOON_RESULTS_GET").map_err(|_| { - error!("RNEX_SPLATOON_RESULTS_GET not set"); - ErrorCode::RendezVous_InvalidConfiguration - })?; - - let url_results = format!("{}?splatfest_id={}", endpoint_results, fest_id); - let response_results = ureq::get(&url_results).call(); - - let results: Vec = match response_results { - Ok(mut res) => res.body_mut().read_json().map_err(|e| { - error!("failed to parse JSON: {:?}", e); - ErrorCode::RendezVous_InvalidConfiguration - })?, - Err(e) => { - error!("GET failed: {:?}", e); - return Err(ErrorCode::RendezVous_InvalidConfiguration); - } - }; - - let offset = param.range.offset as usize; - let size = param.range.size as usize; - - let start = offset.min(results.len()); - let end = (start + size).min(results.len()); - - let team_votes = fetch_team_votes(fest_id)?; - let mut wins = vec![0u32, 0u32]; - for r in &results { - let won_team = (r.team_id ^ (!r.team_win)) & 1; - if let Some(team) = wins.get_mut(won_team as usize) { - *team += 1 - }; - } - - let score_data: Vec = results[start..end] - .iter() - .map(|r| CompetitionRankingScoreData { - unk: 1, - pid: r.user, - score: r.score, - modified: KerberosDateTime::now(), - unk2: 1, - appdata: QBuffer(vec![]), - }) - .collect(); - - let info = CompetitionRankingScoreInfo { - fest_id, - score_data, - unk: 0, - team_wins: wins, - team_votes, - }; - - println!("range: {:?}", param.range); - - Ok(vec![info]) - } - - async fn upload_competition_ranking_score( - &self, - param: UploadCompetitionData, - ) -> Result { - info!("fest results for user {:?}:", self.pid); - info!("fest id: {:?}", param.splatfest_id); - info!("score: {:?}", param.score); - info!("team id: {:?}", param.team_id); - info!("did current team win: {:?}", param.team_win); - - let endpoint = match env::var("RNEX_SPLATOON_RESULTS_POST") { - Ok(url) => url, - Err(_) => { - error!("RNEX_SPLATOON_RESULTS_POST not set"); - return Ok(false); - } - }; - - let payload = CompetitionPostResults { - splatfest_id: param.splatfest_id, - score: param.score, - team_id: param.team_id, - team_win: param.team_win, - user: self.pid, - }; - - let json_body = match serde_json::to_string(&payload) { - Ok(j) => j, - Err(e) => { - error!("error making json_body: {:?}", e); - return Ok(false); - } - }; - - let response = ureq::post(&endpoint) - .header("Content-Type", "application/json") - .send(json_body); - - match response { - Ok(res) => { - info!("POST worked: {}", res.status()); - } - Err(e) => { - error!("POST borked: {:?}", e); - } - } - - Ok(true) - } -} - -impl MessageDelivery for User { - async fn deliver_message(&self, mut message: Any) -> Result<(), ErrorCode> { - let mut msg = message.get()?; - - let _users = match msg.recipient_type { - 1 => { - let Some(user) = self - .matchmake_manager - .users_by_pid - .read() - .await - .get(&msg.recipient_id) - .map(Weak::upgrade) - .flatten() - else { - return Err(ErrorCode::Core_InvalidArgument); - }; - if msg.flags & 1 != 0 { - msg.recipient_id = user.pid; - msg.recipient_type = 1; - } - - message.emplace_parent(&msg)?; - - user.remote.deliver_message(message).await; - } - 2 => { - return Err(ErrorCode::Core_NotImplemented); - } - _ => { - return Err(ErrorCode::Core_InvalidArgument); - } - }; - - Err(ErrorCode::Core_NotImplemented) - } -} diff --git a/rnex-server-nex-modules/rnex-msg/Cargo.toml b/rnex-server-nex-modules/rnex-msg/Cargo.toml new file mode 100644 index 0000000..116c996 --- /dev/null +++ b/rnex-server-nex-modules/rnex-msg/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "rnex-msg" +version = "0.1.0" +edition = "2024" + +[dependencies] + +[lints] +workspace = true diff --git a/rnex-server-nex-modules/rnex-msg/src/main.rs b/rnex-server-nex-modules/rnex-msg/src/main.rs new file mode 100644 index 0000000..e7a11a9 --- /dev/null +++ b/rnex-server-nex-modules/rnex-msg/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/rnex-server-nex-modules/rnex-msg/src/user.rs b/rnex-server-nex-modules/rnex-msg/src/user.rs new file mode 100644 index 0000000..04ffb37 --- /dev/null +++ b/rnex-server-nex-modules/rnex-msg/src/user.rs @@ -0,0 +1,37 @@ +impl MessageDelivery for User { + async fn deliver_message(&self, mut message: Any) -> Result<(), ErrorCode> { + let mut msg = message.get()?; + + let _users = match msg.recipient_type { + 1 => { + let Some(user) = self + .matchmake_manager + .users_by_pid + .read() + .await + .get(&msg.recipient_id) + .map(Weak::upgrade) + .flatten() + else { + return Err(ErrorCode::Core_InvalidArgument); + }; + if msg.flags & 1 != 0 { + msg.recipient_id = user.pid; + msg.recipient_type = 1; + } + + message.emplace_parent(&msg)?; + + user.remote.deliver_message(message).await; + } + 2 => { + return Err(ErrorCode::Core_NotImplemented); + } + _ => { + return Err(ErrorCode::Core_InvalidArgument); + } + }; + + Err(ErrorCode::Core_NotImplemented) + } +} diff --git a/rnex-server-nex-modules/rnex-node-holder/Cargo.toml b/rnex-server-nex-modules/rnex-node-holder/Cargo.toml new file mode 100644 index 0000000..35a6cb0 --- /dev/null +++ b/rnex-server-nex-modules/rnex-node-holder/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "rnex-node-holder" +version = "0.1.0" +edition = "2024" + +[dependencies] +rnex-rmc = { path = "../../rnex-rmc" } +rnex-reggie-protos = { path = "../../rnex-protocols/reggie-protos" } +rnex-server = { path = "../../rnex-server" } +tokio = { version = "1.52.3", features = ["sync"] } +[lints] +workspace = true diff --git a/rnex-server-nex-modules/rnex-node-holder/src/lib.rs b/rnex-server-nex-modules/rnex-node-holder/src/lib.rs new file mode 100644 index 0000000..efe343b --- /dev/null +++ b/rnex-server-nex-modules/rnex-node-holder/src/lib.rs @@ -0,0 +1,84 @@ +use std::{ + convert::Infallible, + net::{Ipv4Addr, SocketAddr, SocketAddrV4}, + sync::{Arc, Weak}, +}; + +use rnex_reggie_protos::reggie::{ + EdgeNodeHolderConnectOption, EdgeNodeManagement, LocalEdgeNodeHolder, RemoteEdgeNodeHolder, +}; +use rnex_rmc::{response::ErrorCode, rmc_struct, tracing::info}; +use rnex_server::{ + ConnectionInitData, PassthroughInitModule, RnexManager, RnexModule, WeakPassthroughInitModule, +}; +use tokio::sync::RwLock; + +#[derive(Debug)] +#[rmc_struct(EdgeNodeHolder)] +pub struct EdgeNode { + em: PassthroughInitModule, + address: SocketAddrV4, +} + +impl EdgeNodeManagement for EdgeNode { + async fn get_url(&self, seed: u64) -> Result { + let nodes = self.em.edge_nodes.read().await; + + let nodes: Vec<_> = nodes.iter().filter_map(|n| n.upgrade()).collect(); + + // avoid a devide by zero + if nodes.len() == 0 { + return Err(ErrorCode::Core_InvalidIndex); + }; + + let node = &nodes[seed as usize % nodes.len()]; + + Ok(node.address) + } +} + +#[derive(Default, Debug)] +pub struct NodeHolderManager { + edge_nodes: RwLock>>, +} +#[derive(Default, Debug)] +pub struct NodeHolderModule; + +impl RnexManager for NodeHolderManager { + type User = Arc; + type InitData = EdgeNodeHolderConnectOption; + async fn init_new_user( + this: PassthroughInitModule, + mod_holder: &rnex_server::ModuleHolder, + remote: &rnex_rmc::RmcConnection, + init_data: &Self::InitData, + _: WeakPassthroughInitModule, + ) -> Self::User { + match init_data { + EdgeNodeHolderConnectOption::DontRegister => Arc::new(EdgeNode { + em: this, + address: SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0), + }), + EdgeNodeHolderConnectOption::Register(socket_addr_v4) => { + let node = Arc::new(EdgeNode { + em: this.clone(), + address: *socket_addr_v4, + }); + this.edge_nodes.write().await.push(Arc::downgrade(&node)); + + node + } + } + } +} + +impl RnexModule for NodeHolderModule { + type Manager = NodeHolderManager; + type InitError = Infallible; + + async fn create_manager( + _: &rnex_server::ModuleHolder, + ) -> Result { + Ok(NodeHolderManager::default()) + } +} diff --git a/rnex-server-nex-modules/rnex-rk/Cargo.toml b/rnex-server-nex-modules/rnex-rk/Cargo.toml new file mode 100644 index 0000000..b1aafdb --- /dev/null +++ b/rnex-server-nex-modules/rnex-rk/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "rnex-rk" +version = "0.1.0" +edition = "2024" + +[dependencies] + +[lints] +workspace = true diff --git a/rnex-server-nex-modules/rnex-rk/src/main.rs b/rnex-server-nex-modules/rnex-rk/src/main.rs new file mode 100644 index 0000000..e7a11a9 --- /dev/null +++ b/rnex-server-nex-modules/rnex-rk/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/rnex-server-nex-modules/rnex-rk/src/user.rs b/rnex-server-nex-modules/rnex-rk/src/user.rs new file mode 100644 index 0000000..a6a17cb --- /dev/null +++ b/rnex-server-nex-modules/rnex-rk/src/user.rs @@ -0,0 +1,155 @@ +#[derive(Serialize, Deserialize)] +pub struct CompetitionPostResults { + pub splatfest_id: u32, + pub score: u32, + pub team_id: u8, + pub team_win: u8, + pub user: PID, +} + +// Seperate function because I cannot give a fuck right now +async fn fetch_team_votes(fest_id: u32) -> Result, ErrorCode> { + let endpoint_votes = env::var("RNEX_SPLATOON_RESULTS_VOTES_GET").map_err(|_| { + error!("RNEX_SPLATOON_RESULTS_VOTES_GET not set"); + ErrorCode::RendezVous_InvalidConfiguration + })?; + + let url_votes = format!("{}?splatfest_id={}", endpoint_votes, fest_id); + let mut response = tokio::task::spawn_blocking(|| { + ureq::get(&url_votes).call().map_err(|e| { + error!("GET for votes failed: {:?}", e); + ErrorCode::RendezVous_InvalidConfiguration + }) + }) + .await?; + + let body = response.body_mut().read_to_string().map_err(|e| { + error!("failed to read votes body: {:?}", e); + ErrorCode::RendezVous_InvalidConfiguration + })?; + + let body = body.trim().trim_start_matches('[').trim_end_matches(']'); + let votes: Result, _> = body.split(',').map(|s| u32::from_str(s.trim())).collect(); + + votes.map_err(|e| { + error!("failed to parse votes: {:?}", e); + ErrorCode::RendezVous_InvalidConfiguration + }) +} + +impl Ranking for User { + async fn competition_ranking_get_param( + &self, + param: CompetitionRankingGetParam, + ) -> Result, ErrorCode> { + let fest_id = param.festival_ids.get(0).copied().unwrap_or(0); + + let endpoint_results = env::var("RNEX_SPLATOON_RESULTS_GET").map_err(|_| { + error!("RNEX_SPLATOON_RESULTS_GET not set"); + ErrorCode::RendezVous_InvalidConfiguration + })?; + + let url_results = format!("{}?splatfest_id={}", endpoint_results, fest_id); + let response_results = ureq::get(&url_results).call(); + + let results: Vec = match response_results { + Ok(mut res) => res.body_mut().read_json().map_err(|e| { + error!("failed to parse JSON: {:?}", e); + ErrorCode::RendezVous_InvalidConfiguration + })?, + Err(e) => { + error!("GET failed: {:?}", e); + return Err(ErrorCode::RendezVous_InvalidConfiguration); + } + }; + + let offset = param.range.offset as usize; + let size = param.range.size as usize; + + let start = offset.min(results.len()); + let end = (start + size).min(results.len()); + + let team_votes = fetch_team_votes(fest_id)?; + let mut wins = vec![0u32, 0u32]; + for r in &results { + let won_team = (r.team_id ^ (!r.team_win)) & 1; + if let Some(team) = wins.get_mut(won_team as usize) { + *team += 1 + }; + } + + let score_data: Vec = results[start..end] + .iter() + .map(|r| CompetitionRankingScoreData { + unk: 1, + pid: r.user, + score: r.score, + modified: KerberosDateTime::now(), + unk2: 1, + appdata: QBuffer(vec![]), + }) + .collect(); + + let info = CompetitionRankingScoreInfo { + fest_id, + score_data, + unk: 0, + team_wins: wins, + team_votes, + }; + + println!("range: {:?}", param.range); + + Ok(vec![info]) + } + + async fn upload_competition_ranking_score( + &self, + param: UploadCompetitionData, + ) -> Result { + info!("fest results for user {:?}:", self.pid); + info!("fest id: {:?}", param.splatfest_id); + info!("score: {:?}", param.score); + info!("team id: {:?}", param.team_id); + info!("did current team win: {:?}", param.team_win); + + let endpoint = match env::var("RNEX_SPLATOON_RESULTS_POST") { + Ok(url) => url, + Err(_) => { + error!("RNEX_SPLATOON_RESULTS_POST not set"); + return Ok(false); + } + }; + + let payload = CompetitionPostResults { + splatfest_id: param.splatfest_id, + score: param.score, + team_id: param.team_id, + team_win: param.team_win, + user: self.pid, + }; + + let json_body = match serde_json::to_string(&payload) { + Ok(j) => j, + Err(e) => { + error!("error making json_body: {:?}", e); + return Ok(false); + } + }; + + let response = ureq::post(&endpoint) + .header("Content-Type", "application/json") + .send(json_body); + + match response { + Ok(res) => { + info!("POST worked: {}", res.status()); + } + Err(e) => { + error!("POST borked: {:?}", e); + } + } + + Ok(true) + } +} diff --git a/rnex-server/Cargo.toml b/rnex-server/Cargo.toml new file mode 100644 index 0000000..bcdcf31 --- /dev/null +++ b/rnex-server/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "rnex-server" +version = "0.1.0" +edition = "2024" + +[dependencies] +anyhow = { version = "1.0.103", features = ["backtrace"] } +ctor = "1.0.8" +dotenv = "0.15.0" +paste = "1.0.15" +rnex-rmc = { path = "../rnex-rmc" } +rnex-util = { path = "../rnex-util" } +sentry = { version = "0.48.4", features = ["tracing"] } +tokio = { version = "1.52.3", features = ["net"] } +tracing = "0.1.44" +tracing-subscriber = "0.3.23" + +[lints] +workspace = true diff --git a/rnex-server/backend-auth/Cargo.toml b/rnex-server/backend-auth/Cargo.toml new file mode 100644 index 0000000..4de678f --- /dev/null +++ b/rnex-server/backend-auth/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "rnex-server-backend-auth" +version = "0.1.0" +edition = "2024" + +[features] +friends = [] + +[dependencies] +rnex-server = {path = ".."} +rnex-auth = {path = "../../rnex-server-nex-modules/rnex-auth"} +tokio = { version = "1.52.3", features = ["rt-multi-thread"] } diff --git a/rnex-server/backend-auth/src/main.rs b/rnex-server/backend-auth/src/main.rs new file mode 100644 index 0000000..c065241 --- /dev/null +++ b/rnex-server/backend-auth/src/main.rs @@ -0,0 +1,10 @@ +use rnex_auth::AuthModule; +use rnex_server::launch_rnex_module_server; +use std::net::SocketAddr; +#[tokio::main] +async fn main() { + launch_rnex_module_server! { + SocketAddr; + AuthModule + } +} diff --git a/rnex-server/backend-node-holder/Cargo.toml b/rnex-server/backend-node-holder/Cargo.toml new file mode 100644 index 0000000..85a7f89 --- /dev/null +++ b/rnex-server/backend-node-holder/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "node-holder-backend" +version = "0.1.0" +edition = "2024" + +[dependencies] +rnex-server = {path = ".."} +rnex-node-holder = {path = "../../rnex-server-nex-modules/rnex-node-holder"} +rnex-reggie-protos = { path = "../../rnex-protocols/reggie-protos" } +tokio = { version = "1.52.3", features = ["rt-multi-thread"] } diff --git a/rnex-server/backend-node-holder/src/main.rs b/rnex-server/backend-node-holder/src/main.rs new file mode 100644 index 0000000..d216192 --- /dev/null +++ b/rnex-server/backend-node-holder/src/main.rs @@ -0,0 +1,11 @@ +use rnex_node_holder::NodeHolderModule; +use rnex_reggie_protos::reggie::EdgeNodeHolderConnectOption; +use rnex_server::launch_rnex_module_server; + +#[tokio::main] +async fn main() { + launch_rnex_module_server! { + EdgeNodeHolderConnectOption; + NodeHolderModule + } +} diff --git a/rnex-server/backend-secure/Cargo.toml b/rnex-server/backend-secure/Cargo.toml new file mode 100644 index 0000000..c19ee17 --- /dev/null +++ b/rnex-server/backend-secure/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "backend-secure" +version = "0.1.0" +edition = "2024" + +[dependencies] +rnex-server = {path = ".."} +rnex-base = {path = "../../rnex-server-nex-modules/rnex-base"} +rnex-mm = {path = "../../rnex-server-nex-modules/rnex-mm", optional = true} +tokio = { version = "1.52.3", features = ["time", "sync", "rt-multi-thread"] } + +[features] +match-making = ["dep:rnex-mm"] diff --git a/rnex-server/backend-secure/src/main.rs b/rnex-server/backend-secure/src/main.rs new file mode 100644 index 0000000..b5d6209 --- /dev/null +++ b/rnex-server/backend-secure/src/main.rs @@ -0,0 +1,15 @@ +use rnex_base::BaseModule; +#[cfg(feature = "match-making")] +use rnex_mm::MatchMakeModule; +use rnex_server::{ConnectionInitData, launch_rnex_module_server}; + +#[tokio::main] +async fn main() { + launch_rnex_module_server! { + ConnectionInitData; + BaseModule, + #[cfg(feature="match-making")] + MatchMakeModule + + } +} diff --git a/rnex-core/build.rs b/rnex-server/build.rs similarity index 75% rename from rnex-core/build.rs rename to rnex-server/build.rs index 2af0e5f..d1e789c 100644 --- a/rnex-core/build.rs +++ b/rnex-server/build.rs @@ -1,11 +1,11 @@ use std::{env, process::Command}; fn main() { let output = Command::new("git") - .args(&["rev-parse", "HEAD"]) + .args(["rev-parse", "HEAD"]) .output() .unwrap(); let git_hash = String::from_utf8(output.stdout).unwrap(); - println!("cargo:rustc-env=GIT_HASH={}", git_hash); + println!("cargo:rustc-env=GIT_HASH={git_hash}"); println!( "cargo:rustc-env=FEATURESET={}", env::var("CARGO_CFG_FEATURE").unwrap() diff --git a/rnex-server/src/lib.rs b/rnex-server/src/lib.rs new file mode 100644 index 0000000..8dfab52 --- /dev/null +++ b/rnex-server/src/lib.rs @@ -0,0 +1,466 @@ +#![allow(async_fn_in_trait)] +use std::net::SocketAddr; +use std::sync::Weak; +use std::{ + any::{Any, TypeId, type_name}, + borrow::Cow, + collections::HashMap, + env, + error::Error, + fmt::{Debug, Display}, + io::{Read, Write}, + net::Ipv4Addr, + ops::Deref, + sync::{Arc, LazyLock, OnceLock}, +}; + +pub use anyhow; +pub use paste; +pub use rnex_rmc as rmc; +use rnex_rmc::{RmcCallable, RmcConnection, RmcSerialize, serialization::RmcSerialize, util::PID}; +pub use rnex_util as util; +pub use tokio; +pub use tracing; +use tracing::{Instrument, Level, error, instrument, span}; +use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; + +#[derive(Debug, PartialEq, Eq, RmcSerialize)] +#[rmc_struct(0)] +pub struct ConnectionInitData { + pub addr: SocketAddr, + pub pid: PID, +} +#[derive(Debug, Default)] +pub struct ModuleHolder { + modules: HashMap>, +} + +// invariant: the [`OnceLock`] inside of the Arc MUST be initialized, +// otherwise creating this is concidered u.b. +#[derive(Debug)] +pub struct PassthroughInitModule(Arc>); +#[derive(Debug)] +pub struct WeakPassthroughInitModule(Weak>); + +impl Clone for PassthroughInitModule { + fn clone(&self) -> Self { + Self(self.0.clone()) + } +} +impl Clone for WeakPassthroughInitModule { + fn clone(&self) -> Self { + Self(self.0.clone()) + } +} + +impl Deref for PassthroughInitModule { + type Target = T; + #[inline(always)] + fn deref(&self) -> &Self::Target { + self.0.get().expect("invariant violated") + } +} + +impl AsRef for PassthroughInitModule { + #[inline(always)] + fn as_ref(&self) -> &T { + self.deref() + } +} + +impl PassthroughInitModule { + pub fn downgrade(this: &Self) -> WeakPassthroughInitModule { + WeakPassthroughInitModule(Arc::downgrade(&this.0)) + } +} +impl WeakPassthroughInitModule { + pub fn upgrade(&self) -> Option> { + self.0.upgrade().map(PassthroughInitModule) + } +} + +impl ModuleHolder { + pub fn get_ref(&self) -> Option>> { + let module = self.modules.get(&TypeId::of::())?; + let Some(module) = module.downcast_ref::>>() else { + let type_name = type_name::(); + error!(type_name, "module type inconsistency"); + return None; + }; + + Some(module.clone()) + } + /// Gets a module passthrough reference to a specific module + /// + /// By using this function you acknowledge to not do anything on + /// this object which invokes the deref() or as_ref() method until + /// AFTER the object has been initialized inside the module holder. + /// Doing so will result in a panic. + pub fn get_ref_init_pt(&self) -> Option> { + self.get_ref::().map(PassthroughInitModule) + } + pub fn create_empty_module_slot(&mut self) { + self.modules + .insert(TypeId::of::(), Arc::new(OnceLock::::new())); + } + /// Initialize a slot on the [`ModuleHolder`] + /// + /// This function allows you to initialize an empty slot in the module holder. + /// An empty slot does not mean that the slot doesnt exist, as such you must have + /// previously created the slot using [`create_empty_module_slot`] + /// + /// # Returns + /// `Ok(_)` on success containing the wrapped value or + /// `Err(_)` on failiure to set containing the value you passed in + #[instrument] + pub fn init_slot(&self, val: T) -> Result, T> { + let Some(slot) = self.get_ref() else { + return Err(val); + }; + if let Err(e) = slot.set(val) { + return Err(e); + }; + Ok(PassthroughInitModule(slot)) + } +} + +pub trait RnexManager: Sized + 'static { + type User: RmcCallable; + type InitData: RmcSerialize; + async fn init_new_user( + this: PassthroughInitModule, + mod_holder: &ModuleHolder, + remote: &RmcConnection, + init_data: &Self::InitData, + weak_user: WeakPassthroughInitModule, + ) -> Self::User; + async fn post_init(_user: &Self::User) {} +} + +pub trait RnexModule { + type Manager: RnexManager; + type InitError: Display; + async fn create_manager(mod_holder: &ModuleHolder) -> Result; +} + +#[macro_export] +macro_rules! launch_rnex_module_server { + { + $init_ty:ty; + $( + $(#[$($tt:tt)*])* + $module_type:ty + ),* $(,)?} => {{ + use $crate::tracing::Instrument; + use $crate::util::UnitPacketRead; + #[allow(nonstandard_style)] + $crate::with_setup(async || { + $crate::paste::paste!{ + #[derive(Debug)] + struct MultiEndpoint { + $( + $(#[$($tt)*])* + []: $crate::PassthroughInitModule< + <<$module_type as $crate::RnexModule>::Manager as $crate::RnexManager>::User, + > + ),* + } + } + $crate::paste::paste!{ + #[derive(Debug)] + struct MultiManager { + $( + $(#[$($tt)*])* + []: $crate::PassthroughInitModule< + <$module_type as $crate::RnexModule>::Manager, + > + ),* + } + } + impl $crate::rmc::RmcCallable for MultiEndpoint { + async fn rmc_call( + &self, + responder: &$crate::util::SendingBufferConnection, + protocol_id: u16, + method_id: u32, + call_id: u32, + rest: &[u8], + ) -> bool{ + $( + $(#[$($tt)*])* + $crate::paste::paste!{ + if self. [] + .rmc_call(responder, protocol_id, method_id, call_id, rest) + .await{ + return true; + } + } + )* + false + } + } + let managers = async { + $crate::tracing::info!("creating module holder for managers"); + let mut holder = $crate::ModuleHolder::default(); + + $( + $(#[$($tt)*])* + $crate::tracing::info!( + module_manager = ::std::any::type_name::<<$module_type as $crate::RnexModule>::Manager>(), + "creating module slot" + ); + $(#[$($tt)*])* + holder.create_empty_module_slot::<<$module_type as $crate::RnexModule>::Manager>(); + )* + + $( + $(#[$($tt)*])* + $crate::tracing::info!( + module_manager = ::std::any::type_name::<<$module_type as $crate::RnexModule>::Manager>(), + "initializing and filling module slot" + ); + $(#[$($tt)*])* + let $crate::paste::paste!{[]} = holder + .init_slot( + <$module_type as $crate::RnexModule>::create_manager(&holder).await?, + ) + .expect("initialized manager twice"); + )* + $crate::paste::paste!{ + Ok::<_, $crate::anyhow::Error>(MultiManager{ + $( $(#[$($tt)*])* [] ),* + }) + } + } + .instrument($crate::tracing::info_span!("initializing rnex server modules")) + .await?; + let socket = $crate::tokio::net::TcpListener::bind(::std::net::SocketAddrV4::new(*$crate::OWN_IP_PRIVATE, *$crate::SERVER_PORT)) + .instrument($crate::tracing::info_span!("binding to tcp socket")) + .await?; + async move { + while let Ok((mut stream, _addr)) = socket.accept().await { + $crate::tracing::info!("new incoming connection"); + async { + let Some(conn_data) = async { + let buffer = match stream.read_buffer().await { + Ok(v) => v, + Err(e) => { + $crate::tracing::error!( + "an error ocurred whilst reading connection data buffer: {e:?}", + ); + return None; + } + }; + + let user_connection_data = + <$init_ty as $crate::rmc::serialization::RmcSerialize>::deserialize(&mut ::std::io::Cursor::new(buffer)); + match user_connection_data { + Ok(v) => Some(v), + Err(e) => { + $crate::tracing::error!("an error ocurred whilst reading connection data: {:?}", e); + return None; + } + } + } + .instrument($crate::tracing::info_span!("parse connection data from stream")) + .await + else { + return; + }; + + $crate::rmc::new_rmc_gateway_connection(stream.into(), + async |r| { + $crate::tracing::info!("creating module holder for module users"); + let mut holder = $crate::ModuleHolder::default(); + + $( + $(#[$($tt)*])* + $crate::tracing::info!( + module_manager = ::std::any::type_name::<<<$module_type as $crate::RnexModule>::Manager as $crate::RnexManager>::User>(), + "creating user module slot" + ); + $(#[$($tt)*])* + holder.create_empty_module_slot::<<<$module_type as $crate::RnexModule>::Manager as $crate::RnexManager>::User>(); + )* + $( + $(#[$($tt)*])* + $crate::tracing::info!( + module_manager = ::std::any::type_name::<<<$module_type as $crate::RnexModule>::Manager as $crate::RnexManager>::User>(), + "initializing and filling user module slot if specified as present" + ); + $crate::paste::paste!{ + $(#[$($tt)*])* + let [] = holder.init_slot($crate::RnexManager::init_new_user(managers.[].clone(), &holder, &r, &conn_data, $crate::PassthroughInitModule::downgrade(&holder.get_ref_init_pt().expect("module slot should be initialized by now"))).await).expect("double init or uninit slot"); + } + )* + $crate::paste::paste!{ + ::std::sync::Arc::new(MultiEndpoint{ + + $( $(#[$($tt)*])* [] ),* + }) + } + } + ).instrument($crate::tracing::info_span!("initializing user")) + .await; + } + .instrument($crate::tracing::info_span!("handeling new incoming connection")) + .await; + } + } + .instrument($crate::tracing::info_span!("awaiting connections")) + .await; + Ok(()) + }) + .await; + }}; +} + +pub fn rnex_release() -> String { + let edition_piece = if let Some(e) = option_env!("EDITION") { + format!("{}", e) + } else { + env!("FEATURESET").into() + }; + + format!( + "rnex {} v{}({})", + edition_piece, + env!("CARGO_PKG_VERSION"), + env!("GIT_HASH") + ) +} + +pub async fn with_setup(f: impl AsyncFnOnce() -> anyhow::Result<()>) { + println!("setting up logger and dotenv"); + dotenv::dotenv().ok(); + let _maybe_sentry = if let Ok(sentry_url) = std::env::var("SENTRY_URL") { + Some(sentry::init(( + sentry_url, + sentry::ClientOptions { + release: Some(Cow::Owned(rnex_release())), + send_default_pii: true, + ..Default::default() + }, + ))) + } else { + None + }; + tracing_subscriber::registry() + .with(tracing_subscriber::fmt::layer()) + .with(sentry::integrations::tracing::layer()) + .try_init() + .expect("failed to init tracing subscriber"); + + if let Err(res) = f().instrument(span!(Level::INFO, "main")).await { + error!("fatal server error: {res}"); + }; + + /*ctrlc::set_handler(||{ + FORCE_EXIT.call_once_force(|_|{ + println!("attempting exit"); + }); + }).unwrap();*/ +} + +const IP_REQ_SERVICE_URLS: &[(&str, &str, &str)] = &[ + ("ipinfo.io:80", "ipinfo.io", "/ip"), + ("api.ipify.org:80", "api.ipify.org", "/"), + // preresolved + ("34.117.59.81:80", "ipinfo.io", "/ip"), + ("104.26.13.205:80", "api.ipify.org", "/"), + ("172.67.74.152:80", "api.ipify.org", "/"), + ("104.26.12.205:80", "api.ipify.org", "/"), +]; + +/* +cfg_if! { + if #[cfg(feature = "database-support")] { + use std::sync::{LazyLock, OnceLock}; + use sqlx::postgres::PgPool; + pub static RNEX_DATABASE_URL: LazyLock = LazyLock::new(|| { + std::env::var("RNEX_DATABASE_URL") + .expect("RNEX_DATABASE_URL must be set") + }); + + pub static DB_POOL: OnceLock = OnceLock::new(); + + pub fn get_db() -> &'static PgPool { + DB_POOL.get().expect("db_pool not initialized") + } + } +} +cfg_if! { + if #[cfg(feature = "datastore")]{ + pub static RNEX_DATASTORE_S3_ENDPOINT: LazyLock = LazyLock::new(|| { + std::env::var("RNEX_DATASTORE_S3_ENDPOINT") + .expect("RNEX_DATASTORE_S3_ENDPOINT must be set") + }); + pub static RNEX_DATASTORE_S3_BUCKET: LazyLock = LazyLock::new(|| { + std::env::var("RNEX_DATASTORE_S3_BUCKET") + .expect("RNEX_DATASTORE_S3_BUCKET must be set") + }); + } +}*/ + +pub fn try_to_log(fun: impl FnOnce() -> Result) -> Option { + match fun() { + Ok(v) => Some(v), + Err(e) => { + error!("{e}"); + None + } + } +} + +pub fn try_get_ip() -> Option { + for url in IP_REQ_SERVICE_URLS { + println!("trying to get ip via: {:?}", url); + if let Some(v) = try_to_log::<_, Box>(|| { + let mut stream = std::net::TcpStream::connect(url.0)?; + stream.write_all( + format!( + "GET {} HTTP/1.0 +Host: {} +User-Agent: RNEX +Accept: */* + +", + url.2, url.1 + ) + .as_str() + .as_bytes(), + )?; + let mut data = vec![]; + stream.read_to_end(&mut data)?; + let string = String::from_utf8(data)?; + let (_, ip) = string + .split_once("\r\n\r\n") + .ok_or("unable to get ip from response")?; + Ok(ip.parse()?) + }) { + return Some(v); + } + } + None +} + +pub static OWN_IP_PRIVATE: LazyLock = LazyLock::new(|| { + env::var("RNEX_SERVER_IP") + .ok() + .map(|s| s.parse().expect("invalid ip address")) + .unwrap_or(Ipv4Addr::UNSPECIFIED) +}); + +pub static OWN_IP_PUBLIC: LazyLock = LazyLock::new(|| { + env::var("RNEX_SERVER_IP_PUBLIC") + .ok() + .map(|s| s.parse().expect("invalid ip address")) + .unwrap_or_else(|| try_get_ip().unwrap()) +}); + +pub static SERVER_PORT: LazyLock = LazyLock::new(|| { + env::var("RNEX_SERVER_PORT") + .ok() + .and_then(|s| s.parse().ok()) + .unwrap_or(10000) +}); diff --git a/rnex-util/Cargo.toml b/rnex-util/Cargo.toml new file mode 100644 index 0000000..8dddbaa --- /dev/null +++ b/rnex-util/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "rnex-util" +version = "0.1.0" +edition = "2024" + +[dependencies] +tokio = { version = "1.52.3", features = ["io-util", "macros", "rt", "sync"] } +tracing = "0.1.44" +chrono = "0.4.39" +bytemuck = { version = "1.25.0", features = ["derive"] } +md-5 = "0.11.0" + +[features] +nx = [] + +[lints] +workspace = true diff --git a/rnex-core/src/nex/account.rs b/rnex-util/src/account.rs similarity index 81% rename from rnex-core/src/nex/account.rs rename to rnex-util/src/account.rs index c5ab04e..e2829e8 100644 --- a/rnex-core/src/nex/account.rs +++ b/rnex-util/src/account.rs @@ -1,9 +1,8 @@ -use macros::RmcSerialize; use md5::{Digest, Md5}; -use rnex_core::PID; +use crate::PID; -#[derive(RmcSerialize, Clone)] +#[derive(Clone, Debug)] pub struct Account { pub pid: PID, pub username: String, @@ -18,17 +17,17 @@ impl Account { let mut key: [u8; 16] = { let mut md5 = Md5::new(); md5.update(passwd); - md5.finalize().try_into().unwrap() + md5.finalize().into() }; for _ in 1..iteration_count { let mut md5 = Md5::new(); md5.update(key); - key = md5.finalize().try_into().unwrap(); + key = md5.finalize().into(); } Self { - nex_key: key.into(), + nex_key: key, username: username.into(), pid, } diff --git a/rnex-util/src/date_time.rs b/rnex-util/src/date_time.rs new file mode 100644 index 0000000..d709db3 --- /dev/null +++ b/rnex-util/src/date_time.rs @@ -0,0 +1,102 @@ +use std::fmt::Display; + +use bytemuck::{Pod, Zeroable}; +use chrono::{Datelike, NaiveDate, Timelike, Utc}; +use tracing::error; + +#[derive(Pod, Zeroable, Copy, Clone, Debug, Eq, PartialEq, Default)] +#[repr(transparent)] +pub struct DateTime(pub u64); + +impl Display for DateTime { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}.{}.{} {}:{}:{}", + self.get_year(), + self.get_month(), + self.get_days(), + self.get_hours(), + self.get_minutes(), + self.get_seconds() + ) + } +} + +impl DateTime { + // this is the time which smm returned as the expriy date, we use it as a + // date so far into the future that it might as well just be never more generally + pub const PRACTICALLY_NEVER: Self = Self::new(0, 0, 0, 31, 12, 9999); + pub fn from_naive(dt: chrono::NaiveDateTime) -> Self { + use chrono::Datelike; + use chrono::Timelike; + Self::new( + dt.second() as u64, + dt.minute() as u64, + dt.hour() as u64, + dt.day() as u64, + dt.month() as u64, + dt.year() as u64, + ) + } + + pub const fn new(second: u64, minute: u64, hour: u64, day: u64, month: u64, year: u64) -> Self { + Self(second | (minute << 6) | (hour << 12) | (day << 17) | (month << 22) | (year << 26)) + } + + pub fn now() -> Self { + let now = chrono::Utc::now(); + Self::new( + now.second() as u64, + now.minute() as u64, + now.hour() as u64, + now.day() as u64, + now.month() as u64, + now.year() as u64, + ) + } + + pub const fn get_seconds(&self) -> u8 { + (self.0 & 0b11_1111) as u8 + } + + pub const fn get_minutes(&self) -> u8 { + ((self.0 >> 6) & 0b11_1111) as u8 + } + pub const fn get_hours(&self) -> u8 { + ((self.0 >> 12) & 0b1_1111) as u8 + } + pub const fn get_days(&self) -> u8 { + ((self.0 >> 17) & 0b11_1111) as u8 + } + pub const fn get_month(&self) -> u8 { + ((self.0 >> 22) & 0b1111) as u8 + } + pub const fn get_year(&self) -> u64 { + (self.0 >> 26) & 0xFFFF_FFFF + } + pub fn to_regular_time(&self) -> chrono::DateTime { + let date = match NaiveDate::from_ymd_opt( + self.get_year() as i32, + self.get_month() as u32, + self.get_days() as u32, + ) { + Some(v) => v, + None => { + error!("invalid datetime...: {}", self); + Default::default() + } + }; + + chrono::NaiveDateTime::new( + date, + chrono::NaiveTime::from_hms_opt( + self.get_hours() as u32, + self.get_minutes() as u32, + self.get_seconds() as u32, + ) + .unwrap_or_default(), + ) + .and_utc() + } +} diff --git a/rnex-core/src/util.rs b/rnex-util/src/lib.rs similarity index 70% rename from rnex-core/src/util.rs rename to rnex-util/src/lib.rs index 2bcf87b..2716646 100644 --- a/rnex-core/src/util.rs +++ b/rnex-util/src/lib.rs @@ -1,16 +1,59 @@ -use crate::reggie::{UnitPacketRead, UnitPacketWrite}; -use log::{error, info}; +#![allow(async_fn_in_trait)] +pub use tracing; +pub mod account; +pub mod date_time; +pub mod result; +pub mod station_url; + use std::ops::Deref; use std::sync::{Arc, Weak}; use std::vec; -use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt}; +use tokio::io::{self, AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; use tokio::sync::Notify; use tokio::sync::mpsc::{Receiver, Sender, channel}; use tokio::task; +use tracing::{error, info}; -#[derive(Clone)] +#[cfg(feature = "nx")] +pub type PID = i64; +#[cfg(not(feature = "nx"))] +pub type PID = i32; + +pub trait UnitPacketRead: AsyncRead + Unpin { + async fn read_buffer(&mut self) -> Result, io::Error> { + let mut len_raw: [u8; _] = [0; size_of::()]; + + self.read_exact(&mut len_raw).await?; + + let len = usize::from_le_bytes(len_raw); + + let mut vec = vec![0u8; len as _]; + + self.read_exact(&mut vec).await?; + + Ok(vec) + } +} + +impl UnitPacketRead for T {} +pub trait UnitPacketWrite: AsyncWrite + Unpin { + async fn send_buffer(&mut self, data: &[u8]) -> Result<(), io::Error> { + let len_data = data.len().to_le_bytes(); + self.write_all(&len_data[..]).await?; + self.write_all(data).await?; + + self.flush().await?; + + Ok(()) + } +} + +impl UnitPacketWrite for T {} + +#[derive(Clone, Debug)] pub struct SendingBufferConnection(Sender>, Arc); +#[derive(Debug)] pub struct SplittableBufferConnection(SendingBufferConnection, Receiver>); impl AsRef for SplittableBufferConnection { @@ -55,7 +98,7 @@ impl SplittableBufferConnection { }; if let Err(e) = stream.send_buffer(&data[..]).await{ - error!("error sending data to backend: {}", e); + error!("error sending data to backend: {e}"); break; } }, @@ -63,24 +106,24 @@ impl SplittableBufferConnection { let data = match data{ Ok(d) => d, Err(e) => { - error!("error reveiving data from backend: {}", e); + error!("error reveiving data from backend: {e}"); break; } }; if let Err(e) = sender.send(data).await{ - error!("a send error occurred {}", e); + error!("a send error occurred {e}"); return; } }, - _ = notify.notified() => { + () = notify.notified() => { info!("shutting down connection"); break; } } } if let Err(e) = stream.shutdown().await { - error!("failed to shut down stream: {}", e); + error!("failed to shut down stream: {e}"); } }); } @@ -93,6 +136,7 @@ impl SendingBufferConnection { pub async fn send(&self, buffer: Vec) -> Option<()> { self.0.send(buffer).await.ok() } + #[must_use] pub fn is_alive(&self) -> bool { !self.0.is_closed() } @@ -109,12 +153,13 @@ impl SplittableBufferConnection { self.1.recv().await } + #[must_use] pub fn duplicate_sender(&self) -> SendingBufferConnection { self.0.clone() } } -struct WeakVec(Vec>); +pub struct WeakVec(Vec>); impl WeakVec { pub fn new() -> Self { @@ -132,6 +177,6 @@ impl WeakVec { } pub fn iter(&self) -> impl Iterator> { - self.0.iter().filter_map(|w| w.upgrade()) + self.0.iter().filter_map(Weak::upgrade) } } diff --git a/rnex-core/src/result.rs b/rnex-util/src/result.rs similarity index 65% rename from rnex-core/src/result.rs rename to rnex-util/src/result.rs index 31a37d1..49535e4 100644 --- a/rnex-core/src/result.rs +++ b/rnex-util/src/result.rs @@ -1,23 +1,23 @@ use std::error::Error; -use log::error; +use tracing::error; -pub trait ResultExtension{ +pub trait ResultExtension { type Output; fn display_err_or_some(self) -> Option; } -impl ResultExtension for Result{ +impl ResultExtension for Result { type Output = T; fn display_err_or_some(self) -> Option { - match self{ + match self { Ok(v) => Some(v), Err(e) => { - error!("{}", e); + error!("{e}"); None } } } -} \ No newline at end of file +} diff --git a/rnex-core/src/prudp/station_url.rs b/rnex-util/src/station_url.rs similarity index 79% rename from rnex-core/src/prudp/station_url.rs rename to rnex-util/src/station_url.rs index 1b8e3bf..d08ae1a 100644 --- a/rnex-core/src/prudp/station_url.rs +++ b/rnex-util/src/station_url.rs @@ -1,15 +1,12 @@ -use crate::prudp::station_url::Type::{PRUDP, PRUDPS, UDP}; -use crate::prudp::station_url::UrlOptions::{ - Address, ConnectionID, NatFiltering, NatMapping, NatType, PID, PMP, Platform, Port, - PrincipalID, ProbeInit, RVConnectionID, StreamID, StreamType, UPNP, +use std::{ + fmt::{Debug, Display, Formatter}, + net::IpAddr, }; -use crate::rmc::structures::Error::StationUrlInvalid; -use crate::rmc::structures::RmcSerialize; -use crate::rmc::structures::helpers::DummyFormatWriter; -use log::error; -use std::fmt::{Debug, Display, Formatter, Write}; -use std::io::Read; -use std::net::IpAddr; + +use tracing::error; + +use crate::PID; + #[derive(Clone, Copy, PartialEq, Eq)] pub enum Type { UDP, @@ -30,7 +27,7 @@ pub enum UrlOptions { StreamID(u8), ConnectionID(u32), ProbeInit(u32), - PrincipalID(rnex_core::PID), + PrincipalID(PID), NatType(u8), NatMapping(u8), NatFiltering(u8), @@ -59,6 +56,8 @@ impl StationUrl { let option_name = option_parts.next()?.to_ascii_lowercase(); let option_value = option_parts.next()?; + use UrlOptions::*; + match option_name.as_ref() { "address" => options_out.push(Address(option_value.parse().ok()?)), "port" => options_out.push(Port(option_value.parse().ok()?)), @@ -95,6 +94,8 @@ impl TryFrom<&str> for StationUrl { let options = &options[2..]; + use Type::*; + let url_type = match url_type { "udp" => UDP, "prudp" => PRUDP, @@ -110,6 +111,7 @@ impl TryFrom<&str> for StationUrl { impl Display for StationUrl { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + use Type::*; let url_type_str = match self.url_type { UDP => "udp:/", PRUDP => "prudp:/", @@ -117,6 +119,7 @@ impl Display for StationUrl { }; write!(f, "{}", url_type_str)?; + use UrlOptions::*; for option in &self.options { match option { Address(v) => write!(f, "address={}", v)?, @@ -149,30 +152,6 @@ impl<'a> Into for &'a StationUrl { } } -impl RmcSerialize for StationUrl { - fn deserialize(reader: &mut (impl Read + ?Sized)) -> crate::rmc::structures::Result { - let str = String::deserialize(reader)?; - - Self::try_from(str.as_str()).map_err(|_| StationUrlInvalid) - } - fn serialize( - &self, - writer: &mut (impl std::io::Write + ?Sized), - ) -> crate::rmc::structures::Result<()> { - let str: String = self.into(); - - str.serialize(writer) - } - - fn serialize_write_size(&self) -> crate::rmc::structures::Result { - let mut dummy = DummyFormatWriter::new(); - - write!(&mut dummy, "{}", self)?; - - Ok(dummy.serialize_str_len()) - } -} - impl Debug for StationUrl { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let str: String = self.into();