/* RPCBinding.c
RPCBinding primitives
Last modified by D. Swinehart, November 11, 1982 10:19 am
L. Stewart December 27, 1982 3:01 PM, flush nested declarations
L. Stewart January 1, 1983 4:15 PM, flush AllocZero
L. Stewart January 1, 1983 4:15 PM, flush CStringToString
L. Stewart January 18, 1983 1:46 PM, formatting
L. Stewart March 6, 1983, GetFixed
L. Stewart March 9, 1983 7:52 PM, flush wf
L. Stewart April 18, 1983 11:34 AM, new ImportInterface
L. Stewart May 4, 1983 12:08 PM, flush GetFixed
*/
#include <Env.h>
#include <queue.h>
#include <rpc.h>
#include <rpcinternal.h>
#include <rpclupine.h>
#include <rpcpkt.h>
#include <rpcbind.h>
#include <signal.h>
/* From RPCSignals */
extern int CallFailed;
extern int ExportFailed;
extern int ImportFailed;
/* From Utils */
extern struct ShortSTRING *CStringToString();
extern int DoubleInc();
extern int EquivalentStrings();
extern Move2();
extern int StringSize();
extern struct ShortSTRING *ShallString();
extern int InstanceToMachine();
/* From Pup package */
extern struct PBI *GetPBI();
extern int Max();
extern int DoubleEq();
extern ReleasePBI();
extern GenerateNets(); /* initializes enumeration handle */
extern int NextNet(); /* next network in enumeration, 0 when done */
/* From Time */
extern ReadCalendar();
/* From OS */
extern MoveBlock();
extern Zero();
extern int *mySoc; /* Going away */
int diagnoseBinding;
static struct ShortSTRING *binderRope;
/* InstanceInfo: TYPE = { ok, badName, allDown, noAddress }; */
#define okI 0
#define badNameI 1
#define allDownI 2
#define noAddressI 3
/* Version checking */
#define okV 0
#define badV 1
#define wrongV 2
#define myMDS 0
struct ExportInstance exportTable[5];
/* Supports SMALL numbers of exported interfaces */
int used; /* How much of exportTable is full? */
static struct DispatcherID lastExportID[1]; /* ← System.GetGreenwichMeanTime(); */
/* UID on this machine */
static struct DispatcherID binderID[1]; /* = SUCC(RPCPkt.noDispatcher); */
static int binderHint; /* ExportHandle */
static int binderProc;
struct VersionRange *matchAllVersions;
static struct VersionRange mAVSpace;
static struct DispatcherID noDispatcher[1]; /* = [0, 0] */
struct BinderResult {
struct VersionRange stubProt;
struct VersionRange version;
struct DispatcherDetails dispatcherDet;
};
#define lenBinderResult (sizeof (struct BinderResult)/2)
struct BinderArgs { /* packet substructure */
num request;
num type; /* offset in pkt, 0 -> NIL */
num instance;
word data[1];
/* offset in pkt, 0 -> NIL; followed by StringBody values for type, instance */
};
#define lenBinderArgs ((sizeof (struct BinderArgs)/2)-1)
/* ************* Export Interface ************* */
/* Representation of exports in the GV database: Each interface
type is a group, such as "Alpine.pa". Members of the group
are the interface instances. Each interface instance is an
individual, such as "MontBlanc.pa". Connect-site for the
individual contains the exporting host. The syntax of
instances' connect-sites is (all octal): net#host#mds.
We accept only the string form of the connect site,
in this implementation.
*/
int ExportInterface(interface, dispatcher, dArgs)
struct InterfaceName *interface;
Dispatcher *dispatcher;
struct DArgs *dArgs; /* UNSPECIFIED */
{
int instance;
struct ExportInstance *expInst;
instance = used++;
expInst = &exportTable[instance];
DoubleInc(lastExportID, 1);
Move2(&expInst->id, lastExportID);
expInst->dispatcher = dispatcher;
expInst->dispatcherArgs = dArgs;
/* expInst->mds = myMDS */
MoveBlock(&expInst->name, interface, lenInterfaceName);
Block();
return instance;
};
/***** Service Request to Bind to Exported Interface *****/
/* Details of the exported dispatcher are kept only in the
exporting machine. The importer obtains the details
via RPC call to dispatcher 1 on that machine. "Bind"
fields the call; "Binder" is dispatcher 1 on every machine.
Returns noDispatcher for unbound instances.
*/
int /* returnLength */
Binder(pkt, callLength, localConversation, unusedArgs)
struct PBI *pkt;
int callLength;
struct Conversation *localConversation;
int unusedArgs;
{
struct BinderArgs *args;
struct BinderResult *binderResult;
struct Header *hdr;
struct ShortSTRING *type, *instance;
int i, anyBind;
struct ExportInstance *inst;
hdr = pkt->pup;
binderResult = (struct BinderResult *) &hdr->callData;
args = (struct BinderArgs *) binderResult;
if (args->request != binderProc) return (lenBinderResult); /* ??? */
type = PktString(args, args->type, callLength);
instance = PktString(args, args->instance, callLength);
anyBind = (instance == 0 || instance->length == 0 || instance->text[0] == '*');
for (i = 1; i<used; ++i) {
inst = &exportTable[i];
if ((DoubleEq(&inst->id, noDispatcher) == 0) &&
(type == 0 || EquivalentStrings(type, inst->name.type)) &&
(anyBind != 0 || EquivalentStrings(instance, inst->name.instance))) {
Move2(&binderResult->version, &inst->name.version);
binderResult->dispatcherDet.mds = myMDS;
Move2(&binderResult->dispatcherDet.dispatcherID, &inst->id);
binderResult->dispatcherDet.dispatcherHint = swab(i);
break;
};
};
if (i==used) Zero(binderResult, lenBinderResult); /* not found */
/*
Free(myZone, type);
Free(myZone, instance);
*/
Block();
return (lenBinderResult);
};
static struct ShortSTRING
*PktString(args, n, callLength)
int args[], n, callLength;
{
/* in packets, string lengths are nums;
return true ShortSTRING
*/
struct ShortSTRING *ss, *res;
if (((n=swab(n)) < lenBinderArgs) || ((n+lenShortSTRING) > callLength)) return (0);
return (ShallString(0, &args[n], 2));
};
/* ********** Import (bind to) Remote Interface *********** */
static union Machine candidateMachine;
static int IfBusy(s, code, seal)
int s,code, seal;
{
return ((code == busy )? RETRY: CONTINUE);
};
static int IfFailed(s, code, seal)
int s,code, seal;
{
return ((candidateMachine.w == 0 && code != badCommunications) ? RETRY: REJECT);
};
ImportInterface(serverMachine, interface, res)
int serverMachine;
struct InterfaceName *interface;
struct ImportInstance *res;
{
struct Seal sl;
struct Seal slf;
union Machine host;
struct BinderResult expDetails;
int handle[2];
if ((!serverMachine && (interface->instance != 0)) || (serverMachine && (interface->instance == 0))) SIGNAL(ImportFailed, badInstance);
if (interface->type == 0) SIGNAL(ImportFailed, badType);
candidateMachine.w = serverMachine;
if (candidateMachine.w == 0) GenerateNets(handle);
/* implied loop until ENABLE succeeds */
ENABLE(ImportFailed, &IfFailed, &slf);
if (ENABLE(CallFailed, &IfBusy, &sl))
SIGNAL(ImportFailed, interfaceUnbound);
else {
switch (LocateInstance(serverMachine, &host, handle)) {
case badNameI: {
SIGNAL(ImportFailed, badInstance);
break;
};
case allDownI: {
SIGNAL(ImportFailed, badCommunications);
break;
};
default: SIGNAL(ERROR, 0);
case okI: break;
};
host.w = RemoteBind(host.w, interface->type, interface->instance, &expDetails);
};
DISABLE(&sl);
Block();
if (DoubleEq(&expDetails.dispatcherDet.dispatcherID, noDispatcher))
SIGNAL(ImportFailed, interfaceUnbound);
switch (CheckVersions(&interface->version, &expDetails.version)) {
case badV: SIGNAL(ImportFailed, badVersion); break;
case wrongV: SIGNAL (ImportFailed, wrongVersion);
default: break;
};
/* Don't allocate until danger of signalling has disappeared */
Zero(res, lenImportInstance);
MoveBlock(&res->dispatcherDet, &expDetails.dispatcherDet, lenDispatcherDetails);
res->host.w = host.w;
res->currentConversation = unencrypted;
Block();
};
static int /* InstanceInfo */
*LocateInstance(serverMachine, lvHost, handle)
int serverMachine;
union Machine *lvHost;
int handle[/*2*/];
{
int net;
if (serverMachine) {
*lvHost = serverMachine;
return okI;
};
if ((net = NextNet(handle))==0) return (allDownI);
lvHost->b.net = net;
lvHost->b.host = 0;
Block();
return (okI);
};
static RBU(s,c,sl)
int s,c;
struct Seal1 *sl;
{
struct PBI *pbi;
if (pbi = (struct PBI *) sl->data[0]) ReleasePBI(pbi);
};
static int /* union Machine */
RemoteBind(host, type, instance, binderResult)
/* (returns host with target machine number in it,
if broadcast binding)
*/
int /* union Machine */ host;
struct ShortSTRING *type, *instance;
struct BinderResult *binderResult;
{
struct ImportInstance binderInterface;
int pktSize, argsUsed, *ptr;
struct BinderArgs *args;
struct PBI *pkt;
struct Header *hdr;
struct Seal1 sl;
sl.data[0] = 0;
binderInterface.host.w = host;
binderInterface.dispatcherDet.mds = 0
Move2(&binderInterface.dispatcherDet.dispatcherID, binderID);
binderInterface.dispatcherDet.dispatcherHint = binderHint;
pktSize = Max(lenBinderArgs+2*34 /*max arg string*/, lenBinderResult);
sl.data[0] = (int) (pkt = GetPBI(mySoc));
ENABLE(UNWIND, &RBU/*just below*/, &sl);
hdr = pkt->pup;
args = (struct BinderArgs *) &hdr->callData;
StartCall(pkt, &binderInterface, unencrypted);
argsUsed=0;
Zero(args, lenBinderArgs);
args->request = binderProc;
if (type) {
args->type = swab(argsUsed+lenBinderArgs);
ShallString(&args->data[argsUsed], type, 1);
argsUsed+=StringSize(type);
};
if (instance) {
args->instance = swab(argsUsed+lenBinderArgs);
ShallString(&args->data[argsUsed], instance, 1);
argsUsed+=StringSize(instance);
};
argsUsed+=lenBinderArgs;
/* now they tell me!! */
if (argsUsed > pktSize) SIGNAL(ERROR, 0);
Call(pkt, argsUsed, pktSize);
MoveBlock(binderResult, args, lenBinderResult);
host = hdr->srceHost.w
ReleasePBI(pkt);
Block();
return (host);
};
static int
CheckVersions(v1, v2)
struct VersionRange *v1, *v2;
{
int m1, m2, v1f, v2f, v1l, v2l;
m1 = DoubleEq(v1, matchAllVersions);
m2 = DoubleEq(v2, matchAllVersions);
v1f=swab(v1->first);
v1l=swab(v1->last);
v2f=swab(v2->first);
v2l=swab(v2->last);
if (m1==false && v1f > v1l) return (badV);
if (m2==false && v2f > v2l) return (badV);
if ( m1 || m2 || (v1f <= v2l && v1l >= v2f)) return (okV);
return (wrongV);
};
/* ******** Initialization ******** */
BindingInitialize()
{
struct ExportInstance *binderInst;
diagnoseBinding = false;
binderHint = 0;
binderProc = 0;
Zero(noDispatcher, 2);
Move2(binderID, noDispatcher);
DoubleInc(binderID, 1);
matchAllVersions = &mAVSpace;
matchAllVersions->first = swapped1;
matchAllVersions->last = 0;
binderInst = &exportTable[binderHint];
Move2(&binderInst->id, binderID);
binderInst->dispatcher = &Binder;
binderInst->name.type = binderRope;
used = 1;
ReadCalendar(lastExportID);
};
BindingRopes()
{
binderRope = CStringToString("Binder");
};
BindingRestart()
{
};