/* Daniel Hellerstein, danielh@econ.ag.gov (portions of this were adapted from code retrieved from the usenet). Please use freely. This demonstrates the "SockIn" rexx procedure -- a timed replacement for the sockrecv procedure (or, more accurately, an extension to sockrecv). SockIn will read data from a socket for waitseconds seconds; and if nothing has been recieved within this time period, a "timeout" message is sent. This demo program can be called: sockrecv servername selector maxseconds servername: the dotted servername request: the resource to request maxsecones: maximum # of seconds to wait ( Examples: sockrecv www.econ.ag.gov / sockrecv search.yahoo.com /search/options 10 If you call with no arguments, the defaults will be used (set below) */ /*------------ Begin user configurable parameters ...... */ def_waitseconds=10 /* number of seconds to wait before giving up on server */ def_server='WWW.yahoo.com' /* default name of server */ httpport=80 /* port of server (typically, 80 for http */ def_request='/' /* default request selector (must start with a / ) */ /*------------ end user configurable parameters ...... */ parse arg server request waitseconds if server="?" then do say " Demo of the sockrecv rexx procedure -- request a resource with a timeout " say " Call as: SOCKRECV servername request timeout_seconds " exit end /* do */ if server='' then server=def_server if request='' then request=def_request request='/'||strip(request,'l','/') if waitseconds='' then waitseconds=def_waitseconds if datatype(waitseconds)<>'NUM' then do say "ERROR: waitseconds must be an integer " exit end waitseconds=trunc(waitseconds) /*--- Load REXX libraries ----- */ /* Load up advanced REXX functions */ foo=rxfuncquery('sysloadfuncs') if foo=1 then do call RxFuncAdd 'SysLoadFuncs', 'RexxUtil', 'SysLoadFuncs' call SysLoadFuncs end if RxFuncQuery("SockLoadFuncs")=1 then do /* already there */ call RxFuncAdd "SockLoadFuncs","rxSock","SockLoadFuncs" call SockLoadFuncs end /* set some tcp/ip constants */ family ='AF_INET' CRLF='0D0A'X rc=1 if verify(server,'1234567890.')>0 then rc=sockgethostbyname(server, "serv.0") /* get dotaddress of server */ else serv.0addr=strip(server) /* couldn't get address -- EXIT */ if rc=0 then do; say 'Unable to resolve "'server'"'; exit; end dotserver=serv.0addr /* .. */ say " Numeric address of server " dotserver gosaddr.0family=family /* set up address */ gosaddr.0port =httpport gosaddr.0addr =dotserver setup1: /* set up a socket */ gosock = SockSocket(family, "SOCK_STREAM", "IPPROTO_TCP") SAY " Using socket:" GOSOCK rc = SockConnect(gosock,"gosaddr.0") if rc<>0 then do say " Unable to SockConnect to " gosock "; error= " rc exit end /* formulate message to this http server */ message='GET 'request ' HTTP/1.0'crlf'HOST:'server||crlf message=message||crlf /* get ready to establish a connection */ got='' rc = SockSend(gosock, message) /* connnect to the server, but don't wait more then waitseconds See description of SOCKIN (below) for details on calling syntax */ YOW=SOCKIN(GOSOCK,waitseconds,50000,,1) SAY " Reponse received:" say " Hit ENTER to see response ("||Length(yow)||" bytes) " parse pull . say yow say '.... (end of response) ' foo=sockclose(gosock) /* close the socket */ EXIT /**************************/ /* SOCKIN: a replacement for sockrecv. call as stuff=sockin(socket,timeout,maxlen,timeoutmess,verbose) where: socket == a socket that's been established using sockconnect timeout == a timeout value in seconds maxlen == maximum length of message to recieve If not specified, then no maximum is imposed timeoutmess == Prefix for "error" and "timeout" message. If not specified, "#SOCKIN: " is used as a prefix For example: #SOCKIN: timeout " will be returned if no response was recieved in timeout seconds. verbose == If 1, then report status messages. If not specified, then do NOT report status messages and stuff = the contents returned from the server (up to maxlen characters) or an error message (starting with the timeoutmess) Note: timeout refers to maximum seconds between "sockrecv" requests. It does NOT refer to total length of time required to recieve a message. Thus, a number of medium length delays (say, a few seconds required to complete each of several sockrecv requests) will NOT cause a timeout (in other words, the timeout counter is reset upon each successful completion of a 1000 byte sockrecv request). */ SOCKIN:PROCEDURE PARSE Arg socket,timeout,maxlen,timeoutmess,verbose if maxlen=0 | maxlen='' then maxlen=100000000 if timeoutmess='' then timeoutmess='#SOCKIN:' if timeout='' then timeout=0.1 if verbose=1 then say "SockIn: will wait for " timeout " seconds ...." if Sockioctl(socket,'FIONBIO',1) = -1 then /* switch to nonblocking mode */ Return timeoutmess||'crashed in ioctl 'errno ict=0 ok=0 incoming='' Do While TimeOut > 0 res=Sockrecv(socket,'data',1000) if res=-1 then do /* error condition ? */ If errno <> 'EWOULDBLOCK' THEN /* real crash ? */ Then Return timeoutmess||'crashed in sockrecv 'errno /* yes */ /* not-fatal,no-data-available-condition: errno = EWOULDBLOCK & sockrecv returned -1 */ ict=ict+1 if verbose=1 then say 'SockIn: Waiting ('ict')...' Call SysSleep 1 /* relinquish the CPU for one second, this is from REXXUTIL */ TimeOut = TimeOut - 1; /* count down my timer */ Iterate; /* loop again */ End; /* if sockrecv = -1 */ if res=0 then do ok=1 ; leave /* got end of message, so exit this do loop*/ end if res<0 then do return timeoutmess||" Error in sockrecv " rc end incoming=incoming||data if verbose=1 then say "SockIn: total data recieved: "length(incoming) if length(incoming)>maxlen then do ok=2 leave end ict=0 /* reset counter */ End /* do while timeout > 0 */ /* here we are timed out, or got entire message */ if ok=1 then do If sockioctl(socket,'FIONBIO',0) = -1 then do /* switch to blocking mode */ if verbose=1 then say 'SockIn: ioctl error on switch to blocking mode: ' errno end return incoming /* success! */ end if ok=2 then do if sockioctl(socket,'FIONBIO',0) = -1 then do /* switch to blocking mode */ if verbose=1 then say 'SockIn: ioctl error on switch to blocking mode: ' errno end Return timeoutmess||' message length exceeds maximum of 'maxlen end Return timeoutmess||' timeout '