/*
                     RECEIVE AND WAIT

  Function: This subroutine has deal with verbs receive_and_wait and
            receive_immediate.
            In case if resource associated with verb has been right defined
            and conversation is in SEND state verb processing will be
            proceeded.

            PS gets records from RM and HS. Actions which will be selected
            depend on received record type. Selected action affects state
            of FSM_ERROR_OR_FAILURE.

 Input: pointer to the structure receive_and_wait or receive_immediate

 CopyRight 1995. Nicholas Poljakov all rights reserved.

 */

#include <stdio.h>
#include <recwait.h>
#include <state1.h>
#include <rcb.h>
#include <tcb.h>
#include <lucb.h>
#include <cma.h>
#include <psp.h>
#include <scb.h>
#include <drcb.h>
#include <prefix.h>
#include <partner.h>
#include <repass.h>
#include <string.h>
#include <malloc.h>

extern struct lucb lu6;
int sk_r_wt(void *);
int SendBlock(void *, void *);
int setrc(void *, void *);
int sendhsf(void *);
int sendhs(void *);
int sendbm(void *, void *);
int sendat(void *);
int rtsend(void *);
unsigned long rmfmh5(void *, void *);
int rcvru(void *, void *);
int rcvhs(void *, void *, void *, void *);
int ralloc(void *, void *);
int psrm(int, void *, void *);
int ps_conv(int, void *);
int proterr(void *, unsigned long);
int preptrcv(void *, void *);
int post_rcb(void *);
struct repass *postopen(void *);
int phsrec(void *);
int pfmh5(void *);
int opndst(void *);
int obtsess(void *, unsigned char);
int Lrf_handler(void *);
int get_sess(void *, void *);
int get_attr(void *);
int fsm_error(unsigned char, void *);
int fsm_conv(unsigned char, unsigned char, void *);
int flush (void *);
int dcp(void *);
int dealloc(void *);
int crtp(void *);
int conv(void *);
int chkparm(void *, void *);
int check_end(unsigned int, void *);
struct rqb *call_appl(void *);
int buffmng(unsigned char, void *, void *, void *, unsigned, unsigned char, unsigned);
unsigned long attltck(void *);
unsigned long attacheck(void *);
char *cgetmem(int, int);
int sendhsf(void *);
int opndst(void *);
int alloc_rcb(void *, void *);
int allocate(void *);
int clsdst(void *);

int recwait(ptr)
struct rcwait *ptr;
 {
struct rcb *ptr_rcb;
struct tcb *ptr_tcb;
struct psp *ptr_psp;
struct repass *p_rep;
struct scb *p_scb;
struct cma ar;
struct drcb del_rcb;
struct pnlu *part;
int  fsm_conv();
int  fsm_err();
int code;
char r;
char s;
char *p;
char *pl;
char fill;
char p1;
int param;
int length;
unsigned int type;
int cnt;
int i;
int state;
unsigned char temp;

#if OS_TYPE == 1
/*********  Trace facility **********/
unsigned int rtype;   /* type of record */
unsigned int pnum;    /* point number */
char pname[8];        /* name of module */
char *drec;       /* record for dump */
int  lenr;            /* record length */

rtype = INPROC;
strcpy(pname, "recwait");
pnum = 1;
drec = ptr;
lenr = sizeof(struct rcwait);
gtf(rtype, pname, pnum, drec, lenr);
/***********************************/
#endif


    if (chkparm(ptr, &ar) == -1) {
       return(0);
    }
    ptr_rcb = ar.p_rcb;
    ptr_tcb = ar.p_tcb;

    ptr -> prim_rc = OK;
    ptr -> sec_rc = OK;

    /*   в  RCB  заносим код примитива  */
    ptr_rcb ->verb_code = ptr -> code;
    ptr_rcb -> verb_ptr = ptr;

    part = ptr_rcb -> p_partner;
    state = 0;

    if (part -> lu_type != 0) {
        if((state = fsm_conv('s',Receive_and_wait,ptr_rcb)) == -1) {
           ptr -> prim_rc = PORT_ABENDED;
           return (0);
        }
    }

    if(state == 1) {
       ptr -> prim_rc = PORT_ABENDED;
       return (0);
    }
    else
    {
            switch (ptr_rcb->error_state)    {
               case CONV_FAILURE_PROTOCOL_ERROR:
                   {
                      fsm_conv('r',RESOURCE_FAILURE_RC,ptr_rcb);
                      setrc(ptr, ptr_rcb);
                      break;
                   }
               case CONV_FAILURE_SON:
                   {
                      ptr->prim_rc = RESOURCE_FAILURE_RETRY;
                      fsm_conv('r',RESOURCE_FAILURE_RC,ptr_rcb);
                      break;
                   }
               case ALLOCATION_FAILURE_RETRY:
               case ALLOCATION_FAILURE_NO_RETRY:
               case SYNC_LEVEL_NOT_SUPPORTED:
                   {
                      ptr->prim_rc = ALLOCATION_ERROR;
                      if(ptr_rcb->error_state == ALLOCATION_FAILURE_RETRY)
                      ptr->sec_rc = ALLOCATION_FAILURE_RETRY;
                      if(ptr_rcb->error_state == ALLOCATION_FAILURE_NO_RETRY)
                           {
                               ptr->sec_rc = ALLOCATION_FAILURE_NO_RETRY;
                           }
                      else
                           {
                               ptr->sec_rc = SYNC_LEVEL_NOT_SUPPORTED_BY_LU;
                           }
                      fsm_conv('r',ALLOCATION_ERROR_RC,ptr_rcb);
                      break;
                   }
	       case RCVD_ERROR:
                   {
                      if(ptr_rcb->conv_state == SEND) {
                           p = &((*ptr_rcb).first_out);
                           type = Prepare_to_receive;
                           buffmng('A', NULL, p, ptr_rcb, 0, 0, type);
                           sendhsf(ptr_rcb);
                      }
                      if ((ptr_rcb->error_state == CONV_FAILURE_SON)||
                          (ptr_rcb->error_state == CONV_FAILURE_PROTOCOL_ERROR))
                           {
                              if (ptr_rcb->error_state == CONV_FAILURE_SON)
                                   {
                                      ptr->prim_rc = RESOURCE_FAILURE_RETRY;
                                   }
                              else
                                   {
                                      ptr->prim_rc = RESOURCE_FAILURE_NO_RETRY;
                                   }
                              fsm_conv('r',RESOURCE_FAILURE_RC,ptr_rcb);
                           }
                      break;
                   }
	       case NO_RQS:
                   {
                            p_rep = ptr;
                            if (ptr_rcb -> hsps != YES) {
                                if (ptr -> code == Receive_immediate) {
                                    ptr -> prim_rc = UNSUCCESSFUL;
                                    return (0);
                                }
                                p_rep -> complete = 1; /* req. to retry */
                                p_rep -> p_rcb = ptr_rcb;
                                return (0);
                            }
                            p_rep -> complete = 0; /* req. will be complete */
                            p_rep -> tp_fd = ptr_tcb -> tp_fd;

                         /* perform_receive_processing */
                            if ((cnt = ptr -> maxlen) <= 0) {
                                 cnt = MAX_RU;
                            }
#if OS_TYPE == 1 /* Unix System V */
                            if ((p = malloc(cnt)) == NULL) {
                                ptr -> prim_rc = PORT_BUSY;
                                return (0);
                            }
                            ptr -> data_addr = p;
#endif
#if OS_TYPE == 0 /* MS-DOS */
                            p = ptr -> data_addr;
#endif
                            switch (rcvhs(&cnt, ptr_rcb, &type, p)) {
                                case 0 :
                                         {
                                            ptr -> data_lt = cnt;
                                            if (type == Request_to_send) {
                                            ptr_rcb -> rq_to_send_rcvd = YES;
                                            }
                                            else
                                                   ptr_rcb->rq_to_send_rcvd = No;
                                            switch (type) {
                                                case DATA :
                                                            {
                                                                ptr -> what_received = Data_INCOMPLETE;
                                                                break;
                                                            }
                                                case Confirm :
                                                            {
                                                                ptr -> what_received = ConfirM;
                                                                break;
                                                            }
                                                case Send_data :
                                                            {
                                                                ptr -> what_received = Data_COMPLETE;
                                                                break;
                                                            }
                                                case SenD :
                                                case PREP_TO_RCV_FLUSH      :
                                                            {
                                                                ptr -> what_received = SenD;
                                                                if (fsm_conv('R', send_indicator, ptr_rcb) != 0) {
                                                                    ptr -> prim_rc = PORT_ABENDED;
                                                                    return (0);
                                                                }
                                                                break;
                                                            }
                                                case Deallocate_confirm :
                                                            {
                                                                if (fsm_conv('R', confirm_dealloc_ind, ptr_rcb) != 0) {
                                                                    ptr -> prim_rc = PORT_ABENDED;
                                                                    return (0);
                                                                }

                                                                ptr -> what_received = Confirm_DEALLOCATE;
                                                                break;
                                                            }
                                                case Deallocate_flush :
                                                            {
                                                                if (fsm_conv('R', Dealloc_normal_rc, ptr_rcb) != 0) {
                                                                    ptr -> prim_rc = PORT_ABENDED;
                                                                    return (0);
                                                                }
                                                                ptr -> prim_rc = deallocate_normal;
                                                                del_rcb.p_tcb = ptr_tcb;
                                                                del_rcb.p_rcb = ptr_rcb;
                                                                psrm(DEALLOCATE_RCB, &del_rcb, 0);
                                                                break;
                                                            }
                                                case PREP_TO_RCV_CONFIRM_SH:
                                                case PREP_TO_RCV_CONFIRM_LG:
                                                            {
                                                                ptr -> what_received = Confirm_SEND;
                                                                break;
                                                            }
                                                default :
                                                            {
                                                                ptr -> what_received = type;
                                                            }
                                             }
                                            goto End;
                                          }
                                case 1 :
                                         {
                                            ptr -> prim_rc = CONV_FAILURE_RETRY;
                                            break;
                                         }
                                case 2 :
                                         {
                                            p1 = service_error_rc;
                                            fsm_conv('R', p1, ptr_rcb);
                                            ptr -> prim_rc = PORT_BUSY;
                                            return (0);
                                         }
                             }
                             if ((p = realloc(p, cnt)) == NULL) {
                                ptr -> prim_rc = UNSUCCESSFUL;
                             }
                   }
            }
    }
    End:
         if ( ptr_rcb->rq_to_send_rcvd == YES ) {
                ptr->rts = YES;
                ptr_rcb->rq_to_send_rcvd = No;
         }
}
