## 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 User | Multi User | Functionality
--- | --- | --- | ---
System- # of Programs in Disk Cache | 0 | 100 | 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 | 0 | 7200
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