Janus Sockets User Language coding considerations
Other Janus products are implemented with algorithms built in to the Sirius Mods to handle the underlying complexity of the incoming and outgoing data. That is, the User Language application is written against well-defined structures, like row-and-column data for Janus Open Server, or HTTP header or form field values for Janus Web Server.
Janus Sockets is different. A socket is generic by design and will allow any sort of data to be passed back and forth. Janus Sockets simply provides the TCP/IP packet handling, buffering and some translation services, and the User Language application is written to handle whatever comes wrapped in the packet. You could, for example, write a web server using Janus Sockets, but the User Language programs would have to handle all the complexity of the HTTP packets. As a rule, Janus Sockets is targeted at more specific services, not general functions like web service.
Defining a port
Before you can use the Janus Sockets $functions or Socket object methods can be used, you must define a Janus port. Janus Sockets applications that originate inside the Model 204 Online require a Janus Sockets client port (CLSOCK). Janus applications that will respond to incoming requests require a Janus Sockets server port (SRVSOCK).
* Specify the domain: JANUS DOMAIN sirius-software.com * Specify the location of the name server: JANUS NAMESERVER 184.108.40.206 * Define a client sockets port: JANUS DEFINE SOCKEM * CLSOCK 5 REMOTE * 80 * Define a server sockets port at port 1234: JANUS DEFINE SERVEM 1234 SRVSOCK 5 CMD SERVPGM * Make the ports available: JANUS START SOCKEM JANUS START SERVEM
Once the port is defined, you reference it in User Language programs using the Janus Sockets $functions or object methods. Whether for a client socket application or a server socket application, the way you use $function or method is nearly the same (unlike other Janus products, where the client and server processes use distinct sets of $functions or methods).
Comparing Client and Server socket programming
As mentioned above, client and server socket programs are nearly identical. The only differences are:
- A client socket must be connected by a "connect" $function ($Sock_Conn) or Socket object New method. A server socket is already connected when the server CMD begins processing.
- Client and server socket objects are identified by number if using $functions, or by object variables if using Socket object methods. If $functions, the socket number for the server socket is 1; the socket number for a client socket is returned by the $Sock_Conn function, as the next unused socket number in the range 2 through max, where max is the value of the SOCKMAX Model 204 system parameter.
- NOCLOSE, the default setting for a server socket, allows the socket to stay in use across User Language requests. The default for a client socket is CLOSE. This setting can be changed by specifying CLOSE or NOCLOSE on the $Sock_Set function (but not on the Socket method Set).
- Some $function ($Sock_Info and $Sock_Set) and Socket method (Info and Set) parameters are valid only for SRVSOCK ports, and some are valid only for CLSOCK ports. For example, AUDTERM is only valid for SRVSOCK ports.
Except for these differences, sending and receiving data and all other operations on client and server sockets are identical.
Note that a User Language program that acts as a socket server application (that is, which can use socket number 1 or a socket instantiated with the Socket method GetSocketObject) can also connect to client socket ports, thus being at the same time a server socket and client socket application.
Determine if executing as SRVSOCK
Since socket number 1 is used for the server socket, the following example shows how an application that might run in multiple contexts can determine whether it is invoked for a SRVSOCK connection:
Begin If $word($sock_num, , 1) Eq 1 Then ... UL code executed when running as SRVSOCK End If ...
If the application is using Socket methods, the presence of the ServerSocket method, which obtains a reference to a Socket object for the server socket, leads to the server socket object variable.
Socket states: OPEN, RESET, FIN indicator
When you use a socket for communicating with a remote partner, the socket can be in one of multiple states, and the state determines the socket operations that can succeed. After a socket connection is established, the socket exists, and the term in-use appies to such a socket. The term "socket" is typically equivalent to using the term "in-use socket."
When your application has completed all its work with a socket, it should invoke the $Sock_Close function or the Socket method Close). After $Sock_Close, the socket number is no longer in-use; after Close, the socket connection is closed, and the socket object is discarded.
When all information about a socket is available, the connection exists, and most of the socket operations can be accomplished, the socket is said to be in the OPEN state, or, more correctly, in one of the OPEN states.
If, after a socket connection is established, the connection is lost but the socket is still in-use, the socket is said to be in the RESET state. In this state, much of the information about the socket (for example, the remote host name and port number) is no longer available, and the only completely meaningful operation for the socket is $Sock_Close or the Close method. However, as described in "Handling connection errors and RESET sockets", some operations and some situations allow you to use a RESET socket's socket number with certain Janus Sockets $functions, or to use a RESET socket object with certain methods.
As stated above, saying that a socket is OPEN actually refers to a set of socket states. Among these states, the use of the FIN indicator is significant. You use the FIN option of the $Sock_Send and $Sock_SendLn functions, or of the Send and SendWithLineEnd methods, to specify that your application will no longer send any data on the socket.
Similarly, the remote partner on a socket may have sent the FIN indicator. After your application has received all data on that socket, and then requested additional data, $Sock_Recv or $Sock_RecvPrs, or the Receive and ReceiveAndParse methods, will indicate that the FIN indication was received. In these case, the socket is still OPEN, but it is in one of three states:
- FINS (no more data will be sent)
- FINR (no more data will be received)
- FINBOTH (no more data will be sent or received)
Invalid $function or method invocation: request cancelled
Many Janus Sockets $functions and methods have restrictions about the supplied arguments. If your User Language program violates these restrictions, the request is cancelled. Some examples of this are:
- Most of the Janus Sockets $functions require an in-use socket number (a value returned by $Sock_Conn, or the special socket number 1 for the inbound connection on a SRVSOCK port) as the first argument. If you provide an argument that is not an in-use socket number, the request is cancelled.
- Many $functions and methods allow an optional argument string to control the operation of the $function or method. For example, $Sock_Send and the Send method allow the options BINARY, FIN, and other strings. If you invoke $Sock_Send or Send with an invalid string for its optional argument, the request is cancelled.
- Janus Sockets $functions and methods are dependent on the state of a socket
only when the state is FINS or FINBOTH.
After sending the FIN indicator on a socket, invoking
$Sock_Send, $Sock_SendLn, or
$Sock_Capture(socket, 'ON')for the socket, or invoking their counterpart methods Send, SendWithLineEnd, or Capture, is another form of programming error, and the request is cancelled.
Handling connection errors and RESET sockets
Other than invalid arguments to a Janus Sockets $function or method, which always cancel the request, there are other situations that are less under the control of the User Language programmer.
CLSOCK (that is, outbound or active) connections, must be established using the $Sock_Conn function or the Socket method New. If the $function is successful, it returns a positive number (called the socket number or socket identifier), which can be used by the other Janus Sockets $functions. If the New method is successful, it returns the positive number one.
A number of situations may prevent $Sock_Conn or New from succeeding: for example, there may not be a JANUS CLSOCK rule in place to allow access to the local port (the first argument of $Sock_Conn and New). Such errors are indicated by a negative value returned by $Sock_Conn or by a null object returned by the New method. The New method also returns error information to $STATUSD that can be queried. For both $Sock_Conn and New, an error message is also returned to the terminal (which you may suppress, as mentioned in the $Sock_Conn and New method individual descriptions).
Once a socket is successfully connected, either via $Sock_Conn or the New method (for a CLSOCK port), or is socket number 1 or an object assigned by the ServerSocket method (if your program is running as part of the CMD processing of a SRVSOCK port), you have several choices for how to handle a socket in the RESET state. Specifying an ONRESET action in a $Sock_Set or Set method call, you determine what (most) Janus Sockets $functions or methods will do if they encounter a RESET socket:
- Jump to a reset handling label.
- Cancel the request.
- CONTINUE the request with the next statement after the $function or method invocation, and return an error indicator.
In some cases, a Janus Sockets $function or method can perform its operation completely, regardless of the state of the socket. You can further refine the RESET handling action for a socket to specify:
- In cases where the request can be performed completely, the request should continue to the next statement.
- In cases where the request cannot be performed completely, the jump label or cancel action should be performed.
Thus, the full set of ONRESET actions is:
|CANCEL||Cancel the request if a RESET socket is encountered.|
|CANCELC||Cancel the request if a RESET socket is encountered, unless the operation is one that can be completely performed — in which case, continue to the next statement.|
|CONTINUE||Continue to the next statement if a RESET socket is encountered.|
|LABEL||Jump to the active ONRESET label if a RESET socket is encountered. If no ONRESET label is active, cancel the request.|
|LABELC||If the operation is one that can be completely performed, continue to the next statement if a RESET socket is encountered. Otherwise, jump to the active ONRESET label if a RESET socket is encountered; if no ONRESET label is active,
cancel the request.
- The jump label option requires that you make a jump label active for the request using $Sock_OnReset or using the OnReset method. Until and unless a label is active, the label action default is to cancel the request.
- Using an ONRESET label (or request cancellation with an APSY error procedure) is a good way to centralize all of an application's sockets error handling. Details about the error can be retrieved in the APSY error procedure or at the ONRESET label (using $Sock_ErrInfo or the ErrInfo method).
- As with any request cancellation, if a request is running in APSY, the error procedure is included.
- A socket RESET condition may be encountered by a User Language print operation (when print is captured) rather than by a Janus Sockets $function or method invocation. In this case, the same error handling mechanisms apply, although, of course, the print operation does not "return" any Janus Sockets error indicator.
- A socket RESET condition may be encountered outside a User Language request, when print is captured and a Model 204 command produces print output. In this case, if cancel (or a jump label) is in effect for a capturing socket, a counting error message is issued.
Operations unaffected by RESET sockets
Some Janus Sockets $functions and methods are not affected by RESET situations or do not follow the ONRESET setting that is in effect:
- Some Janus Sockets functions, such as $Sock_Num, do not have a socket number argument, hence will not encounter a RESET socket, and hence are not affected by any ONRESET setting nor will they return error indicators nor set the last error information.
- The Socket methods equivalent to the $functions that do not have a socket number argument are shared methods that will not encounter a RESET socket, are not affected by any ONRESET setting, will not return error indicators, and will not set the last error information.
- Janus Sockets $functions that may be invoked with -1 (meaning "all sockets"),
$sock_capture(-1...), do not encounter a RESET socket. They will always continue to the next statement with no indication of error.
- If the following Janus Sockets $unctions or methods encounter a RESET socket,
they will always continue to the next statement, and they will not set the last socket error information:
- $Sock_Close or the Close method
- $Sock_Info with an ONRESET argument, or the Info method with an ONRESET argument
$Sock_Set(socknum, 'ONRESET', action), or the Set method with an ONRESET argument
Error information for a RESET socket condition
Excepting these cases, when a RESET socket is encountered:
- The "last socket error" information is always set. The socket number, $function name, and error code number of the latest Janus Sockets $function that could not completely succeed can be obtained by $Sock_ErrInfo or by the ErrInfo method.
- If the request continues at the next statement after the $function (neither ONRESET CANCEL nor ONRESET LABEL is in effect), an error indication is returned. The exceptions to this are $Sock_Tran_In and $Sock_Tran_Out and their method counterparts TranIn and TranOut. These exceptions return the translated string; they do not return an error indication.
The documentation for each Janus Sockets $function and method states the error indicator it returns if continuation is in effect. If continuation is in effect, and if the operation can be completely performed for a RESET socket, the documentation states that continuation is in effect if either CANCELC or LABELC is in effect.
Socket parameters and settings
A number of values control the operation of a socket. Typically, the $Sock_Set function or the Set method is used to change these values. The $Sock_Capture function or the Capture method is used to change the print capture setting.
The print capture setting, and all of the values that can be changed with $Sock_Set or Set, can be examined with the $Sock_Info function or the Info method (which also allow viewing some special values that cannot be changed). Information about the certificate provided by a remote partner (if you are using Janus Network Security) can be examined with $Sock_Cert_Levels and $Sock_Cert_Info, or by their method counterparts CertLevels and CertInfo.
Some socket settings, for example LINEND, are the same as parameters on the JANUS DEFINE command for the port that is used when the socket connection is made. These values are referred to as socket parameters, or, when it is clear that the context of the discussion is about parameters on a JANUS DEFINE command, simply as parameters. The initial setting of a socket parameter is the value specified for the parameter on the socket's associated JANUS DEFINE command. If no explicit value is specified, the socket's initial setting is the default value of that JANUS DEFINE parameter.
Additionally, some values that control a socket's operation can only be set (with $Sock_Set or with the Set method) after a connection is made. RECVLIM is an example. In this documentation, these values are referred to as socket settings. The principal purpose of this distinction is to remind you (if you need to set one of these values for an application) whether you may simply use the port definition to set the value.
Janus Sockets and Longstrings
All Janus Sockets $functions and Janus SOAP object methods are Longstring capable. Longstring capable basically means these things:
- Any Janus Sockets $function or Janus SOAP method that returns a string value might return a Longstring value. Some $functions (such as $Sock_Set) never will, but others (such as $Sock_Tran_In) definitely will under certain circumstances.
- The result of any Janus Sockets $function or Janus SOAP method that returns a string value will be treated as a Longstring for expression-processing purposes.
- All string arguments will be treated as Longstrings for expression-processing purposes, even though in some cases (such as $Sock_Set or $Sock_Capture) all valid values have length less than 255.
- In many cases (such as $Sock_Send and $Sock_URL_Encode), Longstrings
with length greater than 255 are accepted as input.
For example, without Longstring support, the following statement
would only send the first 255 bytes of the concatenation of
%bif it was longer:
%rc = $sock_send(%sock, %a With %b)