Skip to content

Commit

Permalink
fix: fully implement onInbound for unique connection ID
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelfig committed Apr 12, 2021
1 parent 7615292 commit 421b9d4
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 24 deletions.
52 changes: 31 additions & 21 deletions packages/SwingSet/src/vats/network/network.js
Original file line number Diff line number Diff line change
Expand Up @@ -385,10 +385,16 @@ export function makeNetworkProtocol(protocolHandler) {
const [port, listener] = listening.get(listenPrefix);
let localAddr;
try {
// See if we have a listener that's willing to receive this connection.
// See if our protocol is willing to receive this connection.
// eslint-disable-next-line no-await-in-loop
const localSuffix = await E(listener)
.onInbound(port, listenPrefix, remoteAddr, listener)
const localSuffix = await E(protocolHandler)
.onInbound(
port,
listenPrefix,
remoteAddr,
listener,
protocolHandler,
)
.catch(rethrowUnlessMissing);
localAddr = localSuffix
? `${listenPrefix}/${localSuffix}`
Expand Down Expand Up @@ -508,7 +514,7 @@ export function makeEchoConnectionHandler() {
}
return bytes;
},
async onClose(_connection, _connectionHandler) {
async onClose(_connection, _reason, _connectionHandler) {
if (closed) {
throw closed;
}
Expand All @@ -517,50 +523,54 @@ export function makeEchoConnectionHandler() {
});
}

export function makeNonceMaker(prefix = '', suffix = '') {
let nonce = 0;
return async () => {
nonce += 1;
return `${prefix}${nonce}${suffix}`;
};
}

/**
* Create a protocol handler that just connects to itself.
*
* @param {ProtocolHandler['onInbound']} [onInbound]
* @returns {ProtocolHandler} The localhost handler
*/
export function makeLoopbackProtocolHandler() {
export function makeLoopbackProtocolHandler(
onInbound = makeNonceMaker('nonce/'),
) {
/**
* @type {Store<string, [Port, ListenHandler]>}
*/
const listeners = makeStore('localAddr');

let nonce = 0;
const makePortID = makeNonceMaker('port');

return Far('ProtocolHandler', {
// eslint-disable-next-line no-empty-function
async onCreate(_impl, _protocolHandler) {
// TODO
},
async generatePortID(_protocolHandler) {
nonce += 1;
return `port${nonce}`;
return makePortID();
},
async onBind(_port, _localAddr, _protocolHandler) {
// TODO: Maybe handle a bind?
},
async onConnect(_port, localAddr, remoteAddr, _chandler, _protocolHandler) {
async onConnect(_port, localAddr, remoteAddr, _chandler, protocolHandler) {
const [lport, lhandler] = listeners.get(remoteAddr);
// console.log(`looking up onAccept in`, lhandler);
const remoteSuffix =
/** @type {Endpoint} */
(await E(lhandler)
.onInbound(lport, remoteAddr, localAddr, lhandler)
.catch(e => rethrowUnlessMissing(e)));

if (remoteSuffix) {
remoteAddr = `${remoteAddr}/${remoteSuffix}`;
}

const rchandler =
/** @type {ConnectionHandler} */
(await E(lhandler).onAccept(lport, remoteAddr, localAddr, lhandler));
// console.log(`rchandler is`, rchandler);
return [remoteAddr, rchandler];
const remoteSuffix = await E(protocolHandler)
.onInbound(lport, remoteAddr, localAddr, lhandler, protocolHandler)
.catch(rethrowUnlessMissing);
const ra = remoteSuffix ? `${remoteAddr}/${remoteSuffix}` : remoteAddr;
return [ra, rchandler];
},
onInbound,
async onListen(port, localAddr, listenHandler, _protocolHandler) {
// TODO: Implement other listener replacement policies.
if (listeners.has(localAddr)) {
Expand Down
3 changes: 2 additions & 1 deletion packages/SwingSet/src/vats/network/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
/**
* @typedef {Object} ListenHandler A handler for incoming connections
* @property {(port: Port, l: ListenHandler) => Promise<void>} [onListen] The listener has been registered
* @property {(port: Port, listenAddr: Endpoint, remoteAddr: Endpoint, l: ListenHandler) => Promise<Endpoint>} [onInbound] Return metadata for inbound connection attempt
* @property {(port: Port, localAddr: Endpoint, remoteAddr: Endpoint, l: ListenHandler) => Promise<ConnectionHandler>} onAccept A new connection is incoming
* @property {(port: Port, localAddr: Endpoint, remoteAddr: Endpoint, l: ListenHandler) => Promise<void>} onReject The connection was rejected
* @property {(port: Port, rej: any, l: ListenHandler) => Promise<void>} [onError] There was an error while listening
Expand Down Expand Up @@ -61,6 +60,8 @@
* @property {(port: Port, localAddr: Endpoint, p: ProtocolHandler) => Promise<void>} onBind A port will be bound
* @property {(port: Port, localAddr: Endpoint, listenHandler: ListenHandler, p: ProtocolHandler) => Promise<void>} onListen A port was listening
* @property {(port: Port, localAddr: Endpoint, listenHandler: ListenHandler, p: ProtocolHandler) => Promise<void>} onListenRemove A port listener has been reset
* @property {(port: Port, listenAddr: Endpoint, remoteAddr: Endpoint, l: ListenHandler, p: ProtocolHandler) => Promise<Endpoint>} [onInbound] Return suffix for
* inbound connection attempt
* @property {(port: Port, localAddr: Endpoint, remote: Endpoint, c: ConnectionHandler, p: ProtocolHandler) => Promise<[Endpoint, ConnectionHandler]>} onConnect A port initiates an outbound connection
* @property {(port: Port, localAddr: Endpoint, p: ProtocolHandler) => Promise<void>} onRevoke The port is being completely destroyed
*
Expand Down
25 changes: 23 additions & 2 deletions packages/cosmic-swingset/lib/ag-solo/vats/ibc.js
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,9 @@ export function makeIBCProtocolHandler(E, rawCallIBCDevice) {
*/
const portToPendingConns = makeStore('Port');

/** @type {Store<Endpoint, Endpoint>} */
const remoteAddrToLocalSuffix = makeStore();

/**
* @type {ProtocolHandler}
*/
Expand All @@ -263,6 +266,17 @@ export function makeIBCProtocolHandler(E, rawCallIBCDevice) {
};
return callIBCDevice('bindPort', { packet });
},
async onInbound(
_port,
_listenAddr,
remoteAddr,
_lhandler,
_protocolHandler,
) {
// we can take advantage of the fact that remoteAddrs are unique (they
// have their own channelID).
return remoteAddrToLocalSuffix.get(remoteAddr);
},
async onConnect(port, localAddr, remoteAddr, chandler, _protocolHandler) {
console.debug('IBC onConnect', localAddr, remoteAddr);
const portID = localAddrToPortID(localAddr);
Expand Down Expand Up @@ -451,11 +465,18 @@ EOF
const ibcHops = hops.map(hop => `/ibc-hop/${hop}`).join('/');
const remoteAddr = `${ibcHops}/ibc-port/${rPortID}/${order.toLowerCase()}/${rVersion}/ibc-channel/${rChannelID}`;

// See if we allow an inbound attempt for this address pair (without rejecting).
// See if we allow an inbound attempt for this address pair (without
// rejecting).
remoteAddrToLocalSuffix.init(remoteAddr, `ibc-channel/${channelID}`);
const attemptP = E(protocolImpl).inbound(localAddr, remoteAddr);

// Tell what version string we negotiated.
const attemptedLocal = await E(attemptP).getLocalAddress();
const attemptedLocal = await E(attemptP)
.getLocalAddress()
.finally(() => {
// No matter what, delete the temporary mapping.
remoteAddrToLocalSuffix.delete(remoteAddr);
});
const match = attemptedLocal.match(
// Match: ... /ORDER/VERSION ...
new RegExp('^(/[^/]+/[^/]+)*/(ordered|unordered)/([^/]+)(/|$)'),
Expand Down

0 comments on commit 421b9d4

Please sign in to comment.