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.
		
		
		
		
		
			
		
			
				
					
					
						
							160 lines
						
					
					
						
							6.1 KiB
						
					
					
				
			
		
		
	
	
							160 lines
						
					
					
						
							6.1 KiB
						
					
					
				| // 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_
 | |
| 
 |