1
0
mirror of https://github.com/GeorgeMcMullen/rxIRC.git synced 2026-05-08 16:57:34 +00:00
Files
GeorgeMcMullen.rxIRC/vm.modules/rxsocket.read-me
2013-06-08 16:34:24 -07:00

609 lines
20 KiB
Plaintext

TCP/IP Socket support function for REXX (Rxsocket & Rexxwait)
Arty Ecock <eckcu@cunyvm.cuny.edu>
CUNY
Last revised: 17 February 1993
This file contains tips for converting applications from
RXSOCKET Version 1 to RXSOCKET Version 2.
A word about defaults:
----------------------
RXSOCKET Version 2 reads the TCPIP DATA file in order to establish
non-default values for such things as the TCP/IP server userid,
the Name Server IP addresses to use for name resolution, the local
Domain Origin, Resolver Timeout value, etc.
If the TCPIP DATA file is *NOT* available, the following defaults are
used:
TCPIPuserid TCPIP
HostName (the value returned from the TCPIP server)
DomainOrigin (null string)
NSinterAddr 14.0.0.0
NSportAddr 53
ResolveVia UDP
ResolverTimeout 30
ResolverUdpRetries 1 (not fully supported; soon, though)
The value of "TCPIPuserid" can be overridden by specifying a value for
the fourth argument of an "Initialize" subfunction:
Parse Value Socket('Initialize', 'Test', 40, 'TCPIPTST') With rc ...
-or-
Parse Value Socket('Initialize', 'Test', ,'TCPIPTST') With rc ...
RXSOCKET Version 2 uses a specific hierarchy when searching for an
appropriate set of ASCII/EBCDIC translate tables. Using the example
"Initialize" subfunction above, the following translate tables are
sought: (the first table found is used)
1) "TEST TCPXLBIN *". Note that the socket-set name "Test" has
been upper-cased.
2) If not found, RXSOCKET searches for "userid TCPXLBIN *", where
"userid" is the VM userid using RXSOCKET.
3) If not found, RXSOCKET searches for "STANDARD TCPXLBIN *".
(STANDARD TCPXLBIN is usually supplied with VM TCP/IP on the
TCPMAINT 592 minidisk.)
4) Then "RXSOCKET TCPXLBIN *". These tables are *IDENTICAL* to
the tables that are hard-coded into RXSOCKET.
RXSOCKET TCPXLATE contains the source version of these translate
tables. This file is converted to RXSOCKET TCPXLBIN by using the
CONVXLAT MODULE supplied with TCP/IP (on the TCPMAINT 592 disk).
RXSOCKET TCPXLATE and STANDARD TCPXLATE can be used as templates
for cistomizing your own translate tables.
5) If none of these tables are found, an internal set of ASCII/EBCDIC
translate tables are used.
STANDARD TCPXLBIN is usually suitable for most applications. Problems
with square brackets, for example, can usually be overcome by creating
a customized TCPXLBIN file.
A word about the format of the new result string:
-------------------------------------------------
In RXSOCKET, the result of a SOCKET function call is always a character
string. This string usually contains several items. The first item
will always be a return code value. A return code of "0" indicates that
the function call completed without error. The remaining items in the
result string contain function-specific values.
Example 1:
Parse Value Socket('Initialize', 'Test') With rc sockset count server
might yield:
rc = "0" Return code "0" (Success)
sockset = "Test" The name of this socket-set
count = "40" Default number of sockets available
server = "TCPIP" Default TCP/IP server userid
Example 2:
Call Socket 'Initialize', 'Test'
Parse Var result rc sockset count server
should yield the same values. (Remember that the "result" variable
is set by REXX when you "Call" a REXX function.)
If the return code value is other than "0", an error is indicated. In
such a case, the second item in the result string corresponds to an
"Errno Value" as described in Chapter 3 of the IBM TCP/IP Programmer's
Reference manual. "EBADF", "EWOULDBLOCK", "EFAULT", "ENOPROTOOPT" and
"EINVALIDRXSOCKETCALL" are a few of the possible values. The remaining
items (words) of the result string describe the error in more
understandable terms (I hope).
Examples:
"9 EBADF Bad file number"
"35 EWOULDBLOCK Operation would block"
"36 EINPROGRESS Operation now in progress"
"60 ETIMEDOUT Connection timed out"
"61 ECONNREFUSED Connection refused"
Note that rc=36 is not necessarily an error condition.
"EINPROGRESS" may be returned for certain operations on non-blocking
sockets.
See Chapter 3 of the IBM TCP/IP Programmer's Reference manual for
information on which "Errno Values" correspond to which socket calls.
Thus, you must take care when parsing the result of a RXSOCKET
subfunction. Using a trailing "." on a "Parse" statement may cause
you to lose the descriptive text in the case of an error.
Example 1:
Parse Value Socket('Close', socket) With rc .
If "rc" was not "0" then the "Errno Value" and descriptive text of
the error will be lost.
Example 2:
Parse Value Socket('Close', socket) With rc rest
In this case, the "rest" variable will contain both
"Errno Value" and descriptive text when rc is not "0".
Example 3:
Parse Value Socket('Close', socket) With result
Parse Var result rc .
If rc^=0 Then Do
Parse Var result errno errno_value errno_text
...
End
-or-
Call Socket 'Close', socket
Parse Var result rc .
If rc^=0 Then Do
Parse Var result errno errno_value errno_text
...
End
This is fine if you like to use many "Parse" statements.
Example 4:
Parse Value Socket('Close', socket) With result
If Word(result,1)^=0 Then Do
Say TcpError("Error during Close")
Call Exit
End
-or-
Parse Value Socket('Close', socket) With rc .
If rc^=0 Then Do
Say TcpError("Error during Close")
Call Exit
End
The former is nice, but the latter is my personal favorite.
The "TcpError" call in this example would yield:
"Error during Close:" errno_text
where "errno_text" is the descriptive text associated with the
errno value.
Example:
"Error during Close: Bad file number"
There's also less parsing, fuss, and mess with this example.
Comparison of RXSOCKET Version 2 functions to Version 1
-------------------------------------------------------
The Version 2 function and result string will be listed first,
followed by the Version 1 function call.
function: Socket('Initialize', subtaskid, <maxdesc>, <serverid>)
result: rc subtaskid maxdesc serverid
Version1: rc = Socket('Initialize', subtaskid, serverid, maxdesc)
Note: "maxdesc" and "serverid" have swapped places in
RXSOCKET Version 2.
"rc" is no longer set to the "maxdesc" value.
function: Socket('Accept', socket)
result: rc newsocket name
Version1: rc = Socket('Accept', socket, name)
Note: "name" has been moved into the result string.
"name" is now returned as "AF_INET port nnn.nnn.nnn.nnn".
"rc" is no longer set to the "newsocket" number.
function: Socket('Bind', socket, name)
result: rc
Version1: rc = Socket('Bind', socket, name)
Note: "name" is now specified as "AF_INET port ipaddr|hostname"
Examples:
"AF_INET INPORT_ANY CUNYVM"
"AF_INET 123 CUNYVM.CUNY.EDU"
"AF_INET 0 CUNYVM.CUNY.EDU"
"AF_INET 42 128.228.1.2"
"AF_INET 12 INADDR_ANY"
"AF_INET"
"AF_INET 77"
"AF_INET INPORT_ANY INADDR_ANY"
"AF_INET INPORT_ANY ANY"
"AF_INET ANY ANY"
"AF_INET 23 LOOPBACK"
"AF_INET INPORT_ANY INADDR_BROADCAST"
"AF_INET INPORT_ANY BROADCAST"
You get the idea :-)
function: Socket('Close', socket)
result: rc
Version1: rc = Socket('Close', socket)
function: Socket('Connect', socket, name)
result: rc
Version1: rc = Socket('Connect', socket, name)
Note: "name" is now specified as "AF_INET port ipaddr|hostname".
function: Socket('Fcntl', socket, cmd, <data>)
result: rc <data>
Version1: rc = Socket('Fcntl', socket, cmd, data)
Note: "Blocking" and "Non-Blocking" have been added as
permissible values for "data".
"rc" is no longer set to the value of "data" (in the
case of "F_GETFL").
function: Socket('GetClientId', <domain>)
result: rc clientid
Version1: rc = Socket('GetClientId', domain, clientid)
Note: "clientid" has been moved into the result string.
function: Socket('GetDomainName')
result: rc domain
No corresponding RXSOCKET Version 1 subfunction.
The Version 1 GetHostName used to append the domain
origin to the host name. The "GetDomainName" subfunction
has been added to return the domain origin string.
"GetHostName" has been changed to return just the host
name.
function: Socket('GetDTableSize') not implemented in RXSOCKET Version 2
Version1: rc = Socket('GetDTableSize')
The number of sockets for a specified socket set may be
obtained using the "SocketSetStatus" subfunction. The
number of sockets is also returned in the result string
of the "Initialize" subfunction.
function: Socket('GetHostByAddr', ipaddr)
result: rc hostname
Version1: rc = Socket('GetHostByAddr', hostaddr, hostname)
Note: "hostname" has been moved into the result string.
function: Socket('GetHostByName', hostname)
result: rc ipaddr1 ipaddr2 ... ipaddrN
Version1: rc = Socket('GetHostByName', hostname)
Note: "rc" is no longer set to the "ipaddr" value. The
result string may contain a list of "ipaddr" values.
If the specified hostname is not multi-homed, then
a single "ipaddr" value is returned (in the form:
"nnn.nnn.nnn.nnn").
function: Socket('GetHostId')
result: rc ipaddr
Version1: rc = Socket('GetHostId')
Note: "rc" is no longer set to the "ipaddr" value.
"ipaddr" is returned in the form "nnn.nnn.nnn.nnn".
function: Socket('GetHostName')
result: rc hostname
Version1: rc = Socket('GetHostName', hostname)
Note: "hostname" has been moved into the result string.
"hostname" is returned as the "HostName" value from
TCPIP DATA (or the value obtained from the TCPIP
server) *WITHOUT* the Domain Origin string appended.
function: Socket('GetPeerName', socket)
result: rc name
Version1: rc = Socket('GetPeerName', socket, name)
Note: "name" has been moved into the result string.
"name" is now returned as "AF_INET port nnn.nnn.nnn.nnn".
function: Socket('GetProtoByName', protocol_name)
result: rc protocol_number
No corresponding RXSOCKET Version 1 subfunction.
function: Socket('GetProtoByNumber', protocol_number)
result: rc protocol_name
No corresponding RXSOCKET Version 1 subfunction.
function: Socket('GetServByName', service_name, <service_protocol>)
result: rc service_name service_port service_protocol
No corresponding RXSOCKET Version 1 subfunction.
*All* values listed in RFC1340 for "service_name" are
supported. See "well known ports" in RFC1340.
function: Socket('GetServByPort', service_port, <service_protocol>)
result: rc service_name service_port service_protocol
No corresponding RXSOCKET Version 1 subfunction.
*All* values listed in RFC1340 for "service_port" are
supported. See "well known ports" in RFC1340.
function: Socket('GetSockName', socket)
result: rc name
Version1: rc = Socket('GetSockName', socket, name)
Note: "name" has been moved into the result string.
"name" is now returned as "AF_INET port nnn.nnn.nnn.nnn".
function: Socket('GetSockOpt', socket, level, optname)
result: rc optval
Version1: rc = Socket('GetSockOpt', socket, level, optname, optval)
Note: "optval" has been moved into the result string.
Values for "optval" are now returned in a more
human-usable format.
function: Socket('GiveSocket', socket, clientid)
result: rc
Version1: rc = Socket('GiveSocket', socket, clientid)
Note: This subfunction now works.
"clientid" is now specified as "AF_INET subtaskid userid".
function: Socket('Ioctl', socket, cmd, <data>)
result: rc <data>
Version1: rc = Socket('Ioctl', socket, cmd, data)
Note: This subfunction now works.
Values for "data" are now accepted and returned in a
more human-usable format.
function: Socket('Listen', socket, <backlog>)
result: rc
Version1: rc = Socket('Listen', socket, backlog)
Note: "backlog" now defaults to "10".
function: Socket('Path') removed from RXSOCKET Version 2
Version1: rc = Socket('Path', subtaskid)
Note: This function has been renamed to "SocketSet".
function: Socket('Read', socket, <length>)
result: rc length data
Version1: rc = Socket('Read', socket, data, length)
Note: "rc" is no longer set to the number of bytes read.
"length" defaults to "10000", with a maximum value
of "100000".
"data" has been moved into the result string.
function: Socket('Recv', socket, <length>, <flags>)
result: rc length data
Version1: rc = Socket('Recv', socket, data, length, flags)
Note: "rc" is no longer set to the number of bytes read.
"length" defaults to "10000", with a maximum value
of "100000".
"data" has been moved into the result string.
"flags" may now contain more than a single value.
function: Socket('RecvFrom', socket, <length>, <flags>)
result: rc name length data
Version1: rc = Socket('RecvFrom', socket, data, length, flags, name)
Note: "rc" is no longer set to the number of bytes read.
"length" defaults to "10000", with a maximum value
of "100000".
"data" has been moved into the result string.
"name" has been moved into the result string.
"flags" may now contain more than a single value.
function: Socket('Resolve', ipaddr|hostname, <timeout>)
result: rc ipaddr hostname
No corresponding RXSOCKET Version 1 subfunction.
Note: I use "Resolve" instead of "GetHostByAddr" and
"GetHostByName" since "Resolve" does not care
whether its input is an IP address or a hostname.
"timeout" allows you to override the "ResolverTimeout"
value in TCPIP DATA.
function: Socket('Select', 'Read n Write n Exception n', <timeout>)
result: rc numready READ n n WRITE n n n EXCEPTION n
Version1: rc = Socket('Select', nfds, rmask, wmask, xmask, timeout)
Note: All the bitmask manipulation functions (FD_SET, FD_CLR,
etc.) have been removed.
Specifying "0" as a value for "n" still refers to the
console ("Read 0" means, "wait for a Console Attention").
REXXWAIT is far superior in function to "Select"
("Wait('Cons Time 5 Seconds Socket' socket 'SMSG')" is
certainly lots more versatile.)
"Select" is handy for applications that don't require
enhanced "wait" facilities.
function: Socket('Send', socket, data, <flags>)
result: rc length
Version1: rc = Socket('Send', socket, data, flags)
Note: "rc" is no longer set to the number of bytes transmitted.
function: Socket('SendTo', socket, data, <flags>, name)
result: rc length
Version1: rc = Socket('SendTo', socket, data, flags, name)
Note: "rc" is no longer set to the number of bytes transmitted.
"name" is now specified as "AF_INET port ipaddr|hostname".
function: Socket('SetSockOpt', socket, level, optname, optval)
result: rc
Version1: rc = Socket('SetSockOpt', socket, level, optname, optval)
Note: "optval" can now be expressed in a more human-usable
format.
An "optname" of "SO_ASCII" indicates that the data
flowing across the socket should be "ASCII". Please
note that RXSOCKET Version 1 used "SO_EBCDIC" for
this purpose. "SO_EBCDIC" now indicates that the
data flowing across the socket is EBCDIC and is to
be treated as such. "So_ASCII" set to "On" forces
data translation to and from EBCDIC (thus allowing
ASCII data to flow across the socket).
function: Socket('ShutDown', socket, <how>)
result: rc
Version1: rc = Socket('ShutDown', socket, how)
Note: "how" now defaults to "BOTH" (instead of "FROM").
function: Socket('Socket', <domain>, <type>, <protocol>)
result: rc newsocket
Version1: rc = Socket('Socket', domain, type, protocol)
Note: "rc" is no longer set to the value of "newsocket".
"domain" defaults to "AF_INET".
"type" defaults to "Sock_Stream".
"protocol" defaults to "IPPROTO_TCP".
function: Socket('SocketSet', <subtaskid>)
result: rc subtaskid
Version1: rc = Socket('Path', subtaskid)
Note: When switching to a new socket set, the name of the
previously active socket set is returned. This makes
it easier to switch back if switching between many
socket sets. If switching between 2 socket sets,
you needn't bother remembering the previously active
socket set name, since RXSOCKET maintains socket sets
on a push-down stack in Least Recently Used order.
function: Socket('SocketSetList')
result: rc subtaskid1 subtaskid2 ... subtaskidN
No corresponding RXSOCKET Version 1 subfunction.
function: Socket('SocketSetStatus', <subtaskid>)
result: rc subtaskid status <connectinfo>|<reason>
No corresponding RXSOCKET Version 1 subfunction.
function: Socket('TakeSocket', clientid, hissocket)
result: rc newsocket
Version1: rc = Socket('TakeSocket', clientid, hissocket)
Note: This subfunction now works.
"rc" is no longer set to the value of "newsocket".
"clientid" is now specified as "AF_INET subtaskid userid".
function: Socket('Terminate', <subtaskid>)
result: rc subtaskid
Version1: rc = Socket('Terminate', subtaskid)
Note: if "subtaskid" is omitted, the "active" socket set
is terminated. In any case, the name of the terminated
socket set is returned in the result string.
function: Socket('Version')
result: rc REXX/SOCKETS version date
rs = Socket('Version')
Note: "rs" is similar in format to the result string.
The associated "version" values. of course, differ.
function: Socket('Write', socket, data)
result: rc length
Version1: rc = Socket('Write', socket, data)
Note: "rc" is no longer set to the number of bytes transmitted.
A word from your sponsors:
--------------------------
Rainer and I worked long and hard on this collaboration. We hope it
was a successful one. We love feedback, comments and suggestions.
I personally prefer chocolate.
Please let us know if you run into any problems with REXX/SOCKETS.
Cheers,
Arty Ecock - CUNY/UCC
Rainer Hauser - IBM, Zurich