GENIO Socket Device





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.




Socket Device Creation

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:



  -1 Value master
  7624 EndPoint: local any-ip

: new-master   ( -- )
   TCP socket throw to master
   local master binds throw
   master listens throw ;



Exceptions

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.




Glossary

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.

Blocking/Non-Blocking socket API vectors

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).

Common, low level factors

: (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.

Socket driver Entry points

: 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.



Support for ACCEPT

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.

Open and vector table

: +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.

Device Creation

: 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.