diff --git a/.forgejo/workflows/build.yml b/.forgejo/workflows/build.yml index 8d8cd2f..a819fa8 100644 --- a/.forgejo/workflows/build.yml +++ b/.forgejo/workflows/build.yml @@ -341,3 +341,33 @@ jobs: CI_COMMIT_SHORT_SHA: ${{ env.SHORT_SHA }} DATABASE_URL: ${{ secrets.DATABASE_SMM }} run: ./.ci-scripts/make-edition.sh super-mario-maker + + terraria: + runs-on: debian-trixie + + steps: + - name: Checkout repository + uses: actions/checkout@v7 + with: + submodules: recursive + + - name: Cache container storage + uses: actions/cache@v6 + with: + path: | + /var/lib/containers/storage + /run/containers/storage + ~/.local/share/containers/storage + key: image-cache + + - name: Login to registry + run: docker login -u ${{ secrets.PACKAGE_USER }} -p ${{ secrets.PACKAGE_PWD }} git.spbr.net + + - name: Set short SHA + run: echo "SHORT_SHA=${GITHUB_SHA::6}" >> $GITHUB_ENV + + - name: Build Terraria edition + env: + CI_REGISTRY_IMAGE: git.spbr.net/spacebar/rust-nex + CI_COMMIT_SHORT_SHA: ${{ env.SHORT_SHA }} + run: ./.ci-scripts/make-edition.sh terraria diff --git a/editions.yaml b/editions.yaml index 478ea3d..b60d2ea 100644 --- a/editions.yaml +++ b/editions.yaml @@ -138,3 +138,15 @@ super-mario-maker: RNEX_VIRTUAL_PORT_SECURE: "1:10" RNEX_DEFAULT_PORT: 6000 RNEX_ACCESS_KEY: "9f2b4678" +terraria: + include-in-checkall: true + features: + - prudpv1 + - third-notif-param + - v3-8-15 + settings: + AUTH_REPORT_VERSION: "branch:origin/release/ngs/3.8.x.200x build:3_8_13_2004_0" + RNEX_VIRTUAL_PORT_INSECURE: "1:10" + RNEX_VIRTUAL_PORT_SECURE: "1:10" + RNEX_DEFAULT_PORT: 10000 + RNEX_ACCESS_KEY: "3d37fbdb" diff --git a/prudpv0/src/server.rs b/prudpv0/src/server.rs index 96b6416..3c790cb 100644 --- a/prudpv0/src/server.rs +++ b/prudpv0/src/server.rs @@ -38,6 +38,7 @@ pub struct InternalConnection { server_packet_counter: u16, client_packet_counter: u16, unacknowledged_packets: HashMap>>, + packet_buffer: Vec, packet_queue: HashMap>)>, } pub struct Connection { @@ -96,7 +97,7 @@ impl Server { .expect("packet malformed in creation"), );*/ let mut inner = conn.inner.lock().await; - let pieces = data.chunks(700); + let pieces = data.chunks(962); let max_piece = pieces.len() - 1; let mut frag_num = 1; for (i, piece) in pieces.enumerate() { @@ -140,9 +141,18 @@ impl Server { .send_to(&data, conn.addr.regular_socket_addr) .await .ok(); - - break; + sleep(Duration::from_millis(500)).await; } + println!("connection exceeded max fail count, disconnecting"); + let Some(conn) = conn.upgrade() else { + return; + }; + let Some(this) = this.upgrade() else { + return; + }; + let mut conns = this.connections.write().await; + conns.remove(&(conn.addr, conn.session_id)); + drop(conns); }); frag_num += 1; } @@ -282,6 +292,7 @@ impl Server { server_packet_counter: 1, unacknowledged_packets: HashMap::new(), packet_queue: HashMap::new(), + packet_buffer: vec![], }), }); @@ -334,6 +345,13 @@ impl Server { warn!("data packet on inactive connection from: {:?}", addr); return; }; + + if header.type_flags.get_flags() & ACK != 0 { + let mut inner = res.inner.lock().await; + inner.unacknowledged_packets.remove(&header.sequence_id); + return; + } + info!("frag: {}", frag_id); let mut conn = res.inner.lock().await; let ack = new_data_packet( @@ -368,9 +386,16 @@ impl Server { }; conn.crypto_instance.decrypt_incoming(payload); - - res.target.send(payload.to_owned()).await; + conn.packet_buffer.extend_from_slice(payload); conn.client_packet_counter += 1; + if *packet.fragment_id().unwrap() != 0 { + info!("handeling fragmented packet"); + continue; + } + + res.target + .send(std::mem::take(&mut conn.packet_buffer)) + .await; } info!("finished handeling packets, dropping inner connection"); drop(conn); @@ -472,8 +497,8 @@ impl Server { inner.last_action = Instant::now(); drop(inner); }; - if header.type_flags.get_flags() & ACK != 0 { - info!("got ack(acks are ignored for now)"); + if header.type_flags.get_flags() & ACK != 0 && header.type_flags.get_types() != DATA { + info!("got ack(acks are ignored for now(unless they are data acks))"); return; } println!("{:?}", header); diff --git a/prudpv1/src/prudp/socket.rs b/prudpv1/src/prudp/socket.rs index 57f4ce4..0059882 100644 --- a/prudpv1/src/prudp/socket.rs +++ b/prudpv1/src/prudp/socket.rs @@ -50,6 +50,7 @@ struct InternalConnection { socket: Arc, packet_queue: HashMap, last_packet_time: Instant, + partial_packet: Vec, unacknowleged_packets: Vec<(Instant, PRUDPV1Packet)>, } @@ -431,6 +432,7 @@ impl InternalSocket { packet_queue: Default::default(), last_packet_time: Instant::now(), unacknowleged_packets: Vec::new(), + partial_packet: Vec::new(), supported_function_version, }; @@ -573,11 +575,24 @@ impl InternalSocket { while let Some(mut packet) = conn.packet_queue.remove(&counter) { conn.crypto_handler_instance .decrypt_incoming(packet.header.substream_id, &mut packet.payload[..]); - - conn.data_sender.send(packet.payload).await.ok(); - + conn.partial_packet + .extend_from_slice(&mut packet.payload[..]); conn.reliable_client_counter = conn.reliable_client_counter.overflowing_add(1).0; counter = conn.reliable_client_counter; + if packet.options.iter().any(|v| { + if let FragmentId(f) = v { + *f != 0 + } else { + false + } + }) { + println!("handeling fragmented packet"); + continue; + } + + let packet = std::mem::take(&mut conn.partial_packet); + + conn.data_sender.send(packet).await.ok(); } } @@ -690,19 +705,7 @@ impl AnyInternalSocket for InternalSocket { let conn = &**conn; let mut conn = conn.lock().await; - if conn.supported_function_version == 1 { - let mut collected_ids: Vec = Vec::new(); - let mut cursor = Cursor::new(&packet.payload); - - while let Ok(v) = read_u16(&mut cursor) { - collected_ids.push(v); - } - - conn.unacknowleged_packets.retain_mut(|(_, up)| { - !(collected_ids.iter().any(|id| up.header.sequence_id == *id) - || up.header.sequence_id <= packet.header.sequence_id) - }); - } else { + if packet.header.substream_id == 1 { let mut collected_ids: Vec = Vec::new(); let mut cursor = Cursor::new(&packet.payload); @@ -729,10 +732,22 @@ impl AnyInternalSocket for InternalSocket { collected_ids.push(additional_sequence_id); } - conn.unacknowleged_packets.retain_mut(|(_, up)| { + conn.unacknowleged_packets.retain(|(_, up)| { !(collected_ids.iter().any(|id| up.header.sequence_id == *id) || up.header.sequence_id <= sequence_id) }); + } else { + let mut collected_ids: Vec = Vec::new(); + let mut cursor = Cursor::new(&packet.payload); + + while let Ok(v) = read_u16(&mut cursor) { + collected_ids.push(v); + } + + conn.unacknowleged_packets.retain(|(_, up)| { + !(collected_ids.iter().any(|id| up.header.sequence_id == *id) + || up.header.sequence_id <= packet.header.sequence_id) + }); } } else { error!("non connection acknowledgement packet on nonexistent connection...") diff --git a/rnex-core/src/prudp/station_url.rs b/rnex-core/src/prudp/station_url.rs index 1b8e3bf..97ff448 100644 --- a/rnex-core/src/prudp/station_url.rs +++ b/rnex-core/src/prudp/station_url.rs @@ -93,6 +93,10 @@ impl TryFrom<&str> for StationUrl { fn try_from(value: &str) -> Result { let (url_type, options) = value.split_at(value.find(":/").ok_or(())?); + if value.len() >= 1024 { + return Err(()); + } + let options = &options[2..]; let url_type = match url_type {