#!/usr/bin/env rexx

srv = .myserver~new()
srv~listen()

Exit
/* This is technically the end of the rexx script, in the classical sense. 
   Everything after the exit statement above will get parsed by the object 
   generator on the first pass over the script, not the rexx interpreter. Then,
   the rexx interpreter will use the generated objects when it interprets the
   script on the second-pass, to execute the instructions.
*/

::requires 'socket.cls'

::class myserver

::method init
    expose sock shutdown

/*  instantiate an instance of the socket class  */
    sock = .socket~new()

    shutdown = .false

::method monitor unguarded
    expose sock shutdown

/*  this seems to be the only cross platform way of cleanly shutting down.
    this may not be the best method of shutting down, but does work on both
    Linux and Windows  */
    say 'Press [Enter] To Shutdown'
    pull seconds
    if seconds~dataType("n") then do
        say "shutdown in" seconds "sec"
        call SysSleep seconds
    end

    shutdown = .true

/*  instantiate an instance of the socket class  */
    sock = .socket~new()

    host = .inetaddress~new('localhost', '50010')

/*  connect to the server (if it hasn't already shutdown)  */
    if sock~connect(host) < 0 then
    /*  close the socket connection  */
        sock~close()

::method listen
    expose sock shutdown

/*  instantiate an instance of the inetaddress class
    with the host information of the server we will
    contact: localhost and port 50010  */
    host = .inetaddress~new('localhost', '50010')

/*  bind to the host information  */
    sock~setOption('SO_REUSEADDR', 1)
    if sock~bind(host) < 0 then do
        say 'Bind failed:' sock~errno
        exit
    end

    if sock~listen(256) < 0 then do
        say 'Listen failed:' sock~errno
        exit
    end

    say "Server listening at" host~address':'host~port
    self~start('monitor')   --  this will allow the server to be shutdown cleanly

    do forever
        csock = sock~accept()   --  prepare to accept a new client
        if .nil = csock | shutdown then leave   --  if the socket has closed or the shutdown flag is set
    /*  this will spawn a thread to handle the new client and then return to accept the next client  */
        self~start('respond', csock)
    end

    if csock~isa(.socket) then
        if csock~close() < 0 then
            say 'SockClose failed:' sock~errno

    if sock~close() < 0 then
        say 'SockClose failed:' sock~errno

::method respond unguarded
    use arg sock

    do forever
        /*  get data from the client  */
        data = sock~recv(1024)
        if data = .nil | data == "" then leave
        say time data
        /*  echo that data back to the client  */
        sock~send('Echo:' data)
    end