From 70559b8de2a0251d972395523959838964c1360b Mon Sep 17 00:00:00 2001 From: Fabian Meyer <3982806+meyfa@users.noreply.github.com> Date: Tue, 2 Apr 2024 11:45:48 +0200 Subject: [PATCH] feat: Implement protocol handshake --- server.cob | 63 +++++++++++++++++++++++++++++++++++++++++------ src/read.cob | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/socket.cob | 16 ++++++------ 3 files changed, 131 insertions(+), 15 deletions(-) create mode 100644 src/read.cob diff --git a/server.cob b/server.cob index dd1462c..e68862f 100644 --- a/server.cob +++ b/server.cob @@ -3,12 +3,17 @@ PROGRAM-ID. server. DATA DIVISION. WORKING-STORAGE SECTION. -01 PORT PIC X(5) VALUE "25565". -01 LISTEN PIC X(4). -01 HNDL PIC X(4). -01 ERRNO PIC 9(3) VALUE 0. -*> State of the player (0 = handshake, 1 = status, 2 = login, 3 = play, 255 = disconnect) -01 CLIENT-STATE PIC 9(3) VALUE 0. + 01 PORT PIC X(5) VALUE "25565". + 01 LISTEN PIC X(4). + 01 HNDL PIC X(4). + 01 ERRNO PIC 9(3) VALUE 0. + *> State of the player (0 = handshake, 1 = status, 2 = login, 3 = play, 255 = disconnect) + 01 CLIENT-STATE PIC 9(3) VALUE 0. + *> Incoming packet data + 01 BYTE-COUNT PIC 9(5). + 01 PACKET-LENGTH PIC S9(10). + 01 PACKET-ID PIC S9(10). + 01 BUFFER PIC X(64000). PROCEDURE DIVISION. @@ -34,15 +39,59 @@ AcceptConnection. STOP RUN. ReceivePacket SECTION. - *> TODO: Implement packet handling + *> Read packet length + CALL "Read-VarInt" USING HNDL ERRNO BYTE-COUNT PACKET-LENGTH. + PERFORM HandleError. + + *> Read packet ID + CALL "Read-VarInt" USING HNDL ERRNO BYTE-COUNT PACKET-ID. + PERFORM HandleError. + SUBTRACT BYTE-COUNT FROM PACKET-LENGTH GIVING PACKET-LENGTH. + + DISPLAY "[state=" CLIENT-STATE "] Received packet ID: " PACKET-ID " with length " PACKET-LENGTH " bytes.". + + *> Handshake + IF CLIENT-STATE = 0 THEN + PERFORM HandleHandshake + EXIT SECTION + END-IF + + *> TODO: Implement login state, play state, etc. + DISPLAY "Login state not implemented." MOVE 255 TO CLIENT-STATE. EXIT SECTION. +HandleHandshake SECTION. + IF PACKET-ID NOT = 0 THEN + DISPLAY " Unexpected packet ID: " PACKET-ID + MOVE 255 TO CLIENT-STATE + EXIT SECTION + END-IF + + *> Read payload. The final byte encodes the target state. + MOVE PACKET-LENGTH TO BYTE-COUNT + CALL "Read-Raw" USING HNDL BYTE-COUNT ERRNO BUFFER + PERFORM HandleError + MOVE FUNCTION ORD(BUFFER(BYTE-COUNT:1)) TO CLIENT-STATE + SUBTRACT 1 FROM CLIENT-STATE + + *> Validate target state + IF CLIENT-STATE NOT = 1 AND CLIENT-STATE NOT = 2 THEN + DISPLAY " Invalid target state: " CLIENT-STATE + MOVE 255 TO CLIENT-STATE + ELSE + DISPLAY " Target state: " CLIENT-STATE + END-IF + + EXIT SECTION. + HandleError SECTION. IF ERRNO NOT = 0 THEN DISPLAY "Error: " ERRNO STOP RUN END-IF. + EXIT SECTION. + END PROGRAM server. diff --git a/src/read.cob b/src/read.cob new file mode 100644 index 0000000..d241a60 --- /dev/null +++ b/src/read.cob @@ -0,0 +1,67 @@ +*> --- Read-Raw --- +*> Read a raw byte array from the socket. +IDENTIFICATION DIVISION. +PROGRAM-ID. Read-Raw. + +DATA DIVISION. +LINKAGE SECTION. +01 LK-HNDL PIC X(4). +01 LK-READ-COUNT PIC 9(5). +01 LK-ERRNO PIC 9(3). +01 LK-VALUE PIC X(64000). + +PROCEDURE DIVISION USING BY REFERENCE LK-HNDL LK-READ-COUNT LK-ERRNO LK-VALUE. + IF LK-READ-COUNT < 1 + MOVE 0 TO LK-ERRNO + EXIT PROGRAM + END-IF + CALL "CBL_GC_SOCKET" USING "04" LK-HNDL LK-READ-COUNT LK-VALUE GIVING LK-ERRNO. + +END PROGRAM Read-Raw. + +*> --- Read-VarInt --- +*> Read a VarInt from the socket into an S9(10) field. +IDENTIFICATION DIVISION. +PROGRAM-ID. Read-VarInt. + +DATA DIVISION. +WORKING-STORAGE SECTION. + 01 BUFFER PIC X. + 01 BYTE-COUNT PIC 9(5). +LOCAL-STORAGE SECTION. + 01 VARINT-BYTE PIC 9(3) COMP VALUE 0. + 01 VARINT-BYTE-VALUE PIC 9(3) COMP VALUE 0. + 01 VARINT-MULTIPLIER PIC 9(10) COMP VALUE 1. + 01 VARINT-CONTINUE PIC 9 COMP VALUE 1. +LINKAGE SECTION. + 01 LK-HNDL PIC X(4). + 01 LK-ERRNO PIC 9(3). + 01 LK-READ-COUNT PIC 9(5). + 01 LK-VALUE PIC S9(10). + +PROCEDURE DIVISION USING BY REFERENCE LK-HNDL LK-ERRNO LK-READ-COUNT LK-VALUE. + MOVE 0 TO LK-VALUE. + MOVE 0 TO LK-READ-COUNT. + PERFORM UNTIL VARINT-CONTINUE = 0 + *> Receive the next byte + MOVE 1 TO BYTE-COUNT + CALL "CBL_GC_SOCKET" USING "04" LK-HNDL BYTE-COUNT BUFFER GIVING LK-ERRNO + IF LK-ERRNO NOT = 0 + EXIT PROGRAM + END-IF + ADD 1 TO LK-READ-COUNT + MOVE FUNCTION ORD(BUFFER(1:1)) TO VARINT-BYTE + SUBTRACT 1 FROM VARINT-BYTE + *> Extract the lower 7 bits + MOVE FUNCTION MOD(VARINT-BYTE, 128) TO VARINT-BYTE-VALUE + *> This yields the value when multiplied by the position multiplier + MULTIPLY VARINT-BYTE-VALUE BY VARINT-MULTIPLIER GIVING VARINT-BYTE-VALUE + ADD VARINT-BYTE-VALUE TO LK-VALUE + MULTIPLY VARINT-MULTIPLIER BY 128 GIVING VARINT-MULTIPLIER + *> Check if we need to continue (if the high bit is set and the maximum number of bytes has not been reached) + IF VARINT-BYTE < 128 OR LK-READ-COUNT >= 5 + MOVE 0 TO VARINT-CONTINUE + END-IF + END-PERFORM. + +END PROGRAM Read-VarInt. diff --git a/src/socket.cob b/src/socket.cob index b846e94..2783390 100644 --- a/src/socket.cob +++ b/src/socket.cob @@ -4,9 +4,9 @@ PROGRAM-ID. Socket-Listen. DATA DIVISION. LINKAGE SECTION. -01 LK-PORT PIC X(5). -01 LK-LISTEN PIC X(4). -01 LK-ERRNO PIC 9(3). + 01 LK-PORT PIC X(5). + 01 LK-LISTEN PIC X(4). + 01 LK-ERRNO PIC 9(3). PROCEDURE DIVISION USING BY REFERENCE LK-PORT LK-LISTEN LK-ERRNO. CALL "CBL_GC_SOCKET" USING "00" LK-PORT LK-LISTEN GIVING LK-ERRNO. @@ -19,9 +19,9 @@ PROGRAM-ID. Socket-Accept. DATA DIVISION. LINKAGE SECTION. -01 LK-LISTEN PIC X(4). -01 LK-HNDL PIC X(4). -01 LK-ERRNO PIC 9(3). + 01 LK-LISTEN PIC X(4). + 01 LK-HNDL PIC X(4). + 01 LK-ERRNO PIC 9(3). PROCEDURE DIVISION USING BY REFERENCE LK-LISTEN LK-HNDL LK-ERRNO. CALL "CBL_GC_SOCKET" USING "07" LK-LISTEN LK-HNDL GIVING LK-ERRNO. @@ -34,8 +34,8 @@ PROGRAM-ID. Socket-Close. DATA DIVISION. LINKAGE SECTION. -01 LK-HNDL PIC X(4). -01 LK-ERRNO PIC 9(3). + 01 LK-HNDL PIC X(4). + 01 LK-ERRNO PIC 9(3). PROCEDURE DIVISION USING BY REFERENCE LK-HNDL LK-ERRNO. CALL "CBL_GC_SOCKET" USING "06" LK-HNDL GIVING LK-ERRNO.