Previous Topic: PL/I TCP/IP Client ProgramNext Topic: COBOL Examples


PL/I TCP/IP Generic Listener Server Program

 /*RETRIEVAL*/
 /*DMLIST*/

 /******************************************************************/
 /* The following program is an example of a TCP/IP generic        */
 /* listener server program written in PL/I.                       */
 /* The processing is the following:                               */
 /*  - read a message from the client (first 4 bytes = data length)*/
 /*  - send the message back to the client program                 */
 /*  - if the message text is equal to "STOP" or if the connection */
 /*    is closed, then it closes its socket and return to the      */
 /*    generic listener service.                                   */
 /*  - if the message text is not equal to "STOP", then it returns */
 /*    to the generic listener service without closing its socket. */
 /*                                                                */
 /* Notes for the PL/I compiler on VSE.                            */
 /*  - in order to allow arithmetic operations on POINTER type     */
 /*    variables, specify the LANGLVL(OS,SPROG) compiler option    */
 /*  - there is no option to allow external names on 8 characters, */
 /*    so replace all CALL IDMSOCKI by CALL IDMSOCK, as described  */
 /*    in the Callable Services manual.                            */
 /******************************************************************/

 PLILIS: PROC (P1, P2, P3)
           OPTIONS (REENTRANT,FETCHABLE);

 /******************************************************************/
 /* Parameter list with which a listener program receives control  */
 /******************************************************************/
  DCL (P1,P2,P3)          POINTER;
  DCL SOCKET_PARMS        CHAR(80)      BASED (ADDR(P1));
  DCL SOCKET_DESCRIPTOR   FIXED BIN(31) BASED (ADDR(P2));
  DCL SOCKET_RESUME_COUNT FIXED BIN(31) BASED (ADDR(P3));

  DCL MODE(IDMS_DC) DEBUG;
  DCL ADDR BUILTIN;
  DCL IDMSPLI  ENTRY OPTIONS(INTER,ASSEMBLER);
  DCL IDMSOCKI ENTRY OPTIONS(INTER,ASSEMBLER);
  DCL IDMSP    ENTRY;

  INCLUDE IDMS (SUBSCHEMA_CTRL);
  INCLUDE IDMS (SOCKET_CALL_INTERFACE);

  DCL 1 MSG01  CHAR (20) INIT (' Parameter string  :');
  DCL 1 MSG02  CHAR (20) INIT (' Socket descriptor :');
  DCL 1 MSG03  CHAR (20) INIT (' Resume count      :');
  DCL 1 MSG04  CHAR (15) INIT (' Starting read.');
  DCL 1 MSG05  CHAR (16) INIT (' Starting write.');
  DCL 1 MSG06  CHAR (16) INIT (' Closing socket.');
  DCL 1 MSG07  CHAR (20) INIT (' Socket return code:');
  DCL 1 MSG08  CHAR (20) INIT (' Socket reason code:');
  DCL 1 MSG09  CHAR (20) INIT (' Socket errno      :');
  DCL 1 MSG10  CHAR (20) INIT (' Buffer length     :');
  DCL 1 MSG11  CHAR (08) INIT (' Buffer:');
  DCL 1 MSG12  CHAR (22) INIT (' Data length too long.');

  DCL 1 RETLEN         FIXED BINARY(31);
  DCL 1 WK_LENGTH      FIXED BINARY(31);
  DCL 1 WK_PTR         POINTER;
  DCL 1 TEXT           CHAR(80) BASED(WK_PTR);
  DCL 1 TERM_FLAG      FIXED BINARY(31) INITIAL(0);

  DCL 1 BUFFER,
        3 BUFLEN       FIXED BINARY(31),
        3 BUFTXT80     CHAR(80);

  DCL 1 WORKW,
        3 WORK_WCC     CHAR(1),
        3 WORK         CHAR(80);

 /******************************************************************/
 /* Display the 3 input parameters                                 */
 /******************************************************************/
 /******************************************************************/
 /* Read the first 4 bytes: will contain the remaining length      */
 /******************************************************************/
 WK_LENGTH = 4;
 BUFLEN = 0;
 WK_PTR = ADDR(BUFLEN);
 CALL TCP_READ;
 IF (TERM_FLAG = 1) THEN RETURN;

 /******************************************************************/
 /* Read the remaining data (maximum 80 characters are allowed)    */
 /******************************************************************/
 IF (BUFLEN > 80)
   THEN DO;
     WRITE LOG MESSAGE ID (9060300)
       PARMS FROM (MSG12) LENGTH (22);
     CALL TCP_CLOSE;
     RETURN;
     END;

 WK_LENGTH = BUFLEN;
 WK_PTR = ADDR(BUFTXT80);
 CALL TCP_READ;
 IF (TERM_FLAG = 1) THEN RETURN;

 WORK = BUFLEN;
 WRITE LOG MESSAGE ID (9060300)
   PARMS FROM (MSG10) LENGTH (20)
         FROM (WORKW) LENGTH (15);
 WORK = BUFTXT80;
 WK_LENGTH = BUFLEN + 1;
 WRITE LOG MESSAGE ID (9060300)
   PARMS FROM (MSG11) LENGTH (8)
         FROM (WORKW) LENGTH (WK_LENGTH);

 /******************************************************************/
 /* Send the message back to the client                            */
 /******************************************************************/
 WK_LENGTH = BUFLEN + 4;
 WK_PTR = ADDR(BUFLEN);
 CALL TCP_WRITE;

 IF ((BUFLEN = 4) & (SUBSTR(BUFTXT80,1,4) = 'STOP'))
   THEN CALL TCP_CLOSE;

 RETURN;

 /******************************************************************/
 /* Procedure to read a message from the client                    */
 /******************************************************************/
 TCP_READ: PROC;
   WRITE LOG MESSAGE ID (9060300)
     PARMS FROM (MSG04) LENGTH (15);
   DO WHILE (WK_LENGTH > 0);
     CALL IDMSOCKI ( SOCKET_FUNCTION_READ,
                     SOCKET_RETCD,
                     SOCKET_ERRNO,
                     SOCKET_RSNCD,
                     SOCKET_DESCRIPTOR,
                     WK_PTR->TEXT,
                     WK_LENGTH,
                     RETLEN);
     WORK = SOCKET_RETCD;
     WRITE LOG MESSAGE ID (9060300)
       PARMS FROM (MSG07) LENGTH (20)
             FROM (WORKW) LENGTH (15);
     IF ((SOCKET_RETCD ,= 0) | (RETLEN = 0))
       THEN DO;
         CALL TCP_ERROR;
         RETURN;
         END;
     WK_PTR = WK_PTR + RETLEN;
     WK_LENGTH = WK_LENGTH - RETLEN;
     END;
 END TCP_READ;

 /******************************************************************/
 /* Procedure to send a message to the client                      */
 /******************************************************************/
 TCP_WRITE: PROC;
   WRITE LOG MESSAGE ID (9060300)
     PARMS FROM (MSG05) LENGTH (16);
   DO WHILE (WK_LENGTH > 0);
     CALL IDMSOCKI ( SOCKET_FUNCTION_WRITE,
                     SOCKET_RETCD,
                     SOCKET_ERRNO,
                     SOCKET_RSNCD,
                     SOCKET_DESCRIPTOR,
                     WK_PTR->TEXT,
                     WK_LENGTH,
                     RETLEN);
     WORK = SOCKET_RETCD;
     WRITE LOG MESSAGE ID (9060300)
       PARMS FROM (MSG07) LENGTH (20)
             FROM (WORKW) LENGTH (15);
     IF ((SOCKET_RETCD ,= 0) | (RETLEN = 0))
       THEN DO;
         CALL TCP_ERROR;
         RETURN;
         END;
     WK_PTR = WK_PTR + RETLEN;
     WK_LENGTH = WK_LENGTH - RETLEN;
     END;
 END TCP_WRITE;

 /******************************************************************/
 /* Procedure to close the socket                                  */
 /******************************************************************/
 TCP_CLOSE: PROC;
   WRITE LOG MESSAGE ID (9060300)
     PARMS FROM (MSG06) LENGTH (16);
   CALL IDMSOCKI ( SOCKET_FUNCTION_CLOSE,
                   SOCKET_RETCD,
                   SOCKET_ERRNO,
                   SOCKET_RSNCD,
                   SOCKET_DESCRIPTOR);
   WORK = SOCKET_RETCD;
   WRITE LOG MESSAGE ID (9060300)
     PARMS FROM (MSG07) LENGTH (20)
           FROM (WORKW) LENGTH (15);
 END TCP_CLOSE;

 /******************************************************************/
 /* Procedure to process the socket call errors                    */
 /******************************************************************/
 TCP_ERROR: PROC;
   WORK = SOCKET_RSNCD;
   WRITE LOG MESSAGE ID (9060300)
     PARMS FROM (MSG08) LENGTH (20)
           FROM (WORKW) LENGTH (15);
   WORK = SOCKET_ERRNO;
   WRITE LOG MESSAGE ID (9060300)
     PARMS FROM (MSG09) LENGTH (20)
           FROM (WORKW) LENGTH (15);
   WORK = RETLEN;
   WRITE LOG MESSAGE ID (9060300)
     PARMS FROM (MSG10) LENGTH (20)
           FROM (WORKW) LENGTH (15);
   CALL TCP_CLOSE;
   TERM_FLAG = 1;
 END TCP_ERROR;

 END PLILIS;