/* 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() { };