From 2ba9fd6c82e31d2507529e7a5d3027771a95261c Mon Sep 17 00:00:00 2001 From: John Bintz Date: Fri, 26 Apr 2024 22:22:46 -0400 Subject: [PATCH] Finish up 1.1.4 --- API.md | 24 ------------- README.md | 74 +++++++++++++++++++++++++++++++++++--- src/AMOSPro_BSDSocket.Lib | Bin 6180 -> 6200 bytes src/BSDSocket.s | 25 +++++++------ src/BSDSocket_Labels.s | 2 +- src/BSDSocket_Size.s | 2 +- src/absdsocket | 3 +- src/report.txt | 34 ------------------ test/TestSuite | Bin 65428 -> 68324 bytes test/TestSuite.amos | Bin 8960 -> 11938 bytes 10 files changed, 84 insertions(+), 80 deletions(-) delete mode 100644 src/report.txt diff --git a/API.md b/API.md index e1d86ec..246a089 100644 --- a/API.md +++ b/API.md @@ -337,30 +337,6 @@ out. There's no way to set this timeout, or cancel or override it via AMOS. String with IP address, or blank string on error. ---- - -#### RESULT=Socket Status(Socket) - -Returns basic connection information about a socket. - -##### Warning - -Since none of the socket processing of this extension happens in the -background, you're likely better off using other means to detect -socket status. - -* Disconnected: Try a recv and get zero bytes back. Check Socket Errno. -* Broken: Try a send. If it fails, check Socket Errno. -* Ready: Use the Async Wait functions. - -##### Returns - -Status of socket: - -* 0 = Closed -* 2 = Listening -* 6 = Connecting -* 7 = Connected --- diff --git a/README.md b/README.md index 69c1fad..a46a986 100644 --- a/README.md +++ b/README.md @@ -127,6 +127,9 @@ Socket Library Close * [AQUABYSS](https://agedcode.com/agedcode/en/games/aquabyss) * As of April 2023, the extension's been in heavy use for over a month on the client side of the game. +* [Hop to the Top: Bunny's Revenge](https://rabbit.robsmithdev.co.uk/) + * The game uses this extension to send and receive high score information. + I also did some of the art for the game! Doing something cool with the extension? [Contact me](https://theindustriousrabbit.com/about) and I'll add it to the list! @@ -158,7 +161,7 @@ This project uses semantic versioning. ## License -Copyright 2023 John Bintz. Licensed under the MIT License. +Copyright 2023-2024 John Bintz. Licensed under the MIT License. If you use this in your project, and you really want to, throw a link to theindustriousrabbit.com somewhere! You can @@ -181,14 +184,75 @@ to contact me. * Fix bug in Socket Wait Async Writing where result of getsockopt was incorrectly used. -## Development +### 1.1.0 (2024-02-23) + +* Fix bug in `Dns Get Host Address By Name$` where it assumed AMOS strings are + null-terminated. They are not. +* Add `Socket Herrno` to aid in debugging resolver errors. + +### 1.1.1 (2024-03-17) + +* Fix bug in `Socket Inet Ntoa$` where the null terminator on the result of + calling `Inet_NtoA` was being included in the AMOS string. +* Fix crash bug in `Socket Inet Ntoa$` if called with the BSD Socket library + was not open. + +### 1.1.2 (2024-03-18) + +* Fix all functions that return strings so that strings work properly + in AMOS. While you could kind of use the immediate return value of the + string, any future manipulation of that string would fail. This fixes + the following functions: + * `Socket Inet Ntoa$` + * `Dns Get Address By Name$` + * `Socket Recv$` + +### 1.1.3 + +Internal release. + +### 1.1.4 (2024-04-26) + +* Fix bug in fdset macro where using D3 for a parameter could cause corruption +* Copy a null-terminated copy of IP address for `SocketIPAddressPortToSockaddr` +* Add test suite to exercise extension functionality +* Fix several crash bugs found due to the test suite +* Retructure API docs for easier reading + +# Development ### Environment +#### Native Amiga + * Clone the [AMOS Professional source code](https://github.com/AOZ-Studio/AMOS-Professional-Official) -* Run `execute absdsocket` - * Note that you'll have to fix up some assigns and files in the AMOS Professional - source directory. I'll update this README with those changes once I track them down... + * Copy `AMOSPro Sources/+lequ.s` to `+LEqu.s` +* Generate the socket LVO file in the `src` directory + * Install [`fd2pragma`](https://aminet.net/package/dev/misc/fd2pragma) in your path + * Download `https://raw.githubusercontent.com/cnvogelg/amitools/master/amitools/data/fd/bsdsocket_lib.fd` to `src` + * In a Shell: + + ``` + cd src + fd2pragma bsdsocket_lib.fd to "" special 20 + ``` + +* Fix up `src/absdsocket` to match your system's setup +* In a Shell: + +``` +cd src +execute absdsocket +``` + +#### Emulated setup (WinUAE, FS-UAE, Amiberry) + +Run `bin/setup` to do most of the setups above. + +### Debugging + +Modify data in the `DebugArea` and read it by `Peek`/`Deek`/`Leek`ing from +the base address provided by `Socket Get Debug Area`. ### Releasing diff --git a/src/AMOSPro_BSDSocket.Lib b/src/AMOSPro_BSDSocket.Lib index c7308ecba14273d3c79c34456be4b549eb2a9b08..5ed4bb227a74f7d1b2d68f263f30f5e74a4f89a5 100644 GIT binary patch delta 162 zcmZ2tu)|=2xF{~V6j7$tnjLZ}?lJiqi^)eEZvr~(bO7rwmQp+?MRKi??tP~9O4D}EyfldLsJxXX9mU# uhqXP}vNj6{gt1R{;AfxQFP_I`tZQUoWMW`qXg--;LO~G01-XHN`4a#^{UbmC diff --git a/src/BSDSocket.s b/src/BSDSocket.s index e557aad..c465bff 100644 --- a/src/BSDSocket.s +++ b/src/BSDSocket.s @@ -7,7 +7,7 @@ ; extension number 18 ExtNb equ 18-1 Version MACRO - dc.b "1.1.3-20240417" + dc.b "1.1.4-20240426" ENDM VerNumber equ $1 @@ -345,7 +345,7 @@ C_Tk dc.w 1,0 dc.b "socket close socke","t"+$80,"00",-1 AddTokenFunction SocketHerrno - dc.b "socket herrn","0"+$80,"0",-1 + dc.b "socket herrn","o"+$80,"0",-1 ; TOKEN_END dc.w 0 @@ -1372,8 +1372,10 @@ _SocketSelect_PerformSelect PreserveStackFunction EnsureBSDSocketLibrary _SocketInetNtoa_LibraryOpen + MOVE.L ChVide(A5),D3 + RestoreStackFunction - Ret_Int + Ret_String _SocketInetNtoa_LibraryOpen: MOVE.L D3,D0 @@ -1390,9 +1392,6 @@ _SocketInetNtoA_StringSizeLoop: TST.B (A0)+ BNE _SocketInetNtoA_StringSizeLoop - MOVE.L A0,D3 - SUB.L A2,D3 ; D3 = length - SUBQ #1,D3 ; get rid of the null terminator MOVE.L A0,D4 SUB.L A2,D4 ; D4 = length SUBQ #1,D4 ; get rid of the null terminator @@ -1413,13 +1412,8 @@ _SocketInetNtoA_StringSizeLoop: SUBQ #1,D4 _SocketInetNtoA_StringCopyLoop: - MOVE.B (A2,D3),(A0,D3) - DBRA D3,_SocketInetNtoA_StringCopyLoop - - ; make the address even - EvenOutStringAddress A0,D3 - - MOVE.L A0,HiChaine(A5) ; Does L_Demande nuke A5 too? + MOVE.B (A2,D4),(A0,D4) + DBRA D4,_SocketInetNtoA_StringCopyLoop MOVE.L A1,D3 ; string return @@ -2146,7 +2140,12 @@ _SocketCloseSocket_LibraryOpen: Lib_Par SocketHerrno ; - - - - - - - - - - - - - PreserveStackFunction + EnsureBSDSocketLibrary _SocketHerrno_LibraryOpen + RestoreStackFunction + Ret_Int + +_SocketHerrno_LibraryOpen: ; set up tag list memory and place for herrno to go Dlea AcceptScratchArea,A0 MOVE.L A0,A2 diff --git a/src/BSDSocket_Labels.s b/src/BSDSocket_Labels.s index e449567..edcfc99 100644 --- a/src/BSDSocket_Labels.s +++ b/src/BSDSocket_Labels.s @@ -1,5 +1,5 @@ ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -; BSDSocket.s, list of the library functions on the 26-04-2024 14:45:36 +; BSDSocket.s, list of the library functions on the 26-04-2024 20:54:05 ; ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ L_Cold: set 0 diff --git a/src/BSDSocket_Size.s b/src/BSDSocket_Size.s index 7aa7186..9109d2a 100644 --- a/src/BSDSocket_Size.s +++ b/src/BSDSocket_Size.s @@ -1,5 +1,5 @@ ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -; BSDSocket.s, library size on the 26-04-2024 14:45:36 +; BSDSocket.s, library size on the 26-04-2024 20:54:05 ; ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Lib_Size equ 39 diff --git a/src/absdsocket b/src/absdsocket index c7bcab6..7d36159 100644 --- a/src/absdsocket +++ b/src/absdsocket @@ -9,5 +9,4 @@ FAILAT 21 copy AMOSPro_System:APSystem/AMOSPro_BSDSocket.lib AMOSPro_System:APSystem/AMOSPro_BSDSocket.lib.bak FAILAT 10 copy AMOSPro_BSDSocket.Lib AMOSPro_System:APSystem/ -;use an amos file here that includes the plugin to quickly build a test program -;apcmp "aqua_test_plugin.amos" inclib +apcmp "/test/TestSuite.amos" inclib diff --git a/src/report.txt b/src/report.txt deleted file mode 100644 index 9caf71b..0000000 --- a/src/report.txt +++ /dev/null @@ -1,34 +0,0 @@ -[Socket Library Open/Open Library] 1075577444 -[Socket Library Open/Double open] 1075577444 -[Socket Create Inet Socket] 0 -[Socket Set Nonblocking/False] 0 -[Socket Set Nonblocking/True] 0 -[Socket Set Nonblocking/True] Preserving this state for rest of tests -[Dns Get Address By Name$/Bad domain name] -[Dns Get Address By Name$/localhost] 127.0.0.1 -[Dns Get Address By Name$/aminet.net] 35.223.124.178 -[Dns Get Address By Name$/aminet.net] Using this IP address for connection tests -[Dns Get Address By Name$/Returned string can be manipulated] Cat35.223.124.178Dog -[Socket Connect/port too high] -11 -[Socket Connect/blank ip] -14 -[Socket Connect/invalid ip] -1 -[Socket Connect/aminet IP (35.223.124.178) from above] -1 (ok to be -1, will Wait Async Writing next) -[Socket Wait Async Writing/With unconnected socket/2 second timeout] 1 -[Socket Wait Async Writing/With unconnected socket/Zero timeout] 1 -[Socket Wait Async Writing/Connected socket/Two second timeout] 1 -[Socket Wait Async Writing/Connected socket/Zero timeout] 1 -[Socket Wait Async Writing/Connected socket/Attempt to get actual connection] 1 -[Socket Wait Async Writing/Socket Send and Socket Send$/Socket send$ first half] 10 -[Socket Wait Async Writing/Socket Send and Socket Send$/Socket send second half] 18 -[Socket Wait Async Writing/Socket wait Async Reading/With unconnected socket/2 second timeout] 1 -[Socket Wait Async Writing/Socket wait Async Reading/With unconnected socket/Zero timeout] 1 -[Socket Wait Async Writing/Socket wait Async Reading/With aminet socket/2 second timeout] 1 -[Socket Wait Async Writing/Socket wait Async Reading/With aminet socket/Zero timeout] 1 -[Socket Wait Async Writing/Socket Recv$ and Socket Recv/Socket Recv$/Read 20 characters] HTTP/1.1 302 Found - -[Socket Wait Async Writing/Socket Recv$ and Socket Recv/Socket Recv$/String can be manipulated] CatHTTP/1.1 302 Found -Dog -[Socket Wait Async Writing/Socket Recv$ and Socket Recv/Socket Read/Read 20 bytes] 20 -[Socket Wait Async Writing/Socket Recv$ and Socket Recv/Socket Read/Data was read] Date: Fri, 26 Apr 20 -[Socket Wait Async Writing/Socket Library Close/Close] Success -[Socket Wait Async Writing/Socket Library Close/Double close] Success diff --git a/test/TestSuite b/test/TestSuite index 01256c2b0ac118b5486db423a28d07ab4acc556e..77dbabe0564f85a138d85e856567cac9e1e85b3f 100644 GIT binary patch delta 6502 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 MJ>nWW6u-^?584@IS^xk5 delta 3988 zcmb7H4@?`^8GmpBttRXSi+k5GaM3Op$F5ORkUn{Xs7wk&{elDKQL(LklCE=G$I%eUO4U+Ybq7uu;>(rO80n#IyUI@!2w8DqU{d0;v8vYFYsl%E;>zPqE( zdV%Asq%-0fIAuSD4~-L!`$5wQX+E3zq^x&Bj-HU?g>%N#=6?jODE>0RnX)gC=v0T)hk(78`4>9T*UEW&y7XshDoW2 zA}Q7;&IvDAgseIkz%k6p4HA&?WrvXQRWi($Ap(Db z42MfIWIkoj8`Hq}&UD zP#yusfa3r}$sm(20<*w80CDm%u#UWtqXUGFYG4o01@r+4;1F;G0G9(?jw#>;;2haP z9IxZ%7rB!DurOL_Puc{{A-r((r^u|sq{Fo-|{wAEx9NrbH2!^GUhmDn; zz`_z$F_oJXSU(V;N^?xCYN9>OPYRdl`R4EK{_{8qOW!4*ZCAIVt$yPQ5eOM0pSh3X zgNl!@tYPx2nv&H+WGzM8T3QimvL&Xk*+U)bR`siAroT?ICt+;UCSs&fmPJBF1{)px zHzA{NBYk3=RAv^Qt^Hu`_j5geA#=;qqZK<;<2pDsa{FNXTXw&C;Mciq-=8F`E;b%o zG%j=8x5&n|32;f^dfFmenjW3=tHxy-7n5PU!nbH#=D11rcpDKO#hQ>-k-+V62U<-gTMq~cTG#f7FhG0T#>MrI>D9J6as6F-t1Tg}-^%QL z?4(WH5usP(`^6oBjHkUxq?exmWW#0sr$6ft1-Hol@?9*9X_mJr*E diff --git a/test/TestSuite.amos b/test/TestSuite.amos index 58bbeea156371e1e023739d1b7d1f0e283b68858..51ce26b9233b2bf326b1b28b545d6faf9ca6da00 100644 GIT binary patch literal 11938 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 delta 1661 zcma)6L1-IC6#YB0){?Ervbs(eOInX?S*WTBvg4>mZiQ-6W75_wZZ0)0W-YHQ5k*RN z*G>+F=Fn3x#mN^vs3r=)Kd<eiz2;isQ{!54I^Qsg_+=Vv*<_{%%W?+oD1YmI@71JWpi04Ajb&EY3f zl17hh>5@kb5Bhc)gmKxM6XCXZ-unZ{^!1CEDyaBC&WrGue3yZSc7MhXnhaLGc*Ve> zcpQK2&#I7+!8EMxs(rK%%i$w-8*HkfVbqsqkih5BNxbSScH!XA#l7;KYvDfdzk53F zmfyiW^1oq_#)ku!M9>0UhBRZ9Yxt-?f)@s-#cX*ncRZ`%&x4ei#y5k+-ANIl5co|5 z<;;GvlLD+ZTXU(}&>%u-{Ns$kKC*|)U zMF`ziE{$uU+*Dh0S7FEjC=#`lVXzKO)!S-53l$cdf*c({5(4k=l3BmX^^N+D0lNS( zk=Su$r|?}GcKF^Lemw)(0MzZWVXixef1;7MdpDBBMtHf4I$Lyv&Eh}dwnUluR5a3~ zsW$e{F$Wt`zr^>Hk4HP3cX8xPER2yN!f`3g#51Suu3>&;riHsV^3nWHq{#a+*k;AB zgq(R0zlIYB08|gHcPQ4{6i3g_Ts&TcuZ6@x4|@u!|0F$ei-On7?n4w*0FQ?q0{A5= zMcd=v*&MD!3Jeyo5qYS>(f}(}Ov_#`>($cHzBlD4w}6+U$!@>e9e!P-l1um?>iTt) z)5QeKDAsG6PQ7)@)=itZ%1WzjjPAzeyPAS~F`sDSUMyKSCgxu4OpkqfRtC`lmCFj9 z=d@SdXHj-awVe=B6ZrjDk27oG+Ahe`s}sTNyoVE-*#F}M7uj+`NX_HZiBTLMzpuio z%uc>%((@*1d@)XPuA*<^TM@pSI1t=EPdGQWl%SJyoab{c1Ox$JB$D57NnU|DZkH<- z-_fhv2ES3MR(Y|k*R~8^snLoEwqaf~4f^N0#cji~EpBet=q*=7KIb%}XT z+Ln{FRoSrWHBML3aB!qI^sx=yGU%+5piIx4pS^%1lf&~dDgL8WAQHmY3R!gRCxA1yO^~>N+(F?0RemS`-;oiCMzsSb3hX4Qo