This Generic IO Device operates on a TCP socket for input and output. Flags specify whether to create a client or server socket and also the blocking/non-blocking mode.
In order to create a named socket device on the dictionary, use the SOCKDEV: definition given later. These devices can be created in the heap using allocate, and must be initialized using initSockDev.
Under GENIO, sockets are opened by using either open-gen or open-gio. The following flags control options at open time:
When using this driver to program server sockets, it is up to the developer to set up and configure the parent socket with socket, binds and listens or -blocking. An example:
|
When examining the stack signature of GENIO drivers, there were no place to report I/O errors. Two options were available: either ignore them or to throw exceptions. I have chosen the latter strategy as a way to detect bugs and unexpected situations.
The following xxx-gio words may throw exceptions when using the
underlying sockets vocabulary:
open-gio, close-gio, read-gio, readex-gio,
write-gio, key?-gio, key-gio, accept-gio,
emit-gio, type-gio, cr-gio, lf-gio,
ff-gio and bs-gio.
The following xxx-gio words throw
abort" operation not supported" exceptions:
ekey-gio, ekey?-gio, bell-gio, setpos-gio,
getpos-gio and ioctl-gio,
The following xxx-gio words do nothing:
flushOP-gio, init-gio, term-gio and config-gio.
MODULE GENIO-SOCK
GENIO Module name for socket I/O.
struct /SockDev \ -- len ;
The socket SID structure, passed around as a handle by all xxx-gio
words.
gen-sid + \ reuse field names of GEN-SID 1 cells field sd.flags \ Mode flags (see below). end-struct
1 Constant SOCKDEV_NONBLOCK
Non-Blocking bit for fam flag in open-gio.
Also stored in sd.flags.
2 Constant SOCKDEV_SVR
Server bit for fam flag in open-gio.
Also stored in sd.flags.
4 Constant SOCKDEV_ECHO
Echo bit in fam flag in open-gio.
Makes ACCEPT echo character back to the sender socket.
Option available for server sockets only.
Also stored in sd.flags.
Handling blocking or non-blocking socket connections is deferred until open time. It makes much easier life to code several entry points with a slight overhead.
Defer socket-connect \ addr fd -- ior
Vector for connects or connects-mt.
Defer socket-accept \ addr1 fd1 -- fd2 ior
Vector for accepts or acceptss-mt.
Defer socket-send \ c-addr1 +n1 fd -- +n2 ior
Vector for sends or sends-mt.
Defer socket-recv \ c-addr1 +n1 fd -- +n2 ior
Vector for recvs or recvs-mt.
Defer socket-recv-all \ c-addr1 +n1 fd -- +n2 ior
Vector for recvs-all or recvs-all-mt.
Defer sd-key? \ sid -- flag
Vector for (sd-key?) or (sd-key?-mt).
: (sd-key?) \ sid -- flag
Test for any character received by configuirng the socket as
non-blocking mode, do a peek and check for EAGAIN errno. Then, the socket
is configured as blocking again.
: (sd-key?-mt) \ sid -- flag
More efficient operation when socket is already open in non-blocking mode.
: NotSockDev \ --
Issue a SockDev error message.
: (sd-create) \ addr len sid -- addr fd sid 0 | sid ior
Creates the socket.
len is unusued but addr will be used later,
: (sd-connect) \ addr fd sid -- fd sid 0 | sid ior
Connects or closes the socket if not succesfull.
addr is a /sockaddr_in, /enpoint structure
or NULL.
: (sd-accepts) \ addr len sid -- fd sid 0 | sid ior
Creates a new child socket from parent socket.
addr is an /enpoint structure or NULL.
len is the parent spcket descriptor
: (sd-gen!) \ fd sid -- sid 0
Sets the internal handle to be the file descriptor returned by socket
creation words.
: open-client \ addr len sid -- sid ior
Open socket device and connect to remote /sockaddr_in or
/endpoint addr for client sockets.
len is unusued. Leave it to -1.
: open-server \ addr len sid -- sid ior
Open socket device for children server sockets.
addr is an /enpoint structure or NULL.
len is the parent socket descriptor returned
beforehand by socket.
: sd-close \ sid -- ior
Closes the socket and initializes the gen-handle back to invalid state.
: sd-read \ addr len sid -- ior
Read all the bytes up to len from the socket device.
: sd-readex \ addr len sid -- #read ior
Read all the bytes up to len from the socket device.
May return less bytes than requested.
: sd-write \ addr len sid -- ior
: sd-key \ sid -- char
: sd-ekey \ sid -- echar
Not supported.
: sd-ekey? \ sid -- flag
Not supported.
: sd-emit \ char sid --
: sd-emit? \ sid -- flag
ALways true. does not check for full Tx buffer.
: sd-type \ addr len sid --
: sd-cr \ sid --
Send CR+LF characters
: sd-lf \ sid --
Linefeed.
: sd-ff \ sid -- ; page/cls on display devices
: sd-bs \ sid -- ; destructive on display devices
: sd-bell \ sid -- ; audible beeper
Not supported.
: sd-setpos \ x y mode sid -- ior
Not supported.
: sd-getpos \ mode sid -- x y ior
Not supported.
: sd-ioctl \ addr len fn sid -- ior
Not supported. All is done at open time.
: sd-flushOP \ sid -- ior
Not supported.
: sd-init \ addr len sid -- ior
Not supported.
: sd-term \ sid -- ior
Not supported.
: sd-config \ sid -- ior ; produces a dialog
Not supported.
For the sd-accept entry points, we have deconstructed its loop into pieces.
: wait-key \ sid -- sid
Wait until next character arrives.
: /loop \ addr1 len sid - cnt sid addr2 addr3
Initializes accept loop, converting (start, count) pair into
(starting , ending) addresses addr2,addr3.
: cr? \ c -- c flag
Test for carriage return.
Returns true id CR is detected.
: ?echo \ cnt sid c -- cnt sid c
Conditionally echoes back the character, depending
on the SOCKDEV_ECHO flag.
: ?backspace \ cnt1 sid c -- cnt2 sid index
Handle possible backspace character c by going back
into the array and decreasing by 1 the count and loop index.
Normal operation increases by 1 the count and loop index.
: discard-lf \ cnt sid c -- cnt sid
c is a CR, therefore, read LF and discard it.
: sd-accept \ addr len sid -- #read
Accept chars from socket until cr is detected.
Returns number of characters read.
: +block-all
Set vectors for blocking mode.
: -block-all
Set vectors for blocking mode.
: sd-open \ addr len fam sid -- sid ior
addr is an /endpoint structure.
fam containst the two mode bits defined above.
len is -1 for client socke or else the parent fd.
when opening a child server socket.
sid is the /SockDev structure.
create sd-vectors \ -- ; Exec: -- addr
Table of GENIO execution tokens.
: initSockDev \ sid --
Initialise the sid for a socket device. Use it to initialize
the structure has been allocated from the heap.
: SockDev: \ "name" -- ; Exec: -- sid
Create a Socket based Generic IO device in the dictionary.