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.
		
		
		
		
			
				
					161 lines
				
				6.1 KiB
			
		
		
			
		
	
	
					161 lines
				
				6.1 KiB
			| 
											8 years ago
										 | // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
 | ||
|  | // Licensed under the MIT License:
 | ||
|  | //
 | ||
|  | // Permission is hereby granted, free of charge, to any person obtaining a copy
 | ||
|  | // of this software and associated documentation files (the "Software"), to deal
 | ||
|  | // in the Software without restriction, including without limitation the rights
 | ||
|  | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | ||
|  | // copies of the Software, and to permit persons to whom the Software is
 | ||
|  | // furnished to do so, subject to the following conditions:
 | ||
|  | //
 | ||
|  | // The above copyright notice and this permission notice shall be included in
 | ||
|  | // all copies or substantial portions of the Software.
 | ||
|  | //
 | ||
|  | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | ||
|  | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | ||
|  | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | ||
|  | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | ||
|  | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | ||
|  | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | ||
|  | // THE SOFTWARE.
 | ||
|  | 
 | ||
|  | #ifndef CAPNP_RPC_TWOPARTY_H_
 | ||
|  | #define CAPNP_RPC_TWOPARTY_H_
 | ||
|  | 
 | ||
|  | #if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS)
 | ||
|  | #pragma GCC system_header
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #include "rpc.h"
 | ||
|  | #include "message.h"
 | ||
|  | #include <kj/async-io.h>
 | ||
|  | #include <capnp/rpc-twoparty.capnp.h>
 | ||
|  | 
 | ||
|  | namespace capnp {
 | ||
|  | 
 | ||
|  | namespace rpc {
 | ||
|  |   namespace twoparty {
 | ||
|  |     typedef VatId SturdyRefHostId;  // For backwards-compatibility with version 0.4.
 | ||
|  |   }
 | ||
|  | }
 | ||
|  | 
 | ||
|  | typedef VatNetwork<rpc::twoparty::VatId, rpc::twoparty::ProvisionId,
 | ||
|  |     rpc::twoparty::RecipientId, rpc::twoparty::ThirdPartyCapId, rpc::twoparty::JoinResult>
 | ||
|  |     TwoPartyVatNetworkBase;
 | ||
|  | 
 | ||
|  | class TwoPartyVatNetwork: public TwoPartyVatNetworkBase,
 | ||
|  |                           private TwoPartyVatNetworkBase::Connection {
 | ||
|  |   // A `VatNetwork` that consists of exactly two parties communicating over an arbitrary byte
 | ||
|  |   // stream.  This is used to implement the common case of a client/server network.
 | ||
|  |   //
 | ||
|  |   // See `ez-rpc.h` for a simple interface for setting up two-party clients and servers.
 | ||
|  |   // Use `TwoPartyVatNetwork` only if you need the advanced features.
 | ||
|  | 
 | ||
|  | public:
 | ||
|  |   TwoPartyVatNetwork(kj::AsyncIoStream& stream, rpc::twoparty::Side side,
 | ||
|  |                      ReaderOptions receiveOptions = ReaderOptions());
 | ||
|  |   KJ_DISALLOW_COPY(TwoPartyVatNetwork);
 | ||
|  | 
 | ||
|  |   kj::Promise<void> onDisconnect() { return disconnectPromise.addBranch(); }
 | ||
|  |   // Returns a promise that resolves when the peer disconnects.
 | ||
|  | 
 | ||
|  |   rpc::twoparty::Side getSide() { return side; }
 | ||
|  | 
 | ||
|  |   // implements VatNetwork -----------------------------------------------------
 | ||
|  | 
 | ||
|  |   kj::Maybe<kj::Own<TwoPartyVatNetworkBase::Connection>> connect(
 | ||
|  |       rpc::twoparty::VatId::Reader ref) override;
 | ||
|  |   kj::Promise<kj::Own<TwoPartyVatNetworkBase::Connection>> accept() override;
 | ||
|  | 
 | ||
|  | private:
 | ||
|  |   class OutgoingMessageImpl;
 | ||
|  |   class IncomingMessageImpl;
 | ||
|  | 
 | ||
|  |   kj::AsyncIoStream& stream;
 | ||
|  |   rpc::twoparty::Side side;
 | ||
|  |   MallocMessageBuilder peerVatId;
 | ||
|  |   ReaderOptions receiveOptions;
 | ||
|  |   bool accepted = false;
 | ||
|  | 
 | ||
|  |   kj::Maybe<kj::Promise<void>> previousWrite;
 | ||
|  |   // Resolves when the previous write completes.  This effectively serves as the write queue.
 | ||
|  |   // Becomes null when shutdown() is called.
 | ||
|  | 
 | ||
|  |   kj::Own<kj::PromiseFulfiller<kj::Own<TwoPartyVatNetworkBase::Connection>>> acceptFulfiller;
 | ||
|  |   // Fulfiller for the promise returned by acceptConnectionAsRefHost() on the client side, or the
 | ||
|  |   // second call on the server side.  Never fulfilled, because there is only one connection.
 | ||
|  | 
 | ||
|  |   kj::ForkedPromise<void> disconnectPromise = nullptr;
 | ||
|  | 
 | ||
|  |   class FulfillerDisposer: public kj::Disposer {
 | ||
|  |     // Hack:  TwoPartyVatNetwork is both a VatNetwork and a VatNetwork::Connection.  When the RPC
 | ||
|  |     //   system detects (or initiates) a disconnection, it drops its reference to the Connection.
 | ||
|  |     //   When all references have been dropped, then we want disconnectPromise to be fulfilled.
 | ||
|  |     //   So we hand out Own<Connection>s with this disposer attached, so that we can detect when
 | ||
|  |     //   they are dropped.
 | ||
|  | 
 | ||
|  |   public:
 | ||
|  |     mutable kj::Own<kj::PromiseFulfiller<void>> fulfiller;
 | ||
|  |     mutable uint refcount = 0;
 | ||
|  | 
 | ||
|  |     void disposeImpl(void* pointer) const override;
 | ||
|  |   };
 | ||
|  |   FulfillerDisposer disconnectFulfiller;
 | ||
|  | 
 | ||
|  |   kj::Own<TwoPartyVatNetworkBase::Connection> asConnection();
 | ||
|  |   // Returns a pointer to this with the disposer set to disconnectFulfiller.
 | ||
|  | 
 | ||
|  |   // implements Connection -----------------------------------------------------
 | ||
|  | 
 | ||
|  |   rpc::twoparty::VatId::Reader getPeerVatId() override;
 | ||
|  |   kj::Own<OutgoingRpcMessage> newOutgoingMessage(uint firstSegmentWordSize) override;
 | ||
|  |   kj::Promise<kj::Maybe<kj::Own<IncomingRpcMessage>>> receiveIncomingMessage() override;
 | ||
|  |   kj::Promise<void> shutdown() override;
 | ||
|  | };
 | ||
|  | 
 | ||
|  | class TwoPartyServer: private kj::TaskSet::ErrorHandler {
 | ||
|  |   // Convenience class which implements a simple server which accepts connections on a listener
 | ||
|  |   // socket and serices them as two-party connections.
 | ||
|  | 
 | ||
|  | public:
 | ||
|  |   explicit TwoPartyServer(Capability::Client bootstrapInterface);
 | ||
|  | 
 | ||
|  |   void accept(kj::Own<kj::AsyncIoStream>&& connection);
 | ||
|  |   // Accepts the connection for servicing.
 | ||
|  | 
 | ||
|  |   kj::Promise<void> listen(kj::ConnectionReceiver& listener);
 | ||
|  |   // Listens for connections on the given listener. The returned promise never resolves unless an
 | ||
|  |   // exception is thrown while trying to accept. You may discard the returned promise to cancel
 | ||
|  |   // listening.
 | ||
|  | 
 | ||
|  | private:
 | ||
|  |   Capability::Client bootstrapInterface;
 | ||
|  |   kj::TaskSet tasks;
 | ||
|  | 
 | ||
|  |   struct AcceptedConnection;
 | ||
|  | 
 | ||
|  |   void taskFailed(kj::Exception&& exception) override;
 | ||
|  | };
 | ||
|  | 
 | ||
|  | class TwoPartyClient {
 | ||
|  |   // Convenience class which implements a simple client.
 | ||
|  | 
 | ||
|  | public:
 | ||
|  |   explicit TwoPartyClient(kj::AsyncIoStream& connection);
 | ||
|  |   TwoPartyClient(kj::AsyncIoStream& connection, Capability::Client bootstrapInterface,
 | ||
|  |                  rpc::twoparty::Side side = rpc::twoparty::Side::CLIENT);
 | ||
|  | 
 | ||
|  |   Capability::Client bootstrap();
 | ||
|  |   // Get the server's bootstrap interface.
 | ||
|  | 
 | ||
|  |   inline kj::Promise<void> onDisconnect() { return network.onDisconnect(); }
 | ||
|  | 
 | ||
|  | private:
 | ||
|  |   TwoPartyVatNetwork network;
 | ||
|  |   RpcSystem<rpc::twoparty::VatId> rpcSystem;
 | ||
|  | };
 | ||
|  | 
 | ||
|  | }  // namespace capnp
 | ||
|  | 
 | ||
|  | #endif  // CAPNP_RPC_TWOPARTY_H_
 |