/*--------------------------------------------------------------------------*/
/* File name:		ECHO_SR3.C					Revision date:	1998.12.05	*/
/* Try to be an non-resident echo server for NETD (dlanor@oden.se)			*/
/*--------------------------------------------------------------------------*/
#include	<stdio.h>
#include	<tos.h>
#include	<string.h>
#include	<time.h>
#include	<ctype.h>
#include	<stdlib.h>
#include	<screen.h>
/*----*/
#include	<sting\transprt.h>
#include	<sting\port.h>
#include	<sting\layer.h>
#include	<sting\netd.h>
/*----*/
#include	"yield.h"
/*--------------------------------------------------------------------------*/
#define	M_TITLE		"ECHO server"
#define	M_VERSION	"01.02"
#define	M_YEAR		1998
#define	M_MONTH		12
#define	M_DAY		04
#define	M_AUTHOR	"Olivier Booklage"
/*--------------------------------------------------------------------------*/
#define	ECHO_PORT	7
#define	NetD_UDP	0			/* UDP ports will use type_bsize 0		*/
#define	NetD_TCP	1024		/* TCP ports will use type_bsize 1024	*/
#define CON				2				/* stdin */
/*--------------------------------------------------------------------------*/
DRV_LIST	*sting_drivers;
TPL			*tpl;
STX			*stx;
NetD_STX	*NetD_STX_p;
NetD_SRV	*my_SRV;
/*--------------------------------------------------------------------------*/
/* Start of:		Subfunctions for initialization							*/
/*--------------------------------------------------------------------------*/
long  get_sting_cookie(void)
{	long	*work;
	for (work = * (long **) 0x5a0L; *work != 0L; work += 2)
		if (*work == 'STiK')
			return (*++work);
	return (0L);
}
/*--------------------------------------------------------------------------*/
long  get_netd_cookie(void)
{	long	*work;
	for (work = * (long **) 0x5a0L; *work != 0L; work += 2)
		if (*work == 'NetD')
			return (*++work);
	return (0L);
}
/*--------------------------------------------------------------------------*/
int 	is_STING (void)
{	int 	res = 0;

	Cur_home();
	Next_line();	/* Do not overwrite the menu bar */

	sting_drivers = (DRV_LIST *) Supexec (get_sting_cookie);

	if (sting_drivers == 0L)
		return (res);

	if (strcmp (sting_drivers->magic, MAGIC) != 0)
		return (res);

	stx = (STX *) (*sting_drivers->get_dftab) (MODULE_DRIVER);
	if (stx == (STX *) NULL)
		return (res);

	tpl = (TPL *) (*sting_drivers->get_dftab) (TRANSPORT_DRIVER);
	if (tpl == (TPL *) NULL)
		return (res);

	return (TRUE);
}
/*--------------------------------------------------------------------------*/
int 	is_NETD (void)
{	int 	res = 0;

	NetD_STX_p = (NetD_STX *) Supexec (get_netd_cookie);

	if	(NetD_STX_p == (NetD_STX *) NULL)
		return (res);

	return (TRUE);
}
/*--------------------------------------------------------------------------*/
void	wmess (const char *s)	/* Write string to the desktop & keep cnt	*/
{	static	int	lines = 0;

	Cconws (s);
	Next_line();

	if (++lines > 36)
	{	Cur_home();
		Next_line();
		lines = 0;
	}
}
/*--------------------------------------------------------------------------*/
/* End of:			Subfunctions for initialization							*/
/*--------------------------------------------------------------------------*/
/* Start of:		server functions called by NetD STX						*/
/*--------------------------------------------------------------------------*/
int16	SRV_connect (NetD_APP *NetD_APP_p, NetD_CON *new_conn_p)
{	/* This server does no work on connection, so function is almost empty	*/

	return (E_NORMAL);	/* always accepts connection */
}	/* End of: SRV_connect */
/*--------------------------------------------------------------------------*/
void	SRV_traffic (NetD_APP *NetD_APP_p)
{	NetD_CON	*work;
	NDB			*ndb;

	for	(work = my_SRV->active_q; work; work = work->next)
		if	((ndb = CNget_NDB(work->handle)) > 0)
		{	NetD_send_CON(work, ndb->ndata, ndb->len);	/* echo the data */
			KRfree(ndb->ptr);
			KRfree(ndb);
		}
}	/* End of: SRV_traffic */
/*--------------------------------------------------------------------------*/
void	SRV_warning (NetD_APP *NetD_APP_p)
{

	/* This server ignores warning call, so the function is empty */

}	/* End of: SRV_warning */
/*--------------------------------------------------------------------------*/
/* End of:			server functions called by NetD STX						*/
/*--------------------------------------------------------------------------*/
/* Start of:		main program function, used only for server init		*/
/*--------------------------------------------------------------------------*/
int 	main (void)
{
	int key=0;
	NetD_CON	*test_CON_p1;
	NetD_CON	*test_CON_p2;

	if	(!is_STING())
	{	wmess("STiNG not installed!! | Aborting Installation...");
		return (0);
	}
	if	(!is_NETD())
	{	wmess("NetD not installed!! | Aborting Installation...");
		return (0);
	}

	my_SRV = (NetD_SRV *) _BasPag;

/* I've moved the init of the SRV struct where it belongs, *before* the		*/
/* call to NetD_init_SRV.  I really don't understand how I missed that...	*/

	my_SRV->if_ver	= REF_IF_VER;
	my_SRV->date	= ((M_YEAR-1980)<<9)|(M_MONTH<<5)|M_DAY;
	my_SRV->version	= M_VERSION;
	my_SRV->author	= M_AUTHOR;
	my_SRV->name	= M_TITLE;

/*	illegal_n(1);	*/	/* I put breakpoint 1 here to study login */

	if	(NetD_init_SRV(my_SRV) < 0)
	{	wmess("NetD refused server! | Aborting installation...");
		return (0);
	}

	/* The stuff below is specific for each server */

	test_CON_p1 = NetD_init_CON(my_SRV, NetD_UDP, ECHO_PORT);	/* UDP port	*/
	if	((void *) test_CON_p1 == NULL)
		wmess("NetD refused using UDP ECHO_PORT !");
	test_CON_p2 = NetD_init_CON(my_SRV, NetD_TCP, ECHO_PORT);	/* TCP port	*/
	if	((void *) test_CON_p2 == NULL)
		wmess("NetD refused using TCP ECHO_PORT !");

/* Normally the NetD_CON ptrs read above are only intended for that test 	*/
/* of success/failure of initializing service. Traffic invalidates them !	*/

	printf("\n Press Esc key for quit...\n");

	while ( key != 27 )
	{
		if ( Cconis() !=0 )	key=(int)Bconin(CON);
		_appl_yield();	/* This call is needed to task switch NetD APP/ACC */
	}

/* NB:	Without _appl_yield above this server will not work in singleTOS.	*/
/*		Even under MagiC that would waste lots of CPU power on key tests.	*/
/*		So to run long in loops, remember to use _appl_yield inside them.	*/

/*	illegal_n(2);	*/	/* I put breakpoint 2 here to study logout */


/* At this point it is a serious BUG to access the NetD_CONs initialized	*/
/* before server traffic, because that traffic will have caused those		*/
/* structs to have been replaced by others, allocated at need by NetD STX.	*/

/* The pointers used by you below are therefore no longer valid.  The right	*/
/* way to use NetD_exit_CON demands other methods (queue digging).  But it	*/
/* should never be necessary to do this just to remove the server, because	*/
/* the NetD_exit_SRV function will purge all NetD_CONs from all queues of	*/
/* the server which is being logged out from the NetD system.				*/

/* Putting it simply: You don't need NetD_exit_CON at all in this program.	*/
/* But it was a good thing you tried it, because there was a bug in NetD...	*/

/*	if	((void *) test_CON_p1 != NULL)			*/
/*		NetD_exit_CON(my_SRV, test_CON_p1 );	*/
/*	if	((void *) test_CON_p2 != NULL)			*/
/*		NetD_exit_CON(my_SRV, test_CON_p2 );	*/

	NetD_exit_SRV(my_SRV);
	
	printf("Bye, bye..\n");

return (0);					/* we never come here... */
}
/*--------------------------------------------------------------------------*/
/* End of:			main program function, used only for server init		*/
/*--------------------------------------------------------------------------*/
/* End of file:		ECHO_SRV.C												*/
/*--------------------------------------------------------------------------*/
