initial commit
This commit is contained in:
parent
f3880aba6d
commit
c14ba040b2
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
*.uaem
|
||||
*.Bak
|
BIN
AMOSPro_BSDSocket.Lib
Normal file
BIN
AMOSPro_BSDSocket.Lib
Normal file
Binary file not shown.
357
API.md
Normal file
357
API.md
Normal file
@ -0,0 +1,357 @@
|
||||
## BSD Socket Extension API
|
||||
|
||||
Most functions will return -2 if the bsdsocket.library is
|
||||
not open.
|
||||
|
||||
### Setup
|
||||
|
||||
#### ADDR=Socket Library Open
|
||||
|
||||
Try to open bsdsocket.library version 4.
|
||||
|
||||
##### Returns
|
||||
|
||||
* 0 if opening failed
|
||||
* Memory address of library on success
|
||||
* If needed, you'll be able to directly access library functions
|
||||
using this address.
|
||||
|
||||
#### Socket Library Close
|
||||
|
||||
Close bsdsocket.library. This is safe to call if the library
|
||||
is not open
|
||||
|
||||
#### RESULT=Socket Set Nonblocking(Socket, IsNonblocking BOOL)
|
||||
|
||||
Make a socket blocking (False, default), or nonblocking (True).
|
||||
|
||||
##### Returns
|
||||
|
||||
* Result of IoctlSocket call.
|
||||
|
||||
#### RESULT=Socket Reuse Addr(Socket)
|
||||
|
||||
Make a listening socket reuse the address it's trying to bind to.
|
||||
You probably want to call this right before Socket Listen.
|
||||
|
||||
##### Returns
|
||||
|
||||
* Result of setsockopt call.
|
||||
|
||||
|
||||
|
||||
### Connections
|
||||
|
||||
#### SOCKET=Socket Create Inet Socket
|
||||
|
||||
Create a new Internet socket for reading or writing.
|
||||
|
||||
##### Returns
|
||||
|
||||
* Socket number on success
|
||||
* -1 on failure
|
||||
|
||||
#### RESULT=Socket Connect(Socket to IPAddress$, Port)
|
||||
|
||||
Attempt to connect to a remote host. Currently doesn't
|
||||
support DNS lookups.
|
||||
|
||||
##### Returns
|
||||
|
||||
* 0 on connected
|
||||
* -1 on error
|
||||
* If your socket is non-blocking, you have to check
|
||||
the socket with Socket Select and Socket Getsockopt Int
|
||||
to see if the connection succeeded
|
||||
* -11 port out of range
|
||||
|
||||
#### RESULT=Socket Reuse Addr(Socket)
|
||||
|
||||
Set a server socket to reuse an interface and port that had
|
||||
been used recently. You likely want this if you're building
|
||||
something that listens on a port for connections. This calls
|
||||
setsockopt() for you.
|
||||
|
||||
##### Returns
|
||||
|
||||
The result of calling setsockopt() while setting your socket
|
||||
to reuse addresses.
|
||||
|
||||
#### RESULT=Socket Bind(Socket to IPAddress, Port)
|
||||
|
||||
Attempt to bind a socket to a network interface. Use
|
||||
the string "IPADDR_ANY" for IPAddress to bind to all
|
||||
interfaces.
|
||||
|
||||
##### Returns
|
||||
|
||||
* 0 on success
|
||||
* -1 on other error
|
||||
* -11 port out of range
|
||||
|
||||
#### RESULT=Socket Listen(Socket)
|
||||
|
||||
Start listening for connections.
|
||||
|
||||
##### Returns
|
||||
|
||||
* 0 on success
|
||||
* -1 on failure
|
||||
|
||||
#### NEW_SOCKET=Socket Accept(Socket)
|
||||
|
||||
Get the socket that connected to this one. Wait for a connect
|
||||
if this socket is blocking.
|
||||
|
||||
##### Warning
|
||||
|
||||
If this socket is blocking (the default), you will likely
|
||||
get AMOS stuck in a state you can't recover from, due to
|
||||
how AMOS takes over system signals! Be sure to make your
|
||||
socket non-blocking and use Fdsets and Select!
|
||||
|
||||
##### Returns
|
||||
|
||||
* The remote socket number on success
|
||||
* -1 on failure
|
||||
|
||||
#### RESULT=Socket Async Wait Reading(Socket, Wait_ms)
|
||||
|
||||
Wait the given number of milliseconds for the nonblocking socket to be ready for reading.
|
||||
Use this when you're waiting for a client to connect to you, or if you're waiting for
|
||||
a remote socket to send you data.
|
||||
|
||||
##### Returns
|
||||
|
||||
* 0 on timeout
|
||||
* -1,-2 on error
|
||||
* 1 on success
|
||||
|
||||
#### RESULT=Socket Async Wait Writing(Socket, Wait_ms)
|
||||
|
||||
Wait the given number of milliseconds for the nonblocking socket to be ready for writing.
|
||||
Use this when you're connecting to a remote server and want to know if the connection
|
||||
has been completed.
|
||||
|
||||
##### Returns
|
||||
|
||||
* 0 on timeout
|
||||
* -1,-2 on error
|
||||
* 1 on success
|
||||
|
||||
#### RESULT=Socket Set Timeout(Socket, Wait_ms)
|
||||
|
||||
Set a socket to timeout after Wait_ms milliseconds if reading or writing doesn't complete.
|
||||
|
||||
##### Returns
|
||||
|
||||
* 0 on success
|
||||
* -1 on error
|
||||
|
||||
#### RESULT=Socket Close(Socket)
|
||||
|
||||
Close a socket.
|
||||
|
||||
##### Returns
|
||||
|
||||
* 0 on success
|
||||
* -1 on error
|
||||
|
||||
|
||||
|
||||
### Data Transfers
|
||||
|
||||
#### SENT=Socket Send$(Socket, String$)
|
||||
|
||||
Send a string to a connected socket.
|
||||
|
||||
##### Bugs
|
||||
|
||||
For some reason, this command performs incorrectly when
|
||||
used in a Procedure to send a passed-in variable,
|
||||
and Varptr() is not called on the string variable to be sent
|
||||
beforehand within the procedure itself. I believe this is
|
||||
a bug in AMOS itself. You'll know you're having this issue if
|
||||
the byte count returned is abnormally high.
|
||||
|
||||
If you're using this in a Procedure, call Varptr() first:
|
||||
|
||||
```
|
||||
Procedure SEND_STRING[SOCKET, S$]
|
||||
' _shrug_
|
||||
_=Varptr(S$)
|
||||
|
||||
BYTES=Socket Send$(SOCKET,S$)
|
||||
End Proc
|
||||
```
|
||||
|
||||
##### Returns
|
||||
|
||||
* Number of characters sent
|
||||
* -1 on other error
|
||||
|
||||
#### SENT=Socket Send(Socket, Data Pointer, Length)
|
||||
|
||||
Send a block of data to a connected socket.
|
||||
|
||||
##### Returns
|
||||
|
||||
* Number of characters sent
|
||||
* -1 on other error
|
||||
|
||||
#### DATA$=Socket Recv$(Socket, MaxLength)
|
||||
|
||||
Retrieve at most MaxLength bytes from Socket, and put them into a string.
|
||||
If Len(DATA$) < MaxLength, you've read the last bit of data from the socket.
|
||||
|
||||
##### Returns
|
||||
|
||||
* String of data, which is blank if there is no more data.
|
||||
|
||||
### LENGTH=Socket Recv(Socket to Dataptr, MaxLength)
|
||||
|
||||
Retrieve at most MaxLength bytes from Socket, and put them into the memory
|
||||
address at Dataptr.
|
||||
|
||||
#### Returns
|
||||
|
||||
* Count of bytes read
|
||||
* -1 on error
|
||||
|
||||
|
||||
|
||||
### Informational
|
||||
|
||||
#### HOST=Socket Get Host(Socket)
|
||||
|
||||
Get the IPv4 (Long) host value the given socket is using.
|
||||
|
||||
##### Returns
|
||||
|
||||
* Host as a long value
|
||||
|
||||
#### PORT=Socket Get Port(Socket)
|
||||
|
||||
Get the 16-bit port (Word) value the given socket is using.
|
||||
|
||||
##### Returns
|
||||
|
||||
* Port as a word value
|
||||
|
||||
#### RESULT$=Socket Inet Ntoa$(Host)
|
||||
|
||||
Turn a long Host address into a string.
|
||||
|
||||
##### Returns
|
||||
|
||||
* IP address as string
|
||||
|
||||
#### RESULT=Socket Errno
|
||||
|
||||
Get the error from the last command. Note that this is
|
||||
not cleared on a successful command!
|
||||
|
||||
##### Returns
|
||||
|
||||
Error number from last call. Look in <sys/error.h> for more
|
||||
details.
|
||||
|
||||
#### RESULT$=Dns Get Address By Name$(Domain Name$)
|
||||
|
||||
Look up the first IP address associated with this hostname.
|
||||
|
||||
##### Warning
|
||||
|
||||
This is dependent on your stack's name resolution. If DNS lookups
|
||||
aren't working correctly, you may have to wait for the lookup to time
|
||||
out. There's no way to set this timeout, or cancel or override it via AMOS.
|
||||
|
||||
##### Returns
|
||||
|
||||
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
|
||||
|
||||
|
||||
|
||||
### Low Level
|
||||
|
||||
#### RESULT=Socket Setsockopt Int(Socket, Option, Value)
|
||||
|
||||
Set a socket option. You probably want SO_REUSEADDR,
|
||||
which is Option=$4, and you want Value=True. Or, use
|
||||
Socket Reuse Addr().
|
||||
|
||||
##### Returns
|
||||
|
||||
* Result of setsockopt call
|
||||
|
||||
#### RESULT=Socket Getsockopt Int(Socket, Option)
|
||||
|
||||
Get a socket option. You probably want SO_ERROR,
|
||||
which is Option=$1007, and it's what you check when you
|
||||
attempt a connection with a non-blocking socket.
|
||||
|
||||
##### Returns
|
||||
|
||||
* Result of getsockopt call
|
||||
|
||||
#### ADDR=Socket Fdset Zero(fd_set)
|
||||
|
||||
Clear out the specified fd_set.
|
||||
|
||||
##### Returns
|
||||
|
||||
* Address to that particular fd_set
|
||||
* -1 if fd_set out of range. You get 16 of them.
|
||||
|
||||
#### ADDR=Socket Fdset Set(fd_set, Socket to Value BOOL)
|
||||
|
||||
Set or clear a socket bit in an fd_set.
|
||||
|
||||
##### Returns
|
||||
|
||||
* Address to that particular fd_set
|
||||
* -1 if fd_set is out of range or socket is out of range.
|
||||
|
||||
#### RESULT=Socket Fdset Is Set(fd_set, Socket)
|
||||
|
||||
See if the particular socket remained after a Socket Select call.
|
||||
|
||||
##### Returns
|
||||
|
||||
* True or False if the socket is set or not
|
||||
|
||||
#### RESULT=Socket Select(Max Socket, Read fd_set, Write fd_set, Error fd_set, TimeoutMS)
|
||||
|
||||
Wait for the specified number of milliseconds. If any of the sockets
|
||||
in any of the fd_sets become interesting during that time, stop
|
||||
waiting, clear out the uninteresting sockets in the fd_sets, and return
|
||||
how many sockets were left.
|
||||
|
||||
##### Returns
|
||||
|
||||
* 0 on timeout
|
||||
* -1 on error
|
||||
* # of interesting sockets on success
|
BIN
HTTP Client Example.amos
Normal file
BIN
HTTP Client Example.amos
Normal file
Binary file not shown.
165
README.md
165
README.md
@ -1,3 +1,166 @@
|
||||
# amos-pro-bsdsocket-extension
|
||||
|
||||
An extension to use BSD Socket functionality within AMOS Professional.
|
||||
Want to get online with your AMOS program? Now you can in (some) style!
|
||||
|
||||
This extension provides a wrapper around the BSD Socket library
|
||||
provided by your Internet stack. There's some attempt to roll up some
|
||||
of the low-level functionality into something more usable by AMOS.
|
||||
|
||||
## Installation
|
||||
|
||||
* Copy `AMOSPro_BSDSocket.Lib` to `AMOSPro_System:APSystem/`
|
||||
* Within AMOS Professional:
|
||||
* Config -> Set Interpreter
|
||||
* Load Default Configuration
|
||||
* Set Loaded Extensions
|
||||
* Extension Slot 18 -- `AMOSPro_BSDSocket.Lib`
|
||||
* Exit
|
||||
* Save Configuration
|
||||
* Restart AMOS Professional
|
||||
* Type in the following and Run:
|
||||
|
||||
```
|
||||
Print Socket Library Open
|
||||
```
|
||||
|
||||
The line should tokenize, and running it should print -1 if you have no
|
||||
Internet stack running, or a large number if you do.
|
||||
|
||||
## Examples
|
||||
|
||||
### Communicating with an HTTP server
|
||||
|
||||
```
|
||||
LIB=Socket Library Open
|
||||
|
||||
If LIB<=0
|
||||
End
|
||||
End If
|
||||
|
||||
SOCKET=Socket Create Inet Socket
|
||||
_=Socket Set Nonblocking(SOCKET,True)
|
||||
|
||||
' connect to aminet.net
|
||||
IP$=Dns Get Address By Name$("aminet.net")
|
||||
ALREADY_CONNECTED=Socket Connect(SOCKET To IP$,80)
|
||||
|
||||
Reserve As Work 30,1024
|
||||
|
||||
For I=1 To 100
|
||||
If ALREADY_CONNECTED=-1
|
||||
RESULT=Socket Wait Async Writing(SOCKET,100)
|
||||
|
||||
If RESULT>0
|
||||
ALREADY_CONNECTED=0
|
||||
End If
|
||||
End If
|
||||
|
||||
If ALREADY_CONNECTED=0
|
||||
HTTPGET$="GET / HTTP/1.0"+Chr$(10)+"Host: amiga"+Chr$(10)+Chr$(10)
|
||||
Print "Making HTTP request to aminet.net"
|
||||
_=Socket Send(SOCKET,Varptr(HTTPGET$),Len(HTTPGET$))
|
||||
|
||||
For J=1 To 100
|
||||
RESULT=Socket Wait Async Reading(SOCKET,5000)
|
||||
If RESULT>0
|
||||
OUT=Socket Recv(SOCKET To Start(30),1024)
|
||||
_DATA$=""
|
||||
For K=0 To OUT-1
|
||||
_DATA$=_DATA$+Chr$(Peek(Start(30)+K))
|
||||
Next K
|
||||
Print _DATA$
|
||||
If OUT<1024
|
||||
Exit 2
|
||||
End If
|
||||
End If
|
||||
Next J
|
||||
Exit
|
||||
End If
|
||||
Next I
|
||||
|
||||
Socket Library Close
|
||||
```
|
||||
|
||||
### Starting a server
|
||||
|
||||
```
|
||||
If Socket Library Open<=0
|
||||
End
|
||||
End If
|
||||
|
||||
SOCKET=Socket Create Inet Socket
|
||||
|
||||
_=Socket Set Nonblocking(SOCKET,True)
|
||||
_=Socket Reuse Addr(SOCKET)
|
||||
|
||||
RESULT=Socket Bind(SOCKET To "INADDR_ANY",8000)
|
||||
|
||||
_=Socket Listen(SOCKET)
|
||||
Print "listening on port 8000"
|
||||
|
||||
For I=1 To 100
|
||||
RESULT=Socket Wait Async Reading(SOCKET,500)
|
||||
|
||||
If RESULT>0
|
||||
_REMOTE_SOCKET=Socket Accept(SOCKET)
|
||||
|
||||
Print Socket Inet Ntoa$(Socket Get Host(_REMOTE_SOCKET))
|
||||
Print Socket Get Port(_REMOTE_SOCKET)
|
||||
|
||||
Print Socket Recv$(_REMOTE_SOCKET,1024)
|
||||
|
||||
Exit
|
||||
End If
|
||||
Wait Vbl
|
||||
Next I
|
||||
|
||||
Socket Library Close
|
||||
```
|
||||
|
||||
## Who's using the extension?
|
||||
|
||||
* [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.
|
||||
|
||||
Doing something cool with the extension?
|
||||
[Contact me](https://theindustriousrabbit.com/about) and I'll add it to the list!
|
||||
|
||||
## General Notes
|
||||
|
||||
* The BSD Socket library, and all sockets, will close automatically when the program
|
||||
runs again. Sockets will stay open after stopping you code so you can
|
||||
debug issues from the AMOS console.
|
||||
* Since AMOS takes over Ctrl-C handling, you have to continually
|
||||
poll for socket statuses on nonblocking sockets. Trying to use
|
||||
a blocking socket will likely cause AMOS to hang indefinitely!
|
||||
* Using the Wait Async functions with small timeouts are the
|
||||
most system-friendly way of doing this.
|
||||
* MiamiDX can be fiddly, at least it is on my MiSTer set up.
|
||||
If Internet connectivity is not working, try re-connecting to the network.
|
||||
|
||||
## Versioning
|
||||
|
||||
This project uses semantic versioning.
|
||||
|
||||
* If the version number is below 1.0.0, API is not stable.
|
||||
* If the major number increases, API has changed.
|
||||
|
||||
## License
|
||||
|
||||
Copyright 2023 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.
|
||||
|
||||
## Feedback? Bug reports?
|
||||
|
||||
Go to the [About section on The Industrious Rabbit](https://theindustriousrabbit.com/about)
|
||||
to contact me.
|
||||
|
||||
## Development
|
||||
|
||||
### Environment
|
||||
|
||||
* Clone the [AMOS Professional source code](https://github.com/AOZ-Studio/AMOS-Professional-Official)
|
||||
* Copy the contents of
|
||||
|
BIN
http get v3.amos
Normal file
BIN
http get v3.amos
Normal file
Binary file not shown.
2066
src/BSDSocket.s
Normal file
2066
src/BSDSocket.s
Normal file
File diff suppressed because it is too large
Load Diff
9
src/absdsocket
Normal file
9
src/absdsocket
Normal file
@ -0,0 +1,9 @@
|
||||
echo "***Assembling AMOSPro_BSDSocket.Lib"
|
||||
assign AMOSPro_System: MiSTerHD:Development/AMOSPro/AMOS_Pro
|
||||
Stuff:Development/AMOS-Professional-Official-mas/c/Library_Digest BSDSocket.s
|
||||
Stuff:Development/AMOS-Professional-Official-mas/c/Genam FROM BSDSocket.s TO AMOSPro_BSDSocket.Lib
|
||||
;delete >NIL: BSDSocket_Labels.s
|
||||
;delete >NIL: BSDSocket_Size.s
|
||||
copy AMOSPro_System:APSystem/AMOSPro_BSDSocket.lib AMOSPro_System:APSystem/AMOSPro_BSDSocket.lib.bak
|
||||
copy AMOSPro_BSDSocket.Lib AMOSPro_System:APSystem/
|
||||
apcmp "aqua_test_plugin.amos" inclib
|
BIN
the minimum.amos
Normal file
BIN
the minimum.amos
Normal file
Binary file not shown.
BIN
updated sockaddr in.amos
Normal file
BIN
updated sockaddr in.amos
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user