/* rmtfcn */
#ifdef DOCUMENTATION

title	rmtfcn	prototype task for remote functions
index	rmtfcn	prototype task for remote functions

synopsis

	  ins rmtfcn/task=rmtfcn

description

	Remote functions allow executing a function call on
	a remote node. Existing tasks that need to modify
	some portion of a remote system (ie. a resident common)
	can use this technique with the least effect on an existing
	program.

	The file contains a prototype of a remote function task.
	It assumes that a task on a remote node will connect
	to it, send, and optionally receive, one or more packets.

	Status from the desired function should be returned via
	a network send.

	When the function exits, this task will disconnect and exit.

bugs

#endif

#include <stdio.h>
#include <cx.h>
#include <stdnet.h>

#define IE_DAO	0363	/* transfer rejected */
#define IE_REJ	0250	/* transfer rejected */
#define IE_DSQ	0246	/* disk quota exceed, tried to put too much */
#define IE_EOF	0366	/* end of file */

extern int $$nerr;
static NIOV *np;
static char buf[132];

int $$nargs = 1;

main()
{
  int netmsg();
  int len;
  int *ip;

  freopen("NL:", "w", stdout);	/* prevents flushing cr to CO on exit */

  if(!opn_net(netmsg)) {
    tmsg('F', "open net failed nerr %d\n", $$nerr);
    exits(4);
  }

  wtse(10);	/* wait for attach from other task */

  while ((len = get_net(buf, sizeof buf, np)) != NULL) {
    dsar();		/* let code finish */

/**** function specific code goes here *****/

	user_routine(buf, len);

  enar();		/* let asts in */
  }
  finish(1);
}


netmsg(code, acp)
char code[4];		/* message type code */
struct a_conblk *acp;	/* pointer to received message */
{
  switch (code[1]) { 
      case NT_CON:	{
		accept(acp);
		setf(10);
	      break;
	      }    
      case NT_INT:	{
	      tmsg('M', "interrupt message\n");
	      break;
	      }    
      case NT_DSC:	{
	      rclos(0);
/*	      tmsg('D', "NT_DSC exit\n");
*/  	      finish(4);
	      }    
      case NT_ABT:	{
	      rclos(0);
/*	      tmsg('D', "NT_ABT exit\n");
*/  	      finish(4);
	      }    

      case NT_ABO:	{
	      rclos(0);
/*	      tmsg('D', "NT_ABO exit\n");
*/  	      finish(4);
	      }    
    
      default: {
	      tmsg('W', "unexpected msg %d msglen %d lun %d\n",
			code[1], code[2], code[3]);
	      }
      }

  return(1);
}

accept(ap)
struct a_conblk *ap;	/* pointer to received message */
{
  NIOV *acc_net();

  if ((np = acc_net(ap)) == NULL) {
    tmsg('E', "accnt failed, err %o\n", $$nerr);
    return(0);
  }
}

finish(stat)	/* close everything and exit with status = stat */
int stat;
{
  dsc_net(np);
  cls_net();
/*  tmsg('D', "standard exit\n");
*/  exits(stat);
}
