From 24255230c3b14c9d49cf619befe69fa4d28667c1 Mon Sep 17 00:00:00 2001 From: John Bintz Date: Sun, 2 Apr 2023 16:24:33 -0400 Subject: [PATCH] Add assembler client --- README.md | 8 + client_in_asm/README.md | 22 +++ client_in_asm/client-asm | Bin 0 -> 2012 bytes client_in_asm/client-c | Bin 0 -> 8636 bytes client_in_asm/client.asm | 400 +++++++++++++++++++++++++++++++++++++++ client_in_asm/client.c | 145 ++++++++++++++ 6 files changed, 575 insertions(+) create mode 100644 client_in_asm/README.md create mode 100644 client_in_asm/client-asm create mode 100644 client_in_asm/client-c create mode 100644 client_in_asm/client.asm create mode 100644 client_in_asm/client.c diff --git a/README.md b/README.md index 813a406..1b719d0 100644 --- a/README.md +++ b/README.md @@ -18,3 +18,11 @@ This is the code used in the [23 Year Old Code](https://youtu.be/l4GNHJfYOUU) vi prints out what is received, like a very basic `netcat`. This is the code used in the [Simple Server in C for the Commodore Amiga](https://youtu.be/i6_PQUsayN4) video. + +## Client in Assembler + +`client_in_asm` uses AsmPro and the AmiTCK SDK to build a simple client that +connects to a specified host and port and sends some data, like the other end +of a very basic `netcat`. + +This is the code used in the [Building a simple Amiga network client...in assembler?!?](https://youtu.be/HbMPBbF9-RE) video. diff --git a/client_in_asm/README.md b/client_in_asm/README.md new file mode 100644 index 0000000..a6da716 --- /dev/null +++ b/client_in_asm/README.md @@ -0,0 +1,22 @@ +# Amiga BSD Socket Client in Assembler and C + +The versions are identical, except that the C version uses `printf` instead +of `PutStr()`. + +## Assembler Version + +Built using AsmPro. You'll have to adjust the `INCDIR` locations and build +the LVOs for the `bsdsocket` and `dos` libraries. You can get the socket +FD file from the AmiTCP SDK. + +``` +fd2pragma fd/dos.fd to include_i/ special 20 +fd2pragma fd/socket.fd to include_i/ special 20 +``` + +## C Version + +Built using SAS/C 6.58 and the +[AmiTCP 4.3 SDK](http://aminet.net/package/comm/tcp/AmiTCP-SDK-4.3). + +`sc link client.c` diff --git a/client_in_asm/client-asm b/client_in_asm/client-asm new file mode 100644 index 0000000000000000000000000000000000000000..23f4a2f90eab5f7303f6ffaf9fdff2b9df7eebe3 GIT binary patch literal 2012 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 KE*3^Dx%A%>ryxuK literal 0 HcmV?d00001 diff --git a/client_in_asm/client.asm b/client_in_asm/client.asm new file mode 100644 index 0000000..7afdfcb --- /dev/null +++ b/client_in_asm/client.asm @@ -0,0 +1,400 @@ +FUNC_CNT SET -30 +FUNCDEF MACRO +_LVO\1 EQU FUNC_CNT +FUNC_CNT SET FUNC_CNT-6 + ENDM + + INCDIR "AsmPro:Include/include_i/" + INCLUDE "exec/exec_lib.i" + INCLUDE "dos/dos_lvo.i" + INCLUDE "exec/libraries.i" + INCLUDE "exec/memory.i" + INCLUDE "dos/dos.i" + INCLUDE "socket_lvo.i" + +PrintString MACRO + MOVE.L \1,D1 + MOVE.L DOSBase,A6 + CALLLIB _LVOPutStr ; dos/PutStr + ENDM + +OpenLibrary MACRO + MOVEQ \2,D0 + MOVE.L \1,A1 + MOVEA.L 4,A6 + CALLLIB _LVOOpenLibrary ; exec/OpenLibrary + ENDM + +ExitProgram MACRO + MOVEQ \1,D0 + RTS + ENDM + +DoCloseDOSLibrary MACRO + MOVEA.L DOSBase,A1 + MOVEA.L 4,A6 + CALLLIB _LVOCloseLibrary ; exec/CloseLibrary + ENDM + +DoCloseBSDSocketLibrary MACRO + MOVEA.L BSDSocketBase,A1 + MOVEA.L 4,A6 + CALLLIB _LVOCloseLibrary ; exec/CloseLibrary + ENDM + +DeallocateBuffer MACRO + MOVE.L ReadBuffer,A1 + MOVE.L #READ_BUFFER_SIZE,D0 + MOVEA.L 4,A6 + CALLLIB _LVOFreeMem ; exec/FreeMem + ENDM + +DoCloseSocket MACRO + MOVE.L SocketID,D0 + MOVE.L BSDSocketBase,A6 + CALLLIB _LVOCloseSocket ; bsdsocket/CloseSocket + ENDM + +; our user message has a limit of this many characters +READ_BUFFER_SIZE EQU 1024 + +; bsdsocket library stuff +; ported from the various C include headers +SOCK_STREAM EQU 1 +PF_INET EQU 2 +AF_INET EQU PF_INET +IPPROTO_TCP EQU 6 + +len_sockaddr_in EQU 16 +sockaddr_in_sin_len EQU 0 +sockaddr_in_sin_family EQU 1 +sockaddr_in_sin_port EQU 2 +sockaddr_in_sin_addr EQU 4 + +Start: + OpenLibrary #DOSLibrary,#36 + MOVE.L D0,DOSBase + TST.L D0 + BNE OpenBSDSocketLibrary + + ; if this fails, we have bigger problems + MOVE.L #20,ExitCode + BRA Teardown + +OpenBSDSocketLibrary: + OpenLibrary #BSDSocketLibrary,#4 + MOVE.L D0,BSDSocketBase + TST.L D0 + BNE ReserveBuffer + + PrintString #UnableToOpenBSDSocketLibrary + + ; be sure to unwind everything we've opened so far + ; i tried using this with codewatcher and i think there's + ; something up with trying to read command line argument + ; when run under codewatcher. + MOVE.L #1,ExitCode + BRA Teardown + +ReserveBuffer: + MOVE.L #READ_BUFFER_SIZE,D0 + ; we don't care where the memory comes from + ; nor should we! + MOVE.L #MEMF_CLEAR,D1 + MOVEA.L 4,A6 + CALLLIB _LVOAllocMem ; dos/AllocMem + MOVE.L D0,ReadBuffer + TST.L D0 + BNE ReadIPAddress + + PrintString #UnableToAllocateBuffer + + MOVE.L #1,ExitCode + BRA Teardown + +ReadIPAddress: + MOVE.L ReadBuffer,D1 + MOVE.L #READ_BUFFER_SIZE,D2 + MOVEQ #0,D3 + MOVE.L DOSBase,A6 + CALLLIB _LVOReadItem ; dos/ReadItem + + ; fail on an error or a missing parameter + CMP.L #ITEM_ERROR,D0 + BEQ NoIPAddress + CMP.L #ITEM_NOTHING,D0 + BEQ NoIPAddress + + BRA ParseIPAddress + +NoIPAddress: + PrintString #UnableToReadArguments + + MOVE.L #1,ExitCode + BRA Teardown + +ParseIPAddress: + MOVE.L ReadBuffer,A0 + MOVE.L BSDSocketBase,A6 + CALLLIB _LVOinet_addr ; bsdsocket/inet_addr + MOVE.L D0,IPAddress + + TST.L D0 + BNE ReadPort + + PrintString #UnableToParseIPAddress + + MOVE.L #1,ExitCode + BRA Teardown + +ReadPort: + MOVE.L ReadBuffer,D1 + MOVE.L #READ_BUFFER_SIZE,D2 + MOVEQ #0,D3 + MOVE.L DOSBase,A6 + CALLLIB _LVOReadItem ; dos/ReadItem + + ; fail on an error or a missing parameter + CMP.L #ITEM_ERROR,D0 + BEQ NoPort + CMP.L #ITEM_NOTHING,D0 + BEQ NoPort + + BRA ParsePort + +NoPort: + PrintString #UnableToReadArguments + + MOVE.L #1,ExitCode + BRA Teardown + + +ParsePort: + ; the Amiga library way to do atol() + MOVE.L ReadBuffer,D1 + MOVE.L #PortLong,D2 + MOVE.L DOSBase,A6 + CALLLIB _LVOStrToLong ; dos/StrToLong + + CMP.L #-1,D0 + BNE _ParsePort_Continue + + PrintString #UnableToParsePort + + MOVE.L #1,ExitCode + BRA Teardown + +_ParsePort_Continue: + MOVE.L PortLong,D0 + + ; we could just crop the provided port at a word boundary, + ; but let's be nice and tell the user they entered in a bad + ; port number. + CMP.L #65536,D0 + BLT ReadRemainingCommandLine + + PrintString #PortOutOfRange + + MOVE.L #1,ExitCode + BRA Teardown + +ReadRemainingCommandLine: + ; lop off the actual port number + MOVE.W D0,Port + + ; this is the Amiga equivalent of stdin? + MOVE.L DOSBase,A6 + CALLLIB _LVOInput ; dos/Input + MOVE.L D0,Stdin + + MOVE.L ReadBuffer,FGetCLocation + MOVEQ #0,D2 + +_ReadRemainingCommandLine_Loop: + ; loop until fgetc returns -1 or 10 + MOVE.L Stdin,D1 + MOVE.L DOSBase,A6 + CALLLIB _LVOFGetC ; dos/FGetC + + MOVE.L FGetCLocation,A0 + CMP.L #-1,D0 ; end on EOF... + BEQ _ReadRemainingCommandLine_Finish + CMP.L #10,D0 ; or a 10, from you physically hitting enter in the CLI + BEQ _ReadRemainingCommandLine_Finish + + MOVE.B D0,(A0)+ + ADDQ #1,D2 + MOVE.L A0,FGetCLocation + BRA _ReadRemainingCommandLine_Loop + +_ReadRemainingCommandLine_Finish: + ; add the chr(10) back, and end the string with a null + MOVE.B #10,(A0)+ + MOVE.B #0,(A0)+ + + ; we need to know how many characters total we read + ADDQ #2,D2 + MOVE.L D2,ReadBufferLength + +CreateSocket: + MOVE.L #PF_INET,D0 + MOVE.L #SOCK_STREAM,D1 + MOVE.L #IPPROTO_TCP,D2 + MOVE.L BSDSocketBase,A6 + CALLLIB _LVOsocket ; exec/socket + MOVE.L D0,SocketID + +PrintIPAddress: + ; exec/RawDoFmt is basically sprintf. + LEA IPAddrString,A0 + + ; load up the printf arguments + LEA DoFmtBuffer,A1 + MOVE.L IPAddress,(A1)+ + MOVE.W Port,(A1)+ + MOVE.L SocketID,(A1)+ + LEA DoFmtBuffer,A1 + + LEA _StuffChar,A2 + LEA PrintBuffer,A3 + + MOVE.L 4,A6 + CALLLIB _LVORawDoFmt ; exec/RawDoFmt + + PrintString #PrintBuffer + + MOVE.L SocketID,D0 + CMP.L #-1,D0 + BNE ConnectSocket + + PrintString #UnableToOpenSocket + + MOVE.L #1,ExitCode + BRA Teardown + +ConnectSocket: + ; populate sockaddr_in + LEA ConnectSockAddrIn,A0 + MOVE.B #AF_INET,sockaddr_in_sin_family(A0) + MOVE.W Port,sockaddr_in_sin_port(A0) + MOVE.L IPAddress,sockaddr_in_sin_addr(A0) + + MOVE.L SocketID,D0 + MOVE.L #len_sockaddr_in,D1 + MOVE.L BSDSocketBase,A6 + CALLLIB _LVOconnect ; bsdsocket/connect + + ; a socket is connected if the response is 0 + TST.L D0 + BEQ SendData + + PrintString #UnableToConnectSocket + + MOVE.L #1,ExitCode + BRA Teardown + +SendData: + MOVE.L SocketID,D0 + MOVE.L ReadBuffer,A0 + MOVE.L ReadBufferLength,D1 + MOVEQ #0,D2 + MOVE.L BSDSocketBase,A6 + CALLLIB _LVOsend ; bsdsocket/send + + CMP.L #-1,D0 + BNE CloseSocket + + PrintString #UnableToSendData + + MOVE.L #1,ExitCode + BRA Teardown + +CloseSocket: + MOVE.L #0,ExitCode + +; check all of the things we might have allocated and +; tear them down if we did, then return the appropriate exit code. +Teardown: + MOVE.L SocketID,D0 + CMP.L #-1,D0 + BEQ _Teardown_DeallocateBuffer + + DoCloseSocket +_Teardown_DeallocateBuffer: + MOVE.L ReadBuffer,D0 + BEQ _Teardown_CloseBSDSocketLibrary + + DeallocateBuffer +_Teardown_CloseBSDSocketLibrary: + MOVE.L BSDSocketBase,D0 + BEQ _Teardown_CloseDOSLibrary + + DoCloseBSDSocketLibrary +_Teardown_CloseDOSLibrary: + MOVE.L DOSBase,D0 + BEQ _Teardown_Exit + + DoCloseDOSLibrary +_Teardown_Exit: + MOVEQ #0,D0 + MOVE.L ExitCode,D0 + RTS + +; RawDoFmt helper +_StuffChar: + MOVE.B D0,(a3)+ + RTS + + +; libraries we open +DOSBase DCB.L 1,0 +BSDSocketBase DCB.L 1,0 + +; allocated memory +ReadBuffer DCB.L 1,0 +ReadBufferLength DS.L 1 + +; return code for the program +ExitCode DS.L 1 + +; reading command line args +Stdin DS.L 1 + +; user parameters +IPAddress DS.L 1 +Port DS.W 1 +PortLong DS.L 1 + +; message to send +FGetCChar DS.L 1 +FGetCLocation DS.L 1 + +; establishing a connection +SocketID DCB.L 1,-1 +ConnectSockAddrIn DCB.B 16,0 + +; place to build a string for printing via RawDoFmt +PrintBuffer DS.B 100 + +; stack for accepting RawDoFmt arguments as values +DoFmtBuffer DS.B 32 + +DOSLibrary DC.B "dos.library",0 +BSDSocketLibrary DC.B "bsdsocket.library",0 + +;FakeIP DC.B "1.2.3.4",0 +;FakePort DC.B "1234",0 + +; user messages +UnableToOpenBSDSocketLibrary DC.B "Unable to open bsdsocket.library. Have you started a TCP stack?",10,0 +UnableToAllocateBuffer DC.B "Unable to allocate buffer",10,0 +UnableToReadArguments DC.B "client ",10,0 +UnableToParseIPAddress DC.B "Unable to parse IP Address",10,0 +UnableToOpenSocket DC.B "Unable to open socket",10,0 +UnableToConnectSocket DC.B "Unable to connect socket",10,0 +UnableToSendData DC.B "Unable to send data",10,0 +UnableToParsePort DC.B "Unable to parse port",10,0 +PortOutOfRange DC.B "Port out of range (0-65535)",10,0 +;Here DC.B "Here",10,0 +IPAddrString DC.B "IP address is %8lx, port is %d, socket is %ld",10,0 +;FGetCResult DC.B "%ld %ld %ld",10,0 diff --git a/client_in_asm/client.c b/client_in_asm/client.c new file mode 100644 index 0000000..e64bebe --- /dev/null +++ b/client_in_asm/client.c @@ -0,0 +1,145 @@ +#include +#include + +#include +#include + +#include + +#include +#include +#include + +struct Library *SocketBase; +char *ReadBuffer; +int SocketID = -1; + +#define READ_BUFFER_SIZE (1024) + +void teardown() { + if (SocketBase && SocketID != -1) { + CloseSocket(SocketID); + } + + if (ReadBuffer) { + FreeMem(ReadBuffer, READ_BUFFER_SIZE); + } + + if (SocketBase) { + CloseLibrary(SocketBase); + } +} + +int main(void) { + int ReadItemResult; + ULONG IPAddress; + long Port; + char CurrentChar; + int ReadIndex; + BPTR Stdin; + + struct sockaddr_in ConnectSockaddrIn; + + if (!(SocketBase = OpenLibrary("bsdsocket.library", 4))) { + printf("Unable to open bsdsocket.library. Have you started a TCP stack?\n"); + return 1; + } + + if (!(ReadBuffer = AllocMem(READ_BUFFER_SIZE, MEMF_CLEAR))) { + printf("Unable to allocate buffer\n"); + teardown(); + return 1; + } + + // yes we could use argc/argv but we're mimicking what's in the + // original assembler code + + ReadItemResult = ReadItem(ReadBuffer, READ_BUFFER_SIZE, NULL); + if ( + ReadItemResult == ITEM_ERROR || + ReadItemResult == ITEM_NOTHING + ) { + printf("client \n"); + teardown(); + return 1; + } + + if (!(IPAddress = inet_addr(ReadBuffer))) { + printf("Unable to parse IP Address\n"); + teardown(); + return 1; + } + + ReadItemResult = ReadItem(ReadBuffer, READ_BUFFER_SIZE, NULL); + if ( + ReadItemResult == ITEM_ERROR || + ReadItemResult == ITEM_NOTHING + ) { + printf("client \n"); + teardown(); + return 1; + } + + if (-1 == (StrToLong(ReadBuffer, &Port))) { + printf("client \n"); + teardown(); + return 1; + } + + if (Port > 65535) { + printf("Port out of range (0-65535)\n"); + teardown(); + return 1; + } + + Stdin = Input(); + + Port = (short)Port; + CurrentChar = FGetC(Stdin); + ReadIndex = 0; + + while (CurrentChar != -1 && CurrentChar != 10) { + ReadBuffer[ReadIndex++] = CurrentChar; + printf("%d\n",CurrentChar); + CurrentChar = FGetC(Stdin); + } + + ReadBuffer[ReadIndex++] = 10; + ReadBuffer[ReadIndex++] = 0; + + SocketID = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + + // we'll skip on using RawDoFmt here + printf( + "IP address is %8x, port is %d, socket is %d\n", + IPAddress, + Port, + SocketID + ); + + if (SocketID == -1) { + printf("Unable to open socket\n"); + teardown(); + return 1; + } + + ConnectSockaddrIn.sin_family = AF_INET; + ConnectSockaddrIn.sin_port = Port; + ConnectSockaddrIn.sin_addr.s_addr = IPAddress; + + if (connect(SocketID, (struct sockaddr *)&ConnectSockaddrIn, sizeof(struct sockaddr_in)) == -1) { + printf("Unable to connect socket\n"); + teardown(); + return 1; + } + + if (send(SocketID, ReadBuffer, ReadIndex, 0) == -1) { + printf("Unable to send data\n"); + teardown(); + return 1; + } + + teardown(); + return 0; + +}