mirror of https://github.com/lianthony/NT4.0
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.
1610 lines
45 KiB
1610 lines
45 KiB
/*++
|
|
|
|
Copyright (c) 1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
nbltsvr.c
|
|
|
|
Abstract:
|
|
|
|
Loadable transport for NT & OS/2 NetBios - server side.
|
|
This file is packaged as a dynamic link library, that is loaded on
|
|
demand by the RPC runtime. It provides basic connection oriented,
|
|
message based operations. This module will create a static or dynamic
|
|
(that is, the name is generated by this module) NetBios name. Once
|
|
the name is created, it will post listens on the name to accept new
|
|
sessions from clients. The ReceiveAny function will wait for a new
|
|
message on any of the sessions open with this name. Replies are
|
|
returned via the Send function to a given client.
|
|
|
|
Author:
|
|
|
|
Steven Zeck (stevez) 2/12/92
|
|
|
|
Danny Glasser (dannygl) 2/18/93
|
|
--*/
|
|
|
|
#include <NetBCom.h>
|
|
#include <limits.h>
|
|
#include <stdlib.h>
|
|
|
|
#define MAX_ADAPTER_PER_CARD 8
|
|
|
|
#define MAX_ENDPOINT_NUMBER UCHAR_MAX
|
|
#define INITIAL_ENDPOINT_NUMBER 0x21 // 0-0x20 are used by LANMAN components
|
|
|
|
// This table maps system error codes into RPC generic ones.
|
|
|
|
ERROR_TABLE NetBiosErrors[] =
|
|
{
|
|
NRC_BFULL, RPC_S_OUT_OF_RESOURCES,
|
|
NRC_CMDTMO, RPC_P_TIMEOUT,
|
|
NRC_NORES, RPC_S_OUT_OF_RESOURCES,
|
|
NRC_DUPNAME, RPC_S_DUPLICATE_ENDPOINT,
|
|
NRC_NAMTFUL, RPC_S_OUT_OF_RESOURCES,
|
|
NRC_ACTSES, RPC_S_OUT_OF_RESOURCES,
|
|
NRC_LOCTFUL, RPC_S_OUT_OF_RESOURCES,
|
|
NRC_REMTFUL, RPC_S_SERVER_TOO_BUSY,
|
|
NRC_TOOMANY, RPC_S_OUT_OF_RESOURCES,
|
|
NRC_MAXAPPS, RPC_S_OUT_OF_RESOURCES,
|
|
NRC_NORESOURCES, RPC_S_OUT_OF_RESOURCES,
|
|
NRC_SCLOSED, RPC_P_SEND_FAILED,
|
|
NRC_SABORT, RPC_P_SEND_FAILED,
|
|
NRC_BRIDGE, RPC_S_PROTSEQ_NOT_SUPPORTED,
|
|
NRC_SNUMOUT, RPC_P_SEND_FAILED,
|
|
NRC_SYSTEM, RPC_S_OUT_OF_RESOURCES,
|
|
0
|
|
};
|
|
|
|
|
|
// Copy a string from an ANSI buffer to a native format buffer
|
|
#ifdef NTWIN32RPC
|
|
#define COPY_TO_NATIVE_STRING mbstowcs
|
|
#endif
|
|
|
|
#ifdef DOSWIN32RPC
|
|
#define COPY_TO_NATIVE_STRING memcpy
|
|
#endif
|
|
|
|
|
|
// The following macro is used to build a unique connection key to pass to
|
|
// I_RpcTransServer{New,Find}Connection().
|
|
|
|
#define MAKE_CONNECTION_KEY(lana, lsn) ((lana) << 8 | (lsn))
|
|
|
|
// The following macros are used to determine whether to add or delete
|
|
// Receive-Any NCBs dynamically, given the current number of connections
|
|
// and Receive-Any NCBs.
|
|
//
|
|
// The algorithm is that the number of Receive-Any NCBs increases
|
|
// logarithmically w.r.t. the number of clients, e.g. 1 RA for 0-1 clients,
|
|
// 2 RAs for 2-3 clients, 3 RAs for 4-7 clients, 4 RAs for 8-15 clients,
|
|
// etc.
|
|
|
|
#define TOO_FEW_RCVS(conns, rcvs) ( (1 << (rcvs)) <= (conns) )
|
|
#define TOO_MANY_RCVS(conns, rcvs) ( ((rcvs) > 1) \
|
|
&& (1 << ((rcvs) - 1)) > (conns) )
|
|
|
|
|
|
// The following is a generic linked list forward pointer.
|
|
|
|
typedef void ** PLIST_ITEM;
|
|
|
|
// The following is per receive-any NCB information. All receive-any's
|
|
// are linked in a list owned by the adapter. Note: the first
|
|
// member of a linked list structure is the forward pointer.
|
|
|
|
typedef struct _RECEIVE
|
|
{
|
|
struct _RECEIVE *NextReceive; // Forward link in receive list
|
|
|
|
UINT AddrIndex; // Index in address's receive
|
|
// pointer table
|
|
|
|
NCB theNCB; // The NCB structure
|
|
CLIENT_BUFFER buffer; // The NCB buffer
|
|
|
|
} RECEIVE, *PRECEIVE;
|
|
|
|
// Following is the per client session information.
|
|
|
|
typedef struct _CONNECTION{
|
|
|
|
struct _ADAPTER *Adapter; // Adapter over which I'm connected
|
|
UCHAR lsn; // netbios Local Session Number
|
|
DWORD ClientSeqNum; // Sequence # of next client buffer
|
|
|
|
} CONNECTION, *PCONNECTION;
|
|
|
|
// Following is the per adapter information. This allows one address
|
|
// and protocol pair to be used on all the cards that support the protocol.
|
|
|
|
typedef struct _ADAPTER{
|
|
|
|
UCHAR lana_num; // the adapter #
|
|
UCHAR iName; // NetBios name number
|
|
|
|
INT ConnectionCount; // # of connections on this lana
|
|
|
|
NCB ListenNCB; // NCB for async listens
|
|
|
|
INT ReceiveCount; // # of receive-anys on this lana
|
|
struct _RECEIVE *FirstReceive; // First receive in the list
|
|
|
|
} ADAPTER, *PADAPTER;
|
|
|
|
// Following is the per NetBios address information.
|
|
|
|
typedef struct _TADDRESS{
|
|
|
|
UINT AdapterCount; // Number of adapters and a
|
|
PADAPTER Adapters; // control array
|
|
|
|
UINT ReceivePtrCount; // Number of receive pointers
|
|
PRECEIVE *ReceivePtrs; // and an array
|
|
|
|
HANDLE Events[MAXIMUM_WAIT_OBJECTS]; // Array of events
|
|
|
|
} TADDRESS, *PTADDRESS;
|
|
|
|
|
|
// EVENT_COUNT - This macro, which computes the number of events in an
|
|
// address's event array, is primarily for readability.
|
|
#define EVENT_COUNT(pAdd) ((pAdd)->AdapterCount + (pAdd)->ReceivePtrCount)
|
|
|
|
|
|
extern RPC_SERVER_TRANSPORT_INFO TransInfo;
|
|
|
|
INTERNAL_FUNCTION PRECEIVE
|
|
DeleteReceive(
|
|
IN PTADDRESS pAdd,
|
|
IN int Number,
|
|
IN PRECEIVE pReceive
|
|
);
|
|
|
|
|
|
INTERNAL_FUNCTION PLIST_ITEM
|
|
RemoveLinkList(
|
|
PLIST_ITEM pListFirst,
|
|
void *Delete
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Search through a singly linked list and remove the requested item.
|
|
Linked lists use a single forward pointer as the first member of
|
|
the structure.
|
|
|
|
Arguments:
|
|
|
|
pListFirst - pointer to the head of the linked list
|
|
|
|
Delete - the item to delete
|
|
|
|
Returns:
|
|
|
|
A pointer to the linked list element that precedes the one being
|
|
removed.
|
|
|
|
--*/
|
|
{
|
|
CRITICAL_ENTER();
|
|
|
|
// Find the node pointing to the item to be deleted.
|
|
|
|
while (*pListFirst && *pListFirst != Delete)
|
|
pListFirst = (PLIST_ITEM) *pListFirst;
|
|
|
|
ASSERT(pListFirst);
|
|
|
|
// Set the forward link to the deleted one's.
|
|
|
|
*pListFirst = *(PLIST_ITEM) Delete;
|
|
|
|
CRITICAL_LEAVE();
|
|
|
|
return pListFirst;
|
|
}
|
|
|
|
|
|
|
|
INTERNAL_FUNCTION RPC_TRANS_STATUS
|
|
SubmitReceive(
|
|
IN PTADDRESS pAdd,
|
|
IN int Number,
|
|
IN PRECEIVE pReceive OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Submit an async receive-any NCB on the specific adapter and address.
|
|
|
|
Arguments:
|
|
pAdd - the address on which to submit the async receive any.
|
|
|
|
Number - which adapter card to operate on.
|
|
|
|
pReceive - the receive buffer to be submitted. If 0, a new receive is
|
|
to be allocated.
|
|
|
|
--*/
|
|
{
|
|
RPC_TRANS_STATUS status = 0;
|
|
HANDLE event;
|
|
PADAPTER Card = &pAdd->Adapters[Number];
|
|
|
|
if (! pReceive)
|
|
{
|
|
CRITICAL_ENTER();
|
|
|
|
// Verify that we have room for another event, allocate memory for
|
|
// the receive, and create an event for the receive.
|
|
|
|
if (EVENT_COUNT(pAdd) >= MAXIMUM_WAIT_OBJECTS)
|
|
{
|
|
status = RPC_S_OUT_OF_RESOURCES;
|
|
}
|
|
else if (! (pReceive = I_RpcAllocate(sizeof(*pReceive))))
|
|
{
|
|
status = RPC_S_OUT_OF_MEMORY;
|
|
}
|
|
else if (! (event = CreateEvent(NULL, TRUE, TRUE, NULL)))
|
|
{
|
|
I_RpcFree(pReceive);
|
|
|
|
status = RPC_S_OUT_OF_RESOURCES;
|
|
}
|
|
else
|
|
{
|
|
// Everything succeeded!
|
|
|
|
// Add this receive to the adapter's linked list and increment
|
|
// the count.
|
|
pReceive->NextReceive = Card->FirstReceive;
|
|
Card->FirstReceive = pReceive;
|
|
|
|
Card->ReceiveCount++;
|
|
|
|
// Add the receive pointer and event to the address's arrays.
|
|
pAdd->ReceivePtrs[pAdd->ReceivePtrCount] = pReceive;
|
|
pAdd->Events[EVENT_COUNT(pAdd)] = event;
|
|
|
|
// Store the pointer's index in the receive itself, and
|
|
// increment the pointer count.
|
|
pReceive->AddrIndex = pAdd->ReceivePtrCount++;
|
|
|
|
// Zero the NCB and store the event handle in it.
|
|
memset(&pReceive->theNCB, 0, sizeof(pReceive->theNCB));
|
|
|
|
pReceive->theNCB.ncb_event = event;
|
|
}
|
|
|
|
CRITICAL_LEAVE();
|
|
|
|
if (status)
|
|
return status;
|
|
}
|
|
|
|
// Initialize the NCB
|
|
|
|
pReceive->theNCB.ncb_num = Card->iName;
|
|
pReceive->theNCB.ncb_buffer = (PUCHAR) &pReceive->buffer;
|
|
pReceive->theNCB.ncb_length = sizeof(pReceive->buffer);
|
|
pReceive->theNCB.ncb_lana_num = Card->lana_num;
|
|
|
|
// Submit the NCB
|
|
status = execNCB(NCBRECVANY | ASYNCH, &pReceive->theNCB);
|
|
|
|
// Ignore session-closed immediate errors
|
|
if (status == NRC_SCLOSED)
|
|
status = 0;
|
|
|
|
if (status == NRC_BRIDGE) {
|
|
// lana disappeared
|
|
DeleteReceive(pAdd, Number, pReceive);
|
|
status = 0;
|
|
}
|
|
|
|
ASSERT(! status);
|
|
|
|
return(MapStatusCode(NetBiosErrors, status, RPC_S_INTERNAL_ERROR));
|
|
}
|
|
|
|
|
|
INTERNAL_FUNCTION PRECEIVE
|
|
DeleteReceive(
|
|
IN PTADDRESS pAdd,
|
|
IN int Number,
|
|
IN PRECEIVE pReceive
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Deletes a receive-any NCB and the associated data buffer.
|
|
|
|
This function assumes that, once ReceiveAny() has been called for
|
|
this receive's address, it won't be expected to cancel any pending
|
|
NCBs. It should only need to cancel active NCBs when it is called
|
|
by RemoveAdapter().
|
|
|
|
Arguments:
|
|
|
|
pAdd - the address on which to remove the receive.
|
|
|
|
Number - which adapter card to operate on.
|
|
|
|
pReceive - the receive buffer to be deleted.
|
|
|
|
Returns:
|
|
|
|
A pointer to the Receive that precedes this one in the adapter's
|
|
linked list.
|
|
|
|
--*/
|
|
{
|
|
NCB theNCB;
|
|
PADAPTER Card = &pAdd->Adapters[Number];
|
|
PRECEIVE PrevReceive;
|
|
|
|
ASSERT(pReceive);
|
|
|
|
// Cancel the receive NCB if it's pending
|
|
if (pReceive->theNCB.ncb_cmd_cplt == NRC_PENDING)
|
|
{
|
|
memset(&theNCB, 0, sizeof(NCB));
|
|
|
|
theNCB.ncb_lana_num = Card->lana_num;
|
|
theNCB.ncb_buffer = (PUCHAR) &pReceive->theNCB;
|
|
|
|
execNCB(NCBCANCEL, &theNCB);
|
|
|
|
if (theNCB.ncb_retcode != NRC_CANOCCR)
|
|
{
|
|
MapStatusCode(NetBiosErrors,
|
|
theNCB.ncb_retcode,
|
|
RPC_P_SERVER_TRANSPORT_ERROR);
|
|
}
|
|
}
|
|
|
|
CRITICAL_ENTER();
|
|
|
|
// Remove the NCB from the adapter's linked list of NCBs.
|
|
PrevReceive = (PRECEIVE) RemoveLinkList((PLIST_ITEM) &Card->FirstReceive,
|
|
pReceive);
|
|
|
|
ASSERT(PrevReceive);
|
|
|
|
// Decrement the adapter receive buffer count.
|
|
Card->ReceiveCount--;
|
|
|
|
ASSERT(Card->ReceiveCount >= 0);
|
|
|
|
// Remove the event and the receive pointer from the address's list.
|
|
// We do this by taking this last elements of the receive pointer
|
|
// and event arrays and moving them into the positions of the element
|
|
// we're deleting.
|
|
|
|
ASSERT(pAdd->ReceivePtrs[pReceive->AddrIndex] == pReceive);
|
|
ASSERT(pAdd->Events[pAdd->AdapterCount + pReceive->AddrIndex]
|
|
== pReceive->theNCB.ncb_event);
|
|
|
|
if (pReceive->AddrIndex != pAdd->ReceivePtrCount - 1)
|
|
{
|
|
pAdd->ReceivePtrs[pReceive->AddrIndex] =
|
|
pAdd->ReceivePtrs[pAdd->ReceivePtrCount - 1];
|
|
|
|
pAdd->Events[pAdd->AdapterCount + pReceive->AddrIndex] =
|
|
pAdd->Events[EVENT_COUNT(pAdd) - 1];
|
|
|
|
// We need to modify the moved element's address index
|
|
pAdd->ReceivePtrs[pReceive->AddrIndex]->AddrIndex =
|
|
pReceive->AddrIndex;
|
|
}
|
|
|
|
pAdd->ReceivePtrCount--;
|
|
|
|
CRITICAL_LEAVE();
|
|
|
|
// Free the receive's event
|
|
CloseHandle(pReceive->theNCB.ncb_event);
|
|
|
|
// Free the buffer
|
|
I_RpcFree(pReceive);
|
|
|
|
return PrevReceive;
|
|
}
|
|
|
|
|
|
INTERNAL_FUNCTION RPC_STATUS
|
|
AddAdapter(
|
|
IN PADAPTER Card,
|
|
IN UCHAR *Name,
|
|
IN UCHAR LanaNum
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add the NetBIOS name and allocate buffers for a given adapter.
|
|
|
|
Arguments:
|
|
|
|
Card - Adapter to add. We assume it is passed to this function with
|
|
all fields zeroed.
|
|
|
|
Name - NetBIOS name to be added.
|
|
|
|
LanaNum - Lana number for this adapter.
|
|
|
|
--*/
|
|
{
|
|
RPC_STATUS status = 0;
|
|
NCB theNCB;
|
|
|
|
// Initialize the ADDNAME NCB
|
|
memset(&theNCB, 0, sizeof(NCB));
|
|
|
|
theNCB.ncb_lana_num = LanaNum;
|
|
|
|
memcpy(theNCB.ncb_name, Name, sizeof(theNCB.ncb_name));
|
|
|
|
// Submit the ADDNAME NCB
|
|
if ((status = (RPC_STATUS) execNCB(NCBADDNAME, &theNCB))
|
|
|| (status = theNCB.ncb_retcode))
|
|
{
|
|
return(MapStatusCode(NetBiosErrors,
|
|
status, RPC_S_CANT_CREATE_ENDPOINT));
|
|
}
|
|
|
|
// Fill in the appropriate fields of the adapter structure
|
|
Card->lana_num = LanaNum;
|
|
Card->iName = theNCB.ncb_num;
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
INTERNAL_FUNCTION void
|
|
RemoveAdapter(
|
|
IN PTADDRESS pAdd,
|
|
IN int Number
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Remove the NetBIOS name and free buffers for a given adapter.
|
|
|
|
This function assumes that ReceiveAny() has not been called for this
|
|
adapter's address. Otherwise, ReceiveAny() would have to deal with
|
|
the effects of the cancelled NCBs, cancelled sessions, and deleted
|
|
names.
|
|
|
|
Arguments:
|
|
|
|
pAdd - the address on which to remove the adapter.
|
|
|
|
Number - which adapter card to operate on.
|
|
|
|
--*/
|
|
{
|
|
PADAPTER Card = &pAdd->Adapters[Number];
|
|
NCB theNCB;
|
|
|
|
// Cancel the listen if it has been submitted
|
|
if (Card->ListenNCB.ncb_cmd_cplt == NRC_PENDING)
|
|
{
|
|
memset(&theNCB, 0, sizeof(NCB));
|
|
|
|
theNCB.ncb_lana_num = Card->lana_num;
|
|
theNCB.ncb_buffer = (PUCHAR) &Card->ListenNCB;
|
|
|
|
execNCB(NCBCANCEL, &theNCB);
|
|
|
|
if (theNCB.ncb_retcode != NRC_CANOCCR)
|
|
{
|
|
MapStatusCode(NetBiosErrors,
|
|
theNCB.ncb_retcode,
|
|
RPC_P_SERVER_TRANSPORT_ERROR);
|
|
}
|
|
}
|
|
|
|
// Hang up the session if the listen completed
|
|
if (Card->ListenNCB.ncb_retcode == NRC_GOODRET
|
|
&& Card->ListenNCB.ncb_lsn)
|
|
{
|
|
memset(&theNCB, 0, sizeof(NCB));
|
|
|
|
theNCB.ncb_lana_num = Card->lana_num;
|
|
theNCB.ncb_lsn = Card->ListenNCB.ncb_lsn;
|
|
|
|
execNCB(NCBHANGUP, &theNCB);
|
|
|
|
if (theNCB.ncb_retcode != NRC_SCLOSED)
|
|
{
|
|
MapStatusCode(NetBiosErrors,
|
|
theNCB.ncb_retcode,
|
|
RPC_P_SERVER_TRANSPORT_ERROR);
|
|
}
|
|
}
|
|
|
|
// Delete the per-receive data
|
|
while (Card->FirstReceive)
|
|
DeleteReceive(pAdd, Number, Card->FirstReceive);
|
|
|
|
// Delete the NetBIOS name on this lana, if it has been added
|
|
if (Card->iName)
|
|
{
|
|
memset(&theNCB, 0, sizeof(NCB));
|
|
|
|
theNCB.ncb_lana_num = Card->lana_num;
|
|
memcpy(theNCB.ncb_name,
|
|
Card->ListenNCB.ncb_name,
|
|
sizeof(theNCB.ncb_name));
|
|
|
|
execNCB(NCBDELNAME, &theNCB);
|
|
}
|
|
else
|
|
{
|
|
theNCB.ncb_retcode = 0;
|
|
}
|
|
|
|
MapStatusCode(NetBiosErrors,
|
|
theNCB.ncb_retcode,
|
|
RPC_P_SERVER_TRANSPORT_ERROR);
|
|
}
|
|
|
|
|
|
RPC_SERVER_TRANSPORT_INFO * RPC_ENTRY
|
|
TransportLoad (
|
|
IN RPC_CHAR * RpcProtocolSequence
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Loadable transport initialization function.
|
|
|
|
Arguments:
|
|
|
|
RpcProtocolSequence - the protocol string that mapped to this library.
|
|
|
|
Returns:
|
|
|
|
A pointer to a RPC_SERVER_TRANSPORT_INFO describing this transport.
|
|
|
|
--*/
|
|
|
|
{
|
|
InitNBMutex();
|
|
|
|
return(SetupNetBios(RpcProtocolSequence)? &TransInfo: 0);
|
|
}
|
|
|
|
|
|
|
|
INTERNAL_FUNCTION RPC_STATUS
|
|
SubmitListen (
|
|
IN PTADDRESS Address,
|
|
IN int Number
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function sets up NetBios to listen for new connections
|
|
on the address name that we have established.
|
|
|
|
Arguments:
|
|
|
|
pAdd - the address on which to submit the async listen.
|
|
|
|
Number - which adapter card to operate on.
|
|
|
|
Returns:
|
|
|
|
RPC_S_OK, RPC_S_CANT_CREATE_ENDPOINT, Status code mapping.
|
|
|
|
--*/
|
|
|
|
{
|
|
RPC_STATUS status;
|
|
PADAPTER Card = &Address->Adapters[Number];
|
|
|
|
// Note: The ncb_name and ncb_event fields of the ListenNCB are filled
|
|
// in by CreateEndpoint() when the adapter structure is initialized.
|
|
|
|
Card->ListenNCB.ncb_callname[0] = '*';
|
|
Card->ListenNCB.ncb_callname[1] = 0;
|
|
Card->ListenNCB.ncb_rto = 0;
|
|
Card->ListenNCB.ncb_sto = 0;
|
|
Card->ListenNCB.ncb_lana_num = Card->lana_num;
|
|
|
|
status = execNCB(NCBLISTEN | ASYNCH, &Card->ListenNCB);
|
|
|
|
return(MapStatusCode(NetBiosErrors, status, RPC_S_CANT_CREATE_ENDPOINT));
|
|
}
|
|
|
|
|
|
void RPC_ENTRY
|
|
AbortSetupAddress (
|
|
IN PTADDRESS pAdd
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called if an error occurs in setting up the
|
|
address between the time that SetupWithEndpoint or SetupUnknownEndpoint
|
|
successfully completed and before the next call into this loadable
|
|
transport module.
|
|
|
|
It is also called by CreateEndpoint() if this function encounters an
|
|
error while initializing the address.
|
|
|
|
Arguments:
|
|
|
|
pAdd - Supplies the address which is being aborted.
|
|
|
|
--*/
|
|
{
|
|
unsigned int Index;
|
|
|
|
// Perform adapter cleanup
|
|
if (pAdd->Adapters)
|
|
{
|
|
// Perform per-adapter cleanup
|
|
for (Index = 0; Index < pAdd->AdapterCount; Index++)
|
|
RemoveAdapter(pAdd, Index);
|
|
|
|
// Free memory for the adapter array
|
|
I_RpcFree(pAdd->Adapters);
|
|
}
|
|
|
|
// Perform receive pointer cleanup
|
|
if (pAdd->ReceivePtrs)
|
|
{
|
|
// We don't need to free the receive buffers themselves here.
|
|
// It is done on a per-adapter basis (RemoveAdapter calls
|
|
// DeleteReceive).
|
|
|
|
I_RpcFree(pAdd->ReceivePtrs);
|
|
}
|
|
|
|
// Perform event cleanup - delete the per-adapter listen events,
|
|
// stopping when we hit a NULL (the receive events, if any, are
|
|
// deleted by DeleteReceive).
|
|
ASSERT(pAdd->ReceivePtrCount == 0);
|
|
|
|
for (Index = 0;
|
|
Index < pAdd->AdapterCount && pAdd->Events[Index];
|
|
Index++)
|
|
{
|
|
CloseHandle(pAdd->Events[Index]);
|
|
}
|
|
}
|
|
|
|
|
|
INTERNAL_FUNCTION RPC_TRANS_STATUS RPC_ENTRY
|
|
CreateEndpoint (
|
|
IN PTADDRESS pAdd,
|
|
IN unsigned int EndpointNumber,
|
|
OUT RPC_CHAR __RPC_FAR * lNetworkAddress,
|
|
OUT unsigned int PAPI * NumNetworkAddress,
|
|
IN unsigned int NetworkAddressLength,
|
|
IN void __RPC_FAR * SecurityDescriptor, OPTIONAL
|
|
IN unsigned int PendingQueueSize,
|
|
IN RPC_CHAR __RPC_FAR * RpcProtocolSequence
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is used to setup a NetBios address with the specified
|
|
endpoint. We also return the network address of this server. It
|
|
is designed to be called by both SetupWithEndpoint() and
|
|
SetupUnknownEndpoint().
|
|
|
|
Arguments:
|
|
|
|
pAdd - Supplies this loadable transport interface address.
|
|
|
|
EndpointNumber - Supplies the endpoint number to create. It is used
|
|
as the last byte of the NetBIOS name.
|
|
|
|
NetworkAddress - Returns the network address for this machine. This
|
|
buffer will have been allocated by the caller.
|
|
|
|
NetworkAddressLength - Supplies the length of the network address
|
|
argument.
|
|
|
|
SecurityDescriptor - Unused and not allowed.
|
|
PendingQueueSize - Unused.
|
|
|
|
RpcProtocolSequence - this string is used to map to a NetBios apdater
|
|
number. Format of the string is "ncacn_nb_<protocol>. This
|
|
<protocol> (<> are not in the string) is used to do the mapping.
|
|
|
|
Return Value:
|
|
|
|
RPC_S_OK, RPC_P_NETWORK_ADDRESS_TOO_SMALL, RPC_S_INVALID_ARG,
|
|
RPC_S_OUT_OF_RESOURCES, RPC_S_CANT_CREATE_ENDPOINT,
|
|
RPC_S_DUPLICATE_ENDPOINT, RPC_S_INVALID_ENDPOINT_FORMAT,
|
|
SubmitListen(), Status error code mapping.
|
|
|
|
--*/
|
|
{
|
|
RPC_TRANS_STATUS Status;
|
|
PPROTOCOL_MAP ProtocolEntry;
|
|
PADAPTER Card;
|
|
unsigned int Index;
|
|
char LanaNumbers[MAX_ADAPTER_PER_CARD];
|
|
UINT MaxReceives;
|
|
UCHAR ncb_name[NCBNAMSZ];
|
|
UCHAR ncb_status;
|
|
char * PAPI * tmpPtr;
|
|
|
|
// Perform parameter validation.
|
|
|
|
UNUSED(PendingQueueSize); PUNUSED(RpcProtocolSequence);
|
|
|
|
if (SecurityDescriptor)
|
|
return(RPC_S_INVALID_ARG);
|
|
|
|
if (EndpointNumber > MAX_ENDPOINT_NUMBER)
|
|
return(RPC_S_INVALID_ENDPOINT_FORMAT);
|
|
|
|
if (sizeof(MachineName) + sizeof(RPC_CHAR *) > NetworkAddressLength)
|
|
return(RPC_P_NETWORK_ADDRESS_TOO_SMALL);
|
|
|
|
|
|
// Initialize all of the fields of the structure to 0. This lets us
|
|
// know later what fields have been initialized, in the event that we
|
|
// need to abort initialization.
|
|
|
|
memset(pAdd, 0, sizeof(TADDRESS));
|
|
|
|
tmpPtr = (char * PAPI *) lNetworkAddress;
|
|
|
|
tmpPtr[0] = (char *) lNetworkAddress + sizeof(RPC_CHAR * ) ;
|
|
|
|
*NumNetworkAddress = 1;
|
|
|
|
// Copy the network address from the machine name
|
|
COPY_TO_NATIVE_STRING(tmpPtr[0],
|
|
MachineName,
|
|
MachineNameLengthUnpadded);
|
|
|
|
lNetworkAddress[sizeof(RPC_CHAR *) + MachineNameLengthUnpadded] = 0;
|
|
|
|
Status = 0;
|
|
|
|
// Extract the lana_num from the protocol transport field of the protocol.
|
|
|
|
CRITICAL_ENTER();
|
|
|
|
// For all the cards that support this protocol, initialize.
|
|
|
|
for (;pAdd->AdapterCount < MAX_ADAPTER_PER_CARD; pAdd->AdapterCount++)
|
|
{
|
|
if (Status = MapProtocol(RpcProtocolSequence, pAdd->AdapterCount,
|
|
&ProtocolEntry))
|
|
break;
|
|
|
|
LanaNumbers[pAdd->AdapterCount] = ProtocolEntry->Lana;
|
|
|
|
// Call the client DLL to allocate resources for the adapter #.
|
|
if (ncb_status = AdapterReset(ProtocolEntry))
|
|
{
|
|
CRITICAL_LEAVE();
|
|
|
|
return(MapStatusCode(NetBiosErrors,
|
|
ncb_status, RPC_S_PROTSEQ_NOT_SUPPORTED));
|
|
}
|
|
}
|
|
|
|
CRITICAL_LEAVE();
|
|
|
|
if (pAdd->AdapterCount == 0)
|
|
return(Status);
|
|
|
|
Status = 0;
|
|
|
|
// Verify that we don't have too many adapters. We need to be able to
|
|
// wait on at least two events per adapter.
|
|
if (pAdd->AdapterCount * 2 > MAXIMUM_WAIT_OBJECTS)
|
|
{
|
|
return RPC_S_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
// Now that we know how many adapters, allocate memory for them.
|
|
//
|
|
// Note: Since we zero all of the adapter structures, we don't need
|
|
// to worry about initializing fields that default to 0.
|
|
|
|
if (!(pAdd->Adapters = I_RpcAllocate(pAdd->AdapterCount * sizeof(ADAPTER))))
|
|
{
|
|
Status = RPC_S_OUT_OF_MEMORY;
|
|
|
|
goto AddrInitFailed;
|
|
}
|
|
|
|
memset(pAdd->Adapters, 0, pAdd->AdapterCount * sizeof(ADAPTER));
|
|
|
|
// Allocate and initialize memory for the receive pointers. The
|
|
// maximum number of receives we can have per address is the maximum
|
|
// number of objects supported by WaitForMultipleObjects() less the
|
|
// number of adapters. This is because we have one event per receive
|
|
// and one per listen, and we use one listen per adapter.
|
|
|
|
MaxReceives = MAXIMUM_WAIT_OBJECTS - pAdd->AdapterCount;
|
|
|
|
if (!(pAdd->ReceivePtrs = I_RpcAllocate(MaxReceives * sizeof(PRECEIVE))))
|
|
{
|
|
Status = RPC_S_OUT_OF_MEMORY;
|
|
|
|
goto AddrInitFailed;
|
|
}
|
|
|
|
memset(pAdd->ReceivePtrs, 0, MaxReceives * sizeof(PRECEIVE));
|
|
|
|
// Create the events for the listen NCBs
|
|
for (Index = 0; Index < pAdd->AdapterCount; Index++)
|
|
{
|
|
if (! (pAdd->Events[Index] = CreateEvent(NULL, TRUE, TRUE, NULL)))
|
|
{
|
|
Status = RPC_S_OUT_OF_RESOURCES;
|
|
|
|
goto AddrInitFailed;
|
|
}
|
|
}
|
|
|
|
// Add the NCB names to the adapters and submit the listen and
|
|
// receive-any NCBs.
|
|
|
|
memcpy(ncb_name, MachineName, sizeof(MachineName));
|
|
ncb_name[NAME_LAST_BYTE] = (unsigned char) EndpointNumber;
|
|
|
|
for (Index = 0, Card = &pAdd->Adapters[0];
|
|
Index < pAdd->AdapterCount;
|
|
Index++, Card++)
|
|
{
|
|
// Initialize the name and event fields for the Listen NCB
|
|
memcpy(Card->ListenNCB.ncb_name,
|
|
ncb_name,
|
|
sizeof(Card->ListenNCB.ncb_name));
|
|
|
|
Card->ListenNCB.ncb_event = pAdd->Events[Index];
|
|
|
|
if (Status = AddAdapter(Card, ncb_name, LanaNumbers[Index]))
|
|
{
|
|
goto AddrInitFailed;
|
|
}
|
|
|
|
// Finally, setup to receive new clients and calls.
|
|
|
|
Status = SubmitListen(pAdd, Index);
|
|
|
|
if (Status)
|
|
goto AddrInitFailed;
|
|
|
|
Status = SubmitReceive(pAdd, Index, 0);
|
|
|
|
if (Status)
|
|
goto AddrInitFailed;
|
|
|
|
Status = 0;
|
|
}
|
|
|
|
|
|
AddrInitFailed:
|
|
|
|
if (Status)
|
|
AbortSetupAddress(pAdd);
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
|
|
RPC_TRANS_STATUS RPC_ENTRY
|
|
SetupWithEndpoint (
|
|
IN PTADDRESS pAdd,
|
|
IN RPC_CHAR __RPC_FAR * Endpoint,
|
|
OUT RPC_CHAR __RPC_FAR * lNetworkAddress,
|
|
OUT unsigned int PAPI * NumNetworkAddress,
|
|
IN unsigned int NetworkAddressLength,
|
|
IN void __RPC_FAR * SecurityDescriptor, OPTIONAL
|
|
IN unsigned int PendingQueueSize,
|
|
IN RPC_CHAR __RPC_FAR * RpcProtocolSequence
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is used to setup a NetBios address with the specified
|
|
endpoint. It is a front end to CreateEndpoint(), which does most of
|
|
the real work.
|
|
|
|
Arguments:
|
|
|
|
pAdd - Supplies this loadable transport interface address.
|
|
|
|
Endpoint - Supplies the endpoint netbios name to create.
|
|
|
|
NetworkAddress | Passed through to CreateEndpoint
|
|
NetworkAddressLength |
|
|
SecurityDescriptor |
|
|
PendingQueueSize |
|
|
RpcProtocolSequence |
|
|
|
|
Return Value:
|
|
|
|
RPC_S_INVALID_ENDPOINT_FORMAT, CreateEndpoint().
|
|
|
|
--*/
|
|
{
|
|
unsigned int EndpointNumber;
|
|
|
|
// Convert the endpoint string to a single byte.
|
|
|
|
for (EndpointNumber = 0;
|
|
*Endpoint >= RPC_CONST_CHAR('0') && *Endpoint <= RPC_CONST_CHAR('9') &&
|
|
EndpointNumber <= MAX_ENDPOINT_NUMBER;
|
|
Endpoint++)
|
|
|
|
EndpointNumber = EndpointNumber*10 + *Endpoint - RPC_CONST_CHAR('0');
|
|
|
|
if (*Endpoint != 0)
|
|
return(RPC_S_INVALID_ENDPOINT_FORMAT);
|
|
|
|
// BUGBUG - Should we validate that the endpoint number is in the
|
|
// INITIAL_ENDPOINT_NUMBER - UCHAR_MAX range?
|
|
|
|
return CreateEndpoint(pAdd, EndpointNumber, lNetworkAddress, NumNetworkAddress,
|
|
NetworkAddressLength, SecurityDescriptor,
|
|
PendingQueueSize, RpcProtocolSequence);
|
|
}
|
|
|
|
|
|
|
|
RPC_TRANS_STATUS RPC_ENTRY
|
|
SetupUnknownEndpoint (
|
|
IN PTADDRESS pAdd,
|
|
OUT RPC_CHAR __RPC_FAR * Endpoint,
|
|
IN unsigned int EndpointLength,
|
|
OUT RPC_CHAR __RPC_FAR * lNetworkAddress,
|
|
OUT unsigned int PAPI * NumNetworkAddress,
|
|
IN unsigned int NetworkAddressLength,
|
|
IN void __RPC_FAR * SecurityDescriptor, OPTIONAL
|
|
IN unsigned int PendingQueueSize,
|
|
IN RPC_CHAR __RPC_FAR * RpcProtocolSequence
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is used to generate an endpoint and setup a NetBios
|
|
address with that endpoint. It is a front end to CreateEndpoint(),
|
|
which does most of the real work.
|
|
|
|
Arguments:
|
|
|
|
pAdd - Supplies this loadable transport interface address.
|
|
|
|
Endpoint - Returns the endpoint generated for this address. This
|
|
buffer will have been allocated by the caller.
|
|
|
|
EndpointLength - Supplies the length of the endpoint argument.
|
|
|
|
NetworkAddress | Passed through to CreateEndpoint
|
|
NetworkAddressLength |
|
|
SecurityDescriptor |
|
|
PendingQueueSize |
|
|
RpcProtocolSequence |
|
|
|
|
Return Value:
|
|
|
|
RPC_P_ENDPOINT_TOO_SMALL, RPC_S_OUT_OF_RESOURCES, CreateEndpoint()
|
|
|
|
--*/
|
|
{
|
|
// This counter keeps track of the last endpoint we tried to create.
|
|
static unsigned char EndpointCounter = INITIAL_ENDPOINT_NUMBER - 1;
|
|
|
|
RPC_STATUS status;
|
|
char Number[4]; // 4 = 1 + log10(MAX_ENDPOINT_NUMBER)
|
|
unsigned char LastEndpoint = EndpointCounter;
|
|
|
|
if (EndpointLength < sizeof(Number) / sizeof(*Number))
|
|
return(RPC_P_ENDPOINT_TOO_SMALL);
|
|
|
|
// To generate a new endpoint, we call the SetupWithEndpoint function
|
|
// repeatedly until successful or we have tried all 255 values.
|
|
|
|
do
|
|
{
|
|
EndpointCounter++;
|
|
|
|
status = CreateEndpoint(pAdd, EndpointCounter,
|
|
lNetworkAddress, NumNetworkAddress, NetworkAddressLength,
|
|
SecurityDescriptor, PendingQueueSize, RpcProtocolSequence);
|
|
}
|
|
while (status == RPC_S_DUPLICATE_ENDPOINT
|
|
&& EndpointCounter != LastEndpoint);
|
|
|
|
// Return an error if we've tried all of the values
|
|
if (status == RPC_S_DUPLICATE_ENDPOINT)
|
|
return(RPC_S_OUT_OF_RESOURCES);
|
|
|
|
// BUGBUG - Should we decrement the counter if we got an error other
|
|
// than trying to add the name (e.g. RPC_P_NETWORK_ADDRESS_TOO_SMALL)?
|
|
|
|
// On success, convert the endpoint number to an RPC_CHAR string.
|
|
if (status == RPC_S_OK)
|
|
{
|
|
RpcItoa(EndpointCounter, Number, 10);
|
|
|
|
COPY_TO_NATIVE_STRING(Endpoint, Number, EndpointLength);
|
|
}
|
|
|
|
return(status);
|
|
}
|
|
|
|
|
|
RPC_TRANS_STATUS RPC_ENTRY
|
|
Close (
|
|
PCONNECTION pConn
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Close a client connection, by hanging up the NetBios session
|
|
with the client.
|
|
|
|
Arguments:
|
|
|
|
pConn - Client connection to close.
|
|
|
|
Returns:
|
|
|
|
RPC_S_OK
|
|
|
|
--*/
|
|
{
|
|
NCB theNCB;
|
|
|
|
// We use the connection's lsn field to determine if the connection
|
|
// has already been closed. This protects us against race conditions
|
|
// where the client is closing the connection at the same time.
|
|
CRITICAL_ENTER();
|
|
|
|
if (pConn->lsn)
|
|
{
|
|
memset(&theNCB, 0, sizeof(NCB));
|
|
theNCB.ncb_lsn = pConn->lsn;
|
|
theNCB.ncb_lana_num = pConn->Adapter->lana_num;
|
|
|
|
execNCB(NCBHANGUP, &theNCB);
|
|
|
|
// Decrement the adapter's connection count.
|
|
pConn->Adapter->ConnectionCount--;
|
|
|
|
ASSERT(pConn->Adapter->ConnectionCount >= 0);
|
|
|
|
// Reset the connection's lsn field.
|
|
pConn->lsn = 0;
|
|
}
|
|
else
|
|
{
|
|
// The session is already closed, so fake a successful return
|
|
theNCB.ncb_retcode = 0;
|
|
}
|
|
|
|
CRITICAL_LEAVE();
|
|
|
|
if (theNCB.ncb_retcode == NRC_SCLOSED ||
|
|
theNCB.ncb_retcode == NRC_SNUMOUT)
|
|
return(RPC_S_OK);
|
|
|
|
return MapStatusCode(NetBiosErrors, theNCB.ncb_retcode,
|
|
RPC_P_SERVER_TRANSPORT_ERROR);
|
|
}
|
|
|
|
|
|
RPC_TRANS_STATUS RPC_ENTRY
|
|
Send (
|
|
PCONNECTION pConn,
|
|
void __RPC_FAR * Buffer,
|
|
unsigned int BufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Write a message to a client session.
|
|
|
|
Arguments:
|
|
|
|
pConn - Client connection to write the message on.
|
|
|
|
Buffer - address of buffer to write.
|
|
|
|
BufferLength - size of buffer to write.
|
|
|
|
Returns:
|
|
|
|
MapStatusCode()
|
|
|
|
--*/
|
|
{
|
|
NCB theNCB;
|
|
RPC_TRANS_STATUS RpcTransStatus;
|
|
|
|
ASSERT(BufferLength <= NETB_MAXIMUM_DATA);
|
|
|
|
// Now that we're performing the send, we can reset the sequence number
|
|
// on client receives.
|
|
pConn->ClientSeqNum = 0;
|
|
|
|
// Submit the NCB.
|
|
theNCB.ncb_lana_num = pConn->Adapter->lana_num;
|
|
theNCB.ncb_lsn = pConn->lsn;
|
|
theNCB.ncb_buffer = Buffer;
|
|
theNCB.ncb_length = (unsigned short) BufferLength;
|
|
|
|
execNCB(NCBSEND, &theNCB);
|
|
|
|
RpcTransStatus = MapStatusCode(NetBiosErrors, theNCB.ncb_retcode,
|
|
RPC_P_SEND_FAILED);
|
|
|
|
if ( RpcTransStatus == RPC_P_SEND_FAILED )
|
|
{
|
|
RpcTransStatus = Close(pConn);
|
|
ASSERT( RpcTransStatus == RPC_S_OK );
|
|
|
|
return(RPC_P_SEND_FAILED);
|
|
}
|
|
|
|
return(RpcTransStatus);
|
|
}
|
|
|
|
|
|
RPC_TRANS_STATUS RPC_ENTRY
|
|
ReceiveAny (
|
|
IN PTADDRESS pAdd,
|
|
OUT PCONNECTION *pConnCur,
|
|
IN OUT void __RPC_FAR * __RPC_FAR * Buffer,
|
|
IN OUT unsigned int __RPC_FAR * BufferLength,
|
|
IN long Timeout
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine manages connections on the specified address, performing
|
|
three main tasks:
|
|
|
|
1) Accepting new connections from clients.
|
|
2) Shutting down connections that the client has closed.
|
|
3) Returning data sent by clients over existing connections.
|
|
|
|
It returns to the caller when either 2 or 3 has occurred.
|
|
|
|
Arguments:
|
|
|
|
pAdd - The address to act on.
|
|
|
|
pConnCur - Pointer to the connection which is set to the
|
|
connection of the call.
|
|
|
|
Buffer - pointer to a buffer pointer to return the message in.
|
|
|
|
BufferLength - pointer to where the size of the buffer is returned.
|
|
|
|
Timeout - how long to wait for a message.
|
|
|
|
Returns:
|
|
|
|
RPC_S_OK, RPC_P_SERVER_TRANSPORT_ERROR, RPC_P_CONNECTION_CLOSED,
|
|
RPC_S_OUT_OF_MEMORY, RPC_P_TIMEOUT
|
|
|
|
pConnCur is set if there is new data (RPC_S_OK) or a client death
|
|
(RPC_P_CONNECTION_CLOSED).
|
|
|
|
--*/
|
|
|
|
{
|
|
RPC_TRANS_STATUS status = 0;
|
|
BOOL ready_to_return = FALSE;
|
|
DWORD wait_time = Timeout == -1 ? INFINITE : Timeout;
|
|
DWORD event_index;
|
|
PADAPTER Card;
|
|
PCONNECTION pConn;
|
|
PNCB theNCB;
|
|
unsigned int ReceiveDirectFlag;
|
|
|
|
do
|
|
{
|
|
// Wait for any of the events associated with async listen or
|
|
// receive-any NCBs to be signalled.
|
|
|
|
event_index = WaitForMultipleObjects(EVENT_COUNT(pAdd),
|
|
pAdd->Events,
|
|
FALSE,
|
|
wait_time);
|
|
ASSERT(event_index != 0xFFFFFFFF);
|
|
|
|
// Return immediately if we timed out or if we hit an error
|
|
if (event_index == WAIT_TIMEOUT)
|
|
return RPC_P_TIMEOUT;
|
|
|
|
if (event_index == 0xFFFFFFFF)
|
|
return RPC_P_SERVER_TRANSPORT_ERROR;
|
|
|
|
// Otherwise, verify that the index is valid.
|
|
event_index -= WAIT_OBJECT_0;
|
|
|
|
ASSERT(event_index >= 0 && event_index < EVENT_COUNT(pAdd));
|
|
|
|
if (event_index >= EVENT_COUNT(pAdd))
|
|
return RPC_P_SERVER_TRANSPORT_ERROR;
|
|
|
|
|
|
// The event index is valid, so we now process the NCB associated
|
|
// with the event. Events 0 to AdapterCount-1 are for the Listen
|
|
// NCBs on the respective adapters, events AdapterCount and up are
|
|
// for the Receive-Any NCBs that correspond with the pointers in
|
|
// the address's receive pointer array.
|
|
|
|
if (event_index < pAdd->AdapterCount)
|
|
{
|
|
// A Listen NCB completed.
|
|
|
|
|
|
Card = &pAdd->Adapters[event_index];
|
|
theNCB = &Card->ListenNCB;
|
|
|
|
if (theNCB->ncb_cmd_cplt == NRC_NAMERR) {
|
|
// BUGBUG: Ultimately, we will want to delete all RPC resources associated
|
|
// with this lana, and listen for new lanas to come online, but Chicago
|
|
// support for that isn't available yet.
|
|
ResetEvent(pAdd->Events[event_index]);
|
|
ready_to_return = FALSE;
|
|
continue;
|
|
}
|
|
|
|
ASSERT(theNCB->ncb_cmd_cplt != NRC_PENDING);
|
|
|
|
if (theNCB->ncb_retcode != NRC_GOODRET)
|
|
{
|
|
// BUGBUG - We should think about not resubmitting if
|
|
// this occurs.
|
|
|
|
#if 0
|
|
ASSERT(!"Bad ErrorCode on Listen?");
|
|
|
|
status = MapStatusCode(NetBiosErrors,
|
|
theNCB->ncb_retcode,
|
|
RPC_P_SERVER_TRANSPORT_ERROR);
|
|
#endif
|
|
|
|
goto ResubmitListenNCB;
|
|
}
|
|
|
|
// Create a new connection object for this session.
|
|
pConn = I_RpcTransServerNewConnection(
|
|
pAdd,
|
|
MAKE_CONNECTION_KEY(Card->lana_num,
|
|
theNCB->ncb_lsn),
|
|
&ReceiveDirectFlag);
|
|
ASSERT( ReceiveDirectFlag == 0 );
|
|
|
|
if (!pConn)
|
|
{
|
|
ASSERT(!"RT assigned no connections");
|
|
|
|
status = RPC_S_OUT_OF_MEMORY;
|
|
|
|
ready_to_return = TRUE;
|
|
|
|
goto ResubmitListenNCB;
|
|
}
|
|
|
|
pConn->Adapter = Card;
|
|
pConn->lsn = theNCB->ncb_lsn;
|
|
pConn->ClientSeqNum = 0;
|
|
|
|
// Increment the connection count for this adapter
|
|
CRITICAL_ENTER();
|
|
|
|
Card->ConnectionCount++;
|
|
|
|
// We may want to submit an additional Receive, depending
|
|
// upon the number of connections.
|
|
if (TOO_FEW_RCVS(Card->ConnectionCount, Card->ReceiveCount))
|
|
{
|
|
SubmitReceive(pAdd, event_index, 0);
|
|
}
|
|
|
|
CRITICAL_LEAVE();
|
|
|
|
// Post another Async Listen NCB for the next new client.
|
|
|
|
ResubmitListenNCB:
|
|
// Don't bother saving the error code if we already
|
|
// have one.
|
|
if (status)
|
|
{
|
|
SubmitListen(pAdd, event_index);
|
|
}
|
|
else
|
|
{
|
|
status = SubmitListen(pAdd, event_index);
|
|
|
|
if (status)
|
|
{
|
|
ready_to_return = TRUE;
|
|
}
|
|
}
|
|
} // End of processing completed Listen NCB
|
|
else
|
|
{
|
|
// A Receive-Any NCB completed.
|
|
|
|
PRECEIVE pReceive =
|
|
pAdd->ReceivePtrs[event_index - pAdd->AdapterCount];
|
|
|
|
Card = NULL;
|
|
theNCB = &pReceive->theNCB;
|
|
|
|
ASSERT(theNCB->ncb_cmd_cplt != NRC_PENDING);
|
|
|
|
// First, we try to find the matching connection
|
|
pConn = *pConnCur = (PCONNECTION)
|
|
I_RpcTransServerFindConnection(
|
|
pAdd,
|
|
MAKE_CONNECTION_KEY(theNCB->ncb_lana_num,
|
|
theNCB->ncb_lsn));
|
|
|
|
// If we don't find the connection, we assume that the
|
|
// RPC run-time has already closed it explicitly, and
|
|
// so ignore the contents of the NCB. If we do find it,
|
|
// then we process the NCB according to its return code.
|
|
if (! pConn)
|
|
{
|
|
UINT index;
|
|
|
|
|
|
/* ASSERT(theNCB->ncb_retcode == NRC_SCLOSED); */
|
|
#ifdef DEBUGRPC
|
|
PrintToDebugger("No conn. for this lsn -> %x \n" ,
|
|
theNCB->ncb_retcode);
|
|
PrintToDebugger("command of this NCB-> %x \n" ,
|
|
theNCB->ncb_command);
|
|
#endif
|
|
|
|
// In order to resubmit this NCB, we need to associate
|
|
// it with an adapter. Normally we do this by locating
|
|
// the connection (which contains the associated adapter),
|
|
// but if we get here we didn't find the connection.
|
|
// So walk the address's adapter list until we find one
|
|
// with a lana number that matches the one in the NCB.
|
|
|
|
for (index = 0, Card = &pAdd->Adapters[0];
|
|
index < pAdd->AdapterCount;
|
|
index++, Card++)
|
|
{
|
|
if (Card->lana_num == theNCB->ncb_lana_num)
|
|
break;
|
|
}
|
|
|
|
// This should never fail!
|
|
ASSERT(index < pAdd->AdapterCount);
|
|
|
|
ASSERT(Card->iName == theNCB->ncb_num);
|
|
|
|
if (theNCB->ncb_cmd_cplt == NRC_NAMERR ||
|
|
theNCB->ncb_cmd_cplt == NRC_BRIDGE) {
|
|
DeleteReceive(pAdd, Card - pAdd->Adapters, pReceive);
|
|
ready_to_return = FALSE;
|
|
continue;
|
|
}
|
|
|
|
goto ResubmitReceiveNCB;
|
|
}
|
|
|
|
// We've found the connection, so we have the adapter.
|
|
Card = pConn->Adapter;
|
|
|
|
ASSERT(Card->lana_num == theNCB->ncb_lana_num);
|
|
|
|
|
|
// Process the NCB, based on its return code.
|
|
|
|
if (theNCB->ncb_retcode == NRC_SCLOSED ||
|
|
theNCB->ncb_retcode == NRC_NAMERR ||
|
|
theNCB->ncb_retcode == NRC_BRIDGE)
|
|
{
|
|
|
|
// Process a session with a client closing.
|
|
|
|
// Decrement the connection count, if it hasn't been
|
|
// done already by Close(). We set the lsn field of
|
|
// the connection to 0 to indicate that the connection
|
|
// is gone (from the transport's perspective}.
|
|
CRITICAL_ENTER();
|
|
|
|
if (pConn->lsn)
|
|
{
|
|
Card->ConnectionCount--;
|
|
|
|
ASSERT(Card->ConnectionCount >= 0);
|
|
|
|
pConn->lsn = 0;
|
|
}
|
|
|
|
CRITICAL_LEAVE();
|
|
|
|
status = RPC_P_CONNECTION_CLOSED;
|
|
ready_to_return = TRUE;
|
|
}
|
|
else if (theNCB->ncb_retcode == NRC_GOODRET)
|
|
{
|
|
// Process the returned data
|
|
|
|
// Verify that the sequence numbers match.
|
|
//
|
|
// If they do, then we return the data to the caller
|
|
// and increment the sequence number. If they don't,
|
|
// then we need to locate the completed Receive with
|
|
// the matching sequence number.
|
|
|
|
if (pConn->ClientSeqNum != pReceive->buffer.seq_num)
|
|
{
|
|
PRECEIVE pOrigReceive = pReceive;
|
|
|
|
for (pReceive = Card->FirstReceive;
|
|
pReceive != NULL;
|
|
pReceive = pReceive->NextReceive)
|
|
{
|
|
// We need to find a Receive-Any NCB that has
|
|
// completed successfully, has a matching lsn and
|
|
// sequence number. (We also need a matching
|
|
// lana number, but we don't have to check that
|
|
// because we're only looking at Receive-Any NCBs
|
|
// that are submitted on this lana.) If we don't
|
|
// find one, it's a fatal error, because an NCB
|
|
// should not have completed for sequence number
|
|
// N+1 unless one also completed for sequence
|
|
// number N.
|
|
|
|
theNCB = &pReceive->theNCB;
|
|
|
|
if (theNCB->ncb_cmd_cplt != NRC_PENDING
|
|
&& theNCB->ncb_retcode == NRC_GOODRET
|
|
&& theNCB->ncb_lsn == pConn->lsn
|
|
&& pConn->ClientSeqNum
|
|
== pReceive->buffer.seq_num)
|
|
{
|
|
ASSERT(Card->lana_num == theNCB->ncb_lana_num);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
ASSERT(pReceive);
|
|
|
|
// If we can't find the matching packet, we just
|
|
// resubmit the original NCB.
|
|
if (pReceive == NULL)
|
|
{
|
|
pReceive = pOrigReceive;
|
|
|
|
status = RPC_P_SERVER_TRANSPORT_ERROR;
|
|
ready_to_return = TRUE;
|
|
|
|
goto ResubmitReceiveNCB;
|
|
}
|
|
}
|
|
|
|
// If we get here and pReceive is non-NULL, then we
|
|
// have the correct data.
|
|
if (pReceive)
|
|
{
|
|
// Allocate the buffer for the data
|
|
*BufferLength = theNCB->ncb_length - NETB_OVERHEAD;
|
|
|
|
status = I_RpcTransServerReallocBuffer(pConn,
|
|
Buffer, 0, *BufferLength);
|
|
|
|
if (! status)
|
|
{
|
|
// Copy the data into the buffer
|
|
memcpy(*Buffer,
|
|
pReceive->buffer.data,
|
|
*BufferLength);
|
|
}
|
|
else
|
|
{
|
|
status = RPC_S_OUT_OF_MEMORY;
|
|
}
|
|
|
|
ready_to_return = TRUE;
|
|
pConn->ClientSeqNum++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// The Receive completed with a failure (other than
|
|
// session closed).
|
|
|
|
// BUGBUG - We should think about not resubmitting if
|
|
// this occurs.
|
|
|
|
status = MapStatusCode(NetBiosErrors,
|
|
theNCB->ncb_retcode,
|
|
RPC_P_SERVER_TRANSPORT_ERROR);
|
|
|
|
ready_to_return = TRUE;
|
|
}
|
|
|
|
ResubmitReceiveNCB:
|
|
ASSERT(Card);
|
|
|
|
// Resubmit or delete the receive NCB we just handled,
|
|
// depending upon the connection count.
|
|
if (pReceive)
|
|
{
|
|
CRITICAL_ENTER();
|
|
|
|
if (TOO_MANY_RCVS(Card->ConnectionCount, Card->ReceiveCount))
|
|
{
|
|
DeleteReceive(pAdd, Card - pAdd->Adapters, pReceive);
|
|
}
|
|
else
|
|
{
|
|
SubmitReceive(pAdd, Card - pAdd->Adapters, pReceive);
|
|
}
|
|
|
|
CRITICAL_LEAVE();
|
|
}
|
|
|
|
} // End of processing completed Receive-Any NCB
|
|
|
|
// When we get here, we've finished doing processing based on the
|
|
// event that completed. If an event completed that causes us to
|
|
// return information to the caller, then we're done. Otherwise,
|
|
// We go back to the top of the main loop and wait for the next
|
|
// event to complete
|
|
|
|
} // end of do-while loop body
|
|
while (! ready_to_return);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
// This structure is returned to the RPC runtime when the DLL is loaded.
|
|
|
|
RPC_SERVER_TRANSPORT_INFO TransInfo = {
|
|
|
|
RPC_TRANSPORT_INTERFACE_VERSION, // version # of loadable trans interface
|
|
NETB_MAXIMUM_DATA, // maximum # bytes for send or receive
|
|
sizeof(TADDRESS), // # of bytes to allocate for address (server)
|
|
sizeof(CONNECTION), // # of bytes to allocate for connections
|
|
|
|
(TRANS_SERVER_SETUPWITHENDPOINT) SetupWithEndpoint,
|
|
(TRANS_SERVER_SETUPUNKNOWNENDPOINT) SetupUnknownEndpoint,
|
|
(TRANS_SERVER_ABORTSETUPADDRESS) AbortSetupAddress,
|
|
(TRANS_SERVER_CLOSE) Close,
|
|
(TRANS_SERVER_SEND) Send,
|
|
(TRANS_SERVER_RECEIVEANY) ReceiveAny,
|
|
0, 0, 0, 0, 0
|
|
};
|