*DECK IPPRECV 
USETEXT TEXTIPL 
USETEXT TEXTXDR 
      PROC IPPRECV (SOCKID, BUFFER, BUFLEN, ADDRESS, SOCKSTATUS); 
*CALL COPYRITE          CDCNET - COPYRIGHT CONTROL DATA. 1992.
# TITLE IPPRECV - RECEIVE DATA FOR SOCKET                              #
  
      BEGIN                            # IPPRECV                       #
# 
****  IPPRECV  RECEIVE DATA FOR SOCKET
* 
*     THIS PROCEDURE OBTAINS A BLOCK OF DATA FOR THE SOCKET.
* 
*     PROC IPPRECV
* 
*     ENTRY    SOCKID     = INTEGER VALUE OF SOCKET 
*              BUFFER     = BUFFER TO PLACE THE DATA
* 
*     EXIT     BUFFER     = BUFFER WITH RECEIVED DATA 
*              BUFLEN     = INTEGER VALUE OF NUMBER BYTES IN BUFFER 
*              ADDRESS    = 4 WORD SOURCE IP ADDRESS ARRAY
*              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 DATA 
*              IS NOT QUEUED TO THE CONNECTION AND THE SOCKET BLOCKS, 
*              LOOP CALLING THE NAM INPUT HANDLER UNTIL DATA IS 
*              RECEIVED OR THE SPECIFIED BLOCKING TIMER HAS EXPIRED.
*              IF DATA IS RECEIVED, EXTRACT THE HEADER AND VERIFY THE 
*              REQUEST AND UDP VERSION.  PLACE THE SOURCE ADDRESS FROM
*              THE HEADER INTO *ADDRESS*, AND THE REMAINDER DATA INTO 
*              *BUFFER*.  ISSUE A LST/ON SM TO NAM SO MORE DATA CAN 
*              BE SENT TO THE APPLICATION.
# 
  
# 
****  PROC IPPRECV - XREF LIST
# 
      XREF
        BEGIN 
        PROC IMNS;       # MOVE NON-OVERLAPPING STRING                 #
        PROC IPIAIPA;    # ABORT IP APPLICATION                        #
        PROC IPIDOSM;    # DISPATCH OUTPUT SUPERVISORY MESSAGE         #
        PROC IPINITH;    # NAM INPUT TRAFFIC HANDLER                   #
        PROC MESSAGE;    # ISSUE DAYFILE MESSAGE                       #
        PROC RTIME;      # REAL TIME CLOCK                             #
        PROC XDRBYTE;    # CONVERT BYTES TO XDR FORMAT                 #
        PROC XDRINT;     # CONVERT INTEGERS TO XDR FORMAT              #
        PROC XWHD;       # CONVERT HEXIDECIMAL TO DISPLAY              #
        END 
# 
**
# 
      ITEM SOCKID              I;      # SOCKET IDENTIFIER             #
      ARRAY BUFFER  [00:00] S(1);;     # BUFFER TO RECEIVE DATA        #
      ARRAY ADDRESS [00:00] S(1);;     # SOURCE ADDRESS FOR DATA       #
      ITEM BUFLEN              U;      # LENGTH OF DATA IN BUFFER      #
      ITEM SOCKSTATUS S:SOCKSTAT;      # RETURNED SOCKET STATUS        #
  
  
# 
****  THIS ARRAY DEFINES THE DAYFILE MESSAGE FOR DISPLAYING AN INVALID
*     MESSAGE RECEIVED. 
# 
      ARRAY DATAMSG [00:00] S(3); 
        BEGIN 
        ITEM DATA$TEXT   C(00,00,20); 
        ITEM DATA$ZBYTE  U(02,00,60) = [0]; 
        END 
  
# 
****  BASED ARRAY WHICH POINTS TO THE BLOCK OF DATA THAT WAS RECEIVED BY
*     NAM.
# 
  
      BASED ARRAY INP$BUF [00:INPSIZE$] S(1); 
        BEGIN 
        ITEM INP$WRD     U(00,00,60);  # FULL WORD REFERENCE           #
        END 
  
      ITEM DESTBUF             I;      # CURRENT WRD LOCATION IN BUFFER#
      ITEM DESTPOS             U;      # BIT OFFSET IN BUFFER WORD     #
      ITEM INDEX               I;      # LOOP COUNTER                  #
      ITEM INPPOS              U;      # OFFSET IN INP$BUF BYTE        #
      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         #
      BASED ARRAY IPADDR [00:00] S(1);;# SOURCE ADDRESS FOR XDR CALL   #
      CONTROL EJECT;
# 
****  START MAIN PROCEDURE
# 
  
      IF (ACN$ABORT [SOCKID]) 
      THEN
        BEGIN                          # CONNECTION ABORTED            #
        SOCKSTATUS = S"ABORT";
        RETURN; 
        END 
  
      IF NOT ACN$CONNECT [SOCKID] 
      THEN
        BEGIN 
        SOCKSTATUS = SOCKSTAT"INVALIDST"; 
        RETURN; 
        END 
  
      BLOCK = ACN$BLOCK [SOCKID];      # SET GLOBAL BLOCKING FLAG      #
  
      IF NOT ACN$DATAV [SOCKID] 
      THEN
        BEGIN                          # DATA NOT AVAILABLE            #
        IF BLOCK
        THEN
          BEGIN                        # IF BLOCKING                   #
          WAITLOOP = ACN$WAITIME [SOCKID] / 2 + 1;
          RTIME (BWT$TIME);            # CURRENT TIME                  #
          BWT$EXPIRE [0] = BWT$SECONDS [0] + ACN$WAITIME [SOCKID];
  
# 
****  CONTINUE POLLING THE NETWORK FOR DATA UNTIL EITHER DATA IS
*     IS RECEIVED ON THE CONNECTION OR UNTIL THE WAIT TIMER HAS EXPIRED.
*     THE LOOP COUNTER IS SET TO THE TIME/2 DUE TO THE NETWAIT TIME OF
*     2 SECONDS WHILE BLOCKING. 
# 
  
          FOR LOOP = 0
            WHILE (NOT ACN$DATAV [SOCKID])
          DO
            BEGIN                      # WAIT FOR DATA OR EXPIRED TIME #
            FOR INDEX = 1 STEP 1
              WHILE (NOT ACN$DATAV [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 NOT ACN$DATAV [SOCKID] 
            THEN
              BEGIN                    # CHECK IF TIMED OUT            #
              RTIME (BWT$TIME); 
              IF (BWT$SECONDS [0] GQ BWT$EXPIRE [0])
              THEN
                BEGIN                  # TIMER EXPIRED                 #
                SOCKSTATUS = S"NODATA"; 
                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 DATA OR EXPIRED TIME #
          END                          # IF BLOCKING                   #
        ELSE
          BEGIN                        # NO DATA/NOT BLOCKING RETURN   #
          IPINITH;                     # NAM INPUT TRAFFIC HANDLER     #
  
          IF (ACN$ABORT [SOCKID]) 
          THEN
            BEGIN                      # CONNECTION ABORTED            #
            SOCKSTATUS = S"ABORT";
            RETURN; 
            END 
  
          IF (NOT ACN$DATAV [SOCKID]) 
          THEN
            BEGIN 
            SOCKSTATUS = S"NODATA"; 
            RETURN; 
            END 
          END 
        END                            # DATA NOT AVAILABLE            #
  
      P<INP$BUF> = ACN$BUFFER [SOCKID];# INITIALIZE SOURCE POINTER   #
      MOVEBITS = (ACN$DATALNTH [SOCKID] - UDPHEADSZ$) * 8;
  
# 
****  DATA IS AVAILABLE.  VERIFY THE FIRST TWO BYTES OF DATA INDICATE 
*     A VALID UDP REQUEST AND VERSION.  IF IT DOES, THEN EXTRACT THE
*     SOURCE ADDRESS FROM BUFFER AND PLACE IN *ADDRESS*.  MOVE THE
*     REMAINDER OF THE SOURCE BUFFER TO *BUFFER* WITH *IMNS*. 
# 
  
      INPPOS = 0;                      # STARTING OFFSET IN INP$BUF    #
      XDRBYTE (INP$BUF, INPPOS, REC$UDP, 2, XDROPER"READ"); 
  
      IF ((REC$REQ [0] NQ CALLRES$) AND 
         (REC$REQ [0] NQ DATAIND$)) OR
         (REC$VER [0] NQ UDPVERS$) OR 
         (MOVEBITS LS 0)
      THEN
        BEGIN                          # INVALID DATA, ABORT APPLICATIO#
        XWHD (INP$WRD [0], DATAMSG);
        MESSAGE (DATAMSG, 0); 
        XWHD (REC$REQ, DATAMSG);
        MESSAGE (DATAMSG, 0); 
        XWHD (REC$VER, DATAMSG);
        MESSAGE (DATAMSG, 0); 
        IPIAIPA (NINVALID$);
        RETURN; 
        END 
  
      P<IPADDR> = LOC (ADDRESS) + 1;
      INPPOS = 3;                      # BEGIN EXTRACT SOURCE ADDRESS  #
      XDRBYTE (INP$BUF, INPPOS, ADDRESS, 1, XDROPER"READ"); 
      XDRINT (INP$BUF, INPPOS, IPADDR, 3, XDROPER"READ"); 
  
      BUFLEN = MOVEBITS / 8;           # NUMBER OF BYTES IN BUFFER     #
      IF MOVEBITS NQ 0
      THEN
        BEGIN 
        SCRBUF = LOC (INP$BUF) + (INPPOS * 2) / 15; 
        DESTBUF = LOC (BUFFER); 
        SCRPOS = XDRMODU ((INPPOS * 8), 60);# WORD BIT OFFSET          #
        DESTPOS = 0;
        IMNS (MOVEBITS, SCRBUF, SCRPOS, DESTBUF, DESTPOS);
        END 
  
# 
****  CLEAR FLOW CONTROL ON THIS CONNECTION NOW THAT THE DATA HAS 
*     BEEN PROCESSED. 
* 
# 
      IF ACN$DATAV [SOCKID] 
      THEN
        BEGIN 
        ACN$DATAV [SOCKID] = FALSE; 
        P<APSM> = LOC(OUTBUF);
        SPMSG0 [0] = 0; 
        LSTACN [0] = SOCKID;
        IPIDOSM (LSTON, LLST);         # ISSUE LST/ON/R SM             #
        END 
  
      SOCKSTATUS = S"OK"; 
  
      RETURN;                          # RETURN TO CALLER              #
  
      END                              # IPPRECV                       #
  
      TERM
