/* (C) Copyright International Business Machines Corporation 23 January */
/* 1990.  All Rights Reserved. */
/*  */
/* See the file USERAGREEMENT distributed with this software for full */
/* terms and conditions of use. */
/* File: pilxdr.c */
/* Author: David F. Bacon */
#ifndef lint
static char sccsinfo[] = "@(#)pilxdr.c	1.4 3/13/90";
#endif

#define _BSD 43

#include <rpc/rpc.h>

#include "ops.h"
#include "recursiv.h"
#include "storage.h"

xdr_status
hxdr_outport(xdrs, valp)
XDR *xdrs;
valcell *valp;
{
    predef_exception remport_enq();

    extern interpname localaddr;
    remote_address rem, *remptr;


    switch (xdrs->x_op) {
      case XDR_ENCODE: {
	  if (valp->outport->type is RemotePort)
	    remptr = & valp->outport->info.remote;
	  else {
	      remptr = &rem;
	      make_local_remaddr(remptr, (remaddr) valp->outport);
	  }
	  break;
      }

      case XDR_DECODE: {
	  if ((valp->outport = new(channel)) is nil)
	    goto cleanup;
	  remptr = & valp->outport->info.remote;
	  break;
      }
    }

    if (not hxdr_remote_address(xdrs, & remptr))
      goto cleanup;

    if (xdrs->x_op is XDR_DECODE) 
      if (compare_interpnames(remptr, & localaddr) is SUCCESS) {
	  dispose(valp->outport, channel);
	  valp->outport = (channel *) remptr->addr;
      }
      else {
	  valp->outport->type = RemotePort;
	  valp->outport->port_enq = remport_enq;
	  valp->outport->disconnected = FALSE;
	  valp->outport->refcount = 1;
      }

    return(XDR_OK);

  cleanup: {
      abort_nili("hxdr_outport");
      /*NOTREACHED*/
  }
}


xdr_status
hxdr_remote_address(xdrs, rem)
XDR *xdrs;
remote_address **rem;
{
    if (xdrs->x_op is XDR_DECODE and *rem is nil)
      if ((*rem = new(remote_address)) is nil)
	goto cleanup;

    if (not hxdr_interpname(xdrs, & (*rem)->interp) or
	not hxdr_remaddr(xdrs, & (*rem)->addr))
      goto cleanup;

    return(XDR_OK);

  cleanup:
    abort_nili("hxdr_remote_address");
    /*NOTREACHED*/
}

    
xdr_status
hxdr_interpname(xdrs, interp)
XDR *xdrs;
interpname *interp;
{
    char *hp;

    hp = interp->hostname;

    if (not xdr_opaque(xdrs, hp, HOSTIDSIZE) or
	not xdr_u_int(xdrs, & interp->number))
      abort_nili("hxdr_interpname");

    return(XDR_OK);
}



xdr_status
hxdr_remaddr(xdrs, addr)
XDR *xdrs;
remaddr *addr;
{
    return(xdr_u_long(xdrs, addr));
}


xdr_status
hxdr_callmessage(xdrs, valp)
XDR *xdrs;
valcell *valp;
{
    extern interpname localaddr;
    remote_address rem, *remptr;
    counter size;
    int i;
    flag decode_to_local;
    callmessage_info *info;


    switch (xdrs->x_op) {
      case XDR_ENCODE: {
	  size = valp->callmessage->info.callmessage->size;

	  if (not valp->callmessage->info.callmessage->local)
	    remptr = & valp->callmessage->info.callmessage->cminfo.remote;
	  else {
	      remptr = &rem;
	      make_local_remaddr(remptr, (remaddr) valp->callmessage);
	  }
	  break;
      }

      case XDR_DECODE: {
	  remptr = nil;
	  break;
      }
    }

    if (not hxdr_remote_address(xdrs, & remptr))
      goto cleanup;

    if (not xdr_u_int(xdrs, &size))
      goto cleanup;

    decode_to_local = FALSE;

    if (xdrs->x_op is XDR_DECODE) 
      if (compare_interpnames(remptr, & localaddr) is SUCCESS) {
	  decode_to_local = TRUE;

	  valp->callmessage = (dfd_callmessage *) remptr->addr;
	  dispose(remptr, remote_address);
      }
      else {
	  if ((valp->callmessage = getdotmain(size)) is nil)
	    goto cleanup;
	  if ((info = new(callmessage_info)) is nil)
	    goto cleanup;

	  valp->callmessage->info.callmessage = info;
	  info->local = FALSE;
	  info->size = size;
	  info->cminfo.remote = *remptr;
	  dispose(remptr, remote_address);
      }
    
    for (i = 0; i < size; i++) {
	if (decode_to_local) 
	  re_finalize(& valp->callmessage->data[i], F_FREE, (schedblock*) nil)
	    ;
	if (not hxdr_object(xdrs, & valp->callmessage->data[i]))
	  goto cleanup;
    }

    return(XDR_OK);

  cleanup: {
      abort_nili("hxdr_callmessage");
      /*NOTREACHED*/
  }
}
