Using SM32 in Multi User and Enterprise Environment

Overview

In general there are 2 configuartion types of Multi User SM32, they are FAT and THIN Clients. Both use the same SM32.EXE on the desktop. In general the only files that are distributed to the client desktop (both FAT and THIN) are SM32.EXE and SM32.SM32 config file. To better understand multi user configurations consider the following single user SM32 diagram:

Fat Client

Under SM32 the term FAT client means that most if not all SM32 programs are executed by the desktop computer. Programs and data are normally accessed via a Remote File Server in stead of the Local File Server. This is accomplished by using a ROUTE. The default route (no route # in the pathname) is the Local File Server. Other routes can be established using the
ROUTE command but normally routes are established in the configuration and then never changed. The route number is then used in the SETDISK command or in the configuration setdisks.


The following is a sample of setting differences between a single user environment an a multi user environment running the same set of programs. The sample uses a Remote File Server running on a Linux Server serving port # 5000.
Property
PAGE -SETTING
Single UserMulti UserFunctionality
System-
# of Programs in Disk Cache
0100 Establishes program disk caching in C:\SM32CACHE on the client PC. The 100 most recently used programs will be cached. When a program is accessed from the cache and it's header has not been verified in the last 2 hours (7200 seconds), the program header is retrieved from the File Server. If the retrieved program header indicates the program has been modified it is reloaded. Only one instance SM32 can be using any single cache directory at any single time.
System-
Expire Seconds
07200
System-
Cache Directory
 C:\SM32CACHE
Network-
ROUTE:
 0,2,"192.168.1.3:5000" Establish Route # 0 to Remote File Server
Disk I/O-
SETDISK:
0,"PROGS"
1,"DATA"
9,"UTIL"
0,"<0>/u/net/PROGS"
1,"<0>/u/net/DATA"
9,"<0>/u/net/UTIL"
do the SETDISK's

Temporary files are normally located on the PC using the Local File Server.

File Server

The File Server is distributed as SM32FS.EXE for windows and sm32fs for linux.

Windows

Windows supports 2 connection types:
Type 1 - Named Pipes
Type 2 - TCP/IP Sockets
SM32FS.EXE is installed from a console mode prompt as follows:
sm32fs -install max_connections connection_type type_param {root_directory}
The install installs and starts a windows service.
Examples:
sm32fs -install 64 2 5010 C:\SM32FS
    Maximum clients is 64
    Socket type connection serving port 5010
    No file access outside of C:\SM32FS and its subdirectories
ROUTE command to connect:
ROUTE 0,2,"192.168.1.3:5010"
if server IP is 192.168.1.3

sm32fs -install 50 1 \\.\pipe\SM32FS C:\SM32FS
    Maximum clients is 50
    Named Pipe type connection Pipe Name SM32FS
    No file access outside of C:\SM32FS and its subdirectories
ROUTE command to connect:
ROUTE 0,1,"\\MYSERVER\pipe\SM32FS"
if server name is MYSERVER
The service can be uninstalled with:
sm32fs -remove

Linux

Linux only supports the Socket type connection:
The following line could be added to /etc/rc.d to start sm32fs at boot time.
(cd /u ; /usr/bin/sm32fs 50 2 5000 /u)
    Maximum clients is 50
    Socket type connection serving port 5000
    No file access outside of /u and its subdirectories

Thin Client

#!/bin/sh (cd /u ; su -c "/usr/bin/sm32fs 50 2 5000 /u" chris) (cd /u ;/usr/bin/sm32server 5001)

SM32 Pipes

SM32 Pipes allow multiple SM32 user programs (clients) to communicate with an SM32 server program. The pipes use standard SM32 I/O. They are not intended to be used to communicate with non-sm32 programs (SEE
SOCKET for this purpose). SM32 Pipes are implimented using TCP/IP sockets but are less complex for the SM32 programmer to impliment.

There are 2 things to define to get started:
1. A port number usually 5000->9999 are available
2. Choose a location to define the "PIPE" file that the server and all clients have access to. This would mean a directory share or a ROUTE.
PIPE "MYPIPE",6000,4
Where SETDISK #4 is something like:
SETDISK 4,"\\MYSERVER\PUB\SHDISK"
or SETDISK 4,"<0>SHDISK"
Both the Server and the Clients must be able to OPEN "MYPIPE"

One thing should be made clear, "MYPIPE" is a disk file but it has nothing to with the PIPE I/O. It is only used to store the port # and the SERVERS IP address.

The SERVER opens the pipe:
100 OPEN(1,SERVER=#TRUE)"MYPIPE"

For the SERVER open SM32 checks that there is not already a SERVER and if not places the IP address of this user in the "MYPIPE" file. SM32 then starts SERVING the port and sets up to ACCEPT connections on the PORT.

A CLIENT opens the pipe:
100 OPEN(1)"MYPIPE"

For the CLIENT open SM32 checks the "MYPIPE" file to get the port # and the SERVER's IP address. If there is a SERVER SM32 CONNECT's to the SERVER if not the CONNECTion will be attempted at the 1st WRITE.

Consider the following 2 programs. (These are working programs you can cut and paste (use edit all) into SM32. You will need to do the PIPE define to test them.)

SERVER Program

0010 BEGIN 
0020 OPEN (1,SERVER=#true)"MYPIPE"
0030 READ (1)A,A$
0040 LET R=IND(1);REM "return response to connection R"
0050 IF A>=0 AND A<=2 THEN GOTO 0090
0060 LET A$="Invalid Request"
0070 WRITE (1,IND=R)A$
0080 GOTO 0030
0090 ON A GOSUB 1000,2000,3000
0100 WRITE (1,IND=R)A$
0110 GOTO 0030
1000 REM 1000 REQUEST # 0
1010 PRINT "request 0 - ",A$
1020 LET A$="Result of Request # 0"
1030 RETURN 
2000 REM 2000 REQUEST # 1
2010 PRINT "request 1 - ",A$
2020 LET A$="Result of Request # 1"
2030 RETURN 
3000 REM 3000 REQUEST # 2
3010 PRINT "request 2 - ",A$
3020 LET A$="Result of Request # 2"
3030 RETURN 

Client Program

0010 BEGIN 
0020 OPEN (1)"MYPIPE"
0030 INPUT "Enter Request (0->2):",A
0040 INPUT "Extra Request Data:",A$
0050 WRITE (1)A,A$
0060 READ (1)A$
0070 PRINT A$,'lf'
0080 GOTO 0030
This is an example of a trivial transaction server. It has no state information about the connection. It takes a request, handles it and returns a result.

The SM32 PIPE should have been called a FUNNEL as it contains multiple connections on one end and a single connection on the other. The first implimentation of the SM32 Pipe had no syntax for the SERVER to respond to CLIENT( the use of IND). In that version the SERVER was called the READER and the CLIENTs were called the WRITERs.


SM32 Sockets (TCP)

SM32 Sockets allow an SM32 program to act as a CLIENT or SERVER and communicate with any computer that supports TCP/IP sockets. The program on the other end of a connection may or may not be an SM32 program.
The
WAITIO was added to SM32 to allow an SM32 server program to PEND waiting for connections and/or incoming data on multiple connections.

The following 2 programs are logically equivalent to the SM32 pipe example.

SERVER Program

0010 BEGIN 
0100 REM 100,5
0105 LET M=2;REM max connections -1
0110 DIM C[M];REM max M+1 connections
0115 FOR I=0 TO M;LET C[I]=0;NEXT I
0120 KEEP_SERVING: 
0125 GOSUB GET_SCHAN
0130 IF S<>0 THEN GOTO 0145
0135 SOCKET (99,SERVER=#true)"6000";CLOSE (99);REM already M+1 connections
0140 GOTO KEEP_WAITING
0145 SOCKET (S,SERVER=#true)"6000"
0150 KEEP_WAITING: 
0155 WAITIO 3000
0160 FOR I=0 TO M
0165 IF C[I]=0 THEN GOTO 0255
0170 READ RECORD(C[I],SIZ=2,TIM=0,ERR=.+1)L$;GOTO 0195
0175 IF ERR=0 THEN GOTO 0255
0180 CLOSE (C[I]);LET C[I]=0
0185 IF S=0 THEN LET S=-1
0190 GOTO 0255
0195 LET L=DEC(L$)
0200 READ RECORD(C[I],SIZ=L)A$
0205 LET A=NUM(A$(1,1)),A$=A$(2)
0210 IF A>=0 AND A<=2 THEN GOTO 0235
0215 LET A$="Invalid Request"
0220 LET A$=BIN(LEN(A$),2)+A$
0225 WRITE RECORD(C[I])A$
0230 EXITTO 0160
0235 ON A GOSUB 1000,2000,3000
0240 LET A$=BIN(LEN(A$),2)+A$
0245 WRITE RECORD(C[I])A$
0250 EXITTO 0160
0255 NEXT I
0260 IF S=-1 THEN GOTO KEEP_SERVING
0265 IF S=0 THEN GOTO KEEP_WAITING
0270 LET C$=FID(S,ERR=.+1);GOTO 0280
0275 GOTO KEEP_WAITING
0280 FOR I=0 TO M
0285 IF C[I]<>0 THEN GOTO 0300
0290 LET C[I]=S;REM we are connectted
0295 EXITTO KEEP_SERVING
0300 NEXT I
0305 ESCAPE ;REM can' be here
1000 REM 1000 REQUEST # 0
1010 PRINT "request 0 - ",A$
1020 LET A$="Result of Request # 0"
1030 RETURN 
2000 REM 2000 REQUEST # 1
2010 PRINT "request 1 - ",A$
2020 LET A$="Result of Request # 1"
2030 RETURN 
3000 REM 3000 REQUEST # 2
3010 PRINT "request 2 - ",A$
3020 LET A$="Result of Request # 2"
3030 RETURN 
8000 REM 8000,5
8005 GET_SCHAN: 
8010 FOR I=0 TO M
8015 IF C[I]=0 THEN EXITTO 8035
8020 NEXT I
8025 LET S=0
8030 RETURN 
8035 LET S=UNT
8040 RETURN 

Client Program

0010 BEGIN 
0020 SOCKET (1)"192.168.1.100:6000"
0030 INPUT "Enter Request (0->2):",A
0040 INPUT "Extra Request Data:",A$
0050 LET B$=STR(A)
0060 LET A$=B$(1,1)+A$
0070 LET A$=BIN(LEN(A$),2)+A$
0080 WRITE RECORD(1)A$
0090 READ RECORD(1,SIZ=2)L$
0100 LET L=DEC(L$)
0110 READ RECORD(1,SIZ=L)A$
0120 PRINT A$,'lf'
0130 GOTO 0030
As can be seen by the number of lines of code the server program is quite a bit more complex than the PIPE example while client program is very similar.
The complexity arises from the server having to have a unit # for each connection. The server starts by having a 'SERVing' unit # that waits for a connections (S in the example). Once a connection is made the unit # is transformed into a 'CONNECTed' unit # (S is placed in the C[] - line 0290). The program detects that the 'SERVing' unit # has become a 'CONNECTed' unit # by using the FID function. The FID functions gives an error on a 'SERVing' unit # and returns the peers IP and PORT of a 'CONNECTed' unit # (line 0270). Because of this transformation of unit # type SM32 internally serves a port # once an initial serve has been made. This avoids missing a connection. Once maximum # of connections has been reached (M+1 in the example) the internal serving can be stopped by serving and then closing the serving unit #(line 0135). A WIATIO (line 0155) is used to wait for incoming data and connections. NOTE: ALL data MUST be read and any connection must be handled before returning to the WAITIO.

SM32 Sockets (UDP)

SM32 UDP Sockets allow an SM32 program to act as a CLIENT or SERVER and communicate with any computer that supports UDP sockets. UDP Sockets are a connectionless, unreliable datagram (record) protocol. In contrast TCP Sockets are a connection-oriented reliable byte stream.
Creatation:
0100 SOCKET(1,UDP=#true)"5555";REM serve udp port 5555
0200 SOCKET(2,UDP=#true)"";REM get a UDP socket

Reading:
0110 READRECORD(1)A$
Writing:
0210 WRITERECORD(2,IPA="192.168.1.1:5555")A$
0120 WRITERECORD(1)A$; REM send record to the last computer you received from.
Get Last Senders IP address:
0115 P$=IPA(1)


SEE:
CONNECT    RCALL    ROUTE    PIPE SOCKET WAITIO