*DECK RPCCUDP 
USETEXT TEXTIPL 
USETEXT TEXTRPC 
      PROC RPCCUDP (HANDLE, ADDRESS, PROGNUM, VERSION, WAIT, SOCKID,
        RPCSTATUS); 
*CALL COPYRITE
# TITLE RPCCUDP - CREATE UDP CLIENT HANDLE                             #
  
      BEGIN                            # RPCCUDP                       #
# 
****  RPCCUDP  CREATE UDP CLIENT HANDLE 
* 
*     THIS PROCEDURE CREATES A UDP CLIENT HANDLE FOR REMOTE PROCEDURE 
*     CALLS.
* 
*     PROC RPCCUDP
* 
*     ENTRY    ADDRESS    = ADDRESS OF THE SERVER. IF THE PORT NUMBER 
*                           IS 0, PORTMAPPER WILL BE USED TO DETERMINE
*                           THE PORT NUMBER BASED ON ADDRESS, PROGNUM 
*                           AND VERSION.
*              PROGNUM    = THE PROGRAM NUMBER ASSIGNED TO THE SERVER 
*                           BY PORTMAPPER.
*              VERSION    = THE PROTOCOL VERSION REQUESTED BY THE CLIENT
*              WAIT       = THE WAIT TIME USED WHEN WAITING FOR A SERVER
*                           RESPONSE. 
*              SOCKID     = SOCKET IDENTIFIER OF CLIENT SOCKET IF IT HAS
*                           ALREADY BEEN OPENED, OTHERWISE 0. 
* 
*     EXIT     HANDLE     = RPC HANDLE (USED IN ASSOCIATED RPC CALLS) 
*              SOCKID     = SOCKET IDENTIFIER OF CLIENT SOCKET
*              RPCSTATUS  = COMPLETION STATUS 
* 
*     METHOD   AN AVAILABLE RPC HANDLE IS FOUND AND INITIALIZED WITH THE
*              SERVER'S ADDRESS. IF THE SERVER'S PORT NUMBER IS ZERO, 
*              PORTMAPPER IS CALLED TO ACQUIRE IT FROM THE SERVER SYSTEM. 
*              IF THE INPUT VALUE FOR SOCKID IS ZERO, A UDP SOCKET IS 
*              OPENED. ANY SOCKET OPENED BY THIS REQUEST WILL BE CLOSED 
*              BY A CALL TO RPCCDES.
* 
# 
  
# 
****  PROC RPCCUDP - XREF LIST
# 
      XREF
        BEGIN 
        PROC IPPABOS;    # ABORT A SOCKET                              #
        PROC IPPBINS;    # BIND A UDP SOCKET                           #
        PROC IPPOPES;    # OPEN A UDP SOCKET                           #
        PROC IPPSETO;    # SET SOCKET OPTIONS                          #
        PROC PMPREQT;    # REQUEST REMOTE PORT NUMBER                  #
        END 
# 
**
# 
      ARRAY ADDRESS   [0:0] S(1);;     # SERVER ADDRESS (IP$ADDR$REC)  #
      ITEM HANDLE              U;      # RPC HANDLE                    #
      ITEM IGNORE              U;      # IGNORE STATUS                 #
      ITEM PROGNUM             U;      # RPC PROGRAM NUMBER OF SERVER  #
      ITEM RPCSTATUS   S:RPCSTAT;      # RETURNED RPC STATUS           #
      ITEM SOCKID              U;      # SOCKET IDENTIFIER             #
      ITEM VERSION             U;      # SERVER PROTOCOL VERSION       #
      ITEM WAIT                U;      # SOCKET REQUEST WAIT TIME      #
# 
**
# 
      BASED ARRAY SERVER [0:0] S(1);   # SOURCE FOR ADDRESS MOVE       #
        BEGIN 
        ITEM SERVADDR   C(0,0,40);     # CONTAINS TYPE IP$ADDR$REC     #
        END 
      ITEM INDEX                I;     # LOOP INDEX                    #
      ITEM PORTNUM              U;     # SERVER PORT NUMBER            #
      ITEM SOCKET               U;     # INTERNAL SOCKET               #
      ARRAY SOCKADDR [0:0] S(ADDSIZE$);;# CLIENT ADDRESS               #
      ITEM SOCKSTATUS  S:SOCKSTAT;     # SOCKET STATUS                 #
      CONTROL EJECT;
# 
****  START MAIN PROCEDURE
* 
****  FIND AVAILABLE HANDLE ENTRY 
# 
      FOR INDEX = 1 STEP 1 UNTIL MAXHANDLE$ DO
        BEGIN 
        IF NOT RP$ACTIVE [INDEX] THEN 
          BEGIN 
          HANDLE = INDEX; 
          GOTO INIT$HANDLE; 
          END 
        END 
  
      RPCSTATUS = S"NOHANDLE";
      RETURN; 
# 
****  SAVE SERVER ADDRESS IN HANDLE ENTRY 
# 
    INIT$HANDLE:  
      RP$XID [HANDLE] = 0;
      RP$PROGNUM [HANDLE] = PROGNUM;
      RP$VERSION [HANDLE] = VERSION;
      P<SERVER> = LOC (ADDRESS);
      RP$ADDRESS [HANDLE] = SERVADDR [0];# SAVE SERVER ADDRESS         #
      P<IP$ADDR$REC> = LOC (RP$ADDRESS [HANDLE]); 
  
      IF (NOT IP$PIU [0]) 
         OR (IP$PORT [0] EQ 0)         # USE PORTMAPPER TO GET PORT    #
      THEN
        BEGIN 
        PMPREQT (ADDRESS, PROGNUM, VERSION, IPPROTO$UDP,
          PORTNUM, RPCSTATUS);
        IF RPCSTATUS NQ S"OK" 
        THEN
          RETURN; 
  
        P<IP$ADDR$REC> = LOC (RP$ADDRESS [HANDLE]); 
        IP$PIU [0] = TRUE;             # SAVE SERVER PORT NUMBER       #
        IP$PORT [0] = PORTNUM;
        END 
# 
****  OPEN A UDP SOCKET IF ONE IS NOT ALREADY OPEN. 
# 
      IF SOCKID EQ 0
      THEN
        BEGIN                          # OPEN A SOCKET                 #
        IPPOPES (SOCKET, (PTYPE"SOCKETUDP"), SOCKSTATUS); 
  
        IF SOCKSTATUS EQ S"OK"
        THEN
          BEGIN                        # BIND THE SOCKET               #
          IPPBINS (SOCKET, 0, SOCKSTATUS);
          IF (SOCKSTATUS EQ S"REQFAIL") 
          OR (SOCKSTATUS EQ S"ABORT") 
          THEN                         # BIND FAILED - CLOSE SOCKET    #
            IPPABOS (SOCKET, IGNORE); 
          END 
  
        IF SOCKSTATUS NQ S"OK"
        THEN
          BEGIN                        # RETURN IF ERROR ON SOCKET     #
          RPCSTATUS = S"SOCKFAIL";
          RETURN; 
          END 
  
        SOCKID  = SOCKET;              # RETURN SOCKET ID              #
        RP$CLS$SOCK [HANDLE] = TRUE;   # MARK HANDLE TO DELETE SOCKET  #
        END 
      ELSE                             # SOCKID NQ 0                   #
        RP$CLS$SOCK [HANDLE] = FALSE;  # MARK HANDLE TO SAVE SOCKET    #
  
      IPPSETO (SOCKID, TRUE, WAIT, SOCKSTATUS);# SET BLOCKING/WAIT     #
      RP$SOCKID [HANDLE] = SOCKID;     # SAVE SOCKET ID                #
      RP$ACTIVE [HANDLE] = TRUE;       # HANDLE INITIALIZED            #
      RPCSTATUS = S"OK";
      RETURN;                          # RETURN TO CALLER              #
  
      END                              # RPCCUDP                       #
  
      TERM
