Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1985 lines
58 KiB

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
nbp.c
Abstract:
NBP handling for a node (routing and non-routing).
Author:
Garth Conboy initial coding
Nikhil Kamkolkar recoding/mpsafe
Revision History:
GC - (04/05/92): Made the Encode and Decode tuple routines externally
visible for use by Arap.
GC - (06/16/92): Corrected WildMatch to not allow "abcd=cdef" (assume
"=" is approx equal) to match "abcdef". Fix from
ASCOM/Timeplex.
--*/
#include "atalk.h"
ExternForVisibleFunction void DoNameLookup(int port,
NbpTuple far *nbpTuple,
int nbpId,
long whatSocket);
ExternForVisibleFunction Boolean WildMatch(char far *wildString,
char far *masterString);
ExternForVisibleFunction Boolean SendNbpRequest(PendingName pendingName);
#if Iam an AppleTalkRouter
ExternForVisibleFunction void SendLookupDatagram(int port,
char far *zone,
BufferDescriptor
lookupDatagram,
int length);
#endif
ExternForVisibleFunction TimerHandler NbpTimerExpired;
//
// An item on the pending names list can be removed either due to an incoming
// packet OR a timer going off. When a timer goes off the handler is passed
// the address of the pending name structure. It is not sufficient to just
// walk the list looking for the given address; a packet could have come in
// just before the timer handler got around to defering incoming packets, and
// that packet could have removed to item from the pending name list, and if
// we're very unlucky, the address could have been reused, and we could get
// very confused. So, we identify each member of the pending name list with
// both its address as well as a 32 bit ID.
//
typedef struct {long id;
long socket;
PendingName pendingName;
} AdditionalData;
static long nextId = 0;
long far NbpPacketIn(AppleTalkErrorCode errorCode,
long unsigned userData,
int port,
AppleTalkAddress source,
long destinationSocket,
int protocolType,
char far *datagram,
int datagramLength,
AppleTalkAddress actualDestination)
{
StaticForSmallStack char tupleBuffer[MaximumNbpTupleLength];
StaticForSmallStack NbpTuple nbpTuple, usedTuple;
StaticForSmallStack PendingName pendingName, previousPendingName;
StaticForSmallStack long nextTupleOffset;
StaticForSmallStack long nextUsedTupleOffset;
#if Iam an AppleTalkRouter
StaticForSmallStack BufferDescriptor lookupDatagram, copy;
#endif
short nbpCommand;
short tupleCount;
short nbpId;
OpenSocket openSocket;
int currentTupleCount, currentUsedTupleCount;
Boolean repeatTuple, foundIt;
NbpCompletionHandler *completionRoutine;
void far *opaqueBuffer;
AppleTalkAddress tempAddress;
int totalTuples;
short length;
long onWhosBehalf;
#if Iam an AppleTalkRouter
int index;
StaticForSmallStack RoutingTableEntry routingTableEntry;
StaticForSmallStack AppleTalkAddress destination;
#endif
// "Use" unneeded actual parameters.
source, datagramLength, actualDestination;
// Only play if we've been asked nicely!
if (errorCode is ATsocketClosed)
return((long)True);
else if (errorCode isnt ATnoError) {
ErrorLog("NbpPacketIn", ISevError, __LINE__, port,
IErrNbpBadIncomingCode, IMsgNbpBadIncomingCode,
Insert0());
return((long)True);
}
// We only want NBP packets!
if (protocolType isnt DdpProtocolNbp)
return((long)True); // Why are these guys talking to us???
DeferTimerChecking();
DeferIncomingPackets();
// Get static NBP information out of the packet, then switch on command.
nbpCommand = (short)((datagram[NbpControlOffset] >> 4) & 0xF);
tupleCount = (short)(datagram[NbpControlOffset] & 0xF);
nbpId = (unsigned char)datagram[NbpIdOffset];
switch(nbpCommand) {
case NbpBroadcastRequest:
case NbpForwardRequest:
#if IamNot an AppleTalkRouter
// We're just a lowly node (not a router), so ignore these guys.
HandleIncomingPackets();
HandleDeferredTimerChecks();
return((long)True);
#else
// Only one tuple for these guys.
if (tupleCount isnt 1) {
ErrorLog("NbpPacketIn", ISevWarning, __LINE__, port,
IErrNbpTupleCountBadReq, IMsgNbpTupleCountBadReq,
Insert0());
HandleIncomingPackets();
HandleDeferredTimerChecks();
return((long)True);
}
// Decode our tuple.
if (DecodeNbpTuple(datagram, NbpFirstTupleOffset, False,
&nbpTuple) is 0) {
HandleIncomingPackets();
HandleDeferredTimerChecks();
return((long)True); // Bad format in tuple...
}
//
// On extended networks, no '*' zone is allowed; non non-extended
// change '*' to the node's zone.
//
if (GET_PORTDESCRIPTOR(port)->ExtendedNetwork) {
if (nbpTuple.zone[0] is 0 or
(nbpTuple.zone[0] is '*' and
nbpTuple.zone[1] is 0)) {
ErrorLog("NbpPacketIn", ISevWarning, __LINE__, port,
IErrNbpBadZoneReq, IMsgNbpBadZoneReq,
Insert0());
HandleIncomingPackets();
HandleDeferredTimerChecks();
return((long)True);
}
}
else if (nbpTuple.zone[0] is 0 or
(nbpTuple.zone[0] is '*' and
nbpTuple.zone[1] is 0)) {
if (GET_PORTDESCRIPTOR(port)->ThisCableRange.FirstNetworkNumber
isnt source.networkNumber) {
ErrorLog("NbpPacketIn", ISevWarning, __LINE__, port,
IErrNbpBadLTZone, IMsgNbpBadLTZone,
Insert0());
HandleIncomingPackets();
HandleDeferredTimerChecks();
return((long)True);
}
if (not GET_PORTDESCRIPTOR(port)->ThisZoneValid) {
HandleIncomingPackets();
HandleDeferredTimerChecks();
return((long)True);
}
strcpy(
nbpTuple.zone,
GET_PORTDESCRIPTOR(port)->ThisZone);
}
//
// Okay, build up a forward-request or a looklup DDP packet.
// Allocate a buffer descriptor for the beast.
//
if ((lookupDatagram = NewBufferDescriptor(NbpFirstTupleOffset +
MaximumNbpTupleLength)) is
Empty) {
ErrorLog("NbpPacketIn", ISevError, __LINE__, port,
IErrNbpOutOfMemory, IMsgNbpOutOfMemory,
Insert0());
HandleIncomingPackets();
HandleDeferredTimerChecks();
return((long)True);
}
lookupDatagram->data[NbpIdOffset] = (unsigned char)nbpId;
length = EncodeNbpTuple(&nbpTuple, lookupDatagram->data +
NbpFirstTupleOffset);
length += NbpFirstTupleOffset;
//
// A forward request should be turned into a broadcast on the
// directly connected network.
//
if (nbpCommand is NbpForwardRequest) {
lookupDatagram->data[NbpControlOffset] =
(unsigned char)((NbpLookup << 4) + 1);
SendLookupDatagram(port, nbpTuple.zone,
lookupDatagram, length);
//
// That's all for forward requests; SendLookupDatagram will cause
// the buffer chain to be freed.
//
HandleIncomingPackets();
HandleDeferredTimerChecks();
return((long)True);
}
//
// Okay, now for broadcast requests... walk through the routing
// tables sending either a forward request or a lookup (broadcast)
// to each network that contains the specified zone.
//
for (index = 0; index < NumberOfRtmpHashBuckets; index += 1)
for (routingTableEntry = routingTable[index];
routingTableEntry isnt empty;
routingTableEntry = routingTableEntry->next) {
//
// If the network is zero hops away (it's directly connected);
// use the zone list in the portDescriptors rather than the
// routing table -- the routing table may not yet be filled
// with a zone list (due to the normal ZipQuery mechanism).
//
if (not routingTableEntry->zoneListValid) {
if (routingTableEntry->numberOfHops isnt 0)
continue;
if (not ZoneOnList(nbpTuple.zone,
GET_PORTDESCRIPTOR(routingTableEntry->
port)->ThisZoneList))
continue;
}
else if (not ZoneOnList(nbpTuple.zone,
routingTableEntry->zoneList))
continue;
//
// Copy the lookup datagram so we can alter it, and allow it to
// asynchronously freed!
//
if ((copy = CopyBufferChain(lookupDatagram)) is Empty) {
ErrorLog("NbpPacketIn", ISevError, __LINE__, port,
IErrNbpOutOfMemory, IMsgNbpOutOfMemory,
Insert0());
FreeBufferChain(lookupDatagram);
HandleIncomingPackets();
HandleDeferredTimerChecks();
return((long)True);
}
// If not a local network, just send a forward request.
if (routingTableEntry->numberOfHops isnt 0) {
copy->data[NbpControlOffset] =
(unsigned char)((NbpForwardRequest << 4) + 1);
destination.networkNumber =
routingTableEntry->networkRange.firstNetworkNumber;
destination.nodeNumber = AnyRouterNodeNumber;
destination.socketNumber = NamesInformationSocket;
if (DeliverDdp(destinationSocket, destination,
DdpProtocolNbp, copy, length,
Empty, Empty, 0) isnt ATnoError)
ErrorLog("NbpPacketIn", ISevError, __LINE__, port,
IErrNbpBadFwdReqSend, IMsgNbpBadFwdReqSend,
Insert0());
}
else {
// Otherwise, send a lookup.
copy->data[NbpControlOffset] =
(unsigned char)((NbpLookup << 4) + 1);
SendLookupDatagram(routingTableEntry->port,
nbpTuple.zone,
copy, length);
}
}
//
// All set! We only used the copys of the lookup datagram when
// we're taking this exit, so free the original.
//
FreeBufferChain(lookupDatagram);
HandleIncomingPackets();
HandleDeferredTimerChecks();
return((long)True);
#endif
case NbpLookup:
if (tupleCount isnt 1) {
ErrorLog("NbpPacketIn", ISevWarning, __LINE__, port,
IErrNbpTupleCountBadLookup, IMsgNbpTupleCountBadLookup,
Insert0());
HandleIncomingPackets();
HandleDeferredTimerChecks();
return((long)True);
}
if (DecodeNbpTuple(datagram, NbpFirstTupleOffset, False,
&nbpTuple) is 0) {
HandleIncomingPackets();
HandleDeferredTimerChecks();
return((long)True); // Bad format in tuple...
}
DoNameLookup(port, &nbpTuple, nbpId, destinationSocket);
break;
case NbpLookupReply:
//
// This had better be a response to a previous LookUp... get an
// open socket on our node.
//
if ((openSocket = MapSocketToOpenSocket(destinationSocket)) is empty) {
ErrorLog("NbpPacketIn", ISevWarning, __LINE__, port,
IErrNbpCouldntMapSocket, IMsgNbpCouldntMapSocket,
Insert0());
HandleIncomingPackets();
HandleDeferredTimerChecks();
return((long)True);
}
//
// Okay, look on our pending names lists for all sockets within our
// node for the nbpId that we're handling the response for.
//
foundIt = False;
for (openSocket = openSocket->activeNode->openSockets ;
openSocket isnt empty and not foundIt;
openSocket = openSocket->next) {
for (pendingName = openSocket->pendingNames,
previousPendingName = empty;
pendingName isnt empty and not foundIt;
previousPendingName = pendingName,
pendingName = pendingName->next)
if (pendingName->nbpId is nbpId) {
foundIt = True;
break;
}
if (foundIt)
break; // We need pendingName and openSocket to be valid!
}
if (not foundIt) {
#if Verbose & 0
//
// This will happen when a lookup completes with "buffer full"
// and more replies are still coming in...
//
ErrorLog("NbpPacketIn", ISevVerbose, __LINE__, port,
IErrNbpDeadReply, IMsgNbpDeadReply,
Insert0());
#endif
HandleIncomingPackets();
HandleDeferredTimerChecks();
return((long)True);
}
//
// Okay, handle the incoming reply based on why we were doing the
// request:
//
if (pendingName->whyPending is ForRegister or
pendingName->whyPending is ForConfirm) {
if (tupleCount is 0)
{
HandleIncomingPackets();
HandleDeferredTimerChecks();
return((long)True);
}
else if (tupleCount isnt 1)
ErrorLog("NbpPacketIn", ISevWarning, __LINE__, port,
IErrNbpTupleCountBadReply, IMsgNbpTupleCountBadReply,
Insert0());
if (DecodeNbpTuple(datagram, NbpFirstTupleOffset, False,
&nbpTuple) is 0) {
HandleIncomingPackets();
HandleDeferredTimerChecks();
return((long)True); // Bad format reply, ignore it
}
// Does the reply match the one we're trying to register?
if (not CompareCaseInsensitive(pendingName->object,
nbpTuple.object) or
not CompareCaseInsensitive(pendingName->type,
nbpTuple.type)) {
HandleIncomingPackets();
HandleDeferredTimerChecks();
return((long)True); // No match, who cares...
}
completionRoutine = pendingName->completionRoutine;
userData = pendingName->userData;
onWhosBehalf = pendingName->socket;
//
// For confirm, check that the network and node numbers match,
// if so, check socket.
//
if (pendingName->whyPending is ForConfirm) {
if (pendingName->confirming.networkNumber isnt
nbpTuple.address.networkNumber or
pendingName->confirming.nodeNumber isnt
nbpTuple.address.nodeNumber) {
HandleIncomingPackets();
HandleDeferredTimerChecks();
return((long)True); // Not even close...
}
//
// Okay, we have a match, remove the pending name from our
// pending list...
//
if (previousPendingName is empty)
openSocket->pendingNames = pendingName->next;
else
previousPendingName->next = pendingName->next;
CancelTimer(pendingName->timerId);
// Return the correct error code to the completion routine.
if (pendingName->confirming.socketNumber is
nbpTuple.address.socketNumber) {
Free(pendingName);
tempAddress = nbpTuple.address;
HandleIncomingPackets();
HandleDeferredTimerChecks();
(*completionRoutine)(ATnoError, userData, ForConfirm,
onWhosBehalf, nbpId, tempAddress);
return((long)True);
}
else {
Free(pendingName);
tempAddress = nbpTuple.address;
HandleIncomingPackets();
HandleDeferredTimerChecks();
(*completionRoutine)(ATnbpConfirmedWithNewSocket, userData,
ForConfirm, onWhosBehalf, nbpId,
tempAddress);
return((long)True);
}
}
//
// Okay, we're a register and somebody our there has our name!
// Remove the name from our pending list.
//
if (previousPendingName is empty)
openSocket->pendingNames = pendingName->next;
else
previousPendingName->next = pendingName->next;
CancelTimer(pendingName->timerId);
Free(pendingName);
// Call the completion routine, informing it of our bad luck.
HandleIncomingPackets();
HandleDeferredTimerChecks();
(*completionRoutine)(ATnbpNameInUse, userData, ForRegister,
onWhosBehalf, nbpId);
return((long)True);
}
else if (pendingName->whyPending is ForLookup) {
if (tupleCount is 0)
{
HandleIncomingPackets();
HandleDeferredTimerChecks();
return((long)True); // No added information...
}
// Process each tuple in our lookup reply packet...
nextTupleOffset = NbpFirstTupleOffset;
for (currentTupleCount = 1;
currentTupleCount <= tupleCount;
currentTupleCount += 1) {
if ((nextTupleOffset = DecodeNbpTuple(datagram, nextTupleOffset,
False, &nbpTuple)) is 0) {
HandleIncomingPackets();
HandleDeferredTimerChecks();
return((long)True); // Bad format tuple... ignore the rest.
}
//
// Now we have to walk through our list of already stored tuples
// and see if we're a repeat...
//
nextUsedTupleOffset = 0;
repeatTuple = False;
for (currentUsedTupleCount = 1;
not repeatTuple and
currentUsedTupleCount <= pendingName->totalTuples;
currentUsedTupleCount += 1) {
if ((nextUsedTupleOffset =
DecodeNbpTuple(pendingName->opaqueBuffer,
nextUsedTupleOffset, True,
&usedTuple)) is 0) {
ErrorLog("NbpPacketIn", ISevError, __LINE__, port,
IErrNbpBadTupleStored, IMsgNbpBadTupleStored,
Insert0());
HandleIncomingPackets();
HandleDeferredTimerChecks();
return((long)True);
}
if (nbpTuple.address.networkNumber is
usedTuple.address.networkNumber and
nbpTuple.address.nodeNumber is
usedTuple.address.nodeNumber and
nbpTuple.address.socketNumber is
usedTuple.address.socketNumber and
nbpTuple.enumerator is usedTuple.enumerator)
repeatTuple = True;
} // Process all previously stored tuples...
// If we're a repeat, just get the next one off the wire...
if (repeatTuple)
continue;
if (nextUsedTupleOffset isnt pendingName->nextTupleOffset) {
ErrorLog("NbpPacketIn", ISevError, __LINE__, port,
IErrNbpTuplesMunged, IMsgNbpTuplesMunged,
Insert0());
HandleIncomingPackets();
HandleDeferredTimerChecks();
return((long)True);
}
//
// Grab some information out of the pending name structure that
// we may need to call the completion routine (if needed).
//
completionRoutine = pendingName->completionRoutine;
userData = pendingName->userData;
onWhosBehalf = pendingName->socket;
opaqueBuffer = pendingName->opaqueBuffer;
totalTuples = pendingName->totalTuples;
//
// Encode the new tuple into a scratch buffer. Is there room in
// buffer for this new tuple?
//
length = EncodeNbpTuple(&nbpTuple, tupleBuffer);
if (pendingName->nextTupleOffset + length >
pendingName->bufferSize) {
//
// We can't fit the new one... remove us from the pending
// list, return what we can, report the error.
//
if (previousPendingName is empty)
openSocket->pendingNames = pendingName->next;
else
previousPendingName->next = pendingName->next;
CancelTimer(pendingName->timerId);
Free(pendingName);
HandleIncomingPackets();
HandleDeferredTimerChecks();
(*completionRoutine)(ATnbpBufferNotBigEnough, userData,
ForLookup, onWhosBehalf, nbpId,
opaqueBuffer, totalTuples);
return((long)True);
}
//
// Okay, we're pretty well set. Move the new tuple into the
// user's buffer...
//
MoveToOpaque(pendingName->opaqueBuffer,
pendingName->nextTupleOffset, tupleBuffer, length);
pendingName->nextTupleOffset += length;
totalTuples = (pendingName->totalTuples += 1);
// Lastly, have we gotten as many tuples as the user wanted?
if (pendingName->totalTuples is pendingName->maximumTuples) {
//
// Remove from the pending name list and call the completion
// routine...
//
if (previousPendingName is empty)
openSocket->pendingNames = pendingName->next;
else
previousPendingName->next = pendingName->next;
CancelTimer(pendingName->timerId);
Free(pendingName);
HandleIncomingPackets();
HandleDeferredTimerChecks();
(*completionRoutine)(ATnoError, userData, ForLookup,
onWhosBehalf, nbpId,
opaqueBuffer, totalTuples);
return((long)True);
}
} // Process all incoming tuples..
}
else
ErrorLog("NbpPacketIn", ISevError, __LINE__, port,
IErrNbpBadPendingFlag, IMsgNbpBadPendingFlag,
Insert0());
break;
default:
ErrorLog("NbpPacketIn", ISevWarning, __LINE__, port,
IErrNbpBadCommandType, IMsgNbpBadCommandType,
Insert0());
break;
}
HandleIncomingPackets();
HandleDeferredTimerChecks();
return((long)True);
} // NbpPacketIn
#if (Iam a WindowsNT)
AppleTalkErrorCode far _cdecl
#else
AppleTalkErrorCode far
#endif
NbpAction(WhyPending reason,
long socket,
char far *object,
char far *type,
char far *zone,
int nbpId,
int broadcastInterval,
int numberOfBroadcasts,
NbpCompletionHandler *completionRoutine,
long unsigned userData,
...)
{
//
// Perform an NBP name registration, lookup or confirmation for specified
// AppleTalk address. We return an integer:
//
// < 0 - Error code (from AppleDcls.h).
// 0 - ATnoError
//
// The error code indicates whether the operation got STARTED succesfully, if
// it is less that zero, the completion routine will never be called.
//
// BEFORE this routine is called, GetNextNbpIdForNode MUST be called to
// identify the next NbpAction (get the next nbpID). This will set the
// NBP ID that is passed to both NbpAction and NbpAction's completion
// routine. Note that the completion may occure BEFORE NbpAction returns.
//
// Both broadcastInterval and numberOfBroadcasts may be specified as zero,
// in which case default values will be used.
//
// For "register" requests, "zone" must be "empty" or "*".
//
// No meta-characters ("=") are allowed in the "object" or "type" fields
// for register or confirm actions.
//
// If "reason" is ForConfirm then a single "additionalArgument" should
// be passed: "confirming" argument must be specified as the expected
// AppleTalk address of the specified object.
//
// If "reason" is ForLookup then three "additionalArgument"s should be
// passed: "opaqueBuffer" is the address of opaque buffer for the
// reception of matching tuples, "bufferSize" is the length, in bytes, of
// "buffer", "maximumTuples" is the maximum number of tuples to return (zero
// means no maximum, just try to fill the buffer).
//
// At the end of the operation we will call the specified completion routine:
//
// (*completionRoutine)(errorCode, userData, reason, onWhosBehalf, nbpId,
// ...)
//
// The common arguments are:
//
// errorCode - Integer; specifies the completion status of the
// operation (i.e. register-okay, name-in-use, etc.).
// userData - Long unsigned; as passed to this routine.
// reason - Integer; the type of operation operation that has
// completed (ForLookup, ForRegister, or ForConfirm).
// onWhosBehalf - socket; the socket that was performing the
// lookup/register/confirm.
// nbpId - Integer; the value that was returned from the
// GetNextNbpIdForNode call preceeding this call to
// NbpAction (and passed to NbpAction) to indicate what
// action is complete. Note that nbpId's are only
// unique within a single node; so, onWhosBehalf will
// be needed for true uniqueness.
//
// The additional arguments depend of the "reason":
//
// ForRegister:
//
// none.
//
// ForConfirm:
//
// confirmedAddress: AppleTalk address that was confirmed; if the
// error code is no-error, this will be the same
// as the "cofirming" address passed to NbpAction,
// if the error code is new-socket, this will be
// the same as the "confiming" address except with
// a new socket.
//
// ForLookup:
//
// opaqueBuffer: The same address passed to NbpAction, this is the
// buffer full of matching tuples.
// tupleCount: Integer, the number of matching tuples that can
// be found in buffer.
//
//
//
void far *opaqueBuffer;
int bufferSize;
int maximumTuples;
StaticForSmallStack NbpTuple tuple;
StaticForSmallStack AppleTalkAddress replyTo, confirming;
OpenSocket openSocket;
PendingName pendingList;
RegisteredName nameList;
short enumerator;
short length;
Boolean foundMatch;
AdditionalData additionalData;
va_list ap;
int port;
// Grab the additional arguments, as needed:
va_start(ap, userData);
if (reason is ForConfirm)
confirming = va_arg(ap, AppleTalkAddress);
else if (reason is ForLookup) {
opaqueBuffer = va_arg(ap, void far *);
bufferSize = va_arg(ap, int);
maximumTuples = va_arg(ap, int);
if (maximumTuples < 0 or bufferSize < 0)
return(ATnbpBadParameter);
}
va_end(ap);
// A little error checking...
if ((length = (short)strlen(object)) < 1 or
length > MaximumEntityFieldLength or
(length = (short)strlen(type)) < 1 or
length > MaximumEntityFieldLength)
return(ATnbpBadObjectOrTypeOrZone);
if (zone isnt empty and
((length = (short)strlen(zone)) < 1 or
length > MaximumEntityFieldLength))
return(ATnbpBadObjectOrTypeOrZone);
if (zone is empty)
zone = "*";
if (reason is ForRegister or reason is ForConfirm) {
if (object[0] is '=' or type[0] is '=' or
strchr(object, NbpWildCharacter) isnt empty or
strchr(type, NbpWildCharacter) isnt empty)
return(ATnbpNoWildcardsAllowed);
if (reason is ForRegister)
if (zone[0] isnt '*' or zone[1] isnt 0)
return(ATnbpZoneNotAllowed);
}
// Set timer values to defaults, if requested:
if (broadcastInterval <= 0)
broadcastInterval = NbpBroadcastIntervalSeconds;
if (numberOfBroadcasts <= 0)
numberOfBroadcasts = NbpNumberOfBroadcasts;
//
// We're going to the mucking with the PendingNames table, don't allow any
// lookup-replies to bother us...
//
DeferTimerChecking();
DeferIncomingPackets();
// Validate the socket...
if ((openSocket = MapSocketToOpenSocket(socket)) is empty) {
HandleIncomingPackets();
HandleDeferredTimerChecks();
return(ATsocketNotOpen);
}
port = openSocket->port;
// For extended networks, set the zone name correctly.
if (zone[0] is '*' and zone[1] is 0 and
GET_PORTDESCRIPTOR(port)->ExtendedNetwork and
GET_PORTDESCRIPTOR(port)->ThisZoneValid)
zone = GET_PORTDESCRIPTOR(port)->ThisZone;
// We want replies to go the NamesInformationSocket in the requesting node.
if (MapSocketToAddress(socket, &replyTo) isnt ATnoError) {
ErrorLog("NbpAction", ISevError, __LINE__, port,
IErrNbpCouldntFormAddress, IMsgNbpCouldntFormAddress,
Insert0());
HandleIncomingPackets();
HandleDeferredTimerChecks();
return(ATinternalError);
}
replyTo.socketNumber = NamesInformationSocket;
//
// For a register, we have to find an enumerator that is unique amoung all
// registered and names pending for registration within the socket...
//
if (reason is ForRegister)
for (enumerator = 0; enumerator <= 255; enumerator += 1) {
foundMatch = False;
for (nameList = openSocket->registeredNames;
nameList isnt empty and not foundMatch;
nameList = nameList->next)
if (nameList->enumerator is enumerator) {
foundMatch = True;
break;
}
if (foundMatch)
continue;
for (pendingList = openSocket->pendingNames;
pendingList isnt empty and not foundMatch;
pendingList = pendingList->next)
if (pendingList->whyPending is ForRegister and
pendingList->enumerator is enumerator) {
foundMatch = True;
break;
}
if (not foundMatch)
break;
}
else {
foundMatch = False;
enumerator = 0;
}
// Did we find one?
if (foundMatch) {
HandleIncomingPackets();
HandleDeferredTimerChecks();
return(ATnbpTooManyRegisteredNames);
}
// Okay, all looks good, start building up the PendingName structure.
if ((pendingList = (PendingName)Calloc(sizeof(*pendingList), 1)) is empty) {
HandleIncomingPackets();
HandleDeferredTimerChecks();
ErrorLog("NbpAction", ISevError, __LINE__, port,
IErrNbpOutOfMemory, IMsgNbpOutOfMemory,
Insert0());
return(AToutOfMemory);
}
pendingList->whyPending = reason;
pendingList->socket = socket;
strcpy(pendingList->object, object);
strcpy(pendingList->type, type);
strcpy(pendingList->zone, zone);
pendingList->enumerator = enumerator;
pendingList->broadcastInterval = (short)broadcastInterval;
pendingList->remainingBroadcasts = (short)(numberOfBroadcasts - 1);
if (reason is ForConfirm)
pendingList->confirming = confirming;
pendingList->nbpId = (short)nbpId;
pendingList->completionRoutine = completionRoutine;
pendingList->userData = userData;
if (reason is ForLookup) {
pendingList->opaqueBuffer = opaqueBuffer;
pendingList->nextTupleOffset = 0;
pendingList->bufferSize = bufferSize;
pendingList->maximumTuples = (short)maximumTuples;
}
// Hook it up to the pending names list...
pendingList->next = openSocket->pendingNames;
openSocket->pendingNames = pendingList;
//
// We're going to send a directed Lookup for confirms, or either a Broadcast-
// request or a Lookup for registers or lookups depending if we know about
// a router or not. We don't have to bother checking the RegisteredNames
// list, for register, in our node because the broadcast will eventually get
// to us and we'll handle it then! Request packet, with one tuple:
//
if (reason is ForConfirm) // Send to confirming node...
pendingList->datagram[NbpControlOffset] = (NbpLookup << 4) + 1;
else
if (GET_PORTDESCRIPTOR(port)->SeenRouterRecently)
pendingList->datagram[NbpControlOffset] = (NbpBroadcastRequest << 4) + 1;
else
pendingList->datagram[NbpControlOffset] = (NbpLookup << 4) + 1;
pendingList->datagram[NbpIdOffset] = (char)nbpId;
// Okay, encode the tuple into the DDP packet.
tuple.address = replyTo;
tuple.enumerator = enumerator;
strcpy(tuple.object, pendingList->object);
strcpy(tuple.type, pendingList->type);
strcpy(tuple.zone, pendingList->zone);
length = EncodeNbpTuple(&tuple, pendingList->datagram + NbpFirstTupleOffset);
length += NbpFirstTupleOffset; // True DDP packet length
pendingList->datagramLength = length;
//
// Start the re-transmit timer... We'll need the address of the pending-name
// structure when the timer expires...
//
pendingList->id = additionalData.id = nextId++;
additionalData.socket = pendingList->socket;
additionalData.pendingName = pendingList;
pendingList->timerId = StartTimer(NbpTimerExpired, broadcastInterval,
sizeof(additionalData),
(char *)&additionalData);
// Send the packet to the packet.
if (not SendNbpRequest(pendingList))
ErrorLog("NbpAction", ISevError, __LINE__, port,
IErrNbpBadSend, IMsgNbpBadSend,
Insert0());
// The deed is done...
HandleIncomingPackets();
HandleDeferredTimerChecks();
return(ATnoError);
} // NbpAction
AppleTalkErrorCode far NbpRemove(long socket,
char far *object,
char far *type,
char far *zone)
{
// Remove a registered NBP name. "Zone" must be either empty or "*".
OpenSocket openSocket;
int length;
StaticForSmallStack RegisteredName registeredName,
previousRegisteredName = empty;
// A little error checking...
if ((length = (short)strlen(object)) < 1 or
length > MaximumEntityFieldLength or
(length = (short)strlen(type)) < 1 or
length > MaximumEntityFieldLength)
return(ATnbpBadObjectOrTypeOrZone);
if (zone isnt empty and
((length = (short)strlen(zone)) < 1 or
length > MaximumEntityFieldLength))
return(ATnbpBadObjectOrTypeOrZone);
if (zone is empty)
zone = "*";
if (zone[0] isnt '*' or zone[1] isnt 0)
return(ATnbpBadObjectOrTypeOrZone);
if (object[0] is '=' or type[0] is '=' or
strchr(object, NbpWildCharacter) isnt empty or
strchr(type, NbpWildCharacter) isnt empty)
return(ATnbpNoWildcardsAllowed);
//
// We're going to the mucking with the PendingNames table, don't allow any
// lookup-replies bother us...
//
DeferTimerChecking();
DeferIncomingPackets();
// We need to be doing the action on behalf of an open socket...
if ((openSocket = MapSocketToOpenSocket(socket)) is empty) {
HandleIncomingPackets();
HandleDeferredTimerChecks();
return(ATsocketNotOpen);
}
// Okay, look in the socket's registered name list for the entity.
for (registeredName = openSocket->registeredNames;
registeredName isnt empty;
previousRegisteredName = registeredName,
registeredName = registeredName->next)
if (CompareCaseInsensitive(object, registeredName->object) and
CompareCaseInsensitive(type, registeredName->type))
break;
if (registeredName is empty) {
HandleIncomingPackets();
HandleDeferredTimerChecks();
return(ATnbpNameNotRegistered);
}
// Remove from the list...
if (previousRegisteredName is empty)
openSocket->registeredNames = registeredName->next;
else
previousRegisteredName->next = registeredName->next;
Free(registeredName);
// All set!
HandleIncomingPackets();
HandleDeferredTimerChecks();
return(ATnoError);
} // NbpRemove
int far GetNextNbpIdForNode(long socket)
{
// Set and return an available NbpId prepatory to a call to NbpAction.
OpenSocket openSocket, socketList;
int nbpId;
PendingName pendingList;
Boolean foundMatch;
//
// We're going to the mucking with the PendingNames table, don't allow any
// lookup-replies bother us...
//
DeferTimerChecking();
DeferIncomingPackets();
// Validate the socket
if ((openSocket = MapSocketToOpenSocket(socket)) is empty) {
HandleIncomingPackets();
HandleDeferredTimerChecks();
return(ATsocketNotOpen);
}
//
// We need to find an "nbpId" to identify the next NbpAction request...
// look for an unused one in all of the pending-name-lists in all of the
// sockets within this node.
//
for (nbpId = 0; nbpId <= 255; nbpId += 1) {
foundMatch = False;
for (socketList = openSocket->activeNode->openSockets;
socketList isnt empty and not foundMatch;
socketList = socketList->next)
for (pendingList = socketList->pendingNames;
pendingList isnt empty and not foundMatch;
pendingList = pendingList->next)
if (pendingList->nbpId is nbpId) {
foundMatch = True;
break;
}
if (not foundMatch)
break;
}
// Did we find a free nbpId?
if (foundMatch) {
HandleIncomingPackets();
HandleDeferredTimerChecks();
return(ATnbpTooManyNbpActionsPending);
}
// All set!
HandleIncomingPackets();
HandleDeferredTimerChecks();
return(nbpId);
} // GetNextNbpIdForSocket
void _near NbpCloseSocket(OpenSocket socket)
{
PendingName pendingName, nextPendingName;
RegisteredName registeredName, nextRegisteredName;
//
// Before we free the socket, free the registered and pending names
// lists; cancel any outstanding timers...
//
for (registeredName = socket->registeredNames;
registeredName isnt empty;
registeredName = nextRegisteredName) {
nextRegisteredName = registeredName->next;
Free(registeredName);
}
for (pendingName = socket->pendingNames;
pendingName isnt empty;
pendingName = nextPendingName) {
nextPendingName = pendingName->next;
(*pendingName->completionRoutine)(ATsocketClosed,
pendingName->userData,
pendingName->whyPending,
pendingName->socket,
pendingName->nbpId);
CancelTimer(pendingName->timerId);
Free(pendingName);
}
return;
} // NbpCloseSocket
long DecodeNbpTuple(void far *buffer,
long offset,
Boolean bufferIsOpaque,
NbpTuple far *tuple)
{
short length;
unsigned char temp;
//
// Accept an "on the wire" representation of an NBP tuple, decode it into a
// workable structure, return the position in the buffer past the tuple.
//
// First the address.networkNumber.
if (bufferIsOpaque)
MoveFromOpaque(&temp, buffer, offset++, 1);
else
temp = (unsigned char)((char far *)buffer)[offset++];
tuple->address.networkNumber = (unsigned short)(temp << 8);
if (bufferIsOpaque)
MoveFromOpaque(&temp, buffer, offset++, 1);
else
temp = (unsigned char)((char far *)buffer)[offset++];
tuple->address.networkNumber += (unsigned short)temp;
// Next the address.nodeNumber.
if (bufferIsOpaque)
MoveFromOpaque(&temp, buffer, offset++, 1);
else
temp = (unsigned char)((char far *)buffer)[offset++];
tuple->address.nodeNumber = temp;
// Next the address.socketNumber.
if (bufferIsOpaque)
MoveFromOpaque(&temp, buffer, offset++, 1);
else
temp = (unsigned char)((char far *)buffer)[offset++];
tuple->address.socketNumber = temp;
// Next the enumerator.
if (bufferIsOpaque)
MoveFromOpaque(&temp, buffer, offset++, 1);
else
temp = (unsigned char)((char far *)buffer)[offset++];
tuple->enumerator = temp;
// Now the Nbp object.
if (bufferIsOpaque)
MoveFromOpaque(&temp, buffer, offset++, 1);
else
temp = (unsigned char)((char far *)buffer)[offset++];
length = temp;
if (length < 1 or length > MaximumEntityFieldLength)
return(0);
if (bufferIsOpaque)
MoveFromOpaque(tuple->object, buffer, offset, length);
else
MoveMem(tuple->object, (char far *)buffer + offset, length);
tuple->object[length] = 0;
offset += length;
// Now the Nbp type.
if (bufferIsOpaque)
MoveFromOpaque(&temp, buffer, offset++, 1);
else
temp = (unsigned char)((char far *)buffer)[offset++];
length = temp;
if (length < 1 or length > MaximumEntityFieldLength)
return(0);
if (bufferIsOpaque)
MoveFromOpaque(tuple->type, buffer, offset, length);
else
MoveMem(tuple->type, (char far *)buffer + offset, length);
tuple->type[length] = 0;
offset += length;
// Last the zone name.
if (bufferIsOpaque)
MoveFromOpaque(&temp, buffer, offset++, 1);
else
temp = (unsigned char)((char far *)buffer)[offset++];
length = temp;
if (length is 0) {
tuple->zone[0] = '*';
tuple->zone[1] = 0;
return(offset);
}
if (length < 1 or length > MaximumEntityFieldLength)
return(0);
if (bufferIsOpaque)
MoveFromOpaque(tuple->zone, buffer, offset, length);
else
MoveMem(tuple->zone, (char far *)buffer + offset, length);
tuple->zone[length] = 0;
offset += length;
// All set.
return(offset);
} // DecodeNbpTuple
short far EncodeNbpTuple(NbpTuple far *tuple,
char far *buffer)
{
char far *bufferStart = buffer;
short length;
//
// Accept our internal NbpTuple representation and produce an equivalent
// "on the wire" representation; fill a user buffer with the new
// representation, and return the number of bytes used by the encoded
// representation.
//
*buffer++ = (char)(tuple->address.networkNumber >> 8);
*buffer++ = (char)(tuple->address.networkNumber & 0xFF);
*buffer++ = (char)(tuple->address.nodeNumber & 0xFF);
*buffer++ = (char)(tuple->address.socketNumber & 0xFF);
*buffer++ = (char)(tuple->enumerator & 0xFF);
length = (short)strlen(tuple->object);
*buffer++ = (char)length;
MoveMem(buffer, tuple->object, length);
buffer += length;
length = (short)strlen(tuple->type);
*buffer++ = (char)length;
MoveMem(buffer, tuple->type, length);
buffer += length;
length = (short)strlen(tuple->zone);
if (length is 0) {
*buffer++ = 1;
*buffer++ = '*';
}
else {
*buffer++ = (char)length;
MoveMem(buffer, tuple->zone, length);
buffer += length;
}
return((short)(buffer - bufferStart));
} // EncodeNbpTuple
ExternForVisibleFunction void far
NbpTimerExpired(long unsigned timerId,
int additionalDataSize,
char far *incomingAdditionalData)
{
StaticForSmallStack PendingName pendingName, currentPendingName,
previousPendingName;
StaticForSmallStack OpenSocket openSocket;
long onWhosBehalf;
RegisteredName registeredName;
int nbpId;
WhyPending reason;
void far *opaqueBuffer;
int totalTuples;
NbpCompletionHandler *completionRoutine;
long unsigned userData;
long id;
AdditionalData far *additionalData =
(AdditionalData far *)incomingAdditionalData;
AppleTalkErrorCode errorCode;
// "Use" unneeded actual parameter.
timerId;
previousPendingName = empty;
//
// Grab the pointer to pending-name structure, that should be our timer's
// additional data.
//
if (additionalDataSize isnt sizeof(AdditionalData)) {
ErrorLog("NbpTimerExpired", ISevError, __LINE__, UnknownPort,
IErrNbpBadData, IMsgNbpBadData,
Insert0());
return;
}
//
// We may need to mess with the pending names lists, don't handle incoming
// packets now...
//
DeferIncomingPackets();
pendingName = additionalData->pendingName;
id = additionalData->id;
onWhosBehalf = additionalData->socket;
//
// Try to find the current (expired) pendingName on the pending names
// list of the current socket. There is a vauge chance that it has been
// freed out from under us.
//
if ((openSocket = MapSocketToOpenSocket(onWhosBehalf)) is empty) {
HandleIncomingPackets();
HandleDeferredTimerChecks();
ErrorLog("NbpTimerExpired", ISevVerbose, __LINE__, UnknownPort,
IErrNbpSocketClosed, IMsgNbpSocketClosed,
Insert0());
return;
}
for (currentPendingName = openSocket->pendingNames;
currentPendingName isnt empty and
(id isnt currentPendingName->id and
currentPendingName isnt pendingName);
previousPendingName = currentPendingName,
currentPendingName = currentPendingName->next)
;
if (currentPendingName is empty) {
ErrorLog("NbpTimerExpired", ISevVerbose, __LINE__, openSocket->port,
IErrNbpNoLongerPending, IMsgNbpNoLongerPending,
Insert0());
HandleIncomingPackets();
HandleDeferredTimerChecks();
return;
}
// Has our timer expired for the last time?
reason = pendingName->whyPending;
if (pendingName->remainingBroadcasts is 0) {
//
// Grab any information that we may need before we free the pending name
// structure.
//
nbpId = pendingName->nbpId;
opaqueBuffer = pendingName->opaqueBuffer;
totalTuples = pendingName->totalTuples;
completionRoutine = pendingName->completionRoutine;
userData = pendingName->userData;
if (previousPendingName is empty)
openSocket->pendingNames = pendingName->next;
else
previousPendingName->next = pendingName->next;
// Okay, call the completion routine with the correct arguments.
if (reason is ForConfirm) {
Free(pendingName);
HandleIncomingPackets();
HandleDeferredTimerChecks();
(*completionRoutine)(ATnbpNotConfirmed, userData, ForConfirm,
onWhosBehalf, nbpId);
return;
}
else if (reason is ForRegister) {
//
// Create a RegisteredName node and move our pending name to this
// list.
//
if ((registeredName =
(RegisteredName)Calloc(sizeof(*registeredName), 1)) is empty)
errorCode = AToutOfMemory;
else {
errorCode = ATnoError;
strcpy(registeredName->object, pendingName->object);
strcpy(registeredName->type, pendingName->type);
registeredName->enumerator = pendingName->enumerator;
registeredName->next = openSocket->registeredNames;
openSocket->registeredNames = registeredName;
}
// Okay, call the completion routine.
Free(pendingName);
HandleIncomingPackets();
HandleDeferredTimerChecks();
(*completionRoutine)(errorCode, userData, ForRegister, onWhosBehalf,
nbpId);
return;
}
else if (reason is ForLookup) {
Free(pendingName);
HandleIncomingPackets();
HandleDeferredTimerChecks();
(*completionRoutine)(ATnoError, userData, ForLookup, onWhosBehalf,
nbpId, opaqueBuffer, totalTuples);
return;
}
else {
Free(pendingName);
ErrorLog("NbpTimerExpired", ISevError, __LINE__, openSocket->port,
IErrNbpBadPendingFlag, IMsgNbpBadPendingFlag,
Insert0());
}
HandleIncomingPackets();
HandleDeferredTimerChecks();
return;
}
//
// Re-start the re-transmit timer... We'll need the address of the pending-
// name structure when the timer expires...
//
pendingName->timerId = StartTimer(NbpTimerExpired,
pendingName->broadcastInterval,
sizeof(AdditionalData),
(char *)additionalData);
// Otherwise, we need to re-send the inquiry packet...
if (not SendNbpRequest(pendingName))
ErrorLog("NbpTimerExpired", ISevError, __LINE__, openSocket->port,
IErrNbpBadBrRqSend, IMsgNbpBadBrRqSend,
Insert0());
pendingName->remainingBroadcasts -= 1;
// The deed is done...
HandleIncomingPackets();
HandleDeferredTimerChecks();
return;
} // NbpTimerExpired
ExternForVisibleFunction void DoNameLookup(int port,
NbpTuple far *nbpTuple,
int nbpId,
long whatSocket)
{
StaticForSmallStack BufferDescriptor packet;
StaticForSmallStack NbpTuple matchedTuple;
StaticForSmallStack OpenSocket openSocket, currentOpenSocket;
StaticForSmallStack RegisteredName nameList;
StaticForSmallStack PendingName pendingList;
StaticForSmallStack AppleTalkAddress ourAddress;
int index;
short tupleCount = 0;
// Does the requester at least have the zone correct?
if (nbpTuple->zone[0] isnt '*' or
nbpTuple->zone[1] isnt 0)
while(True) {
// If we know our zone and it matches, we're okay.
if (GET_PORTDESCRIPTOR(port)->ThisZoneValid and
CompareCaseInsensitive(nbpTuple->zone,
GET_PORTDESCRIPTOR(port)->ThisZone))
break;
//
// If we're non-extended we won't know our zone name (unless we're
// a router), so assume the best. A router shouldn't have forwarded
// a lookup to the wrong zone!
//
if (not GET_PORTDESCRIPTOR(port)->ExtendedNetwork)
break;
// Otherwise, wrong zone -- ignore the request.
return;
}
// Find an open socket on the correct node.
if ((openSocket = MapSocketToOpenSocket(whatSocket)) is empty) {
ErrorLog("DoNameLookup", ISevError, __LINE__, port,
IErrNbpOpenSocketMissing, IMsgNbpOpenSocketMissing,
Insert0());
return;
}
if (MapSocketToAddress(whatSocket, &ourAddress) isnt ATnoError) {
ErrorLog("DoNameLookup", ISevError, __LINE__, port,
IErrNbpCouldntFormAddress, IMsgNbpCouldntFormAddress,
Insert0());
return;
}
//
// Allocate a buffer descriptor for the reply tuples and fill in the static
// portions.
//
if ((packet = NewBufferDescriptor(MaximumDdpDatagramSize)) is Empty) {
ErrorLog("DoNameLookup", ISevError, __LINE__, port,
IErrNbpOutOfMemory, IMsgNbpOutOfMemory,
Insert0());
return;
}
packet->data[NbpControlOffset] = (NbpLookupReply << 4);
packet->data[NbpIdOffset] = (char)(nbpId & 0xFF);
index = NbpFirstTupleOffset;
//
// Walk the registered names lists on all sockets open on this node and see
// if we have a matching name. We have to walk the PendingNames list also
// (but don't answer if we're the node trying to register the name).
//
for (currentOpenSocket = openSocket->activeNode->openSockets;
currentOpenSocket isnt empty;
currentOpenSocket = currentOpenSocket->next) {
// Check regisered names...
for (nameList = currentOpenSocket->registeredNames;
nameList isnt empty;
nameList = nameList->next) {
// Do the "object"s match?
if (not WildMatch(nbpTuple->object, nameList->object))
continue;
// Do the "type"s match?
if (not WildMatch(nbpTuple->type, nameList->type))
continue;
// We have full match, build complete NbpTuple.
matchedTuple.address.networkNumber = ourAddress.networkNumber;
matchedTuple.address.nodeNumber = ourAddress.nodeNumber;
matchedTuple.address.socketNumber = currentOpenSocket->actualSocket;
matchedTuple.enumerator = nameList->enumerator;
strcpy(matchedTuple.object, nameList->object);
strcpy(matchedTuple.type, nameList->type);
matchedTuple.zone[0] = '*';
matchedTuple.zone[1] = 0;
// Encode the matching tuple into the packet.
index += EncodeNbpTuple(&matchedTuple, packet->data + index);
tupleCount += 1;
// Can the packet hold another tuple?
if (index + MaximumNbpTupleLength > MaximumDdpDatagramSize or
tupleCount is 0xF) {
packet->data[NbpControlOffset] &= 0xF0;
packet->data[NbpControlOffset] |= (char)(tupleCount & 0xF);
if (DeliverDdp(whatSocket, nbpTuple->address, DdpProtocolNbp,
packet, index, Empty, Empty, 0) isnt ATnoError)
ErrorLog("DoNameLookup", ISevError, __LINE__, port,
IErrNbpBadReplySend, IMsgNbpBadReplySend,
Insert0());
// Allocate a new bufer descriptor.
if ((packet = NewBufferDescriptor(MaximumDdpDatagramSize)) is Empty) {
ErrorLog("DoNameLookup", ISevError, __LINE__, port,
IErrNbpOutOfMemory, IMsgNbpOutOfMemory,
Insert0());
return;
}
packet->data[NbpControlOffset] = (NbpLookupReply << 4);
packet->data[NbpIdOffset] = (char)(nbpId & 0xFF);
index = NbpFirstTupleOffset;
tupleCount = 0;
}
}
// Check pending names...
for (pendingList = currentOpenSocket->pendingNames;
pendingList isnt empty;
pendingList = pendingList->next) {
if (pendingList->whyPending isnt ForRegister)
continue; // Confirms or lookups don't count!
//
// Don't say we have a match if we run into the register that we're
// trying to do...
//
if (ourAddress.networkNumber is nbpTuple->address.networkNumber and
ourAddress.nodeNumber is nbpTuple->address.nodeNumber and
nbpId is pendingList->nbpId)
continue;
// Do the "object"s match?
if (not WildMatch(nbpTuple->object, pendingList->object))
continue;
// Do the "type"s match? ('=' is a wildcard)
if (not WildMatch(nbpTuple->type, pendingList->type))
continue;
// We have full match, build complete NbpTuple.
matchedTuple.address.networkNumber = ourAddress.networkNumber;
matchedTuple.address.nodeNumber = ourAddress.nodeNumber;
matchedTuple.address.socketNumber = currentOpenSocket->actualSocket;
matchedTuple.enumerator = pendingList->enumerator;
strcpy(matchedTuple.object, pendingList->object);
strcpy(matchedTuple.type, pendingList->type);
matchedTuple.zone[0] = '*';
matchedTuple.zone[1] = 0;
// Encode the matching tuple into the packet.
index += EncodeNbpTuple(&matchedTuple, packet->data + index);
tupleCount += 1;
// Can the packet hold another tuple?
if (index + MaximumNbpTupleLength > MaximumDdpDatagramSize or
tupleCount is 0xF) {
packet->data[NbpControlOffset] &= 0xF0;
packet->data[NbpControlOffset] |= (char)(tupleCount & 0xF);
if (DeliverDdp(whatSocket, nbpTuple->address, DdpProtocolNbp,
packet, index, Empty, Empty, 0) isnt ATnoError)
ErrorLog("DoNameLookup", ISevError, __LINE__, port,
IErrNbpBadReplySend, IMsgNbpBadReplySend,
Insert0());
// Allocate a new bufer descriptor.
if ((packet = NewBufferDescriptor(MaximumDdpDatagramSize)) is Empty) {
ErrorLog("DoNameLookup", ISevError, __LINE__, port,
IErrNbpOutOfMemory, IMsgNbpOutOfMemory,
Insert0());
return;
}
packet->data[NbpControlOffset] = (NbpLookupReply << 4);
packet->data[NbpIdOffset] = (char)(nbpId & 0xFF);
index = NbpFirstTupleOffset;
tupleCount = 0;
}
}
}
// Do we have a partially filled packet of tuples?
if (tupleCount isnt 0) {
packet->data[NbpControlOffset] &= 0xF0;
packet->data[NbpControlOffset] |= (char)(tupleCount & 0xF);
if (DeliverDdp(whatSocket, nbpTuple->address, DdpProtocolNbp,
packet, index, Empty, Empty, 0) isnt ATnoError)
ErrorLog("DoNameLookup", ISevError, __LINE__, port,
IErrNbpBadReplySend, IMsgNbpBadReplySend,
Insert0());
}
else
FreeBufferChain(packet); // Free the unused buffer chain.
// The deed is done.
return;
} // DoNameLookup
#if Verbose or (Iam a Primos)
void DumpNbpNamesFor(long socket)
{
OpenSocket openSocket;
PendingName pendingName;
RegisteredName registeredName;
// Walk the pending and registered lists and tell all.
DeferTimerChecking();
DeferIncomingPackets();
if ((openSocket = MapSocketToOpenSocket(socket)) is empty) {
HandleIncomingPackets();
HandleDeferredTimerChecks();
printf("Bad socket supplied.\n");
return;
}
printf("Pending NBP names on %d are:\n", socket);
for (pendingName = openSocket->pendingNames;
pendingName isnt empty;
pendingName = pendingName->next)
printf(" Object = \"%s\", type = \"%s\", enumerator = %d.\n",
pendingName->object, pendingName->type, pendingName->enumerator);
printf("Registered NBP names on %d are:\n", socket);
for (registeredName = openSocket->registeredNames;
registeredName isnt empty;
registeredName = registeredName->next)
printf(" Object = \"%s\", type = \"%s\", enumerator = %d.\n",
registeredName->object, registeredName->type,
registeredName->enumerator);
HandleIncomingPackets();
HandleDeferredTimerChecks();
return;
} // DumpNbpNamesFor
#endif
ExternForVisibleFunction Boolean WildMatch(char far *wildString,
char far *masterString)
{
char far *before, far *after, far *wild;
int beforeLength, afterLength, masterLength;
// Match using NBP wildcards. See Inside AppleTalk for details.
if (wildString[0] is 0)
return(True);
if (wildString[0] is '=' and
wildString[1] is 0)
return(True);
if ((wild = strchr(wildString, NbpWildCharacter)) is empty)
return(CompareCaseInsensitive(wildString, masterString));
beforeLength = (wild - wildString);
before = wildString;
after = wild + 1;
afterLength = (short)strlen(after);
masterLength = (short)strlen(masterString);
if (masterLength >= (beforeLength + afterLength) and
FixedCompareCaseInsensitive(before, beforeLength,
masterString, beforeLength) and
CompareCaseInsensitive(after, masterString + masterLength -
afterLength))
return(True);
else
return(False);
} // WildMatch
ExternForVisibleFunction Boolean SendNbpRequest(PendingName pendingName)
{
AppleTalkAddress replyTo, destination;
long replySocket;
OpenSocket openSocket;
int port;
BufferDescriptor descriptor;
// We want to a reply to come to the NIS in the requesting node.
if ((openSocket = MapSocketToOpenSocket(pendingName->socket)) is empty) {
ErrorLog("SendNbpRequest", ISevError, __LINE__, UnknownPort,
IErrNbpCouldntMapSocket, IMsgNbpCouldntMapSocket,
Insert0());
return(False);
}
port = openSocket->port;
if (MapSocketToAddress(pendingName->socket, &replyTo) isnt ATnoError) {
ErrorLog("SendNbpRequest", ISevError, __LINE__, port,
IErrNbpCouldntFormAddress, IMsgNbpCouldntFormAddress,
Insert0());
return(False);
}
replyTo.socketNumber = NamesInformationSocket;
if ((replySocket = MapAddressToSocket(port, replyTo)) < ATnoError) {
ErrorLog("SendNbpRequest", ISevError, __LINE__, port,
IErrNbpCouldntFormAddress, IMsgNbpCouldntFormAddress,
Insert0());
return(False);
}
// Pick destination...
if (pendingName->whyPending is ForConfirm) // Send to confirming node... {
destination = pendingName->confirming;
destination.socketNumber = NamesInformationSocket;
}
else {
if (GET_PORTDESCRIPTOR(port)->SeenRouterRecently)
{
destination.networkNumber =
GET_PORTDESCRIPTOR(port)->ARouter.NetworkNumber;
destination.nodeNumber =
GET_PORTDESCRIPTOR(port)->ARouter.NodeNumber;
destination.socketNumber = NamesInformationSocket;
}
else {
destination.networkNumber = CableWideBroadcastNetworkNumber;
destination.nodeNumber = AppleTalkBroadcastNodeNumber;
destination.socketNumber = NamesInformationSocket;
}
}
//
// Build a buffer descriptor for the datagram. Copy the datagram due
// to the possibility of asynchronous transmit completion.
//
if ((descriptor = NewBufferDescriptor(pendingName->datagramLength)) is Empty) {
ErrorLog("SendNbpRequest", ISevError, __LINE__, port,
IErrNbpOutOfMemory, IMsgNbpOutOfMemory,
Insert0());
return(False);
}
MoveMem(descriptor->data, pendingName->datagram, pendingName->datagramLength);
// Do the deed.
if (DeliverDdp(replySocket, destination, DdpProtocolNbp,
descriptor, pendingName->datagramLength,
Empty, Empty, 0) is ATnoError)
return(True);
else
return(False);
} // SendNbpRequest
#if Iam an AppleTalkRouter
ExternForVisibleFunction void
SendLookupDatagram(int port,
char far *zone,
BufferDescriptor lookupDatagram,
int length) {
AppleTalkAddress source, destination;
char far *multicastAddress;
long sourceSocket;
// Send from the NIS of our router on the given port.
source.networkNumber =
GET_PORTDESCRIPTOR(port)->ARouter.NetworkNumber;
source.nodeNumber = GET_PORTDESCRIPTOR(port)->ARouter.NodeNumber;
source.socketNumber = NamesInformationSocket;
if ((sourceSocket = MapAddressToSocket(port, source)) < 0) {
ErrorLog("SendLookupDatagram", ISevError, __LINE__, port,
IErrNbpBadSourceSocket, IMsgNbpBadSourceSocket,
Insert0());
return;
}
// To the target network...
destination.nodeNumber = AppleTalkBroadcastNodeNumber;
destination.socketNumber = NamesInformationSocket;
if (GET_PORTDESCRIPTOR(port)->ExtendedNetwork) {
// Send to "0000FF" at correct zone multicast address.
destination.networkNumber = CableWideBroadcastNetworkNumber;
multicastAddress = MulticastAddressForZoneOnPort(port, zone);
if (multicastAddress is empty) {
ErrorLog("SendLookupDatagram", ISevError, __LINE__, port,
IErrNbpBadMutlicastAddr, IMsgNbpBadMutlicastAddr,
Insert0());
return;
}
if (DeliverDdp(sourceSocket, destination,
DdpProtocolNbp, lookupDatagram, length,
multicastAddress, Empty, 0) isnt ATnoError)
ErrorLog("SendLookupDatagram", ISevError, __LINE__, port,
IErrNbpBadMulticastSend, IMsgNbpBadMulticastSend,
Insert0());
}
else {
// Send to "nnnnFF" as braodcast.
destination.networkNumber =
GET_PORTDESCRIPTOR(port)->ThisCableRange.firstNetworkNumber;
if (DeliverDdp(sourceSocket, destination,
DdpProtocolNbp, lookupDatagram, length,
Empty, Empty, 0) isnt ATnoError)
ErrorLog("SendLookupDatagram", ISevError, __LINE__, port,
IErrNbpBadBroadcastSend, IMsgNbpBadBroadcastSend,
Insert0());
}
return;
} // SendLookupDatagram
#endif