SRI-NOSC/ncpd/files.c

#

/*	files.c		*/

/*	globals declared in this file:
		n_f_left

	functions declared in this file:
		f_make
		fi_sktnm
		fi_sopn
		fi_sgone
		fi_all
		f_rlse
		f_by_id
		fi_ssn
		fi_rfnm
*/

#include	"hstlnk.h"
#include	"files.h"
#include	"globvar.h"
#include	"kread.h"
#include	"kwrite.h"
#include	"socket.h"
#include	"leader.h"

/* SCCS PROGRAM IDENTIFICATION STRING */
char id_files[] "~|^`files.c\tV3.9E0\tJan78\n";

int	n_f_left	nfiles;	/* counter for allocating files */

/*name:
	f_make

function:
	attempts to allocate a file struct and reserve the speified number of
	socket structs. if unsuccessful, it 
	returns 1; otherwise it sets the global fp to the
	address of the file struct allocated, initializes the file
	struct, and returns 0.

algorithm:
	if the number of files left is 0 or the number of sockets left
	is less than the number requested:
		return 1.
	loop thru all file structs:
		if the file state is null:
			set global file pointer fp.
			set id as given by the parameter.
			set socket number base to zero.
			set number of sockets reserved as specified.
			set all f_skt_x to null.
			set number of attached sockets to zero.
			decrement file allocation counter by 1.
			decrement socket allocation counter by the number
			reserved for this file.
			return 0.
	if we fall out of the loop then the file allocation counter is 
	inconsistent with the state of the tables and we die with
	a suitable error message.

parameters:
	id		kernel id to be assigned to the file.
	n_r_skts	number of socket structs to be reserved for this
			file.

returns:
	1	if the attempt to allocate file and/ or sockets was
		unsuccessful.
	0	if it was successful.
	dies	if it discovers inconsistency in the tables.

globals:
	fp=
	files=
	fs_null
	fsx_null
	n_f_left=
	n_s_left=

calls:
	die

called by:
	kr_oicp
	kr_odrct

history:
	initial coding 12/30/74 by G. R. Grossman
	clearing f_sbase added 5/28/75 by G. R. Grossman.

*/

int	f_make(id,n_r_skts)
int	id,n_r_skts;
{
	register struct file	*lfp;	/* will point to file structs
					   during search */

	if ( n_f_left <= 0 || n_s_left < n_r_skts )	/* can we allocate
							   file and socket
							   structs? */
		return(1);	/* no, return 1 */
	for ( lfp = &files[0] ; lfp < &files[nfiles] ; lfp++ )
			/* loop thru all file structs */
	{
		if ( lfp->f_state == fs_null )	/*this one not in use? */
		{
			fp = lfp;		/* set global file pointer */
			lfp->f_id = id;		/* set file's kernel id */
			lfp->f_sbase = 0;	/* we don't have a base socket
						   number yet */
			lfp->f_nsrsrv = n_r_skts;	/* set number of
							   reserved sockets */
			lfp->f_skt_x[0] =	/* null socket indices */
				lfp->f_skt_x[1] =
					lfp->f_skt_x[2] = fsx_null;
			lfp->f_nsatt = 0;	/* number of attached sockets */
			n_f_left =- 1;		/* update file struct
						   allocation counter */
			n_s_left =- n_r_skts;	/* update socket struct
						   allocation counter */
			return(0);		/* signifies success */
		}
	}
	die("f_make - file allocation inconsistent");
		/* if we got here the file allocation counter did not
		   agree with the number of free files, so die */
}

/*name:
	fi_sktnm

function:
	handles the socket number transmitted by the foreign logger in
	user icp.

algorithm:
	set global file pointer to point to the associated file.
	if the file is in the socket number wait state:
		if the socket number is of the wrong (odd) polarity:
			log the occurrance.
			kill the socket (this will eventually cause the
			socket to be closed and fi_sgone to be called
			while the file is still in the socket number
			wait state, causing the open to be terminated
			abnormally).
			return.
		set file state to data open wait.
		compute proper socket offset for local base socket (add 2
		to icp local socket.
		create the data sockets via sm_dux.
		kill the icp socket.
	(NOTE that if the file was not in socket number wait state, we
	 take no action; this happens only if a close is in progress
	 when the socket number arrives.)

parameters:
	icpsktp		pointer to icp socket for connection on which
			socket number has arrived.
	fkstn_p		pointer to socket number.

returns:
	nothing.

globals:
	fp=
	fs_uisnw
	fs_dopnw
	si_init

calls:
	log_bin
	kill_skt
	sm_dux

called by:
	hr_data

history:
	initial coding 12/30/74 by G. R. Grossman

*/

fi_sktnm(icpsktp,fsktn_p)
struct socket	*icpsktp;
char	*fsktn_p;
{
	register struct file	*f_p;	/* will point to file struct
					   associated with socket */
	char	lskt[2];		/* will hold base for local data
					   sockets */
	fp = f_p = icpsktp->s_filep;	/* set global file pointer and local 
					   one to socket's file pointer */
	if ( f_p->f_state == fs_uisnw )	/* file state = socket number wait? */
	{
		if ( fsktn_p[3] & 1 )	/* wrong socket polarity? */
		{
			log_bin("fi_sktnm - bad uicp fskt",fsktn_p,4);
				/* log socket number */
			log_bin("....from host",&host,1);	/* and host */
			kill_skt(icpsktp);	/* kill connection */
			return;
		}
		f_p->f_state = fs_dopnw;	/* set state to data open
						   wait */
		skt_off(&icpsktp->s_lskt[2],&lskt[2],2,2);
			/* compute proper local socket: offset 2 from
			   number of icp socket */
		sm_dux(&lskt[0],fsktn_p,si_init);	/* make 2 data 
							   sockets */
		kill_skt(icpsktp);		/* kill icp socket */
	}
}

/*name:
	fi_sopn

function:
	called every time a connection is opened; handles the opening
	of a connection at the file level: initial allocations and mods
	are taken care of here.

algorithm:
	set global file pointer fp.
	if the just-opened socket is an icp socket:
		if file state is user icp open wait:
			write mod to kernel ( status = open, daemon data
					      messages =1, bits = 32 )
			send all to host (messages = 1, bits = 32 )
			set file state to socket number wait.
			return.
		if file state is server icp open wait:
			write mod to kernel (status = open, daemon data).
			save current time for possible time out
			set file state to ALL wait.
			return.
		otherwise file state is invalid:
			die with appropriate messages.
	otherwise the just-opened socket is a data socket:
		if file state is data open wait:
			if socket is a receive socket:
				write mod to kernel(status = open,
						    messages and bits nominal )
				send all to host (messages and bits nominal )
			else it is a send socket:
				write mod to kernel(status = open,
						    messages and bits zero )
		otherwise file state is invalid:
			die with appropriate messages.
		if all reserved sockets are attached,
		and other data socket is non-existent or open:
			set file state to open.
			reset timer info
			write ready to kernel.

parameters:
	skt_p	pointer to socket struct for just-openend socket.

returns:
	nothing.

globals:
	fp=
	ksx_icp
	fs_uiopw
	kwi_mod
	ksb_open
	ksb_ddat
	fs_uisnw
	fs_dopnw
	nom_mall
	nom_ball
	fsx_null
	ss_open
	fs_open
	fs_siopw
	fs_sialw

calls:
	die
	log_bin
	kw_sumod
	hw_all
	kw_rdy
	time (sys)

called by:
	lsint_q
	rfc_rfcw

history:
	initial coding 12/31/74 by G. R. Grossman
	fix to check for all reserved sockets attached before
	checking for existence or openness of other data socket
	made 1/10/75 by G. R. Grossman.
	server icp state handling added 7/3/75 by G. R. Grossman.
	time out code for server connection added 6/14/76 by S. F. Holmgren

*/

fi_sopn(skt_p)
struct socket	*skt_p;
{
	register int	oth_skt;	/* holds index of socket for other
					   direction */
	register struct socket	*s_p;	/* will point to socket struct */
	register struct file	*f_p;	/* will point to file struct */

	s_p = skt_p;			/* get pointer to socket */
	fp = f_p = s_p->s_filep;	/* get pointer to associated file
					   and set global file pointer */
	if ( s_p->s_sinx == ksx_icp )	/* icp socket? */
	{
		switch ( f_p->f_state )	/* decode file state */
		{
			case	fs_uiopw:	/* user icp open wait */
			{
				kw_sumod(kwi_mod,s_p,(ksb_open|ksb_ddat),
					 1,0,32);/* write mod:open, daemon data
						   1 message, 32 bits */
				hw_all(s_p,1,32);	/* send all:
							   1 msg, 32 bits */
				f_p->f_state = fs_uisnw;/* file state =
							   socket number wait */
				return;
			}
			case	fs_siopw:	/* server icp open wait */
			{
				kw_sumod ( kwi_mod, s_p, ( ksb_open | ksb_ddat ),
					   0, 0, 0 );	/* write mod: open,
							   daemon data */
				/* keep track of time this open takes */
				time( &f_p->f_timeo );
				f_p->f_timeo =+ FTIMEOUT;
				ftimeo++;                       /* inc people waiting */
				f_p->f_state = fs_sialw;	/* file state =
								   ALL wait */
				return;
			}
invalid:		default:		/* bad file state */
				die("fi_sopn - bad file state");
		}
	}
	else				/* data socket */
	{
		if ( f_p->f_state != fs_dopnw )	/* bad file state? */
			goto invalid;		/* go take care of it */
		if ( (s_p->s_lskt[1] & 1) == 0 )	/* receive socket? */
		{
			kw_sumod(kwi_mod,s_p,ksb_open,nom_mall,0,nom_ball);
				/* write mod:state = open, nominal alloc */
			hw_all(s_p,nom_mall,nom_ball);	/* send nominal alloc */
		}
		else		/* send sokcket */
		{
			kw_sumod(kwi_mod,s_p,ksb_open,0,0,0);
				/* write mod:state = open, zero alloc */
		}
		if ( (fp->f_nsatt == fp->f_nsrsrv)	/* all needed sockets
							   attached? */
		&& ( ((oth_skt = f_p->f_skt_x[s_p->s_sinx^1]) == fsx_null)
			/* no other socket? */
		    ||(sockets[oth_skt].s_state == ss_open) ) )
			/* or other socket open? */
		{
			f_p->f_state = fs_open;	/* set file state to open */
			f_p->f_timeo = 0;
			kw_rdy(f_p->f_id,0);	/* write errorless ready */
		}
	}
}

/*name:
	fi_sgone

function:
	handles the closing of a connection at the file level.

algorithm:
	the global file pointer, fp, is set to point to the file
	associated with the socket.
	the socket is detached from the file by setting the 
	corresponding socket index byte to null and decrementing the
	attached and reserved counters.
	if the socket was an icp socket:
		if the file is in the user icp open or socket number wait
		or server icp open or ALL wait or rfnm wait
		states:
			write error ready to kernel (due to premature
			closing of contact connection).
			release the file via f_rlse.
			return
		if the file is in the gone wait state:
	gonechk:	if the number of attached sockets is now zero:
				release the file via f_relse.
			return.
	otherwise the socket was a data socket:
		if the file was in the data open wait state:
			send error ready to kernel.
			if there is another data socket:
				kill other data socket.
			set file state to gone wait.
			go to gonechk.
		if the file was in the open state:
			if there is another data socket:
				kill other data socket.
			set file state to gone wait.
			go to gonechk.
		if the file was in the gone wait state:
			go to gonechk.

parameters:
	skt_p	points to socket whose connection has just been closed.

returns:
	nothing.

globals:
	fp=
	fsx_null
	ksx_icp
	fs_uiopw
	fs_uisnw
	fs_gonew
	fs_siopw
	fs_sialw
	fs_sirfw
	EDAEIO
	fs_dopnw
	sockets

calls:
	kw_rdy
	f_rlse
	kill_skt

called by:
	free_skt

history:
	initial coding 12/31/74 by G. R. Grossman
	setting file state to gone wait in data socket cases added
	5/29/75 by G. R. Grossman.
	server icp state handling added 7/3/75 by G. R. Grossman.
	modified user & server open waits to just release the file
	6/27/76 by S. F. Holmgren

*/

fi_sgone(skt_p)
struct socket	*skt_p;
{
	register struct socket	*s_p;		/* will point to socket */
	register struct file	*f_p;		/* will point to its file */
	register int	x;	/* in one case will hold index of other data
				   socket; at first, holds type index of socket
				   we're passed */

	s_p = skt_p;			/* get pointer to socket */
	fp = f_p = s_p->s_filep;	/* set global file pointer from 
					   socket's file pointer */
	x = s_p->s_sinx;		/* get socket type index form socket */
	f_p->f_skt_x[x] = fsx_null;	/* set corresponding skt_x to null */
	f_p->f_nsatt =- 1;		/* decrement attached socket count */
	f_p->f_nsrsrv =- 1;		/* decrement reserved socket count */
	if ( x == ksx_icp )		/* icp socket? */
	{
		switch ( f_p->f_state )	/* decode file state */
		{
		case	fs_uisnw:	/* user icp socket number wait */
		case	fs_sialw:	/* server icp ALL wait */
		case	fs_sirfw:	/* server icp rfnm wait */
		case	fs_uiopw:	/* user icp open wait */
		case	fs_siopw:	/* server icp open wait */

				kw_rdy(f_p->f_id,EDAEIO);/* write error ready
							   to kernel */
				f_rlse();		/* release file */
				return;

gonechk:	case	fs_gonew:	/* gone wait */
			{
				if ( f_p->f_nsatt == 0 )/* no sockets 
							   attached? */
					f_rlse();	/* release file */
				return;
			}
		}
	}
	else	/* data socket */
	{
		switch ( f_p->f_state )		/* decode file state */
		{
		case	fs_dopnw:	/* data open wait */
			kw_rdy(f_p->f_id,EDAEIO);	/* write error ready */
		case	fs_open:	/* file was open */
			if ( (x = f_p->f_skt_x[x^1]) != fsx_null )
#ifndef HALFCLOSE
				/* socket for other direction exists? */
				kill_skt(&sockets[x]);	/* kill it */
#endif
#ifdef HALFCLOSE
				/* null statement */;
			else
#endif
			f_p->f_state = fs_gonew;	/* set file state to
							   gone wait */
		case	fs_gonew:	/* gone wait */
			goto gonechk;	/* go check for release */
		}
	}
}

/*name:
	fi_all

function:
	handles the reception of an ALL at the file level.

algorithm:
	if the socket is an icp socket:
		if the socket is a receive socket:
			go die, see below.
		if the file associated with the socket is not in the ALL
		wait state:
			return, ignoring the ALL.
		if the allocation is insufficient ( msgs < 1, bits < 32 ):
			initiate close, aborting the icp.
			return.
		send socket number via fi_ssn.
		set file state to rfnm wait.
	otherwise:
		if the socket is a data send socket:
			write mod to kernel passing on the ALL parameters.
		otherwise:
			die because it is inconsistent for us to get an ALL
			on receive socket, as table structure, notably the
			oring in of 0200 to send links, should preclude this.

parameters:
	skt_p	pointer to socket struct for which the ALL was received.
	msgs	message filed from ALL as an int.
	bits_hi	hi 16 bits of bits field from ALL as an int.
	bits_lo	lo 16 bits as above.

returns:
	nothing.

globals:
	ksx_icp
	ksx_xmit
	kwi_mod
	ksb_open
	s_*
	f_*
	fp=
	fs_*

calls:
	kw_sumod
	die
	kill_skt
	fi_ssn

called by:
	hr_all

history:
	initial coding 1/11/75 by G. R. Grossman
	modified to handle server icp 7/8/75 by G. R. Grossman.

*/

fi_all(skt_p,msgs,bits_hi,bits_lo)
struct socket	*skt_p;
char	*msgs,*bits_hi,*bits_lo;
{
	register struct socket	*s_p;	/* will point to socket struct */

	s_p = skt_p;
	fp = s_p->s_filep;
	if ( s_p->s_sinx == ksx_icp )		/* icp socket? */
	{
		if ( ( s_p->s_lskt[1] & 1 ) == 0 )
			goto broken;	/* ALL on receive socket, go dump */
		if ( fp->f_state != fs_sialw )		/* not ALL wait? */
			return;		/* simply ignore */
		if (    ( msgs == 0 )	/* no msgs allocated? */
		     ||	( ( bits_hi == 0 ) && ( bits_lo < 32 ) ) )
				/* or not enough bits? */
		{
			kill_skt ( s_p );	/* initiate close which will
						   abort icp */
			return;
		}
		fi_ssn ( s_p );		/* alles ist in ordnung, send socket
					   number */
		fp->f_state = fs_sirfw	;	/* set file to rfnm
						   wait state */
		s_p->s_state = ss_orfnmw;
	}
	else					/* data socket */
		if ( s_p->s_sinx == ksx_xmit )	/* send socket? */
			kw_sumod(kwi_mod,s_p,ksb_open,msgs,bits_hi,bits_lo);
				/* pass ALL parameters to kernel */
		else				/* rcv socket */
broken:			die("fi_all - ALL on bad socket");	/* let's see */
}

/*name:
	f_rlse

function:
	releases a socket struct from use.

algorithm:
	increment the free socket count by the number of sockets still
	reserved for the file.
	set the file state to null.
	make sure timer info is stepped on
	increment the free file count by 1.
	if the socket number base is non-zero:
		loop thru all file structs:
			if the struct is in use and it has the same socket
			number base:
				return.
		if we get here no other file is using the same base:
			release the socket number group via rls_sktn.

parameters:
	none.

returns:
	nothing.

globals:
	fp
	fs_null
	n_f_left=
	n_s_left=

calls:
	rls_sktn
	kw_frlse

called by:
	fi_sgone
	kr_osicp

history:
	initial coding 12/31/74 by G. R. Grossman
	releasing socket number group added 5/28/75 by G. R. Grossman.
	step on time out information added 6/15/76 by S. F. Holmgren
	call kw_frlse added 7/8/76 by S. F. Holmgren

*/

f_rlse()
{
	register struct file	*f_p;	/* for searching socket structs
					   for matching socket number bases */
	register int	sbase;		/* will hold socket number base for
					   speeding up search */

	n_s_left =+ fp->f_nsrsrv;	/* add still-reserved socket count
					   to free socket count */
	fp->f_state = fs_null;		/* set file state to null (THIS
					   frees the file struct */
	fp->f_timeo = 0;                /* step on timer info */
	n_f_left++;			/* increment free file count */
	kw_frlse();			/* tell kernel to release file */
	if ( ( sbase = fp->f_sbase ) != 0 )	/* own a socket group? */
	{
		for ( f_p = &files[0] ; f_p < &files[nfiles] ; f_p++ )
					/* loop thru all file structs */
		{
			if (  ( f_p->f_state != fs_null )	/* struct in
								   use? */
			    &&( f_p->f_sbase == sbase ) )	/* and match? */
				return;		/* can't release socket group,
						   so quit */
		}
		rls_sktn( sbase );	/* if we got here no-one else is
					   using the socket group, so release
					 */
	}
}


/*name:
	f_by_id

function:
	attempts to find an in-use file struct whose id field is identical
	to the specified id.

algorithm:
	loop thru all file structs:
		if file state is not null ( therefore in use ):
			if file id matches specified id:
				return file struct address.
	if fall out of loop, no match:
		return -1

parameters:
	fid	file id for which a match is sought.

returns:
	address of file whose id matches the parameter fid, if any.
	-1 otherwise.

globals:
	files
	fs_null

calls:
	nothing.

called by:
	kr_odrct
	kr_close
	kr_open

history:
	initial coding 6/9/75 by G. R. Grossman.

*/

struct file	*f_by_id ( fid )
int	fid;
{
	register struct file	*f_p;	/* will point to file structs during
					   search */
	register int	id;		/* will hold id during search for
					   faster code */

	id = fid;			/* copy sought id */
	for ( f_p = &files[0] ; f_p < &files[nfiles] ; f_p++ )
			/* loop thru all file structs */
		if (    ( f_p->f_state != fs_null )	/* struct in use? */
		     && ( f_p->f_id == id ) )		/* and id matches? */
			return ( f_p );		/* return address of struct */
	return ( -1 );		/* return -1 on failure */
}

/*name:
	fi_ssn

function:
	sends socket number for server icp.

algorithm:
	set up leader in kw_buf via mak_ldr.
	set link field in leader from that in socket struct ( masking out 
	hi-order bit ).
	set byte size in leader to 32.
	set byte count in leader to 1.
	set first two bytes of data to zero.
	set next two bytes to the local socket number base of the file
	assooiated with the socket ( this assumes fp valid ).
	send the leader and data via kw_write.

parameters:
	skt_p	pointer to the icp socket on which the socket number
		base is to be sent as data.

returns:
	nothing.

globals:
	kw_buf=
	fp
	s_*
	f_*

calls:
	mak_ldr
	kw_write

called by:
	fi_all

history:
	initial coding 7/8/75 by G. R. Grossman.

*/

fi_ssn ( skt_p )
struct socket	*skt_p;
{
	mak_ldr();		/* set up default leader fields */
	kw_buf.kw_data->l_link = skt_p->s_hstlnk.hl_link & 0177;
		/* set link, masking out the 0200 which identifies a send
		   link */
	kw_buf.kw_data->l_bysz = 32;		/* and byte size */
	kw_buf.kw_data->l_bycnt = ( 1 << 8 );	/* and byte count */
	kw_buf.kw_data->l_data[0] =		/* zero 1st 2 bytes of data */
	kw_buf.kw_data->l_data[1] = 0;
	kw_buf.kw_data->l_data[2] = fp->f_sbase.lo_byte;	/* copy socket */
	kw_buf.kw_data->l_data[3] = fp->f_sbase.hi_byte;	   /* from file */
	kw_write ( &kw_buf.kw_data->l_data[4] - &kw_buf.lo_byte );
			/* send off leader and data */
}
/*name:
	fi_rfnm

function:
	handles rfnm's at the file level ( for server icp ).

algorithm:
	if the file is in the rfnm wait state:
		set file state to data open wait.
		compute foreign socket from that of the icp socket + 2, via
		skt_off.
		initiate duplex data connection via sm_dux.
		initiate close of icp socket via kill_skt.

parameters:
	skt_p	pointer to server icp contact socket ( hopefully ) for
		which rfnm arrived.

returns:
	nothing.

globals:
	fp=
	s_*
	f_*
	fs_*
	si_init

calls:
	skt_off
	sm_dux
	kill_skt

called by:
	ir_rfnm

history:
	initial coding 7/8/75 by G. R. Grossman.

*/

fi_rfnm ( skt_p )
struct socket	*skt_p;
{
	char	fskt[4];	/* for holding foreign data socket */

	fp = skt_p->s_filep;	/* set global file pointer */
	if ( fp->f_state == fs_sirfw )		/* file in server icp rfnm wait
						   state? */
	{
		fp->f_state = fs_dopnw;		/* set file state to data open
						   wait */
		skt_off ( &skt_p->s_fskt[4], &fskt[4], 2, 4 );
				/* compute offset of 2 from foreign socket */
		sm_dux ( &fp->f_sbase, fskt, si_init );
				/* initiate duplex data connection  */
		kill_skt ( skt_p );	/* start closing contact socket */
	}
}