[comp.protocols.appletalk] New files for AUX2 version of CAP with native AppleTalk

liam@cs.qmw.ac.uk (William Roberts) (07/28/90)

You need these two new files in addition to the patches given in a separate
message. Even if you have lost the patches then you could still build
the thing - these two files simply replace the abkip.c, atalkdbm.c,
abddp.c and abnbp.c with no changes to any of the others.

These files provide enough support to build both lwsrv and aufs. It 
is not yet enough to build all of the other CAP programs, so
don't be disheartened if snitch and suchlike don't build. The good 
news is that you don't need atis!

This might well work under A/UX 1.1 with "AppleTalk for A/UX". The 
library is the same, but no promises.... It definitely won't work
with the original AppleTalk stuff that relied on an extra NuBUS card.

#         This is a shar archive.
#         Remove everything above and including the cut line.
#         Then run the rest of the file through sh.
#--------cut--------cut--------cut--------cut--------cut--------
#! /bin/sh
#  shar:  Shell Archiver
#         Run the following with /bin/sh to create:
#             auxat_ddp.c
#             auxat_nbp.c
# This archive created: Fri Jul 27 21:15:46 WET DST 1990
echo shar: extracting "auxat_ddp.c" '('12105 chars')'
if test -f auxat_ddp.c
then
    echo shar: will not overwrite existing file "auxat_ddp.c"
else
cat << \SHAR_EOF > auxat_ddp.c
/*
 * $Author: root $ $Date: 90/07/27 21:12:42 $
 * $Header: auxat_ddp.c,v 1.4 90/07/27 21:12:42 root Locked $
 * $Revision: 1.4 $
*/

/*
 * abddp.c - Datagram Delivery Protocol
 *
 * AppleTalk package for UNIX (4.2 BSD).
 *
 * Copyright (c) 1986, 1987, 1988 by The Trustees of Columbia University
 *  in the City of New York.
 *
 *
 * Edit History:
 *
 *  June 19, 1986    Schilit    Created.
 *  July  9, 1986    CCKim      Clean up some of Bill's stuff and allow
 *                              Appletalk protocols on ethernet with CAP
 *  Feb. 1988 Charlie - don't like the way the encapsulation code runs
 *   into the DDP code.  Drop out all the encapsulation code into
 *   another module (interface dep) and drop out part of DDP into it.
 *
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/uio.h>

/* Use the direct Apple support for ddp. We insist on a long form
 * DDP header, and we can open our own file descriptor instead of
 * calling abOpen to do it for us. iDDPOpenSocketIOV and DDPClose
 * are modified to set up the fdlistener stuff that abOpen/abClose
 * used to deal with.
 */
#include <at/appletalk.h>
#include <at/lap.h>
#include <at/ddp.h>
#include <sys/stropts.h>        /* for strioctls */
#include <netinet/in.h>         /* for ntohs */

/* Fortunately the CAP include and the Apple ones don't conflict */

#include <netat/appletalk.h>    /* for private, boolean etc */
#include "cap_conf.h"

#ifndef DONT_DOCHKSUM
# define DO_CHKSUM 1
#else
# define DO_CHKSUM 0
#endif
boolean dochecksum = DO_CHKSUM;         /* can be patched if necessary */


extern int errno;

/* room for up to ddp + 1 for data buffer */
#define DDPIOVLEN (IOV_DDP_SIZE+1)
private DDP ddph;
private byte ddpdatabuffer[ddpMaxData];
private struct iovec rddpiov[DDPIOVLEN] = {
  {NULL, 0},                    /* LAP header */
  {(caddr_t)&ddph, ddpSize},    /* DDP header (me) (redundant) */
  {(caddr_t)ddpdatabuffer, ddpMaxData} /* ddp data */
};

typedef struct {
  int (*lproc)();               /* socket listener routine */
  int flags;                    /* flags */
#define DDPL_OLDINTERFACE 1
  int fd;                       /* DDP file descriptor */
} LISENTRY;                     /* listener entry */

private LISENTRY ddpl[ddpMaxSkt+1]; /* table of listeners */


/* abInit(disp)
 *
 * Get things started and find out our Node and Net
 * Maybe we should wait until later in case a seed bridge starts up?
 */

export word this_net;
export byte this_node;

export word bridge_net;         /* do we care about this any more? */
export byte bridge_node;
export word nis_net;            /* do we care about this any more? */
export byte nis_node;

export DBUG dbug;

abInit(disp)
int disp;
{
    int fd, x;
    at_ddp_cfg_t cfg;
    at_socket socket;
    struct strioctl si;

    init_fdlistening();
    DDPInit();

    /* find out our address */

    socket = 0;         /* don't care */
    fd = ddp_open(&socket);
    if (fd < 0) {
	perror("ddp_open");
	exit(0);
    }

    si.ic_cmd = DDP_IOC_GET_CFG;
    si.ic_timout = 1;
    si.ic_len = sizeof(cfg);
    si.ic_dp = (char *)&cfg;

    x = ioctl(fd, I_STR, &si);
    if (x < 0) {
	perror("abInit: strioctl failed");
	exit(-1);
    }

    if (disp || dbug.db_lap) {
	printf("abInit: [ddp %3d.%02d, %d] starting\n",
	    ntohs(cfg.node_addr.net)>>8,
	    ntohs(cfg.node_addr.net)&0x0FF,
	    cfg.node_addr.node);
    }
    this_net  = cfg.node_addr.net;
    this_node = cfg.node_addr.node;
    bridge_net  = cfg.router_addr.net;
    bridge_node = cfg.router_addr.node;

    x = ddp_close(fd);
    if (x < 0) {
	perror("ddp_close");
	exit(0);
    }
}

OSErr
GetNodeAddress(mynode, mynet)
int *mynode, *mynet;
{
    *mynode = this_node;
    *mynet  = this_net;
    return (noErr);
}

DDPInit()
{
  int i;

  /* initialize ddp listener array */
  for (i = 0; i < ddpMaxSkt+1; i++) {
    ddpl->lproc = NILPROC;
    ddpl->flags = 0;
  }

}


/*
 * OSErr DDPOpenSocket(int *skt, ProcPtr sktlis)
 * OSErr DDPOpenSocketIOV(int *skt,ProcPtr sktlis,struct iovec *iov,int iovlen)
 *
 * Open a DDP socket and optionally install a socket listener to the
 * listener table.  If skt is nonzero (it must be in the range of
 * 1 to 127) it specifies the socket's number.  If skt is 0 then
 * DDPOpenSocket dynamically assigns a socket number in the range
 * 128 to 254, and returns it in skt.  You can actually specify a socket
 * in the 128 to 254 range, but it's not a good idea :-).
 *
 * sktlis contains a pointer (ProcPtr) to the socket listener; if
 * it is NILPROC, the default listener will be used (NYI)
 *
 * If calling DDPOpenSocketIOV, then the iovector passed must be of
 * size (IOV_DDP_SIZE+1) (length for ddp+lap) plus one (data for caller).
 * In addition, it must be filled in from DDP_LVL+1 to the end
 *
 *
 * The listener is defined as:
 *  XXX_listener(int skt, PKT *pkt, int len, AddrBlock *addr)
 * if called from DDPOpenSocket and:
 *  XXX_listener(int skt, struct iovec *iov, int iovlen, AddrBlock *addr)
 * if called from DDPOpenSocketIOV
 *
 * The iov passed back to the listener will start after the ddp header
 * block
 *
*/
OSErr
DDPOpenSocketIOV(skt, sktlis, iov, iovlen)
int *skt;
ProcPtr sktlis;
struct iovec *iov;
int iovlen;
{
  int fd;
  at_socket s;
  int defDDPlis();      /* which always fails anyway - clearly a throwback */
  int ddp_upcall();

  /* allow 0 - means dynamic assignment */
  s = *skt;                     /* socket wanted */
  if (s >= ddpMaxSkt) {
    fprintf(stderr,"ddpOpenSocket: skt out of range\n");
    exit(0);
  }
  /* open the socket please */
  if ((fd = ddp_open(&s)) < 0) {
    if (dbug.db_ddp)
      fprintf(stderr,"ddp: open socket - socket open failed: %d\n", errno);
    return(fd);              /* return error if failed */
  }
  *skt = s;             /* socket number actually obtained */
  if (dbug.db_ddp) {
    fprintf(stderr, "ddp: open socket: opened socket %d\n", s);
  }

  iov[IOV_DDP_LVL].iov_base = (caddr_t)&ddph; /* install */
  iov[IOV_DDP_LVL].iov_len = ddpSize; /* install */

  /* add default or user's listener */
  ddpl[s].lproc = ((sktlis == NILPROC) ? defDDPlis : sktlis);
  ddpl[s].flags = 0;
  ddpl[s].fd = fd;

  /* add the file descriptor to the list of those listened for */
  fdlistener(fd, ddp_upcall, iov+IOV_DDP_LVL, iovlen-IOV_DDP_LVL);

  return(noErr);                        /* and return */
}


OSErr
DDPOpenSocket(skt,sktlis)
int *skt;
ProcPtr sktlis;
{
  OSErr err;

  err = DDPOpenSocketIOV(skt, sktlis, rddpiov, DDPIOVLEN);
  if (err == noErr) {
    ddpl[*skt].flags = DDPL_OLDINTERFACE;
  }
  return(err);
}


/*
 * OSErr DDPCloseSocket(int skt)
 *
 * DDPCloseSocket closes the skt, cancels all pending DDPRead calls
 * that have been made on that socket, and removes the socket listener
 * procedure.
 *
*/

OSErr
DDPCloseSocket(skt)
int skt;
{
  if (skt == 0 || skt >= ddpMaxSkt) {
    if (dbug.db_ddp)
      fprintf(stderr, "ddpCloseSocket: Socket %d out of range\n", skt);
    return;
  }
  ddpl[skt].lproc = NILPROC;    /* no procedure */

  fdunlisten(ddpl[skt].fd);     /* stop listening to the socket */
  return(ddp_close(ddpl[skt].fd));
}

OSErr
DDPWrite(abr)
abRecPtr abr;
{
  struct iovec iov[IOV_DDP_SIZE+1];

  iov[IOV_DDP_LVL+1].iov_base = (caddr_t) abr->proto.ddp.ddpDataPtr;
  iov[IOV_DDP_LVL+1].iov_len = abr->proto.ddp.ddpReqCount;

  return(DDPWriteIOV(abr,iov,IOV_DDP_SIZE+1));
}

/*
 * DDPWriteIOV
 *
 * DDPWriteIOV builds up DDP header and then passes off to routeddp
 *  who decides where to send it.  In the most cases, we'll probably
 *  have a version of routeddp per "network" type so we can "optimize"
 *
*/
/*ARGSUSED*/
OSErr
DDPWriteIOV(abr,iov,iovl)
abRecPtr abr;
struct iovec iov[];
int iovl;
{
  at_ddp_t ddp;
  ddpProto *dpr;
  at_socket skt;
  int err;

  dpr = &abr->proto.ddp;
  skt = dpr->ddpSocket; /* our socket number */

  if (skt == 0 || skt >= ddpMaxSkt || ddpl[skt].lproc == NILPROC) {
	return -1;
  }

  /* the DDP streams driver fills in everything else given
   * just checksum, dst_net, dst_node, dst_socket, type and data.
   * The length is inferred from the write or writev command.
   */
  ddp.dst_net = dpr->ddpAddress.net;
  ddp.dst_node = dpr->ddpAddress.node;
  ddp.dst_socket = dpr->ddpAddress.skt;
  ddp.type = dpr->ddpType;
  ddp.checksum = dochecksum;    /* driver computes the correct value */

  /* The DDP streams driver deals with LAP headers etc, so must
   * adjust the iov to point to the start of the DDP stuff
   */
  iov += IOV_DDP_LVL; iovl -= IOV_DDP_LVL;

  iov->iov_base = (caddr_t) &ddp; /* DDP header */
  iov->iov_len = ddpSize;

  err = writev(ddpl[skt].fd, iov, iovl);
  if (err <= 0) {
    if (dbug.db_ddp) {
	perror("ddp_write failed");
    }
    return -1;
  }
  return 0;
}

/*ARGSUSED*/
OSErr
DDPRead(abr,retCkSumErrs,async)
abRecPtr abr;
int retCkSumErrs,async;
{
  fprintf(stderr,"DDPRead NYI\n");
}

OSErr
DDPRdCancel(abr)
abRecPtr abr;
{
  fprintf(stderr,"DDPRdCancel NYI\n");
}

defDDPlis(skt,ddp,len,addr)
DDP *ddp;
AddrBlock *addr;
{
  fprintf(stderr,"defDDPlis NYI\n");
/***** copy data into user buffer *****/
}

/*
 * ddp_protocol(ddp,len)
 *
 * ddp_protocol is the installed LAP protocol handler for protocol
 * type lapDDP (2).  This routine gets called by LAP when a packet
 * is received with lapDDP in the protocol field.  ddp_protocol
 * passes the packet to the socket listener installed by the
 * DDPOpenSocket call.
 *
 * With direct support for DDP, this routine is entered from the
 * very simple ddp_upcall routine installed as the fdlistener for
 * the appropriate file descriptor.
 *
 * Caller provides an iov pointing to DDP header
*/

int ddp_protocol(iov, iovlen, plen)
struct iovec *iov;
int iovlen;
int plen;
{
  at_socket skt;
  AddrBlock addr;
  int len, cnt, oldstyle;
  at_ddp_t *ddp;

  /* iovlen == 1 means just a ddp header */
  if (iovlen < 1 || iov->iov_len != ddpSize) {
    return -1;
  }

  ddp = (at_ddp_t *)iov->iov_base; /* it must be aligned ok already*/
  len = ntohs(ddp->length) & 0x3ff; /* get the "real" length */
  if (plen < len) {             /* not enought data? */
    if (dbug.db_ddp)
      fprintf(stderr, "BAD PACKET: ddp reports more data than came in\n");
    return;                     /* drop pkt */
  }

  skt = ddp->dst_socket;

  if (ddpl[skt].lproc == NILPROC) { /* listener proc for socket */
    if (dbug.db_ddp)
      fprintf(stderr,"ddp_protocol: no socket listener!\n");
    return;
  }

  addr.net = ddp->src_net;
  addr.node = ddp->src_node;
  addr.skt = ddp->src_socket;
  iov++;                        /* skip ddp header */
  iovlen--;
  plen -= ddpSize;              /* reduce to data size */
  if (iovlen < 1) {
    return 0;   /* nothing to send, so drop it */
  }
  if (ddpl[skt].lproc) {        /* be postitive */
    if (ddpl[skt].flags & DDPL_OLDINTERFACE)
      (*ddpl[skt].lproc)(skt,ddp->type,iov->iov_base,plen,&addr);
    else
      (*ddpl[skt].lproc)(skt, ddp->type, iov, iovlen, plen, &addr);
  }
  return 0;
}

private int ddp_upcall(fd, iov, iovlen)
int fd;
struct iovec *iov;
int iovlen;
{
    int nbytes;

    nbytes = readv(fd, iov, iovlen);
    return (ddp_protocol(iov, iovlen, nbytes));
}


/*
 * Call with TRUE or FALSE - FALSE means ignore, TRUE means don't ignore
 *
*/
checksum_error(which)
boolean which;
{
  /* who cares - we certainly don't */
}


/* Utility routine to sprintf an address in a standard format
 *
 *      net_hi.net_lo,node socket
 *
 * It returns its first argument, for convenient use in printf.
 */
char *appletalk_ntoa(buf, addr)
char buf[];
AddrBlock *addr;
{
    sprintf(buf, "%d.%02d,%d %d",
	((addr->net)>>8)& 0x0FF, (addr->net)& 0x0FF,
	addr->node, addr->skt);
    return buf;
}

/* int ddp_skt2fd(skt)
 *
 * Converts a socket number into a file descriptor, or returns -1.
 * Used by upper layers which have converted over to A/UX support,
 * since CAP is otherwise keen only to pass around socket numbers.
 */

int ddp_skt2fd(skt)
byte skt;
{
    if (skt > 0 && skt <= ddpMaxSkt && ddpl[skt].lproc != NILPROC) {
	return ddpl[skt].fd;
    }

    /* invlaid skt or no socket listener - presumed not open */
    return -1;
}
SHAR_EOF
if test 12105 -ne `wc -c < auxat_ddp.c`
then
    echo shar: error transmitting "auxat_ddp.c" '('should be 12105 chars')'
else
    echo auxat_ddp.c
fi
fi
echo shar: extracting "auxat_nbp.c" '('14498 chars')'
if test -f auxat_nbp.c
then
    echo shar: will not overwrite existing file "auxat_nbp.c"
else
cat << \SHAR_EOF > auxat_nbp.c
/*
 * $Author: root $ $Date: 90/07/27 21:13:04 $
 * $Header: auxat_nbp.c,v 1.5 90/07/27 21:13:04 root Locked $
 * $Revision: 1.5 $
*/

/*
 * abnbp.c - nbp access.
 *
 * AppleTalk package for UNIX (4.2 BSD).
 *
 * Copyright (c) 1986, 1987, 1988 by The Trustees of Columbia University
 *  in the City of New York.
 *
 *
 * Edit History:
 *
 *  June 13, 1986    Schilit    Created
 *  June 15, 1986    CCKim      move to abnbp.c, add extract
 *  July  1, 1986    Schilit    rewrite with async and NBPConfirm
 *  July  9, 1986    CCKim      Clean up and rewrite create_entity
 *  July 15, 1986    CCKim      Add nbpregister, nbpdelete
 *
 */

#include <stdio.h>
#include <sys/types.h>
#include <netat/appletalk.h>
#include <netat/abnbp.h>
#ifdef USESTRINGDOTH
# include <string.h>
#else
# include <strings.h>
#endif

/* Include files for A/UX NBP support
 *
 * at_nvestr_t corresponds to str32, but uses Pascal Strings
 * Subject to that proviso, and the changes of field names, the
 * sizes and layouts of the following are the same:
 *
 *      at_entity_t   matches EntityName
 *      at_inet_t     matches AddrBlock
 *      at_nbptuple_t matches NBPTEntry
 */
#include <at/appletalk.h>
#include <at/nbp.h>
#include <sys/errno.h>
extern int errno;

extern char *appletalk_ntoa();

private nbpProto *nbpQ;
private byte next_nbpid = 0;
private int nbpSkt = -1;

/* Public functions */

OSErr nbpInit();                /* initialize NBP */
OSErr NBPLookup();              /* lookup a name or group of names */
OSErr NBPConfirm();             /* confirm a name/address pair */
OSErr NBPExtract();             /* extract entity information after lookup */

void zoneset();			/* absorbed from atalkdbm.c */

/* Internal functions */

private OSErr nbpFcn();         /* common NBP function */
private void SndNBP();          /* send request to appletalk */
private void nbp_timeout();     /* timeout monitor */
private void nbp_listener();    /* DDP listener process */
private void LkUpReply();       /* handle LkUpReply response */
private int nbp_match();        /* find matching request upon response */
private int nbpcpy();           /* copy entity into user buffer */
private int c2pkt_ename();      /* convert entity name from c to packed */
private int pkt2c_ename();      /* convert entity name from packed to c */
private int c2pas_ename();      /* convert entity name from c to pascal */
private int pas2c_ename();      /* convert entity name from c to pascal */

/*
 * OSErr nbpInit()
 *
 * Redundant under A/UX AppleTalk support.
 */

OSErr
nbpInit()
{
    return noErr;
}

void
zoneset(zonename)
char *zonename;
{
    /* ignored */
}

/*
 * Close currently open NBP socket
 *
*/
OSErr
nbpShutdown()
{
  return(noErr);
}

/*
 * NBPLookup(nbpProto *pr,int async)
 *
 * NBPLookup returns the address of all entities with a specified
 * name. The nbpProto structure contains
 *
 * nbpBufSize, nbpBufPtr - data area for result
 * nbpDataField   - number of entries to look for/entries found.
 * nbpEntityName  - name of the entity we are interested in
 *
 * Result code noErr or -1 (for some major failure).
*/

OSErr
NBPLookup(abr,async)
nbpProto *abr;
int async;
{
  int maxx;
  at_entity_t lookup_ent;
  at_nbptuple_t *ep;
  at_retry_t  retry_info;
  EntityName *entp;
  char buf[30];         /* for printing addresses */

  c2pas_ename(abr->nbpEntityPtr, &lookup_ent);

  maxx = abr->nbpBufSize/sizeof(NBPTEntry); /* max entries */
  abr->nbpMaxEnt =                      /* set it up */
    (maxx < abr->nbpDataField) ? maxx : abr->nbpDataField;
  abr->nbpDataField = 0;

  retry_info.interval = abr->nbpRetransmitInfo.retransInterval;
  retry_info.retries  = abr->nbpRetransmitInfo.retransCount;
  retry_info.backoff  = 1;      /* ??? */

  if (async) {
     fprintf(stderr, "NBP: async NBPLookup not implemented\n");
     return -1;
  }

  if (dbug.db_nbp) {
     printf("NBP: calling NBP lookup %s:%s@%s\n",
	abr->nbpEntityPtr->objStr.s,
	abr->nbpEntityPtr->typeStr.s,
	abr->nbpEntityPtr->zoneStr.s);
  }
  maxx = nbp_lookup(&lookup_ent,
		abr->nbpBufPtr, abr->nbpMaxEnt, &retry_info);
  if (maxx < 0) {
     return -1;
  }
  if (dbug.db_nbp) {
     printf("nbp: NBP lookup returned %d entries\n", maxx);
  }

  abr->nbpDataField = maxx;
  ep = (at_nbptuple_t *)(abr->nbpBufPtr);
  while (maxx--) {
     entp = (EntityName *)(&(ep->enu_entity));
     pas2c_ename(&(ep->enu_entity), entp);
     if (dbug.db_nbp) {
	printf("NBP:   tuple %02d = %s:%s@%s at %s\n",
		abr->nbpDataField - maxx,
		entp->objStr.s, entp->typeStr.s, entp->zoneStr.s,
		appletalk_ntoa(buf, (AddrBlock *)(&ep->enu_addr)));
     }
     ep++;
  }

  return(noErr);
}

/*
 * OSErr NBPConfirm(nbpProto *pr, int async)
 *
 * NBPConfirm confirms that an entity known by name and address still
 * exists.
 *
 * nbpEntityPtr - points to a variable of type EntityName that contains
 * the name to confirm.  No meta characters are allowed in the entity
 * name (otherwise the result would be ambigous).
 *
 * nbpAddress - specifies the address to be confirmed.
 *
 * nbpRetransmitInfo - contains the retry interval and retry count.
 *
 * The correct socket number is returned in nbpDataField.
 *
 * NBPConfirm is more efficient than NBPLookup in terms of network
 * traffic.  Since NBPConfirm only waits for a single response it
 * is also quicker (i.e. doesn't need to wait for the timeout period).
 *
 * Result Codes:
 *      noErr           No error
 *      nbpConfDiff     Name confirmed for different socket
 *      nbpNoConfirm    Name not confirmed
 *
*/

OSErr
NBPConfirm(abr,async)
nbpProto *abr;
int async;
{
  int answer;
  at_entity_t lookup_ent;
  at_retry_t  retry_info;
  at_inet_t   address;
  char buf[30];

  c2pas_ename(abr->nbpEntityPtr, &lookup_ent);

  retry_info.interval = abr->nbpRetransmitInfo.retransInterval;
  retry_info.retries  = abr->nbpRetransmitInfo.retransCount;
  retry_info.backoff  = 1;      /* ??? */

  address.net    = abr->nbpAddress.net;
  address.node   = abr->nbpAddress.node;
  address.socket = abr->nbpAddress.skt;

  if (async) {
     fprintf(stderr, "NBP: async NBPConfirm not implemented\n");
     return -1;
  }
  if (dbug.db_nbp) {
     printf("NBP: calling NBP Confirm %s:%s@%s as %s\n",
	abr->nbpEntityPtr->objStr.s,
	abr->nbpEntityPtr->typeStr.s,
	abr->nbpEntityPtr->zoneStr.s,
	appletalk_ntoa(buf, &abr->nbpAddress));
  }

  answer = nbp_confirm(&lookup_ent, &address, &retry_info);
  switch (answer) {

     case 1:    /* successful */
	abr->nbpDataField = address.socket;
	if (dbug.db_nbp) {
	   printf("NBP: Confirmed OK on socket %d\n", address.socket);
	}
	return (address.socket == abr->nbpAddress.skt)?
		    noErr : nbpConfDiff;


     case 0:    /* not confirmed */
	if (dbug.db_nbp) {
	   printf("NBP: Not confirmed\n");
	}
	return(nbpNoConfirm);
  }
  if (dbug.db_nbp) {
     printf("NBP: confirm error (errno=%d)\n", errno);
  }
  return(-1);
}

/*
 * OSErr NBPExtract(NBPTEntry t[],int nument,int whichone,
 *              EntityName *en, AddrBlock *addr)
 *
 * NBPExtract returns one address from the list of addresses returned
 * by NBPLookup.
 *
 * t - is a table of entries in the form NBPTEntry as returned by
 * NBPLookUp.
 *
 * nument - is the number of tuples in "t" as returned in nbpDataField
 * by NBPLookUp
 *
 * whichone - specifies which one of the tuples in the buffer should
 * be returned.
 *
 * en, addr - are pointers to an EntityName and AddrBlock into which
 * NBPExtract stores the selected entity information.
 *
 * Result Codes:
 *      noErr           No error
 *      extractErr      Can't find tuple in buffer
 *
 */

OSErr
NBPExtract(t,nument,whichone,ent,addr)
NBPTEntry t[];
EntityName *ent;
AddrBlock *addr;
{
  if (whichone > nument) {
    fprintf(stderr,"NBPExtract: whichone too large!");
    return(extractErr);         /* return error code, not found */
  } else {
    *ent = t[whichone-1].ent;   /* pretty simple */
    *addr = t[whichone-1].addr; /*  stuff... */
  }
  return(noErr);
}

/*
 * register a nve
 *
*/
NBPRegister(abr, async)
nbpProto *abr;
boolean async;
{
  int err, fd;
  at_entity_t new_ent;
  at_retry_t  retry_info;
  char buf[30];

#ifdef no_longer_needed
  if ((err = NBPLookup(abr, FALSE)) < 0) /* i guess this is the right */
    return(err);                /* thing to do */
#endif

  c2pas_ename(abr->nbpEntityPtr, &new_ent);

  retry_info.interval = abr->nbpRetransmitInfo.retransInterval;
  retry_info.retries  = abr->nbpRetransmitInfo.retransCount;
  retry_info.backoff  = 1;      /* ??? */

  if (async) {
     fprintf(stderr, "NBP: async NBPRegister not implemented\n");
     return -1;
  }
  if (dbug.db_nbp) {
     printf("NBP: calling NBP Register %s:%s@%s for socket %d\n",
	abr->nbpEntityPtr->objStr.s,
	abr->nbpEntityPtr->typeStr.s,
	abr->nbpEntityPtr->zoneStr.s,
	abr->nbpAddress.skt);
  }

  fd = ddp_skt2fd(abr->nbpAddress.skt);
  if (fd < 0) {
     fprintf(stderr, "NBP: can't register unopened socket %d\n",
	abr->nbpAddress.skt);
     return -1;
  }

  err = nbp_register(&new_ent, fd, &retry_info);

  if (err == -1 && errno == EADDRNOTAVAIL) {
      if (dbug.db_nbp) {
	  printf("NBP: %s:%s@%s already registered\n",
		  abr->nbpEntityPtr->objStr.s,
		  abr->nbpEntityPtr->typeStr.s,
		  abr->nbpEntityPtr->zoneStr.s);
      }
      return nbpDuplicate;
  }

  /* record the entity name and the file descriptor for NBPRemove
   * Record the entity name in contiguous pascal form for simple
   * comparisons.
   */

  return err;
}

/*
 * remove a nve
 *
*/
NBPRemove(abEntity)
EntityName *abEntity;
{
  int err, fd;
  at_entity_t new_ent;

  c2pas_ename(abEntity, &new_ent);

  /* need to look up a file descriptor to go with the entity name
   * Either we keep the list of names we've registered, or we
   * use NBPLookup to find them. The former is probably better.
   */

  err = nbp_remove(&new_ent, fd);

  if (dbug.db_nbp) {
     printf("NBP: NBP Remove %s:%s@%s (fd=%d) returns %d\n",
	abEntity->objStr.s, abEntity->objStr.s,
	abEntity->zoneStr.s, fd, err);
  }
  return err;
}



/*
 * private int c2pkt_ename(EntityName *cn, u_char *pn)
 *
 * Copy entity name from c form into contiguous Apple Pascal
 * form (packet form).
 *
 * return: length of pascal form entity name
 *
 */
private int
c2pkt_ename(cn,pn)
byte *pn;
EntityName *cn;
{
  int i, cnt;
  byte *s;
  byte *pc;

  cnt = 0;
  for (s = cn->objStr.s, pc = pn++, i = 0; i < ENTITYSIZE; i++, pn++, s++) {
    *pn = *s;
    if (*s == '\0')
      break;
  }
  if (i > ENTITYSIZE)           /* increment to cnt and check aginst cutoff */
    i = ENTITYSIZE;             /* too large: turncated to 32 chars */
  *pc = i;
  cnt += (i+1);
  for (s = cn->typeStr.s, pc = pn++, i = 0; i < ENTITYSIZE; i++, pn++, s++) {
    *pn = *s;
    if (*s == '\0')
      break;
  }
  if (i > ENTITYSIZE)           /* increment to cnt and check aginst cutoff */
    i = ENTITYSIZE;             /* too large: turncated to 32 chars */
  *pc = i;
  cnt += (i+1);
  for (s = cn->zoneStr.s, pc = pn++, i = 0; i < ENTITYSIZE; i++, pn++, s++) {
    *pn = *s;
    if (*s == '\0')
      break;
  }
  if (i > ENTITYSIZE)           /* increment to cnt and check aginst cutoff */
    i = ENTITYSIZE;             /* too large: turncated to 32 chars */
  *pc = i;
  cnt += (i+1);
  return(cnt);          /* return number of bytes used */
}

/*
 * private int pkt2c_enames(u_char *pn, EntityName *cn);
 *
 * Copy entity names from packet form (abutting Apple Pascal
 * strings) to c form into structure of type EntityName.
 *
 * return: the length of the packed string.
 *
 */

private int
pkt2c_ename(pn,cn)
byte *pn;
EntityName *cn;
{
  int ol,tl,zl;

  ol = *pn;                     /* length of object */
  tl = *(pn+ol+1);              /* length of type */
  zl = *(pn+ol+tl+2);           /* length of zone */
  if (ol > ENTITYSIZE || tl > ENTITYSIZE || zl > ENTITYSIZE) {
    fprintf(stderr,"pkt2c_entity_names: invalid length!\n");
    return(0);
  }
  cpyp2cstr(cn->objStr.s,pn);   /* copy them... */
  cpyp2cstr(cn->typeStr.s,pn+ol+1);
  cpyp2cstr(cn->zoneStr.s,pn+ol+tl+2);
  return(ol+tl+zl+3);           /* return length */
}

/*
 * Convert name in the form 'LaserWriter:LaserWriter@*' (object, type,
 * zone) to entity form (LaserWriter, LaserWriter, *).
 *
 * Assumes no ':' in object name , and no '@' in object or type name
 *
*/
void
create_entity(name, en)
char *name;
EntityName *en;
{
  char *zs, *ts;
  int ol, tl, zl;

  ts = index(name, ':');
  zs = index(name, '@');
  ol = ts ? (ts - name) : (zs ? (zs - name) : strlen(name));
  tl = ts == NULL ? 0 : ((zs == NULL) ? strlen(ts+1) : (zs - ts - 1));
  zl = zs == NULL ? 0 : strlen(zs+1);
  /* make foo@bar be =:foo@bar */
  /* make foo be =:=@foo */
  /* make foo@ be =:foo@* */
  if (ol != 0 && tl == 0 && ts == NULL) {
    if (zl != 0 || zs)
      tl = ol, ts = name - 1;
    else
      zs = name - 1, zl = ol;
    ol = 0;
  }

  bzero(en->objStr.s, sizeof(en->objStr.s));
  bzero(en->typeStr.s, sizeof(en->typeStr.s));
  bzero(en->zoneStr.s, sizeof(en->zoneStr.s));
  strncpy(en->objStr.s, name, min(ENTITYSIZE, ol)); /* just copy */
  if (ts)
    strncpy(en->typeStr.s, ts+1, min(ENTITYSIZE, tl));
  if (zs)
    strncpy(en->zoneStr.s, zs+1, min(ENTITYSIZE, zl));
}



/* c2pas_str(unsigned char *cn, at_nvestr_t *pn)
 * pas2c_str(at_nvestr_t *pn, unsigned char *cn);
 *
 * Converts between C strings and Pascal strings. Will work
 * correctly even if cn and pn point to the same place.
 */

private void c2pas_str(cn, pn)
unsigned char *cn;
at_nvestr_t *pn;
{
   int length;
   register unsigned char *from, *to;

   length = strlen(cn);
   if (length > NBP_NVE_STR_SIZE) length = NBP_NVE_STR_SIZE;

   /* copy from last character, working backwards */
   if (length) {
       from = cn + length - 1;  /* last char */
       to = (pn->str) + length - 1;
       do {
	   *to-- = *from;
       } while (from-- >= cn);
   }
   pn->len = length;
}

private void pas2c_str(pn, cn)
at_nvestr_t *pn;
register unsigned char *cn;
{
   int length;
   register unsigned char *from;

   from = pn->str;
   length = pn->len;

   while (length--) {
       *cn++ = *from++;
   }
   *cn = '\0';
}

private int c2pas_ename(cn, pn)
EntityName *cn;
at_entity_t *pn;
{
    c2pas_str(&cn->objStr,  &pn->object);
    c2pas_str(&cn->typeStr, &pn->type);
    c2pas_str(&cn->zoneStr, &pn->zone);
}

private int pas2c_ename(cn, pn)
at_entity_t *pn;
EntityName *cn;
{
    pas2c_str(&pn->object, &cn->objStr);
    pas2c_str(&pn->type,   &cn->typeStr);
    pas2c_str(&pn->zone,   &cn->zoneStr);
}
SHAR_EOF
if test 14498 -ne `wc -c < auxat_nbp.c`
then
    echo shar: error transmitting "auxat_nbp.c" '('should be 14498 chars')'
else
    echo auxat_nbp.c
fi
fi
#         End of shar archive
exit 0
-- 

William Roberts                 ARPA: liam@cs.qmw.ac.uk
Queen Mary & Westfield College  UUCP: liam@qmw-cs.UUCP
Mile End Road                   AppleLink: UK0087
LONDON, E1 4NS, UK              Tel:  071-975 5250 (Fax: 081-980 6533)