/*
This is an example of a stand-alone/inedt service.
It waits on port 10000/tcp for a pkt and send back
a formatted date.
It also opens an ARexx port called DS.10000 and waits
for messages on it as well.
The only command acccepted on the port is "QUIT".
It can also be run as an inetd service, adding the service
ds             10000/tcp
to the services database, and the inetd entry
dsc             stream tcp   nowait root   rxs rxs  path:ds.rexx
to the inedt database.

ds accempt just on optiona argument:
VERBOSE which makes ds to log the connections to syslog

dsfun.rexx is the single connection handler
ds.rexx is the client for the service
*/

l="rmh.library";if ~show("L",l) then;if ~addlib(l,0,-30) then call err "rmh.library not found"
if AddLibrary("rexxsupport.library","rxsocket.library")~=0 then call err result "not found"

call initGlobal

ls=LastSocket()
if ls>=0 then do
    call handle(ls)
    exit
end

call createPort
call createSocket
call info "Started on port" global.port
call start
call info "Ended"
exit
/***************************************************************************/
initGlobal: procedure expose global.
    call pragma("D",PathPart(ProgramName("FULL")))
    global.prg=ProgramName("NOEXT")
    call SysLogCtl(global.prg)
    if ~RMH_ReadArgs("VERBOSE/S") then call err DosString(IoErr())
    global.verbose=parm.0.flag
    call SetVar("VERBOSE",global.verbose,"LOCAL")
    global.port=10000
    return
/***************************************************************************/
err: procedure
parse arg msg
    call SysLog(msg,"ERR")
    exit
/***************************************************************************/
info: procedure
parse arg msg
    call SysLog(msg,"INFO")
    return
/***************************************************************************/
createPort: procedure expose global.
    global.portName=upper(global.prg)"."global.port
    if ~OpenPort(global.portName) then call err "can't create port"
    global.ps=PortSignal(global.portName)
    return
/***************************************************************************/
createSocket: procedure expose global.
    global.sock=socket("INET","STREAM")
    if global.sock<0 then call err "can't create socket %m"
    local.addrFamily="INET"
    local.addrPort=global.port
    if bind(global.sock,"LOCAL")<0 then call err "can't bind socket %m"
    if listen(global.sock,5)<0 then call err "can't listen on socket %m"
    return
/***************************************************************************/
start: procedure expose global.
    sel.read.0=global.sock
    sigWait=or(2**12,global.ps)
    open=1
    do while open
        res = WaitSelect("SEL",,,sigWait)
        if and(sel.signals,2**12)~=0 then return
        if res==1 then do
            rsock=accept(global.sock,"REMOTE")
            if rsock>=0 then call handle(rsock)
        end
        if and(sel.signals,global.ps)~=0 then do
            pkt=GetPkt(global.PortName)
            if pkt~=Null() then do
                comm=GetArg(pkt)
                res=0
                select
                    when upper(comm)=="QUIT" then open = 0
                    otherwise res=15
                end
                call Reply(pkt,res)
            end
        end
    end
    return
/***************************************************************************/
handle: procedure
parse arg sock
    call RXSCall("dsfun",sock)
    call CloseSocket(sock)
    return
/***************************************************************************/
