// This must be called on the creation thread before any other methods are
// called, and before references to this object are given to any other
- // threads. |handle| should be a handle to a (platform-appropriate)
- // bidirectional communication channel (e.g., a socket on POSIX, a named pipe
- // on Windows). Returns true on success. On failure, no other methods should
- // be called (including |Shutdown()|).
- bool Init(embedder::ScopedPlatformHandle handle);
+ // threads. |raw_channel| should be uninitialized. Returns true on success. On
+ // failure, no other methods should be called (including |Shutdown()|).
+ bool Init(scoped_ptr<RawChannel> raw_channel);
// This must be called on the creation thread before destruction (which can
// happen on any thread).
// which it returns. The first message pipe endpoint attached will always have
// |kBootstrapEndpointId| as its local ID. (For bootstrapping, this occurs on
// both sides, so one should use |kBootstrapEndpointId| for the remote ID for
- // the first message pipe across a channel.)
+ // the first message pipe across a channel.) Returns |kInvalidEndpointId| on
+ // failure.
+ // TODO(vtl): Maybe limit the number of attached message pipes.
MessageInTransit::EndpointId AttachMessagePipeEndpoint(
- scoped_refptr<MessagePipe> message_pipe, unsigned port);
- void RunMessagePipeEndpoint(MessageInTransit::EndpointId local_id,
+ scoped_refptr<MessagePipe> message_pipe,
+ unsigned port);
+
+ // Runs the message pipe with the given |local_id| (previously attached), with
+ // the given |remote_id| (negotiated using some other means, e.g., over an
+ // existing message pipe; see comments above for the bootstrap case). Returns
+ // false on failure, in particular if no message pipe with |local_id| is
+ // attached.
+ bool RunMessagePipeEndpoint(MessageInTransit::EndpointId local_id,
MessageInTransit::EndpointId remote_id);
// Tells the other side of the channel to run a message pipe endpoint (which
// |FlushWriteBufferAndShutdown()| or something like that.
bool IsWriteBufferEmpty();
- // This removes the message pipe/port's endpoint (with the given local ID,
+ // This removes the message pipe/port's endpoint (with the given local ID and
+ // given remote ID, which should be |kInvalidEndpointId| if not yet running),
// returned by |AttachMessagePipeEndpoint()| from this channel. After this is
// called, |local_id| may be reused for another message pipe.
- void DetachMessagePipeEndpoint(MessageInTransit::EndpointId local_id);
+ void DetachMessagePipeEndpoint(MessageInTransit::EndpointId local_id,
+ MessageInTransit::EndpointId remote_id);
+
+ // See |RawChannel::GetSerializedPlatformHandleSize()|.
+ size_t GetSerializedPlatformHandleSize() const;
private:
+ struct EndpointInfo {
+ enum State {
+ // Attached, possibly running or not.
+ STATE_NORMAL,
+ // "Zombie" states:
+ // Waiting for |DetachMessagePipeEndpoint()| before removing.
+ STATE_WAIT_LOCAL_DETACH,
+ // Waiting for a |kSubtypeChannelRemoveMessagePipeEndpointAck| before
+ // removing.
+ STATE_WAIT_REMOTE_REMOVE_ACK,
+ // Waiting for both of the above conditions before removing.
+ STATE_WAIT_LOCAL_DETACH_AND_REMOTE_REMOVE_ACK,
+ };
+
+ EndpointInfo();
+ EndpointInfo(scoped_refptr<MessagePipe> message_pipe, unsigned port);
+ ~EndpointInfo();
+
+ State state;
+ scoped_refptr<MessagePipe> message_pipe;
+ unsigned port;
+ };
+
friend class base::RefCountedThreadSafe<Channel>;
virtual ~Channel();
void OnReadMessageForDownstream(const MessageInTransit::View& message_view);
void OnReadMessageForChannel(const MessageInTransit::View& message_view);
+ // Removes the message pipe endpoint with the given local ID, which must exist
+ // and be a zombie, and given remote ID. Returns false on failure, in
+ // particular if no message pipe with |local_id| is attached.
+ bool RemoveMessagePipeEndpoint(MessageInTransit::EndpointId local_id,
+ MessageInTransit::EndpointId remote_id);
+
// Handles errors (e.g., invalid messages) from the remote side.
void HandleRemoteError(const base::StringPiece& error_message);
// Handles internal errors/failures from the local side.
void HandleLocalError(const base::StringPiece& error_message);
- struct EndpointInfo {
- EndpointInfo();
- EndpointInfo(scoped_refptr<MessagePipe> message_pipe, unsigned port);
- ~EndpointInfo();
+ // Helper to send channel control messages. Returns true on success. Should be
+ // called *without* |lock_| held.
+ bool SendControlMessage(MessageInTransit::Subtype subtype,
+ MessageInTransit::EndpointId source_id,
+ MessageInTransit::EndpointId destination_id);
- scoped_refptr<MessagePipe> message_pipe;
- unsigned port;
- };
+ bool is_running_no_lock() const { return is_running_; }
base::ThreadChecker creation_thread_checker_;
base::Lock lock_; // Protects the members below.
scoped_ptr<RawChannel> raw_channel_;
+ bool is_running_;
typedef base::hash_map<MessageInTransit::EndpointId, EndpointInfo>
IdToEndpointInfoMap;