*DECK IPPSEND 
USETEXT TEXTIPL 
USETEXT TEXTXDR 
      PROC IPPSEND (SOCKID, BUFFER1, BUFLEN1, BUFFER2, BUFLEN2, 
                    ADDRESS, SOCKSTATUS); 
*CALL COPYRITE          CDCNET - COPYRIGHT CONTROL DATA. 1992.
# TITLE IPPSEND - SEND DATA FROM A SOCKET                              #
  
      BEGIN                            # IPPSEND                       #
# 
****  IPPSEND  SEND DATA FROM A SOCKET
* 
*     THIS PROCEDURE SENDS A BLOCK OF DATA FROM THE SOCKET *SOCKID* 
*     TO THE HOST AT *ADDRESS*. 
* 
*     PROC IPPSEND
* 
*     ENTRY    SOCKID     = INTEGER VALUE OF SOCKET 
*              BUFFER1    = FIRST BUFFER WHICH CONTAINS THE DATA TO SEND
*              BUFLEN1    = NUMBER OF BYTES IN *BUFFER1* TO SEND
*              BUFFER2    = SECOND BUFFER WHICH CONTAINS THE DATA TO SEND 
*              BUFLEN2    = NUMBER OF BYTES IN *BUFFER2* TO SEND
*              ADDRESS    = 4 WORD DESTINATION IP ADDRESS ARRAY 
* 
*     EXIT     SOCKSTATUS = COMPLETION STATUS 
* 
*     METHOD   IF THE SOCKET HAS BEEN ABORTED BY NAM, RETURN AN 
*              ABORT STATUS TO INFORM THE CALLER.  IF THE SOCKET
*              IS NOT CONNECTED, RETURN AN ERROR STATUS.  IF THE
*              APPLICATION BLOCK LIMIT HAS NOT BEEN REACHED, SET UP 
*              THE UDP CALL BLOCK HEADER AND COPY THE CONTENTS OF 
*              *BUFFER1* AND *BUFFER2* INTO THE DATA BLOCK AND SEND 
*              THE BLOCK TO NAM.
*              IF THE APPLICATION BLOCK LIMIT HAS BEEN REACHED, CALL THE
*              NAM INPUT TRAFFIC HANDLER WAITING FOR THE OUTSTANDING
*              BLOCK COUNT TO FALL BELOW THE LIMIT OR FOR THE BLOCKING
*              WAIT TIMER TO EXPIRE.
*              IF NOT BLOCKING, CALL THE NAM INPUT TRAFFIC HANDLER
*              ONCE.  IF THE DATA BLOCK CAN NOT BE SENT, SET THE STATUS 
*              TO *FLOWCTRL* TO INDICATE THE BLOCK WAS NOT SENT.
# 
  
# 
****  PROC IPPSEND - XREF LIST
# 
      XREF
        BEGIN 
        PROC IMNS;       # MOVE NON-OVERLAPPING STRING                 #
        PROC IPINITH;    # NAM INPUT TRAFFIC HANDLER                   #
        PROC NETPUT;     # SEND OUTPUT BUFFER TO NETWORK               #
        PROC RTIME;      # REAL TIME CLOCK                             #
        PROC XDRBYTE;    # CONVERT BYTES TO XDR FORMAT                 #
        PROC XDRINT;     # CONVERT INTEGERS TO XDR FORMAT              #
        END 
# 
**
# 
      ITEM SOCKID              I;      # SOCKET IDENTIFIER             #
      ARRAY BUFFER1 [00:00] S(1);;     # OUTPUT BUFFER TO SEND         #
      ITEM BUFLEN1             U;      # LENGTH OF DATA IN *BUFFER1*   #
      ARRAY BUFFER2 [00:00] S(1);;     # SECOND OUTPUT BUFFER TO SEND  #
      ITEM BUFLEN2             U;      # LENGTH OF DATA IN *BUFFER2*   #
      ARRAY ADDRESS [00:00] S(1);;     # SOURCE ADDRESS FOR DATA       #
      ITEM SOCKSTATUS S:SOCKSTAT;      # RETURNED SOCKET STATUS        #
  
  
      ITEM BUFPOS              U;      # OFFSET IN *OUTBUF*            #
      ITEM DESTBUF             I;      # CURRENT WRD LOCATION IN BUFFER#
      ITEM DESTPOS             U;      # BIT OFFSET IN BUFFER WORD     #
      ITEM INDEX               I;      # LOOP COUNTER                  #
      ITEM LOOP                I;      # LOOP COUNTER                  #
      ITEM MOVEBITS            U;      # BITS TO MOVE TO *BUFFER*      #
      ITEM SCRBUF              U;      # CURRENT LOCATION INP$BUF      #
      ITEM SCRPOS              U;      # BIT OFFSET IN INP$BUF WORD    #
      ITEM WAITLOOP            I;      # NUMBER OF WAIT CYCLES         #
      ITEM WRITENUM            I;      # NUMBER OF XDR ITEMS TO WRITE  #
      CONTROL EJECT;
# 
****  START MAIN PROCEDURE
# 
  
      IF (ACN$ABORT [SOCKID]) 
      THEN
        BEGIN                          # CONNECTION ABORTED            #
        SOCKSTATUS = S"ABORT";
        RETURN; 
        END 
  
      IF ACN$STATE [SOCKID] NQ S"BOUND" 
      THEN
        BEGIN 
        SOCKSTATUS = SOCKSTAT"INVALIDST"; 
        RETURN; 
        END 
  
      IF (ACN$OBC [SOCKID] GQ ACN$ABL [SOCKID]) 
      THEN
        BEGIN                          # MAXIMUM OUTSTANDING BLOCK LMT #
        BLOCK = ACN$BLOCK [SOCKID];    # SET GLOBAL BLOCKING FLAG      #
        IF BLOCK
        THEN
          BEGIN                        # WAIT FOR FC/ACK ON CONNECTION #
          WAITLOOP = ACN$WAITIME [SOCKID] / 2 + 1;
          RTIME (BWT$TIME);            # CURRENT TIME                  #
          BWT$EXPIRE [0] = BWT$SECONDS [0] + ACN$WAITIME [SOCKID];
  
# 
****  CONTINUE POLLING THE NETWORK WAITING FOR FC/ACK SUPERVISORY 
*     MESSAGES TO BE RECEIVED ON THE CONNECTION OR UNTIL THE WAIT TIMER 
*     HAS EXPIRED.  THE LOOP COUNTERIS SETTO THE WAIT TIME/2 DUE TO THE 
*     NETWAIT TIME OF 2 SECONDS WHILE BLOCKING. 
# 
  
          FOR LOOP = 0
            WHILE (ACN$OBC [SOCKID] GQ ACN$ABL [SOCKID])
          DO
            BEGIN                      # WAIT FOR ACK OR EXPIRED TIME  #
            FOR INDEX = 1 STEP 1
              WHILE (ACN$OBC [SOCKID] GQ ACN$ABL [SOCKID]) AND
                    (NOT ACN$ABORT [SOCKID]) AND
                    (INDEX LQ WAITLOOP) 
            DO
              BEGIN 
              IPINITH;                 # NAM INPUT TRAFFIC HANDLER     #
              END 
  
            IF (ACN$ABORT [SOCKID]) 
            THEN
              BEGIN                    # CONNECTION ABORTED            #
              SOCKSTATUS = S"ABORT";
              RETURN; 
              END 
  
            IF (ACN$OBC [SOCKID] GQ ACN$ABL [SOCKID]) 
            THEN
              BEGIN                    # CHECK IF TIMED OUT            #
              RTIME (BWT$TIME); 
              IF (BWT$SECONDS [0] GQ BWT$EXPIRE [0])
              THEN
                BEGIN                  # TIMER EXPIRED                 #
                SOCKSTATUS = S"FLOWCTRL"; 
                RETURN; 
                END 
              ELSE
                BEGIN                  # TIME STILL TO WAIT            #
                WAITLOOP = (BWT$EXPIRE [0] -
                            BWT$SECONDS [0]) / 2 + 1; 
                END 
              END                      # CHECK IF TIMED OUT            #
            END                        # WAIT FOR ACK OR EXPIRED TIME  #
          END                          # WAIT FOR FC/ACK ON CONNECTION #
        ELSE
          BEGIN                        # NO ACK/NOT BLOCKING           #
          IPINITH;                     # NAM INPUT TRAFFIC HANDLER     #
  
          IF (ACN$ABORT [SOCKID]) 
          THEN
            BEGIN                      # CONNECTION ABORTED            #
            SOCKSTATUS = S"ABORT";
            RETURN; 
            END 
  
          IF (ACN$OBC [SOCKID] GQ ACN$ABL [SOCKID]) 
          THEN
            BEGIN 
            SOCKSTATUS = S"FLOWCTRL"; 
            RETURN; 
            END 
          END                          # NO ACK/NOT BLOCKING           #
        END                            # DATA NOT AVAILABLE            #
  
# 
****  DATA CAN BE SENT.  PLACE THE UDP CALL HEADER INTO *OUTBUF*.  THE
*     REQUEST CONSISTS OF THE CALL TYPE, UDP VERSION, AND FOUR 32 BIT 
*     INTEGER ADDRESS.  FOLLOWING THE ADDRESS THE CONTENTS OF *BUFFER*
*     ARE MOVED INTO *OUTBUF*.   IF THE BLOCK TO BE TRANSMITTED IS
*     GREATER THAN *INPSIZE$* THEN AN ERROR STATUS IS RETURNED. 
# 
  
      BUFPOS = 0;                      # INITIALIZE BUFFER POSITION    #
      P<IP$ADDR$REC> = LOC (ADDRESS); 
      UDP$HEADER [0] = DESTREQ$;
  
      WRITENUM = 2; 
      XDRBYTE (OUTBUF, BUFPOS, UDP$HEAD$REC, WRITENUM, XDROPER"WRITE"); 
  
      WRITENUM = 4; 
      XDRINT (OUTBUF, BUFPOS, IP$ADDR$REC, WRITENUM, XDROPER"WRITE"); 
  
      P<ABH> = LOC (DABH);             # BASE ABH POINTER              #
      ABHTLC [0] = BUFPOS + BUFLEN1 + BUFLEN2;# STORE LENGTH IN BYTES  #
  
      IF ((ABHTLC [0] * 2) / 15) GR INPSIZE$
      THEN
        BEGIN                          # *OUTBUF* TOO SMALL FOR DATA   #
        SOCKSTATUS = S"REQFAIL";
        RETURN; 
        END                            # *OUTBUF* TOO SMALL FOR DATA   #
  
      IF BUFLEN1 GR 0 
      THEN
        BEGIN 
        MOVEBITS = BUFLEN1 * 8; 
        DESTBUF = LOC (OUTBUF) + (BUFPOS * 2) / 15; 
        DESTPOS = XDRMODU ((BUFPOS * 8), 60);# WORD BIT OFFSET         #
        SCRBUF = LOC (BUFFER1); 
        SCRPOS = 0; 
        IMNS (MOVEBITS, SCRBUF, SCRPOS, DESTBUF, DESTPOS);
  
        IF BUFLEN2 GR 0 
        THEN
          BEGIN 
          SCRBUF = LOC (BUFFER2); 
          SCRPOS = 0; 
          MOVEBITS = BUFLEN2 * 8; 
          IMNS (MOVEBITS, SCRBUF, SCRPOS, DESTBUF, DESTPOS);
          END 
        END 
  
      ABHADR [0] = SOCKID;             # STORE CONNECTION NUMBER       #
      ABHABN [0] = ACN$ABN [SOCKID];   # STORE APPLICATION BLOCK NUMBER#
      ACN$ABN [SOCKID] = ACN$ABN [SOCKID] + 1;
      ACN$OBC [SOCKID] = ACN$OBC [SOCKID] + 1;
      NETPUT (DABH, OUTBUF);           # SEND THE REQUEST              #
  
      SOCKSTATUS = S"OK"; 
  
      RETURN;                          # RETURN TO CALLER              #
  
      END                              # IPPSEND                       #
  
      TERM
