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