Net2/usr/src/contrib/isode/rosap/ro2ssrespond.c

/* ro2ssrespond.c - responder */

#ifndef	lint
static char *rcsid = "$Header: /f/osi/rosap/RCS/ro2ssrespond.c,v 7.3 91/02/22 09:41:23 mrose Interim $";
#endif

/* 
 * $Header: /f/osi/rosap/RCS/ro2ssrespond.c,v 7.3 91/02/22 09:41:23 mrose Interim $
 *
 * Based on an TCP-based implementation by George Michaelson of University
 * College London.
 *
 *
 * $Log:	ro2ssrespond.c,v $
 * Revision 7.3  91/02/22  09:41:23  mrose
 * Interim 6.8
 * 
 * Revision 7.2  90/11/05  13:33:09  mrose
 * update
 * 
 * Revision 7.1  90/07/01  21:05:56  mrose
 * pepsy
 * 
 * Revision 6.0  89/03/18  23:42:19  mrose
 * Release 5.0
 * 
 */

/*
 *				  NOTICE
 *
 *    Acquisition, use, and distribution of this module and related
 *    materials are subject to the restrictions of a license agreement.
 *    Consult the Preface in the User's Manual for the full terms of
 *    this agreement.
 *
 */


/* LINTLIBRARY */

#include <stdio.h>
#include "../acsap/OACS-types.h"
#include "ropkt.h"
#include "tailor.h"

/*    RO-BEGIN.INDICATION */

int	RoInit (vecp, vec, ros, roi)
int	vecp;
char  **vec;
struct RoSAPstart *ros;
struct RoSAPindication *roi;
{
    int     result;
    register struct assocblk   *acb;
    register PE	pe;
    struct SSAPref ref;
    struct SSAPstart    sss;
    register struct SSAPstart  *ss = &sss;
    struct SSAPindication   sis;
    register struct SSAPindication *si = &sis;
    register struct SSAPabort  *sa = &si -> si_abort;
    struct type_OACS_PConnect	*pconn;

    isodetailor (NULLCP, 0);

    missingP (vec);
    missingP (ros);
    missingP (roi);

    if ((acb = newacblk ()) == NULL)
	return rosaplose (roi, ROS_CONGEST, NULLCP, "out of memory");
    acb -> acb_flags |= ACB_ROS;
    (void) RoSService (acb, roi);

    if (SInit (vecp, vec, ss, si) == NOTOK) {
	(void) ss2roslose (acb, roi, "SInit", sa);
	goto out1;
    }

    acb -> acb_fd = ss -> ss_sd;
    acb -> acb_uabort = SUAbortRequest;

    acb -> acb_requirements = ss -> ss_requirements & SR_BCSUBSET;
    if (acb -> acb_requirements & SR_DUPLEX)
	acb -> acb_requirements = SR_DUPLEX;
    else
	if (acb -> acb_requirements & SR_HALFDUPLEX)
	    acb -> acb_requirements = SR_HALFDUPLEX;
	else {
	    (void) rosaplose (roi, ROS_PROTOCOL, NULLCP,
		    "desired session requirements unavailable");
	    goto out2;
	}

    if (acb -> acb_requirements & SR_HALFDUPLEX) {
	if (((ss -> ss_settings >> ST_DAT_SHIFT) & ST_MASK) == ST_RESP_VALUE) {
	    acb -> acb_settings = ss -> ss_settings;
	    acb -> acb_flags |= ACB_TURN;
	}
	else {
	    acb -> acb_settings = ST_INIT_VALUE << ST_DAT_SHIFT;
	    acb -> acb_flags &= ~ACB_TURN;
	}	    
    }

    if ((pe = ssdu2pe (ss -> ss_data, ss -> ss_cc, NULLCP, &result))
	    == NULLPE) {
	(void) rosaplose (roi, result != PS_ERR_NMEM ? ROS_PROTOCOL
		: ROS_CONGEST, NULLCP, "%s", ps_error (result));
	goto out2;
    }

    SSFREE (ss);

    if (parse_OACS_PConnect (pe, 1, NULLIP, NULLVP, &pconn) == NOTOK) {
	(void) pylose ();
	pe_free (pe);
	goto out2;
    }

    PLOGP (rosap_log,OACS_PConnect, pe, "PConnect", 1);

    bzero ((char *) ros, sizeof *ros);
    ros -> ros_sd = acb -> acb_fd;
    ros -> ros_initiator.roa_addr = ss -> ss_calling;	/* struct copy */
    ros -> ros_port = htons ((u_short) pconn -> pUserData -> applicationProtocol);
    if (pconn -> pUserData -> member_OACS_2 -> offset
	    == type_OACS_ConnectionData_open)
	ros -> ros_data = pe_expunge (pe, pconn -> pUserData
						-> member_OACS_2 -> un.open);
    else
	ros -> ros_data = NULLPE;

    free_OACS_PConnect (pconn);
    return OK;

out2: ;
    bzero ((char *) &ref, sizeof ref);
    (void) SConnResponse (acb -> acb_fd, &ref, NULLSA, SC_CONGEST, 0, 0,
	    SERIAL_NONE, NULLCP, 0, si);
    acb -> acb_fd = NOTOK;

out1: ;
    SSFREE (ss);
    freeacblk (acb);

    return NOTOK;
}

/*    RO-BEGIN.RESPONSE */

int	RoBeginResponse (sd, status, data, roi)
int	sd;
int	status;
PE	data;
struct RoSAPindication *roi;
{
    int	    len,
	    result;
    char   *base;
    PE	pe;
    register struct assocblk   *acb;
    struct SSAPref ref;
    struct SSAPindication sis;
    register struct SSAPindication *si = &sis;
    register struct SSAPabort *sa = &si -> si_abort;
    struct type_OACS_PAccept	paccpt;
    struct type_OACS_DataTransferSyntax	dts;
    struct type_OACS_ConnectionData condata;
    struct member_OACS_4 udata;

    if ((acb = findacblk (sd)) == NULL || (acb -> acb_flags & ACB_CONN))
	return rosaplose (roi, ROS_PARAMETER, NULLCP,
		"invalid association descriptor");
    if (!(acb -> acb_flags & ACB_ROS))
	return rosaplose (roi, ROS_PARAMETER, NULLCP,
		"not an association descriptor for ROS");
    switch (status) {
	case ROS_ACCEPT: 
	    break;

	case ROS_VALIDATE: 
	case ROS_BUSY: 
	    if (data)
		return rosaplose (roi, ROS_PARAMETER, NULLCP,
			"user data not permitted when refusing association");
	    break;

	default: 
	    return rosaplose (roi, ROS_PARAMETER, NULLCP,
		    "bad value for status parameter");
    }
    missingP (roi);

    bzero ((char *) &ref, sizeof ref);	/* ECMA says don't encode this yet */

    base = NULLCP;
    switch (status) {
	case ROS_ACCEPT: 
	    paccpt.member_OACS_3 = &dts;
	    dts.parm = int_OACS_DataTransferSyntax_x409;
	    paccpt.pUserData = &udata;
	    udata.checkpointSize = 0;
	    udata.windowsize = 3;
	    udata.member_OACS_5 = &condata;
	    condata.offset = type_OACS_ConnectionData_open;
	    if (data == NULLPE)
		condata.un.open = pe_alloc (PE_CLASS_UNIV, PE_FORM_PRIM,
					    PE_PRIM_NULL);
	    else
		condata.un.open = data;

	    if (encode_OACS_PAccept (&pe, 1, 0, NULLCP, &paccpt) == NOTOK) {
	no_mem: ;
		(void) rosaplose (roi, ROS_CONGEST, NULLCP, "out of memory");
		goto out1;
	    }
	    status = SC_ACCEPT;
	    break;

	default: 
	    {
	        struct type_OACS_PRefuse prefuse;

	        prefuse.parm = status;
	        if (encode_OACS_PRefuse(&pe, 1, 0, NULLCP, &prefuse) == NOTOK){
		    goto no_mem;
	        }
	    }
	    status = SC_REJECTED;
	    break;
    }

#ifdef	DEBUG
    if (rosap_log -> ll_events & LLOG_PDUS)
	if (status == SC_ACCEPT)
	    pvpdu (rosap_log, print_OACS_PAccept_P, pe, "PAccept", 0);
	else
	    pvpdu (rosap_log, print_OACS_PRefuse_P, pe, "PRefuse", 0);
#endif

    if (pe2ssdu (pe, &base, &len) == NOTOK)
	goto no_mem;

    if (SConnResponse (acb -> acb_fd, &ref, NULLSA, status,
		acb -> acb_requirements, acb -> acb_settings, SERIAL_NONE,
		base, len, si) == NOTOK) {
	acb -> acb_fd = NOTOK;
	(void) ss2roslose (acb, roi, "SConnResponse", sa);
	goto out3;
    }

    if (status == SC_ACCEPT)
	acb -> acb_flags |= ACB_CONN;
    else {
	acb -> acb_fd = NOTOK;
	freeacblk (acb);
    }
    result = OK;

out2: ;
    if (pe) {
	if (data)
	    (void) pe_extract (pe, data);
	pe_free (pe);
    }
    if (base)
	free (base);

    return result;

out1: ;
    (void) SConnResponse (acb -> acb_fd, &ref, NULLSA, SC_CONGEST, 0, 0,
	    SERIAL_NONE, NULLCP, 0, si);
    acb -> acb_fd = NOTOK;
out3: ;
    freeacblk (acb);
    result = NOTOK;
    goto out2;
}