Google
 

Trailing-Edge - PDP-10 Archives - TOPS-20_V6.1_DECnetSrc_7-23-85 - mcb/sc/scsub.bli
There is 1 other file named scsub.bli in the archive. Click here to see a list.
module SCSUB (			! Session Control Subroutines
		ident = 'X01250'
		) =
begin

!
!                    COPYRIGHT (c) 1980, 1981, 1982
!                    DIGITAL EQUIPMENT CORPORATION
!                        Maynard, Massachusetts
!
!     This software is furnished under a license and may  be  used
!     and copied only in accordance with the terms of such license
!     and with the inclusion of the above copyright notice.   This
!     software  or any other copies thereof may not be provided or
!     otherwise made available to any other person.  No  title  to
!     and ownership of the software is hereby transferred.
!
!     The information  in  this  software  is  subject  to  change
!     without  notice  and should not be construed as a commitment
!     by DIGITAL EQUIPMENT CORPORATION.
!
!     DIGITAL assumes no responsibility for the use or reliability
!     of  its  software  on  equipment  which  is  not supplied by
!     DIGITAL.
!

!++
!
! FACILITY:	Session Control
!
! ABSTRACT:	Support subroutines for the MCB Session Control
!
! ENVIRONMENT:	MCB
!
! AUTHOR: 	Buren Hoffman		CREATION DATE: 24-Jun-80
!
! MODIFIED BY:
!	X01010	Changed code to use $byt_ptr macro in place of the
!		ch$ptr macro.
!	X01020	Fixed mapping problem in CONBKI.
!	X01030	Provided error recording byte pointer in CONBKI.
!	X01040	Fixed improper reference to byte value in CONBKI, and
!		corrected dot bug in FINDOB.
!	X01050	Incorporated I$OPN routine.
!	X01060	Fixed logic problems in CONBKI and CONBKO.
!	X01070	CONBKI was storing PIX in wrong location.
!	X01080	Fixed error where buffer length was not being set
!		on incoming connects.
!	X01090	Install new FINDOB routine to allow mapping of named
!		processes on incoming connects.
!	X01100	Removed old external reference to previous mapping table.
!	X01110	Fixed mapping bug in new FINDOB routine.
!	X01120	CONBKI wasn't releasing memory on error condition.
!	X01130	Fixed mapping bug in CONBKI.
!	X01140	Improved documentation, and added info on SIGNAL_STOPs
!	X01150	Bias was not being set for connect block buffer sent to user
!	X01160	Mods to support new Network Management interface.
!	X01170	Use new Comm/Exec to process linkage (.CRDAT for database)
!	X01180	Updated to use library calls, instead of requires.
!	X01190	Fixed bug in decimal to ascii conversion (CNVDA$).
!	X01200	Put routines into alphabetical order
!	X01210	Changed STKCCB to pass along user-provided chain of CCBs.
!	X01220	Cleaned up node-finding in FINDND
!	X01230	Cleanup of CNVAD$ routine
!	X01240	Optimization work
!	x01250	add range check code to FINDND
!--
!
! INCLUDE FILES:
!
library 'SCPRM';		! Our parameter and macro definitions
library 'MCB:MCBLIB';
library 'MCB:RSXLIB';
library 'MCB:XPORTX';
library 'MCB:SCSYS';

require 'NSP:NSINFO';

!
! TABLE OF CONTENTS:
!
forward routine
    CNVAD$,				! Convert ASCII to decimal
    CNVDA$: novalue,			! Convert decimal to ASCII
    CONBKI,				! Do connect data translation
    CONBKO,				! ...
    DO_RCP: linkage_ccb novalue,	! Do RCP processing
    DO_XME: linkage_ccb novalue,	! Do XME processing
    DST_SRC_I,				! Validate dest/src object descriptors
    DST_SRC_O,				!   (same, except for outgoing)
    FINDLL,				! Find available logical link
    FINDND,				! Find node address
    FINDOB,				! Find specified object type
    I$CLS: novalue,			! Close a port
    I$OPN: novalue,			! Open a port
    STKCCB: novalue,			! Stack CCBs and set C_BUF
    STSMAP;				! Map from NSP to SC status

!
! MACROS:
!
!
! EQUATED SYMBOLS:
!
literal				! MENU word in connect message
    U_INFO = 1,			! USRID, PASSWD, and ACCNT info
    U_DATA = 2;			! Optional data

!
! OWN STORAGE:
!

!
! EXTERNAL REFERENCES:
!
global routine CNVAD$ (PTR , LEN) =

!++
! FUNCTIONAL DESCRIPTION:
!	This routine converts a decimal ASCII field to binary.
!	If a non-numeric character, other than a blank or null
!	is found, zero is returned. A blank or null terminates
!	the conversion.
!
! FORMAL PARAMETERS:
!	PTR = String pointer to the field
!	LEN = Length of the field
!
! IMPLICIT INPUTS:
!	None
!
! ROUTINE VALUE:
!	Numeric value, or zero if non-numeric
!
! COMPLETION CODES:
! SIDE EFFECTS:
!	None
!--

    begin
    local
	DIGIT, VALUE;
    register
	P;

    VALUE = 0;
    P = .PTR;

    incr I from 1 to .LEN do
	begin
	DIGIT = ch$rchar_a (P);
	if (.DIGIT eql 0) or (.DIGIT eql %c' ') then return .VALUE;
	if (.DIGIT geq %c'0') and (.DIGIT leq %c'9')
	then VALUE = (.VALUE * 10) + .DIGIT - %c'0'
	else return 0
	end;

    return .VALUE
    end;
global routine CNVDA$ (NUM, PTR): novalue =

!++
! FUNCTIONAL DESCRIPTION:
!	This routine converts a decimal integer to ASCII.
!
! FORMAL PARAMETERS:
!	NUM = Decimal positive integer
!	PTR = Address of string pointer
!
! IMPLICIT INPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin
    local
	DIGIT;

    DIGIT = (.NUM mod 10) + %c'0';
    NUM = .NUM / 10;
    if .NUM gtr 0 then CNVDA$ (.NUM, .PTR);
    ch$wchar_a (.DIGIT, .PTR)
    end;
global routine CONBKI (CCB, LCCB, LNK) =

!++
! FUNCTIONAL DESCRIPTION:
!	Process incoming connect message.
!
! FORMAL PARAMETERS:
!	CCB	CCB which owns received message
!	LCCB	CCB which owns connect block
!	LNK	Logical link block in use
!
! IMPLICIT INPUTS:
!	LLT mapped
!
! IMPLICIT OUTPUTS:
!	Connect block built in LCCB [C_BUF]
!	LNK [C_PIX] set for destination process
!
! ROUTINE VALUE:
!	True, if successful
!	False, if failure
!
! COMPLETION CODES:
!	LCCB [C_PRM1] set for error xmission
!
! SIDE EFFECTS:
!	None
!--
    begin
    $sc_get_data_base (SCDB);
    map
	CCB: ref block field (C_FIELDS),
	LCCB: ref block field (C_FIELDS),
	LNK: ref block field (LLT_FIELDS);
    local
	PTR,
	EPTR,
	ERR,
	MENU;
    bind
	CB = LCCB [C_ADDR]: ref block field (CB_FIELDS),
	NMT = SCDB [SC_NMT_ADDR]: ref blockvector [, NMT_SIZE] field (NMT_FIELDS);
    label
	CBE;

    EPTR = byt$ptr (LCCB [C_PRM1]);		! This is where to write code
    if not $MCB_GET_DSR (CB_SIZE*bytes_word, CB) ! Get connect block memory
    then
	begin					! No luck, so grouse a bit
	byt$short_string (uplit (-S_ERES), EPTR);
	return false
	end;

    LCCB [C_BIAS] = 0;
    ch$fill (0, CB_SIZE*bytes_word, .CB);		! Clear block to zeroes
    MAP$ (.SCDB [SC_NMT_BIAS]);				! Look at node mapping table
    PTR = byt$ptr (NMT [.CCB [C_PRM1], NMT_NAME]);	! Examine subject name
    if ch$rchar (.PTR) neq 0				! If a name is defined,
    then ch$move (6, .PTR, byt$ptr (CB [CB_NODE]))	!   then move it to CB
    else
	begin
	PTR = byt$ptr (CB [CB_NODE]);			! Undefined, concoct a
	CNVDA$ (.CCB [C_PRM1], PTR);			!   name from number
	ch$fill (%c' ', 6 - ch$diff (.PTR, byt$ptr (CB [CB_NODE])), .PTR)
	end;

    MAP$ (.CCB [C_BIAS]);			! Look at connect message
    PTR = .CCB [C_ADDR];			! ...

    if not (DST_SRC_I (CB [CB_DFMT], PTR) and DST_SRC_I (CB [CB_SFMT], PTR))
    then ERR = -S_EIOF
    else ERR = CBE:
	begin
	MENU = ch$rchar_a (PTR);		! Get menu byte

	if (.MENU and U_INFO) neq 0
	then
	    begin
	    if (CB [CB_RQDL] = ch$rchar_a (PTR)) gtr 16
		then leave CBE with -S_ECBE;
	    ch$move (.CB [CB_RQDL], .PTR, CB [CB_RQID]);
	    PTR = ch$plus (.PTR, .CB [CB_RQDL]);
	    if (CB [CB_PASL] = ch$rchar_a (PTR)) gtr 8
		then leave CBE with -S_ECBE;
	    ch$move (.CB [CB_PASL], .PTR, CB [CB_PASW]);
	    PTR = ch$plus (.PTR, .CB [CB_PASL]);
	    if (CB [CB_ACTL] = ch$rchar_a (PTR)) gtr 16
		then leave CBE with -S_ECBE;
	    ch$move (.CB [CB_ACTL], .PTR, CB [CB_ACNT]);
	    PTR = ch$plus (.PTR, .CB [CB_ACTL])
	    end;

	if (.MENU and U_DATA) neq 0
	then
	    begin
	    if (CB [CB_OPDL] = ch$rchar_a (PTR)) gtr 16
		then leave CBE with -S_ECBE;
	    ch$move (.CB [CB_OPDL], .PTR, CB [CB_OPTD]);
	    PTR = ch$plus (.PTR, .CB [CB_OPDL])
	    end;

	S_SSUC
	end;

    MAP$ (.SCDB [SC_LLT_BIAS]);			! Back to original mapping

    if .ERR eql S_SSUC
    then
	begin
	local
	    PIX;
	if not FINDOB (CB [CB_DFMT], PIX)
	then ERR = -S_EURO else LNK [L_PIX] = .PIX
	end;

    byt$short_string (ERR, EPTR);		! Record the error code

    if .ERR eql S_SSUC
    then
	begin
	LCCB [C_CNT] = CB_SIZE*bytes_word;	! Set connect block length
	return true
	end
    else
	begin
	$MCB_RETURN_DSR (CB_SIZE*bytes_word, .CB);
	return false
	end
    end;
global routine CONBKO (CCB, LCCB) =

!++
! FUNCTIONAL DESCRIPTION:
!	Translates connect block to protocol form, in buffer
!
! FORMAL PARAMETERS:
!	CCB	CCB which owns connect block
!	LCCB	CCB which owns xmit buffer
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	Connect message built in LCCB [C_BUF]
!
! ROUTINE VALUE:
!	True, if successful
!	False, if failure
!
! COMPLETION CODES:
!	CCB [C_STS] set for error
!
! SIDE EFFECTS:
!	None
!--
    begin
    $sc_get_data_base (SCDB);
    map CCB: ref block field (C_FIELDS),
	LCCB: ref block field (C_FIELDS);
    local
	PTR,				! Dest buffer pointer
	MENU,				! Message word to construct
	CB: ref block field (CB_FIELDS),! The connect block
	SAV_MAP;
    label CB_PARSE;

    if not $MCB_GET_DSR (CB_SIZE*bytes_word, CB) ! Memory to copy connect block
    then
	begin
	CCB [C_STS] = S_ERES;		! Not enuf memory !!
	return false
	end;

    SMAP$ (SAV_MAP);			! Save current mapping
    MAP$ (.CCB [C_BIAS]);		! Map to user connect block and copy it
    ch$move (CB_SIZE*bytes_word, .CCB [C_ADDR], byt$ptr (.CB));
    MAP$ (.LCCB [C_BIAS]);		! Map to connect message buffer
    PTR = .LCCB [C_ADDR];		! Point to buffer

    CCB [C_STS] = CB_PARSE:
	begin

	! Check destination & source specs, and copy to msg buffer
	if not (DST_SRC_O(CB [CB_DFMT], PTR) and DST_SRC_O(CB [CB_SFMT], PTR))
	then leave CB_PARSE with S_EIOF;

	MENU = 0;			! See what rest of message contains
	if .CB [CB_RQDL] neq 0 then MENU = U_INFO;		! We have ID
	if .CB [CB_OPDL] neq 0 then MENU = .MENU or U_DATA;	!  and data
	ch$wchar_a (.MENU, PTR);				! Write menu

	if (.MENU and U_INFO) neq 0
	then
	    begin
	    ch$wchar_a (.CB [CB_RQDL], PTR);
	    PTR = ch$move (.CB [CB_RQDL], byt$ptr (CB [CB_RQID]), .PTR);
	    ch$wchar_a (.CB [CB_PASL], PTR);
	    PTR = ch$move (.CB [CB_PASL], byt$ptr (CB [CB_PASW]), .PTR);
	    ch$wchar_a (.CB [CB_ACTL], PTR);
	    PTR = ch$move (.CB [CB_ACTL], byt$ptr (CB [CB_ACNT]), .PTR)
	    end;

	if (.MENU and U_DATA) neq 0
	then
	    begin
	    ch$wchar_a (.CB [CB_OPDL], PTR);
	    PTR = ch$move (.CB [CB_OPDL], byt$ptr (CB [CB_OPTD]), .PTR)
	    end;

	LCCB [C_CNT] = ch$diff (.PTR, .LCCB [C_ADDR]);
	S_SSUC
	end;

    $MCB_RETURN_DSR (CB_SIZE*bytes_word, .CB);	! Recover memory
    MAP$ (.SAV_MAP);				! Finally restore mapping

    if .CCB [C_STS] geq 0
    then return true
    else return false
    end;
global routine DO_RCP (CCB, MODIFIER, LNK): linkage_ccb novalue =

!++
! FUNCTIONAL DESCRIPTION:
!	Do RCP processing
!
! FORMAL PARAMETERS:
!	CCB	CCB address
!	MODIFIER RCP modifier
!	LNK	LNK address
!
! IMPLICIT INPUTS:
!	LLT mapped
!
! IMPLICIT OUTPUTS:
!	CCB scheduled
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--
    begin
    $sc_get_data_base (SCDB);
    map CCB: ref block field (C_FIELDS),
	LNK: ref block field (LLT_FIELDS);

    CCB [C_FNC] = FC_RCP;
    CCB [C_MOD] = .MODIFIER;
    CCB [C_PIX] = .LNK [L_PIX];
    CCB [C_LIX] = .LNK [L_LLA];
    CCB [$sub_field (C_PRM1, LO_BYTE)] = .LNK [L_ULA];
    $MCB_SCHEDULE_CCB (.CCB)
    end;
global routine DO_XME (CCB, MODIFIER, LNK): linkage_ccb novalue =

!++
! FUNCTIONAL DESCRIPTION:
!	Do XME processing
!
! FORMAL PARAMETERS:
!	CCB	CCB address
!	MODIFIER RCP modifier
!	LNK	LNK address
!
! IMPLICIT INPUTS:
!	LLT mapped
!
! IMPLICIT OUTPUTS:
!	CCB scheduled
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--
    begin
    $sc_get_data_base (SCDB);
    map CCB: ref block field (C_FIELDS),
	LNK: ref block field (LLT_FIELDS);

    CCB [C_FNC] = FC_XME;
    CCB [C_MOD] = .MODIFIER;
    CCB [C_PIX] = .SCDB [SC_NSPIX];
    CCB [C_LIX] = .LNK [L_PID];
    $MCB_SCHEDULE_CCB (.CCB)
    end;
global routine DST_SRC_I (BLK, PTR) =

!++
! FUNCTIONAL DESCRIPTION:
!	This routine transcribes source and destination
!	specifications from the message indicated by PTR
!	to the connect block segment identified by BLK.
!	The descriptors are also validated for correct format.
!
! FORMAL PARAMETERS:
!	BLK	DST/SRC block address
!	PTR	Buffer pointer address
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	PTR is updated
!
! ROUTINE VALUE:
!	True is success, else False
!
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--

    begin
    map BLK: ref block field (CBSD_FIELDS);
    bind
	P = .PTR;

    BLK [CB_FMT] = ch$rchar_a (P);		! Get Format Code
    BLK [CB_OBJ] = ch$rchar_a (P);		! Get Object Type

    case .BLK [CB_FMT] from 0 to 2 of
	set

	[0]:
	    if .BLK [CB_OBJ] eql 0
	    then return false;

	[1]:
	    begin
	    if	(.BLK [CB_OBJ] neq 0) or
		((BLK [CB_LEN] = ch$rchar_a (P)) eql 0) or
		(.BLK [CB_LEN] gtr 16)
	    then
		return false
	    else
		begin
		ch$move (.BLK [CB_LEN], .P, byt$ptr (BLK [CB_NAM]));
		P = ch$plus (.P, .BLK [CB_LEN])
		end
	    end;

	[2]:
	    begin
	    if .BLK [CB_OBJ] neq 0 then return false;
	    ch$move (4, .P, byt$ptr (BLK [CB_GRP]));
	    P = ch$plus (.P, 4);
	    if ((BLK [CB_LN2] = ch$rchar_a (P)) eql 0) or
		(.BLK [CB_LN2] gtr 12)
	    then return false;
	    ch$move (.BLK [CB_LN2], .P, byt$ptr (BLK [CB_NM2]));
	    P = ch$plus (.P, .BLK [CB_LN2])
	    end;

	[inrange, outrange]:
	    return false;

	tes;

    return true
    end;
routine DST_SRC_O (BLK, PTR) =

!++
! FUNCTIONAL DESCRIPTION:
!	This routine validates the destination or source object
!	specification in a connect block, and copies it to the
!	buffer.
!
! FORMAL PARAMETERS:
!	BLK	DST/SRC block address
!	PTR	Buffer pointer address
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	PTR is updated
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	True is success, else False
!
! SIDE EFFECTS:
!	None
!--
    begin
    map BLK: ref block field (CBSD_FIELDS);
    local
	LEN,
	DAT;
    bind
	P = .PTR;

    ch$wchar_a (.BLK [CB_FMT], P);
    ch$wchar_a (.BLK [CB_OBJ], P);

    case .BLK [CB_FMT] from 0 to 2 of
	set

	[0]:
	    if .BLK [CB_OBJ] eql 0
	    then return false
	    else return true;

	[1]:
	    begin
	    if (.BLK [CB_OBJ] neq 0) or (.BLK [CB_LEN] eql 0)
	    then return false;
	    LEN = .BLK [CB_LEN];
	    DAT = BLK [CB_NAM]
	    end;

	[2]:
	    begin
	    if .BLK [CB_OBJ] neq 0 then return false;
	    P = ch$move (4, byt$ptr (BLK [CB_DES]), .P);
	    LEN = .BLK [CB_LN2];
	    DAT = BLK [CB_NM2]
	    end;

	[inrange, outrange]:
	    return false;

	tes;

    P = ch$move (1, byt$ptr (LEN), .P);
    P = ch$move (.LEN, byt$ptr (.DAT), .P);
    return true
    end;
global routine FINDLL (LL) =

!++
! FUNCTIONAL DESCRIPTION:
!	Locate an available logical link, and return its index
!	in LL.
!
! FORMAL PARAMETERS:
!	LL	Word to receive logical link index
!
! IMPLICIT INPUTS:
!	LLT mapped
!
! IMPLICIT OUTPUTS:
!	LL block is initialized
!
! ROUTINE VALUE:
!	true = logical link found
!	false = logical link not found
!
! SIDE EFFECTS:
!	None
!--
    begin
    $sc_get_data_base (SCDB);
    bind
	LLT = SCDB [SC_LLT_ADDR]: ref blockvector [,L_SIZE] field (LLT_FIELDS);

    .LL =
	begin
	incr L from 0 to .SCDB [SC_LINKS]-1 do
	    begin
	    bind
		LNK = LLT [.L, L_TOP]: block field (LLT_FIELDS);

	    if (.LNK [L_STATE] eql ST_OFF) and (.LNK [L_FLAGS] eql 0)
	    then
		begin
		ch$fill (0, L_SIZE*bytes_word, byt$ptr (LNK));
		LNK [L_FLAGS] = 0;
		LNK [L_I_TAIL] = LNK [L_I_HEAD];
		LNK [L_O_TAIL] = LNK [L_O_HEAD];
		LNK [L_N_TAIL] = LNK [L_N_HEAD];
		LNK [L_LLA] = .L;
		exitloop .L
		end
	    end
	end;

    if ..LL eql -1
    then false
    else true
    end;
global routine FINDND (CCB, LNK) =

!++
! FUNCTIONAL DESCRIPTION:
!	Determine address of node specified in connect block.
!
! FORMAL PARAMETERS:
!	CCB	CCB pointing to connect block
!	LNK	Link block address
!
! IMPLICIT INPUTS:
!	LLT mapped
!
! IMPLICIT OUTPUTS:
!	LNK [L_RNA] = remote node address
!	LNK [L_CHN] = channel #
!
! ROUTINE VALUE:
!	true = Node address determined
!	false = Node address not determined
!
! SIDE EFFECTS:
!	None
!--
    begin
    $sc_get_data_base (SCDB);
    map
	CCB: ref block field (C_FIELDS),
	LNK: ref block field (LLT_FIELDS);
    local
	REMOTE_NODE_ADDR,
	CHANNEL_NUMBER,
	CH,
	LEN,
	PTR,
	NODE: vector [byt$allocation (6)];
    bind
	NMT = SCDB [SC_NMT_ADDR]: ref blockvector [ , NMT_SIZE] field (NMT_FIELDS);

    MFBF$S (6, .CCB [C_BIAS], .CCB [C_ADDR], byt$ptr (NODE));

    PTR = byt$ptr (NODE);
    LEN = 0;					! Calc length of name
    incr I from 1 to 6 do
	if (CH = ch$rchar_a (PTR)) eql %c' ' or .CH eql 0
	then exitloop
	else LEN = .LEN + 1;

    LNK [L_CHN] = 0;				! Assume not loopnode
    if (LNK [L_RNA] = CNVAD$ (byt$ptr (NODE), .LEN)) neq 0
	then if (.LNK[L_RNA] gtru .SCDB[SC_NODES])
		then return false
		else return true;

    PTR = byt$ptr (NODE);
    incr I from 1 to 6 do			! Do the shift to uppercase
	begin
	if (CH = ch$rchar (.PTR)) geq %c'a' and .CH leq %c'z'
	then CH = .CH - (%c'a' - %c'A');
	ch$wchar_a (.CH, PTR)
	end;

    if .LEN eql 0
    then
	begin
	LNK [L_RNA] = .SCDB [SC_LADDR];
	return true
	end;

    MAP$ (.SCDB [SC_NMT_BIAS]);
    REMOTE_NODE_ADDR = CHANNEL_NUMBER = 0;

    incr N from 0 to .SCDB [SC_NODES] + .SCDB [SC_LOOPS] - 1 do
	begin
	if ch$eql (.LEN, byt$ptr (NODE), .NMT [.N, NMT_NAML], byt$ptr (NMT [.N, NMT_NAME]), 0)
	then
	    begin
	    if .N lss .SCDB [SC_NODES]
	    then
		REMOTE_NODE_ADDR = .NMT [.N, NMT_ADDR]
	    else
		CHANNEL_NUMBER = .NMT [.N, NMT_CHAN];
	    exitloop
	    end
	end;

    MAP$ (.SCDB [SC_LLT_BIAS]);
    LNK [L_RNA] = .REMOTE_NODE_ADDR;
    LNK [L_CHN] = .CHANNEL_NUMBER;
    if (.REMOTE_NODE_ADDR + .CHANNEL_NUMBER) neq 0 then return true else false
    end;
routine FINDOB (DST, PIX) =

!++
! FUNCTIONAL DESCRIPTION:
!	Locate object type, and return process index
!
! FORMAL PARAMETERS:
!	DST	Destination portion of connect block
!	PIX	Place to return process index
!
! IMPLICIT INPUTS:
!	Connect block format checking already performed.
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!	True if object found
!	False if object not found
!
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--
    begin
    $sc_get_data_base (SCDB);
    map DST: ref block field (CBSD_FIELDS);
    local
	SAV_MAP,
	PROC_NAM,
	NAM_LEN,
	NAM_PTR,
	NAME: vector [byt$allocation (6)];
    bind
	OTN = SCDB [SC_OTN_ADDR]: ref blockvector [,OTN_SIZE] field (OTN_FIELDS),
	ONP = SCDB [SC_ONP_ADDR]: ref blockvector [,ONP_SIZE] field (ONP_FIELDS);

    SMAP$ (SAV_MAP);
    case .DST [CB_FMT] from 0 to 2 of
	set

	[0]:			! Format 0
	    begin
	    MAP$ (.SCDB [SC_OTN_BIAS]);		! Set to object table map
	    NAM_LEN = 0;			! Be pessimistic
	    incr I from 0 to .SCDB [SC_OTN_LEN]-1 do
		begin
		if .DST [CB_OBJ] eql .OTN [.I, OTN_TYPE]
		then
		    begin
		    NAM_PTR = byt$ptr (NAME);	! Copy name to local store
		    ch$move (6, byt$ptr (OTN [.I, OTN_NAME]), .NAM_PTR);
		    NAM_LEN = .OTN [.I, OTN_NLEN];
		    exitloop
		    end
		end;

	    if .NAM_LEN eql 0
	    then
		begin
		MAP$ (.SAV_MAP);		! Restore mapping
		return false			!   and bomb
		end
	    end;

	[1]:			! Format 1
	    begin
	    NAM_PTR = byt$ptr (DST [CB_NAM]);
	    NAM_LEN = .DST [CB_LEN]
	    end;

	[2]:			! Format 2
	    begin
	    NAM_PTR = byt$ptr (DST [CB_NM2]);
	    NAM_LEN = .DST [CB_LN2]
	    end;
	tes;

    MAP$ (.SCDB [SC_ONP_BIAS]);		! Now look at object-to-process table
    PROC_NAM = 0;			! Again, be a pessimist

    incr I from 0 to .SCDB [SC_ONP_LEN]-1 do
	begin
	if ch$eql (.NAM_LEN, .NAM_PTR, .ONP [.I, ONP_NLEN], byt$ptr (ONP [.I, ONP_NAME]), %c'.')
	then
	    begin
	    PROC_NAM = .ONP [.I, ONP_PROC];	! Set selected process name
	    exitloop
	    end
	end;

    MAP$ (.SAV_MAP);				! Restore mapping
    if .PROC_NAM eql 0 then PROC_NAM =		! Default to SCX
	%if %bliss (bliss36) %then %rad50_10 'SCX' %else %rad50_11 'SCX' %fi;
    PDVID$ (.PROC_NAM, .PIX)			! Locate the PIX
    end;
global routine I$CLS (LNK): novalue =

!++
! FUNCTIONAL DESCRIPTION:
!	Issue a close on the specified link to NSP.
!
! FORMAL PARAMETERS:
!	LNK	Link data base address
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--
    begin
    $sc_get_data_base (SCDB);
    map LNK: ref block field (LLT_FIELDS);
    local
	CCB: ref block field (C_FIELDS);

    if .LNK [L_STATE] eql ST_CLI then return;	! If close started, then return
    LNK [LL_CLSI] = true;			! Ok, we are fixing to start
    if CCBGT$ (CCB)
    then
	begin
	$SC_DO_XME (.CCB, N_PCLS, .LNK);
	LNK [L_STATE] = ST_CLI			! Now we've done it
	end
    else
	begin
	LNK [LL_KLOK] = true;			! Request clock service
	LNK [L_TIMER] = 1;			! ...
	SCDB [SCF_KLOK] = true			! ...
	end
    end;
global routine I$OPN: novalue =

!++
! FUNCTIONAL DESCRIPTION:
!	Open an NSP port if one is needed.
!
! FORMAL PARAMETERS:
!	None
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--
    begin
    $sc_get_data_base (SCDB);
    local
	LL,
	SAV_MAP,
	CCB: ref block field (C_FIELDS);
    bind
	LLT = SCDB [SC_LLT_ADDR]: ref blockvector [,L_SIZE] field (LLT_FIELDS);

    if (not .SCDB [SCF_OPEN]) and (.SCDB [SC_IPORT] lss .SCDB [SC_RPORT])
    then
	begin
	if not CCBGT$ (CCB) then return;
	SMAP$ (SAV_MAP);
	MAP$ (.SCDB [SC_LLT_BIAS]);
	if FINDLL (LL)
	then
	    begin
	    bind
		LNK = LLT [.LL, L_TOP]: block field (LLT_FIELDS);

	    CCB [C_PRM1] = LLT [.LL, L_TOP];
	    $SC_DO_XME (.CCB, N_POPN, LNK [L_TOP]);
	    LNK [LL_BUSY] = true;
	    LNK [L_STATE] = ST_OI;
	    SCDB [SCF_OPEN] = true
	    end
	else
	    CCBRT$ (.CCB);

	MAP$ (.SAV_MAP)
	end
    end;
global routine STKCCB (NCCB, OCCB): novalue =

!++
! FUNCTIONAL DESCRIPTION:
!	Performs stacking of NCCB onto OCCB, and transfers
!	buffer pointers.
!
! FORMAL PARAMETERS:
!	NCCB	New top-level CCB
!	OCCB	Old instigator CCB
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--
    begin
    map
	NCCB: ref block field (C_FIELDS),
	OCCB: ref block field (C_FIELDS);

    NCCB [C_STK] = .OCCB;		! Point to originator CCB
    NCCB [C_CHN] = .OCCB [C_CHN];	! Copy chain info
    NCCB [C_BIAS] = .OCCB [C_BIAS];	! Copy buffer info
    NCCB [C_ADDR] = .OCCB [C_ADDR];	! ...
    NCCB [C_CNT] = .OCCB [C_CNT]	! ...
    end;
global routine STSMAP (CODE) =

!++
! FUNCTIONAL DESCRIPTION:
!	Map from NSP error code to SC error code
!
! FORMAL PARAMETERS:
!	CODE	The NSP error code
!
! IMPLICIT INPUTS:
!	None
!
! IMPLICIT OUTPUTS:
!	None
!
! ROUTINE VALUE:
!	SC code value
!
! COMPLETION CODES:
!	None
!
! SIDE EFFECTS:
!	None
!--
    begin
    macro
	C (NSP_CODE, SC_CODE) = ((NSP_CODE - N$LO)^1, SC_CODE) %;
    bind
	STATUS_MAP = TABLE$ (S_EERR, (N$HI - N$LO)^1,
	    C (N$SSUC, S_SSUC),
	    C (N$SACC, S_SSUC),
	    C (N$SREJ, S_ERBO),
	    C (N$ERES, S_ERES),
	    C (N$ECON, S_ENUR),
	    C (N$ESTE, S_EERR),
	    C (N$EOPN, S_ERES),
	    C (N$EABR, S_EABS),
	    C (N$ETMI, S_EERR),
	    C (N$ERMO, S_EIDM),
	    C (N$ELST, S_ELST),
	    C (N$EMTL, S_EMTL),
	    C (N$ECLS, S_EABL),
	    C (N$EABL, S_EABO),
	    C (N$ENUR, S_ENUR)): vector;

    .STATUS_MAP [.CODE - N$LO]
    end;

end
eludom