mirror of https://github.com/lianthony/NT4.0
922 lines
24 KiB
922 lines
24 KiB
/*++
|
|
|
|
Copyright (c) 1994 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
adspclnt.c
|
|
|
|
Abstract:
|
|
|
|
Appletalk Data Stram Protocol (ADSP) connection-oriented full
|
|
duplex transport interface for RPC.
|
|
|
|
Author:
|
|
|
|
Mario Goertzel (mariogo) 23-Oct-1994
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "sysinc.h"
|
|
#include "rpc.h"
|
|
#include "rpcdcep.h"
|
|
#include "rpctran.h"
|
|
#include "rpcerrp.h"
|
|
|
|
#include <AppleTalk.h>
|
|
#include <Adsp.h>
|
|
#include <Devices.h>
|
|
|
|
typedef struct
|
|
{
|
|
unsigned long MyA5; // My application's A5
|
|
unsigned short ccbRefNum; // Reference number for the CCB
|
|
TPCCB pCcb; // Ptr to connections' connection control block
|
|
Ptr pBuffers; // Send, receive and attn buffers
|
|
} CONNECTION, *PCONNECTION;
|
|
|
|
#define MAXIMUM_FRAGMENT 4096
|
|
#define QUEUE_SIZE (MAXIMUM_FRAGMENT + 256)
|
|
#define NETADDR_LEN (MAX_COMPUTERNAME_LENGTH + 1)
|
|
#define HOSTNAME_LEN (MAX_COMPUTERNAME_LENGTH)
|
|
#define ADDRESS_FAMILY AF_APPLETALK
|
|
#define PROTOCOL ATPROTO_ADSP
|
|
#define SOCKET_TYPE SOCKET_STREAM
|
|
#define MAX_HOSTNAME_LEN 32
|
|
#define OBJECTTYPE_PREFIX "DceDspRpc "
|
|
#define OBJECT_PREFIX_LEN (sizeof(OBJECTTYPE_PREFIX) - 1)
|
|
#define DEFAULTZONE "*"
|
|
#define ENDPOINT_MAPPER_EP "Endpoint Mapper"
|
|
|
|
|
|
|
|
#define ByteSwapLong(Value) \
|
|
Value = ( (((Value) & 0xFF000000) >> 24) \
|
|
| (((Value) & 0x00FF0000) >> 8) \
|
|
| (((Value) & 0x0000FF00) << 8) \
|
|
| (((Value) & 0x000000FF) << 24))
|
|
|
|
#define ByteSwapShort(Value) \
|
|
Value = ( (((Value) & 0x00FF) << 8) \
|
|
| (((Value) & 0xFF00) >> 8))
|
|
|
|
extern MACYIELDCALLBACK g_pfnCallback ;
|
|
|
|
|
|
/*
|
|
Global variables.
|
|
|
|
These are really initialized in ClientOpen().
|
|
|
|
BUGBUG MAC DLL: Need to do something different is multiple
|
|
processes can call ClientOpen and open driver.
|
|
|
|
*/
|
|
|
|
int driverInitialized = 0; // 1 - dspDriverReference valid.
|
|
short dspDriverReference; // DSP driver handle (ref num)
|
|
|
|
/*
|
|
Following Macros and structs are needed for Tower Stuff
|
|
*/
|
|
|
|
#pragma pack(1)
|
|
|
|
#define TRANSPORTID 0x16
|
|
#define TRANSPORTHOSTID 0x18
|
|
#define TOWERFLOORS 5
|
|
#define PROTSEQ "ncacn_at_dsp"
|
|
|
|
|
|
typedef struct _FLOOR_234 {
|
|
unsigned short ProtocolIdByteCount;
|
|
unsigned char FloorId;
|
|
unsigned short AddressByteCount;
|
|
unsigned char Data[2];
|
|
} FLOOR_234, PAPI * PFLOOR_234;
|
|
|
|
|
|
#define NEXTFLOOR(t,x) (t)((unsigned char PAPI *)x +((t)x)->ProtocolIdByteCount\
|
|
+ ((t)x)->AddressByteCount\
|
|
+ sizeof(((t)x)->ProtocolIdByteCount)\
|
|
+ sizeof(((t)x)->AddressByteCount))
|
|
|
|
/*
|
|
End of Tower Stuff!
|
|
*/
|
|
|
|
#pragma pack()
|
|
|
|
/*
|
|
Helper functions
|
|
*/
|
|
|
|
|
|
void __inline
|
|
SetupRemoteEntity(
|
|
OUT char *remoteName,
|
|
IN RPC_CHAR *address,
|
|
IN RPC_CHAR *endpoint
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Produces an appletale 'entityName' based on the servers name,
|
|
endpoint and optional zone.
|
|
|
|
entityName is of the format:
|
|
|
|
1 byte obj len bytes 1 b type len 1 b zone len
|
|
[obj len][ object string w/o null ][type len][ type string][zone len][ zone string]
|
|
|
|
|
|
Arguments:
|
|
|
|
remoteName - Upon return this contains the packed array
|
|
of sized strings representing the servers name.
|
|
|
|
address - 'sz' string containing the name and (optionally)
|
|
the zone of the server.
|
|
|
|
endpoint - The endpoint that the server is listening to.
|
|
|
|
Return Value:
|
|
|
|
n/a
|
|
|
|
--*/
|
|
{
|
|
RPC_CHAR *zone;
|
|
RPC_CHAR *temp = NULL ;
|
|
|
|
// Find zone name, if any.
|
|
|
|
zone = strchr(address, '@');
|
|
|
|
if (zone)
|
|
{
|
|
// Server address is of form "MyServer@MyZone"
|
|
temp = zone ;
|
|
*zone = '\0'; // Truncate "MyServer@MyZone" to "MyServer"
|
|
zone++; // zone is now "MyZone"
|
|
}
|
|
|
|
if (zone == 0 ||
|
|
*zone == '\0')
|
|
{
|
|
// Either no zone ("MyServer") or empty zone ("MyServer@"),
|
|
// use "*" which means the local zone. Does NOT mean ALL zones!)
|
|
|
|
zone = "*";
|
|
}
|
|
|
|
// Servers name is the object
|
|
|
|
*remoteName = RpcpStringLength(address);
|
|
RpcpMemoryCopy(remoteName + 1, address, *remoteName);
|
|
remoteName += (1 + *remoteName);
|
|
|
|
if (temp)
|
|
{
|
|
*temp = '@' ;
|
|
}
|
|
|
|
// Type name is OBJECTTYPE_PREFIX<endpoint>
|
|
|
|
*remoteName = OBJECT_PREFIX_LEN + RpcpStringLength(endpoint);
|
|
RpcpMemoryCopy(remoteName + 1, OBJECTTYPE_PREFIX, OBJECT_PREFIX_LEN);
|
|
RpcpMemoryCopy(remoteName + 1 + OBJECT_PREFIX_LEN, endpoint, RpcpStringLength(endpoint));
|
|
remoteName += (1 + *remoteName);
|
|
|
|
// Zone name
|
|
|
|
*remoteName = RpcpStringLength(zone);
|
|
RpcpMemoryCopy(remoteName + 1, zone, *remoteName);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
Transport interfaces
|
|
*/
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
ClientOpen (
|
|
IN PCONNECTION pConn,
|
|
IN RPC_CHAR * NetworkAddress,
|
|
IN RPC_CHAR * Endpoint,
|
|
IN RPC_CHAR * NetworkOptions,
|
|
IN RPC_CHAR * TransportAddress,
|
|
IN RPC_CHAR * RpcProtocolSequence,
|
|
IN unsigned int Timeout
|
|
)
|
|
|
|
// Open a client connection
|
|
|
|
{
|
|
OSErr status;
|
|
DSPParamBlock pb; // Parameter block for DSP functions
|
|
volatile MPPParamBlock mppPb; // Parameter block for MPP functions (nbpPb)
|
|
volatile NBPparms *nbpPb; // Set to NBPparms field of MPPParamBlock
|
|
TPCCB pDspCcb; // Pointer to DSP connection control block
|
|
unsigned short ccbRef; // CCB reference number (handle)
|
|
char remoteName[99];// Appletalk name for server
|
|
AddrBlock remoteAddress;// Address of remote connection
|
|
char nbpBuf[104]; // Room for one name + address + pad
|
|
Ptr dspQ; // Data queue for the connection.
|
|
RPC_CHAR *zoneName; // Name of the zone to look in.
|
|
Str32 realEndpoint; // "DCE RPC ADSP-" + Endpoint
|
|
|
|
if (NetworkAddress == 0 || *NetworkAddress == '0')
|
|
{
|
|
// Local servers not supported on Mac
|
|
return(RPC_S_SERVER_UNAVAILABLE);
|
|
}
|
|
|
|
ASSERT(Endpoint && *Endpoint);
|
|
|
|
if (strlen(Endpoint) > 20)
|
|
{
|
|
return(RPC_S_INVALID_ENDPOINT_FORMAT);
|
|
}
|
|
|
|
if (driverInitialized <= 0)
|
|
{
|
|
// BUGBUG MAC DLL work: If multiple processes can call this at
|
|
// once we need a better solution for this.
|
|
|
|
if (!IsMPPOpen())
|
|
{
|
|
status = MPPOpen();
|
|
if (status != noErr)
|
|
{
|
|
#ifdef DEBUGRPC
|
|
PrintToDebugger("MPPOpen() failed: %d\n", status);
|
|
#endif
|
|
return(RPC_S_OUT_OF_RESOURCES);
|
|
}
|
|
}
|
|
|
|
status = opendriver(".DSP", &dspDriverReference);
|
|
|
|
if (status != noErr)
|
|
{
|
|
#ifdef DEBUGRPC
|
|
PrintToDebugger(".DSP Open failed: %d\n", status);
|
|
#endif
|
|
return(RPC_S_OUT_OF_RESOURCES);
|
|
}
|
|
|
|
driverInitialized = 1;
|
|
|
|
}
|
|
|
|
pb.ioCRefNum = dspDriverReference; // Drivers ref used to dispatch trap
|
|
pb.ioCompletion = 0; // ClientOpen completely sync.
|
|
|
|
|
|
nbpPb = &mppPb.NBP;
|
|
nbpPb->ioRefNum = mppRefNum;
|
|
nbpPb->ioCompletion = 0;
|
|
|
|
//
|
|
// Drivers initalized okay, now lookup the servers address with NBP.
|
|
//
|
|
|
|
// Could support x.z[y] style address, too.
|
|
// (w) net-^ ^ ^-socket (b)
|
|
// |-node (b)
|
|
|
|
SetupRemoteEntity(remoteName, NetworkAddress, Endpoint);
|
|
|
|
// Setup nbp parameter block to lookup the name.
|
|
|
|
nbpPb->csCode = lookupName;
|
|
nbpPb->interval = 0x4; // 4x8 ticks = ~500ms
|
|
ASSERT(Timeout <= 10);
|
|
nbpPb->count = 2 + Timeout; // Retry for 2 to 12 times based on Timeout
|
|
#if _MSC_VER >= 1000
|
|
nbpPb->nbpPtrs.entityPtr = (Ptr) &remoteName; // Name put together above
|
|
#else
|
|
nbpPb->NBPPtrs.entityPtr = (Ptr) &remoteName; // Name put together above
|
|
#endif
|
|
nbpPb->parm.verifyFlag = 0;
|
|
nbpPb->parm.Lookup.retBuffPtr = nbpBuf;
|
|
nbpPb->parm.Lookup.retBuffSize = 104;
|
|
nbpPb->parm.Lookup.maxToGet = 1;
|
|
nbpPb->parm.Lookup.numGotten = 0;
|
|
|
|
// Retry in the case of infinite timeout. Normal timeouts are
|
|
// controled but nbpPb->count value.
|
|
|
|
do {
|
|
status = PLookupName(&mppPb, FALSE);
|
|
}
|
|
while ( Timeout == RPC_C_BINDING_INFINITE_TIMEOUT
|
|
&& status != noErr
|
|
&& nbpPb->parm.Lookup.numGotten == 0 );
|
|
|
|
if ( status != noErr
|
|
|| nbpPb->parm.Lookup.numGotten == 0)
|
|
{
|
|
return(RPC_S_SERVER_UNAVAILABLE);
|
|
}
|
|
|
|
// Found atleast one name, we only try the first one.
|
|
|
|
status =
|
|
NBPExtract(nbpBuf,
|
|
nbpPb->parm.Lookup.numGotten,
|
|
1,
|
|
(EntityName *)&remoteName,
|
|
&remoteAddress);
|
|
|
|
ASSERT(status == noErr);
|
|
|
|
#ifdef DEBUGRPC
|
|
PrintToDebugger("Open found :%s[%s] with address %4x.%02x.%02x\n",
|
|
NetworkAddress, Endpoint,
|
|
remoteAddress.aNet, remoteAddress.aNode, remoteAddress.aSocket);
|
|
#endif
|
|
|
|
// Allocate memory and initialize the local end of the connection.
|
|
|
|
pDspCcb = (TPCCB)NewPtr(sizeof(TRCCB));
|
|
if (pDspCcb == 0)
|
|
{
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
dspQ = NewPtr( 2*QUEUE_SIZE + attnBufSize);
|
|
if (dspQ == 0)
|
|
{
|
|
DisposePtr((Ptr)pDspCcb);
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
// Initialize DSP driver
|
|
|
|
pb.csCode = dspInit;
|
|
pb.u.initParams.ccbPtr = pDspCcb;
|
|
pb.u.initParams.sendQSize = QUEUE_SIZE;
|
|
pb.u.initParams.recvQSize = QUEUE_SIZE;
|
|
pb.u.initParams.sendQueue = dspQ;
|
|
pb.u.initParams.recvQueue = dspQ + QUEUE_SIZE;
|
|
pb.u.initParams.attnPtr = dspQ + 2*QUEUE_SIZE;
|
|
pb.u.initParams.localSocket = 0; // Make appletalk choose local socket.
|
|
pb.u.initParams.userRoutine = 0; // Client shouldn't get connection events.
|
|
|
|
status = PBControl((ParmBlkPtr)&pb, FALSE);
|
|
|
|
if (status != noErr)
|
|
{
|
|
#ifdef DEBUGRPC
|
|
PrintToDebugger("dspInit failed %d\n", status);
|
|
#endif
|
|
DisposePtr((Ptr)pDspCcb);
|
|
DisposePtr(dspQ);
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
// Note: We may want to call the dspOptions trap here to set checksum,
|
|
// blocking factor, or such.
|
|
|
|
|
|
//
|
|
// Connect to remote address
|
|
//
|
|
|
|
pb.csCode = dspOpen;
|
|
// ccbRefNum set from before.
|
|
pb.u.openParams.remoteCID = 0; // Please choose this for me.
|
|
pb.u.openParams.remoteAddress = remoteAddress; // 4 byte copy.
|
|
pb.u.openParams.filterAddress = remoteAddress; // 4 byte copy.
|
|
pb.u.openParams.ocMode = ocRequest; // Open a connection to remoteAddr
|
|
pb.u.openParams.ocInterval = 0x3; // 3*(1/6s) = 1/2s
|
|
pb.u.openParams.ocMaximum = 1 + Timeout; // 1 to 11 retries.
|
|
|
|
if (Timeout == RPC_C_BINDING_INFINITE_TIMEOUT)
|
|
pb.u.openParams.ocMaximum = 0xff; // means retry forever.
|
|
|
|
status = PBControl((ParmBlkPtr)&pb, FALSE);
|
|
|
|
if (status != noErr)
|
|
{
|
|
#ifdef DEBUGRPC
|
|
PrintToDebugger("Open failed %d\n", status);
|
|
#endif
|
|
pb.csCode = dspRemove;
|
|
// ccRefNum already set
|
|
pb.u.closeParams.abort = 1; // throw away any data
|
|
|
|
status =
|
|
PBControl((ParmBlkPtr)&pb, FALSE);
|
|
|
|
ASSERT(status == noErr);
|
|
|
|
DisposePtr((Ptr)pDspCcb);
|
|
DisposePtr(dspQ);
|
|
return(RPC_S_SERVER_UNAVAILABLE);
|
|
}
|
|
|
|
// Save new connection the runtime's Connection object.
|
|
|
|
pConn->pCcb = pDspCcb;
|
|
pConn->ccbRefNum = pb.ccbRefNum;
|
|
pConn->MyA5 = SetCurrentA5();
|
|
pConn->pBuffers = dspQ;
|
|
|
|
return (RPC_S_OK);
|
|
}
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
ClientClose (
|
|
IN PCONNECTION pConn
|
|
)
|
|
|
|
// Close a client connection
|
|
|
|
{
|
|
OSErr status;
|
|
DSPParamBlock pb; // Parameter block for DSP functions
|
|
|
|
ASSERT(driverInitialized == 1);
|
|
|
|
pb.ioCRefNum = dspDriverReference;
|
|
pb.csCode = dspRemove;
|
|
pb.ioCompletion = 0;
|
|
pb.ccbRefNum = pConn->ccbRefNum;
|
|
pb.u.closeParams.abort = 1; // throw away any remaining data without sending
|
|
|
|
status = PBControl((ParmBlkPtr)&pb, FALSE);
|
|
|
|
if (status != noErr)
|
|
{
|
|
ASSERT(status == errRefNum)
|
|
#ifdef DEBUGRPC
|
|
PrintToDebugger("Closed bad connection\n");
|
|
ASSERT(0);
|
|
#endif
|
|
// Nobody really cares if they close a bad connection except
|
|
// when debugging a problem, right?
|
|
}
|
|
|
|
DisposePtr(pConn->pBuffers);
|
|
DisposePtr((Ptr)pConn->pCcb);
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
ClientSend (
|
|
IN PCONNECTION pConn,
|
|
IN void PAPI * Buffer,
|
|
IN unsigned int BufferLength
|
|
)
|
|
|
|
// Send a message to a connection.
|
|
|
|
{
|
|
OSErr status;
|
|
DSPParamBlock pb; // Parameter block for DSP functions
|
|
|
|
ASSERT(driverInitialized == 1);
|
|
|
|
pb.ioCRefNum = dspDriverReference;
|
|
pb.ioCompletion = 0; // sync sends because runtime may change
|
|
// contents of Buffer after we return.
|
|
pb.csCode = dspWrite;
|
|
pb.ccbRefNum = pConn->ccbRefNum;
|
|
pb.u.ioParams.reqCount = BufferLength;
|
|
pb.u.ioParams.dataPtr = Buffer;
|
|
pb.u.ioParams.eom = 1; // Each fragment is a message.
|
|
pb.u.ioParams.flush = 1; // Send it now, silly!
|
|
|
|
//
|
|
// Note: If we add shutdowns to the NT server we'll need to
|
|
// check for incoming data here if it has been sufficiently
|
|
// long since the last send. See the NT TCP/IP ClientSend() fn.
|
|
//
|
|
|
|
status =
|
|
PBControl((ParmBlkPtr)&pb, FALSE);
|
|
|
|
if (status != noErr)
|
|
{
|
|
|
|
// Errors as listed in Inside Mac: Networking
|
|
// errState -1278 Connection not open.
|
|
// errAborted -1279 Request aborted by dspRemove or dspClose
|
|
// errRefNum -1280 Bad ccbRefNum
|
|
//
|
|
// Only errState is expected.
|
|
|
|
ASSERT(status == errState);
|
|
|
|
ClientClose(pConn) ;
|
|
return(RPC_P_SEND_FAILED);
|
|
}
|
|
|
|
|
|
// I don't know how or why this wouldn't be true. If it isn't
|
|
// we'll probably need to loop around the send until the whole
|
|
// thing is sent.
|
|
ASSERT(pb.u.ioParams.actCount == BufferLength);
|
|
|
|
return(RPC_S_OK);
|
|
|
|
}
|
|
|
|
RPC_TRANS_STATUS RPC_ENTRY
|
|
ClientRecv (
|
|
IN PCONNECTION pConn,
|
|
IN OUT void PAPI * PAPI * Buffer,
|
|
IN OUT unsigned int PAPI * BufferLength
|
|
)
|
|
|
|
// Read a message from a connection.
|
|
|
|
{
|
|
RPC_STATUS RpcStatus;
|
|
OSErr status;
|
|
volatile DSPParamBlock pb; // Parameter block for DSP functions
|
|
int totalBytes = 0;
|
|
|
|
ASSERT(driverInitialized == 1);
|
|
|
|
if (*Buffer == 0)
|
|
{
|
|
*BufferLength = 512; // Min cached buffer size
|
|
RpcStatus = I_RpcTransClientReallocBuffer(pConn,
|
|
Buffer,
|
|
0,
|
|
*BufferLength);
|
|
if (RpcStatus != RPC_S_OK)
|
|
{
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
}
|
|
|
|
|
|
pb.ioCRefNum = dspDriverReference;
|
|
pb.ioCompletion = 0; // sync reads here
|
|
pb.csCode = dspRead;
|
|
pb.ccbRefNum = pConn->ccbRefNum;
|
|
|
|
do
|
|
{
|
|
|
|
pb.u.ioParams.dataPtr = (char *)*Buffer + totalBytes;
|
|
pb.u.ioParams.reqCount = *BufferLength - totalBytes;
|
|
|
|
ASSERT(pb.u.ioParams.reqCount);
|
|
|
|
status =
|
|
PBControl((ParmBlkPtr)&pb, FALSE);
|
|
|
|
if ( status != noErr
|
|
|| ( (pb.u.ioParams.eom == 0)
|
|
&& (pb.u.ioParams.actCount == 0) ) )
|
|
{
|
|
|
|
// If both eom and actCount are 0 then the connection is closed.
|
|
|
|
// Errors as listed in Inside Mac: Networking
|
|
// errFwdReset -1275 Read terminated by forward reset
|
|
// errState -1278 State isn't open, closing or closed
|
|
// errAborted -1279 Request aborted by dspRemove or dspClose
|
|
// errRefNum -1280 Bad ccbRefNum
|
|
//
|
|
// Only noErr and errState are expected. (maybe errFwdReset too?)
|
|
|
|
ASSERT( status == noErr
|
|
|| status == errState);
|
|
|
|
ClientClose(pConn) ;
|
|
return(RPC_P_RECEIVE_FAILED);
|
|
}
|
|
|
|
ASSERT(pb.u.ioParams.actCount || pb.u.ioParams.eom);
|
|
|
|
totalBytes += pb.u.ioParams.actCount;
|
|
|
|
if ( !pb.u.ioParams.eom
|
|
&& totalBytes == *BufferLength)
|
|
{
|
|
ASSERT(*BufferLength < I_RpcTransClientMaxFrag(pConn));
|
|
|
|
// Need a larger fragment
|
|
|
|
*BufferLength = I_RpcTransClientMaxFrag(pConn);
|
|
RpcStatus = I_RpcTransClientReallocBuffer(pConn,
|
|
Buffer,
|
|
totalBytes,
|
|
*BufferLength);
|
|
if (RpcStatus != RPC_S_OK)
|
|
{
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
}
|
|
}
|
|
while ( !pb.u.ioParams.eom );
|
|
|
|
*BufferLength = totalBytes;
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
|
|
#pragma pack(1)
|
|
RPC_STATUS RPC_ENTRY
|
|
ClientTowerConstruct(
|
|
IN char PAPI * Endpoint,
|
|
IN char PAPI * NetworkAddress,
|
|
OUT UNALIGNED short PAPI * Floors,
|
|
OUT UNALIGNED unsigned long PAPI * ByteCount,
|
|
OUT unsigned char PAPI * UNALIGNED PAPI * Tower,
|
|
IN char PAPI * Protseq
|
|
)
|
|
{
|
|
unsigned long TowerSize;
|
|
UNALIGNED PFLOOR_234 Floor, Floor1;
|
|
|
|
|
|
*Floors = TOWERFLOORS;
|
|
TowerSize = ((Endpoint == NULL) || (*Endpoint == '\0')) ?
|
|
2 : strlen(Endpoint) + 1;
|
|
TowerSize += ((NetworkAddress== NULL) || (*NetworkAddress== '\0')) ?
|
|
2 : strlen(NetworkAddress) + 1;
|
|
TowerSize += 2*sizeof(FLOOR_234) - 4;
|
|
|
|
if ((*Tower = (unsigned char PAPI*)I_RpcAllocate(*ByteCount = TowerSize))
|
|
== NULL)
|
|
{
|
|
return (RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
Floor = (PFLOOR_234) *Tower;
|
|
|
|
Floor->ProtocolIdByteCount = 1;
|
|
Floor->FloorId = (unsigned char)(TRANSPORTID & 0xFF);
|
|
if ((Endpoint) && (*Endpoint))
|
|
{
|
|
memcpy((char PAPI *)&Floor->Data[0], Endpoint,
|
|
(Floor->AddressByteCount = strlen(Endpoint)+1));
|
|
}
|
|
else
|
|
{
|
|
Floor->AddressByteCount = 2;
|
|
Floor->Data[0] = 0;
|
|
}
|
|
//Onto the next floor
|
|
Floor1 = NEXTFLOOR(PFLOOR_234, Floor);
|
|
ByteSwapShort(Floor->AddressByteCount) ;
|
|
ByteSwapShort(Floor->ProtocolIdByteCount) ;
|
|
|
|
Floor1->ProtocolIdByteCount = 1;
|
|
Floor1->FloorId = (unsigned char)(TRANSPORTHOSTID & 0x0F);
|
|
if ((NetworkAddress) && (*NetworkAddress))
|
|
{
|
|
memcpy((char PAPI *)&Floor1->Data[0], NetworkAddress,
|
|
(Floor1->AddressByteCount = strlen(NetworkAddress) + 1));
|
|
}
|
|
else
|
|
{
|
|
Floor1->AddressByteCount = 2;
|
|
Floor1->Data[0] = 0;
|
|
}
|
|
|
|
ByteSwapShort(Floor1->AddressByteCount) ;
|
|
ByteSwapShort(Floor1->ProtocolIdByteCount) ;
|
|
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
ClientTowerExplode(
|
|
IN unsigned char PAPI * Tower,
|
|
OUT char PAPI * UNALIGNED PAPI * Protseq,
|
|
OUT char PAPI * UNALIGNED PAPI * Endpoint,
|
|
OUT char PAPI * UNALIGNED PAPI * NetworkAddress
|
|
)
|
|
{
|
|
UNALIGNED PFLOOR_234 Floor = (PFLOOR_234) Tower;
|
|
RPC_STATUS Status = RPC_S_OK;
|
|
|
|
if (Protseq != NULL)
|
|
{
|
|
*Protseq = I_RpcAllocate(strlen(PROTSEQ) + 1);
|
|
if (*Protseq == NULL)
|
|
{
|
|
Status = RPC_S_OUT_OF_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
memcpy(*Protseq, PROTSEQ, strlen(PROTSEQ) + 1);
|
|
}
|
|
}
|
|
|
|
if ((Endpoint == NULL) || (Status != RPC_S_OK))
|
|
{
|
|
return (Status);
|
|
}
|
|
|
|
*Endpoint = I_RpcAllocate(Floor->AddressByteCount);
|
|
if (*Endpoint == NULL)
|
|
{
|
|
Status = RPC_S_OUT_OF_MEMORY;
|
|
if (Protseq != NULL)
|
|
I_RpcFree(*Protseq);
|
|
}
|
|
else
|
|
{
|
|
memcpy(*Endpoint, (char PAPI *)&Floor->Data[0], Floor->AddressByteCount);
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
#pragma pack()
|
|
|
|
// BUGBUG: Mac DLL: must have per process
|
|
|
|
Boolean RecvPending = 0;
|
|
|
|
RPC_TRANS_STATUS RPC_ENTRY
|
|
ClientAsyncRecv (
|
|
IN PCONNECTION pConn,
|
|
IN OUT void PAPI * PAPI * Buffer,
|
|
IN OUT unsigned int PAPI * BufferLength
|
|
)
|
|
|
|
// Read a message from a connection.
|
|
|
|
{
|
|
RPC_STATUS RpcStatus;
|
|
OSErr status;
|
|
volatile DSPParamBlock pb; // Parameter block for DSP functions
|
|
|
|
int totalBytes = 0;
|
|
|
|
if(RecvPending)
|
|
return(RPC_P_RECEIVE_FAILED);
|
|
|
|
ASSERT(driverInitialized == 1);
|
|
|
|
if (*Buffer == 0)
|
|
{
|
|
*BufferLength = 512; // Min cached buffer size
|
|
RpcStatus = I_RpcTransClientReallocBuffer(pConn,
|
|
Buffer,
|
|
0,
|
|
*BufferLength);
|
|
if (RpcStatus != RPC_S_OK)
|
|
{
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
}
|
|
|
|
|
|
pb.ioCRefNum = dspDriverReference;
|
|
pb.ioCompletion = 0;
|
|
pb.csCode = dspRead;
|
|
pb.ccbRefNum = pConn->ccbRefNum;
|
|
|
|
do
|
|
{
|
|
|
|
pb.u.ioParams.dataPtr = (char *)*Buffer + totalBytes;
|
|
pb.u.ioParams.reqCount = *BufferLength - totalBytes;
|
|
|
|
ASSERT(pb.u.ioParams.reqCount);
|
|
|
|
RecvPending = 1 ;
|
|
pb.ioResult = 1 ;
|
|
status =
|
|
PBControl((ParmBlkPtr)&pb, TRUE);
|
|
|
|
if ( status != noErr )
|
|
{
|
|
|
|
// If both eom and actCount are 0 then the connection is closed.
|
|
|
|
// Errors as listed in Inside Mac: Networking
|
|
// errFwdReset -1275 Read terminated by forward reset
|
|
// errState -1278 State isn't open, closing or closed
|
|
// errAborted -1279 Request aborted by dspRemove or dspClose
|
|
// errRefNum -1280 Bad ccbRefNum
|
|
//
|
|
// Only noErr and errState are expected. (maybe errFwdReset too?)
|
|
|
|
ASSERT( status == noErr
|
|
|| status == errState);
|
|
|
|
RecvPending = 0 ;
|
|
|
|
ClientClose(pConn) ;
|
|
return(RPC_P_RECEIVE_FAILED);
|
|
}
|
|
|
|
// the yeild function must return only when pb.ioResult != 1
|
|
while(pb.ioResult == 1)
|
|
{
|
|
if(g_pfnCallback)
|
|
(*g_pfnCallback)(&(pb.ioResult)) ;
|
|
}
|
|
|
|
if(pb.ioResult != noErr || ((pb.u.ioParams.eom == 0)
|
|
&& (pb.u.ioParams.actCount == 0)))
|
|
{
|
|
RecvPending = 0 ;
|
|
|
|
ClientClose(pConn) ;
|
|
return(RPC_P_RECEIVE_FAILED);
|
|
}
|
|
|
|
totalBytes += pb.u.ioParams.actCount;
|
|
|
|
if ( !pb.u.ioParams.eom
|
|
&& totalBytes == *BufferLength)
|
|
{
|
|
ASSERT(*BufferLength < I_RpcTransClientMaxFrag(pConn));
|
|
|
|
// Need a larger fragment
|
|
|
|
*BufferLength = I_RpcTransClientMaxFrag(pConn);
|
|
RpcStatus = I_RpcTransClientReallocBuffer(pConn,
|
|
Buffer,
|
|
totalBytes,
|
|
*BufferLength);
|
|
if (RpcStatus != RPC_S_OK)
|
|
{
|
|
RecvPending = 0 ;
|
|
return(RPC_S_OUT_OF_MEMORY);
|
|
}
|
|
}
|
|
}
|
|
while ( !pb.u.ioParams.eom );
|
|
|
|
*BufferLength = totalBytes;
|
|
|
|
RecvPending = 0 ;
|
|
return(RPC_S_OK);
|
|
}
|
|
|
|
|
|
RPC_STATUS RPC_ENTRY
|
|
ClientSendReceive (
|
|
IN PCONNECTION CConnection,
|
|
IN void PAPI * SendBuffer,
|
|
IN unsigned int SendBufferLength,
|
|
IN OUT void PAPI * PAPI * ReceiveBuffer,
|
|
IN OUT unsigned int PAPI * ReceiveBufferLength
|
|
)
|
|
{
|
|
RPC_STATUS status ;
|
|
|
|
if((status = ClientSend(CConnection, SendBuffer, SendBufferLength)) != RPC_S_OK)
|
|
return status ;
|
|
|
|
return ClientAsyncRecv(CConnection, ReceiveBuffer, ReceiveBufferLength) ;
|
|
}
|
|
|
|
|
|
|
|
RPC_CLIENT_TRANSPORT_INFO ClientAdspTransInfo =
|
|
{
|
|
RPC_TRANSPORT_INTERFACE_VERSION,
|
|
TRANSPORTID,
|
|
|
|
ClientTowerConstruct,
|
|
ClientTowerExplode,
|
|
|
|
4096,
|
|
sizeof (CONNECTION),
|
|
|
|
ClientOpen,
|
|
ClientClose,
|
|
ClientSend,
|
|
ClientRecv,
|
|
ClientSendReceive,
|
|
0,
|
|
|
|
0,
|
|
0
|
|
};
|
|
|
|
RPC_CLIENT_TRANSPORT_INFO PAPI * RPC_ENTRY ClientAdspTransportLoad (
|
|
IN RPC_CHAR PAPI * RpcProtocolSequence
|
|
)
|
|
|
|
// Loadable transport initialization function
|
|
|
|
{
|
|
return(&ClientAdspTransInfo);
|
|
}
|