PROGRAMMING COMPONENTS FOR GOPHER SERVER

The Programming components needed by the gopher server delivery system are listed below:

Conventions for COBOL gopher "state-less" programming and testing is described within this paper using COBOL subroutines. "State-less" programming will fail if "logon" terminal programming techniques are used. The general strategy of gopher "state-less" programming consists of these points:

Gopher Report Transaction is defined as:

COBOL subprogram:

Always keep in mind that the response of YOUR program affects the ENTIRE performance of the gopher server!

+Passes socket actually is a disconnect and connect performed between the Gopher Unix gateway and HP server.

The "state-less" gopher design means that gopher requests are shared among many other concurrent requests. There is a limit to the number of concurrent gopher requests, so that the length of time any request takes directly affects the number of clients that get serviced. Target response times on the HPDEV machine should be under 6 seconds.

2. GOPHER Logon environment is shared by a collective library of report programs. Your new program affects every previous gopher program in this collective library in some way.

Global MPE logon resources must be used with discretion because there is only one logon server environment. "Global" resources are Inter-Process Communication (IPC) devices, such as Job Control Word (JCW's), MPE variables, temporary files, even permanent files if used as a temporary storage of information. If such files are needed, then the file names must be "unique" among all other concurrent gopher processes. This is accomplished using the Process Identification Number (PIN) of the executing program. PIN is obtained through the "PROCINFO()" MPE intrinsic call, then converted to ASCII and used as part of a file name.

Another option is to open a file as ",NEW" and close it with ";DEL". Files allocated in this manner are connected only to the open process since the close disposition of ;DEL doesn't catalog the file within any file domain. For example, a file EQuation could be setup within the server job as:

!FILE TEMPWORK,NEW;DEL;REC=-172,12,F,ASCII;DISC=8000;ACC=UPDATE

Multiple concurrent processes can OPEN this file equation and use their own unique version of it, even though the file name is the same for every process. This is sometimes tricky, because any FCLOSE on the file will DELETE it! Since COBOL "CLOSE" cannot be used to rewind this file without deleting it, you must use intrinsic "FCONTROL" with a code value of five (5 - rewind file) so that the file pointer can be re-positioned at the beginning of file (BOF) without using "CLOSE" (faster, also).

Don't use XL libraries that you know nothing about until the interactions between them are predictable. Try to isolate the particular routine needed and copy the routine within GOPHERXL.PUB, if possible. Otherwise, the server program will need to be re-linked with the additional library.

This strategy is needed to keep "state-less" load times short and interactions between routines predictable. SPT (System Performance Tool) software might be needed to determine what is being called within "XL" routines to determine these interactions.

3. You can't discount program "startup" time as a throwaway like you can on a terminal Logon. Startup time is included as part of the total GOPHER transaction time.

This rule generally applies to "XL" library software. Any kind of terminal based checking must be removed. Try to accomplish reporting goals within the constraints of the COBOL language, if possible.

COBOL LINKAGE FOR GOPHER SUBPROGRAMS

Write the application program as subprogram: $DYNAMIC,POST85. The parameter list will consist of:

     $CONTROL DYNAMIC

     ...

     You may declare any WORKING STORAGE needed within the program.

     ...

     010500 LINKAGE SECTION.

     010600

     010700 01  SOCKET-FILE                PIC S9(9) COMP. 

     011100 01  ND-SOC-SEC                 PIC X(10).

     011400 01  GOPHER-PLUS-FORM.

     011500     05  FILLER                 PIC X(04).

     010700 01  RETURN-STATUS              PIC S9(9) COMP. 

     012500

     012600 PROCEDURE DIVISION USING SOCKET-FILE

     012700                          ND-SOC-SEC

     012800                          GOPHER-PLUS-FORM

     013000                          RETURN-STATUS.



USING INTRINSIC "FCONTROL" TO REWIND A COBOL FILE



     010700 01  DUMMY                PIC X(04).

     012500

     012600 CALL INTRINSIC "FCONTROL"

     012700                   USING \SELECT-FILE-NAME\ *

     012800                         \5\

     013000                         DUMMY.

*By using the name contained within the COBOL "SELECT" statement, this name will translate into the required file number required by this intrinsic.

REPORTING ERRORS USING "DISPLAY" VERB

There are two lines of communication going on here. The first line is the network socket communication to the gopher client. The second line is the $STDLIST of the executing program.

When the "DISPLAY" verb is used, these messages are written to the $STDLIST of the GOPHER server job, which acts as a log file of exceptional conditions. So, when you encounter serious errors within your COBOL subroutine, details of the errors, such as IMAGE status codes, etc. should be written using the DISPLAY verb. The Gopher server job listing can be checked for these errors.

A freindly message lacking of techno-talk should be sent to the gopher client, such as: "Sorry, can't do the report right now, try later."

"SENDLINE" SOCKET PROCEDURE CALL

This socket I/O function is used to send ASCII text to gopher client. This function is an inhouse routine that can be modified on demand and behaves much like the COBOL "WRITE" statement.

012600 CALL "SENDLINE" USING \SOCKET-FILE\,

012700                       OUTPUT-LINE,

012701                       \LINE-SIZE\,

012800                       \ADVANCE-LINES\,

013000                       RETURN-STATUS.

Where: SOCKET-FILE: PIC S9(9) COMP. Socket passed by gopher server or zero. If zero (0) is passed, the socket output is printed to $STDLIST so that testing can be performed using a driver program (see below).

OUTPUT-LINE: Working storage buffer size of text sent to gopher client. Typically PIC X(80), can be PIC x(1) through X(256). You must pass the corresponding parameter "LINE-SIZE" indicating the buffer size of the output-line (see next parm).

NOTE: 99% of Gopher clients can display line sizes up to 80 characters. Line sizes greater than 80 may cause problems or truncation with some clients. The "official" gopher protocol supports line sizes no greater than 70 but the defacto standard is 80.

LINE-SIZE: PIC S9(9) COMP. Varies as the size of OUTPUT-LINE varies (for example, 80 for a line, or maybe 12 for a single field).

Allowed values: (0 thru 256). Individual lines are buffered within an internal buffer until the buffer fills up, then the entire buffer is sent to client as a single block. The proper method to send blank lines is to set LINE-SIZE to zero (0) and ADVANCE-LINES to the desired number of lines, so that trailing blanks need not be stripped and line feeds are generated on the output file. Otherwise, if a blank line of 80 is sent, the routine must burn CPU stripping 80 blanks.

This number cannot be larger than the declared Working Storage field size or a bounds violation could occur. It is best to compute the buffer size using the COBOL function "LENGTH" to be accurate.

EXAMPLE: Send an entire COBOL formatted line:

               COMPUTE LINE-SIZE = FUNCTION LENGTH(OUTPUT-LINE).

               CALL "SENDLINE" USING

                              \SOCKET-FILE\,

                              OUTPUT-LINE,

                              \LINE-SIZE\, 

                              \ADVANCE-LINES\,

                              RETURN-STATUS.

ADVANCE-LINES: PIC S9(9) COMP. If positive number, indicates number of lines to advance after trailing blanks are stripped from OUTPUT-LINE. If zero or a negative number, no lines are advanced and indicates number of trailing blanks remaining on OUTPUT-LINE, limited by LINE-SIZE.

RETURN-STATUS: PIC S9(9) COMP. Zero (0) if successful in writing. Otherwise, non-zero indicates an error.

OPERATIONAL NOTES:

If (0) is passed for SOCKET-FILE, output is printed to $STDLIST. This allows testing of the routine on a normal terminal or allows user terminal access using same gopher subprogram code. Otherwise, output is routed through Berkeley Socket call "SEND()" to gopher client.

This routine will strip trailing blanks from "OUTPUT-LINE" and append carriage return and line feed ASCII control characters to the line when "ADVANCE-LINES" is greater than (0) zero.

However, if "ADVANCE-LINES" is equal to zero (0) or less than zero (-1), no or line feed is appended. If zero is passed, all trailing blanks are stripped. If (-1...-n) is passed, all trailing blanks are stripped except the last blank or (...n) blanks. In this way, several individual fields can be concatenated together on the same line and the programmer can vary the number of blanks between fields when using negative numbers.

"FORMATLINE" PROCEDURE CALL

This function formats a line of text using up to five (5) parameters using HP/C format routines. See HP/C "sprintf" library function for details about how to specify format strings. The only format supported is the string format (%s and %000s, where 000 can be field length) wildcard.

Sample call showing five fields, returning a COBOL buffer:

014314     CALL "FORMATLINE"

014601       USING \COL-POS\, A-BUFFER,

014620             C-FORMAT, \CFMT-SIZE\,

014820             FIELD-1,  \FIELD-1-SIZE\,

014820             FIELD-2,  \FIELD-2-SIZE\,

014820             FIELD-3,  \FIELD-3-SIZE\,

014820             FIELD-4,  \FIELD-4-SIZE\,

014820             FIELD-5,  \FIELD-5-SIZE\,

015020       GIVING COL-POS.

Sample call showing two fields, internal buffering used:

014314     CALL "FORMATLINE"

014601       USING  \COL-POS\, \0\,

014620              C-FORMAT,  \CFMT-SIZE\,

014820              FIELD-1,   \FIELD-1-SIZE\,

014820              FIELD-2,   \FIELD-2-SIZE\,

014820              \0\,

015020       GIVING COL-POS.

Where:
COL-POS: PIC S9(9) COMP. Starting Column position on the output line of the entire string format, defined by "C-FORMAT".

A-BUFFER or \0\ PIC X(80) - PIC X(256). COBOL Buffer to hold formatted fields or \0\ to format the line directly into the internal "SENDLINE" buffer. However, to advance to the next line, you must call "SENDLINE" using a zero buffer size unless you want to append more text to the previous line.

For example:

               CALL "SENDLINE" USING \SOCKET-FILE\,

                         OUTPUT-LINE,

                         \0\, 

                         \ADVANCE-2-LINES\,

                         RETURN-STATUS.

Advances the current formatted buffer by two lines (resulting in one formatted line, followed by one blank line).

C-FORMAT, \C-FMT-SIZE\: C-FORMAT contains free text with string substitution markers. The parameters are formatted within the specified order. For example:

               MOVE "Date: %s" TO C-FORMAT.

               MOVE 60 to COL-POS.

               COMPUTE  CFMT-SIZE = FUNCTION

               LENGTH(C-FORMAT).

               COMPUTE  DATE-SIZE = FUNCTION LENGTH(A-DATE).



               CALL "FORMATLINE" USING \COL-POS\,\0\,

                    C-FORMAT, \CFMT-SIZE\,

                    A-DATE,   \DATE-SIZE\

               ....

Will output the literal:
"Date: 06/30/94"

starting at column 60 on the internal buffer output line. However, if the format is specified with a field length indicator (such as length 5):

"Date: %5s",

the output text would look like:

"Date: 06/30"

the "/94" would be truncated.

Sample program using "FORMATLINE" procedure:

000100$CONTROL DYNAMIC,POST85

002000 IDENTIFICATION DIVISION.

002100

002200 PROGRAM-ID.  TESTCOB.

002300 AUTHOR.

002700 DATE-WRITTEN.

002800 DATE-COMPILED.

003600 ENVIRONMENT DIVISION.

003800 CONFIGURATION SECTION.

004000 SOURCE-COMPUTER.  HP3000.

004100 OBJECT-COMPUTER.  HP3000.

005000 DATA DIVISION.

005800 WORKING-STORAGE SECTION.

006200 01  FIRSTNM                  PIC X(14) VALUE "Eric".

006202 01  MID                      PIC X(14) VALUE "James".

006204 01  LASTNM                   PIC X(20) VALUE "Schubert".

006206 01  THE-DATE                 PIC X(30) VALUE "6/28/94".

006210 01  C-FORMAT                 PIC X(80).

006400 01  LINE3                    PIC X(80) VALUE "line number 3".

006220 01  A-NUMBER                 PIC 9999V99 VALUE 12.56.

006221 01  A-BUFFER                 PIC X(120).

006230 01  A-EDIT                   PIC ZZZZ.99.

000660 01  DUMMY                    PIC X(4).

008510 01  FIRSTNM-SIZE             PIC S9(9) COMP VALUE 0.

008511 01  MID-SIZE                 PIC S9(9) COMP VALUE 0.

008512 01  LASTNM-SIZE              PIC S9(9) COMP VALUE 0.

008513 01  CFMT-SIZE                PIC S9(9) COMP VALUE 0.

008514 01  DATE-SIZE                PIC S9(9) COMP VALUE 0.

008514 01  A-BUF-SIZE               PIC S9(9) COMP VALUE 0.

008515 01  COL-POS                  PIC S9(9) COMP VALUE 1.

008516 01  ADV1-LINES               PIC S9(9) COMP VALUE 1.

008520 01  ADV2-LINES               PIC S9(9) COMP VALUE 2.

008600

010500 LINKAGE SECTION.

010700 01  SOCKET-FILE                  PIC S9(9) COMP.

010800 01  ND-SS                        PIC X(10).

010900 01  GOPHER-PLUS                  PIC X(4).

011300 01  RETURN-CODE                  PIC S9(9) COMP.

011700

012600 PROCEDURE DIVISION USING SOCKET-FILE

012700                          ND-SS

012800                          GOPHER-PLUS

013000                          RETURN-CODE.



014200 A100-MAINLINE.

014300     COMPUTE FIRSTNM-SIZE = FUNCTION LENGTH (FIRSTNM).

014302     COMPUTE   MID-SIZE = FUNCTION LENGTH (MID).

014303     COMPUTE  LASTNM-SIZE = FUNCTION LENGTH (LASTNM).

014304     COMPUTE  DATE-SIZE = FUNCTION LENGTH (THE-DATE).

014305     COMPUTE  CFMT-SIZE = FUNCTION LENGTH (C-FORMAT).

014305     COMPUTE  A-BUF-SIZE = FUNCTION LENGTH (A-BUFFER).



This section of code formats the line into "A-BUFFER" COBOL variable instead of

the "sendline" internal buffer.  Notice the returned COL-POS is used to start

appending the next string to the line.



014310     MOVE "My name is: '%s %s %s' the date is %s" TO C-FORMAT.

014311     MOVE 1 TO COL-POS.

014312     MOVE SPACES TO A-BUFFER.

014314     CALL "FORMATLINE"

014601       USING \COL-POS\,

014610             A-BUFFER,

014620             C-FORMAT, \CFMT-SIZE\,

014820             FIRSTNM,  \FIRSTNM-SIZE\,

014900             MID,      \MID-SIZE\,

015000             LASTNM,   \LASTNM-SIZE\,

015001             THE-DATE, \DATE-SIZE\,

015010             \0\,

015020       GIVING COL-POS.

015030

015031     MOVE " this gets appended" TO C-FORMAT.

015040     CALL "FORMATLINE"

015050       USING \COL-POS\,

015051             A-BUFFER,

015060             C-FORMAT,\CFMT-SIZE\,

015090             \0\,

015095       GIVING COL-POS.

015100

015110     CALL "SENDLINE"

015120       USING  \SOCKET-FILE\,

015141              A-BUFFER, \A-BUF-SIZE\,

015150              \ADV2-LINES\,

015160              RETURN-CODE.

015195

This section of code performs almost the same function but writes the lines into the internal "sendline" buffer. A zero must be passed within the "buffer" parm (second parm) to indicate not to return buffer to this COBOL program. However, "sendline" must be called to write the proper and line feed characters after the line is formatted.

015198

015199     MOVE "2My name is: '%s %s %s' the date is %s" TO C-FORMAT.

015201     CALL "FORMATLINE"

015202       USING \1\,

015203             \0\,

015204             C-FORMAT, \CFMT-SIZE\,

015205             FIRSTNM,  \FIRSTNM-SIZE\,

015206             MID,      \MID-SIZE\,

015207             LASTNM,   \LASTNM-SIZE\,

015208             THE-DATE, \DATE-SIZE\,

015209             \0\,

015210       GIVING COL-POS.

015211

015212     MOVE " this gets appended" TO C-FORMAT.

015213     CALL "FORMATLINE"

015214       USING \COL-POS\,

015215             \0\,

015216             C-FORMAT,\CFMT-SIZE\,

015217             \0\,

015218       GIVING COL-POS.

015219

015220     CALL "SENDLINE"

015221       USING  \SOCKET-FILE\,

015222              DUMMY, \0\,

015223              \ADV2-LINES\,

015224              RETURN-CODE.

015225

015226     GOBACK.

Sample program produces this output:
Machine Origin: schubert.adminis.nd.edu wed, jun 29, 1994, 2:58 pm
My name is: 'Eric James Schubert' the date is 6/28/94 this gets appended
2My name is: 'Eric James Schubert' the date is 6/28/94 this gets appended

SAMPLE RUN OF 'C' DRIVER PROGRAM FOR COBOL SUBROUTINES.

'C' program, name of driver source: COBOLCC Compile:

:CCXLLK COBOLCC,$newpass;info="-Aa -O"
:SAVE $OLDPASS,XCOBOLCC

Run test program. Library names contained within GOPHERXL.PUB must be entered in lower case. Otherwise, load errors will occur. Also see notice at end of this page on MPE caching.

:RUN XCOBOLCC;XL="GOPHERXL.PUB"

Enter Proc:testcob

-Load time is 757 Millisec

Enter SSN: 12345678
My name is: 'Eric James Schubert' the date is 6/28/94 this gets appended
2My name is: 'Eric James Schubert' the date is 6/28/94 this gets appended
-Response for testcob is 62 Millisec
-Total time (load & report) is 819 Millisec
:do

:xcobolcc

Enter Proc:testcob
-Load time is 141 Millisec
Enter SSN: 12345678
My name is: 'Eric James Schubert' the date is 6/28/94 this gets appended
2My name is: 'Eric James Schubert' the date is 6/28/94 this gets appended
-Response for testcob is 3 Millisec
-Total time (load & report) is 144 Millisec

NOTICE the difference between load times, the difference being MPE caching of the program module. The second time the program is run, MPE has a copy of the program within memory and takes little load time. So, when doing performance timings, always run the program twice and take the second time.

DECODING DRIVER PROGRAM LOAD ERRORS FOR COBOL SUBROUTINES.

If you encounter load errors other than -103 (module not found), use the following utility to decode the loader error message.

:RUN msgutil.pub.sys



************************************************************************

******      MSGUTIL  --  SYSTEM CATALOG MESSAGE DISPLAY UTILITY         

************************************************************************

---------------- INTERACTIVE MODE ----------------

                 M - Message display

                 T - Time display

                 E - Exit



Menu Selection > M

Enter SUBSYSTEM # [ = quit] > 44



NM LOADER ERROR MESSAGES



Enter MESSAGE # [ = quit] > 103



------------------------------------------------------------------------

DYNAMIC LOADING UNRESOLVED EXTERNAL:   ( LDRERR 103)

------------------------------------------------------------------------