1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef CHROMECAST_NET_SMALL_MESSAGE_SOCKET_H_
6 #define CHROMECAST_NET_SMALL_MESSAGE_SOCKET_H_
7 
8 #include <memory>
9 
10 #include "base/macros.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/memory/weak_ptr.h"
13 
14 namespace base {
15 class SequencedTaskRunner;
16 }  // namespace base
17 
18 namespace net {
19 class GrowableIOBuffer;
20 class IOBuffer;
21 class Socket;
22 }  // namespace net
23 
24 namespace chromecast {
25 class IOBufferPool;
26 
27 // Sends small messages (< 64 KB) over a Socket. All methods must be called on
28 // the same sequence. Any of the virtual methods can destroy this object if
29 // desired.
30 class SmallMessageSocket {
31  public:
32   class Delegate {
33    public:
34     // Called when sending becomes possible again, if a previous attempt to send
35     // was rejected.
OnSendUnblocked()36     virtual void OnSendUnblocked() {}
37 
38     // Called when an unrecoverable error occurs while sending or receiving. Is
39     // only called asynchronously.
OnError(int error)40     virtual void OnError(int error) {}
41 
42     // Called when the end of stream has been read. No more data will be
43     // received.
OnEndOfStream()44     virtual void OnEndOfStream() {}
45 
46     // Called when a message has been received and there is no buffer pool. The
47     // |data| buffer contains |size| bytes of data. Return |true| to continue
48     // reading messages after OnMessage() returns.
49     virtual bool OnMessage(char* data, size_t size) = 0;
50 
51     // Called when a message has been received. The |buffer| contains |size|
52     // bytes of data, which includes the first 2 bytes which are the size in
53     // network byte order. Note that these 2 bytes are not included in
54     // OnMessage()! Return |true| to continue receiving messages.
55     virtual bool OnMessageBuffer(scoped_refptr<net::IOBuffer> buffer,
56                                  size_t size);
57 
58    protected:
59     virtual ~Delegate() = default;
60   };
61 
62   SmallMessageSocket(Delegate* delegate, std::unique_ptr<net::Socket> socket);
63   virtual ~SmallMessageSocket();
64 
socket()65   net::Socket* socket() const { return socket_.get(); }
task_runner()66   base::SequencedTaskRunner* task_runner() const { return task_runner_.get(); }
buffer_pool()67   IOBufferPool* buffer_pool() const { return buffer_pool_.get(); }
68 
69   // Adds a |buffer_pool| used to allocate buffers to receive messages into;
70   // received messages are passed to OnMessageBuffer(). If a message would be
71   // too big to fit in a pool-provided buffer, a dynamically allocated IOBuffer
72   // will be used instead for that message.
73   void UseBufferPool(scoped_refptr<IOBufferPool> buffer_pool);
74 
75   // Removes the buffer pool; subsequent received messages will be passed to
76   // OnMessage().
77   void RemoveBufferPool();
78 
79   // Prepares a buffer to send a message of the given |message_size|. Returns
80   // nullptr if sending is not allowed right now (ie, another send is currently
81   // in progress). Otherwise, returns a buffer at least large enough to contain
82   // |message_size| bytes. The caller should fill in the buffer as desired and
83   // then call Send() to send the finished message.
84   // If nullptr is returned, then OnSendUnblocked() will be called once sending
85   // is possible again.
86   void* PrepareSend(size_t message_size);
87   void Send();
88 
89   // Sends an already-prepared buffer of data, if possible. The first 2 bytes of
90   // the buffer must contain the size of the rest of the data, encoded as a
91   // 16-bit integer in big-endian byte order. Returns true if the buffer will be
92   // sent; returns false if sending is not allowed right now (ie, another send
93   // is currently in progress). If false is returned, then OnSendUnblocked()
94   // will be called once sending is possible again.
95   bool SendBuffer(scoped_refptr<net::IOBuffer> data, size_t size);
96 
97   // Enables receiving messages from the stream. Messages will be received and
98   // passed to OnMessage() until either an error occurs, the end of stream is
99   // reached, or OnMessage() returns false. If OnMessage() returns false, you
100   // may call ReceiveMessages() to start receiving again. OnMessage() will not
101   // be called synchronously from within this method (it always posts a task).
102   void ReceiveMessages();
103 
104   // Same as ReceiveMessages(), but OnMessage() may be called synchronously.
105   // This is more efficient because it doesn't post a task to ensure
106   // asynchronous reads.
107   void ReceiveMessagesSynchronously();
108 
109  private:
110   class BufferWrapper;
111 
112   void OnWriteComplete(int result);
113   bool HandleWriteResult(int result);
114   void OnError(int error);
115 
116   void Read();
117   void OnReadComplete(int result);
118   bool HandleReadResult(int result);
119   bool HandleCompletedMessages();
120   bool HandleCompletedMessageBuffers();
121   void ActivateBufferPool(char* current_data, size_t current_size);
122 
123   Delegate* const delegate_;
124   const std::unique_ptr<net::Socket> socket_;
125   const scoped_refptr<base::SequencedTaskRunner> task_runner_;
126 
127   const scoped_refptr<net::GrowableIOBuffer> write_storage_;
128   const scoped_refptr<BufferWrapper> write_buffer_;
129   bool send_blocked_ = false;
130 
131   const scoped_refptr<net::GrowableIOBuffer> read_storage_;
132 
133   scoped_refptr<IOBufferPool> buffer_pool_;
134   const scoped_refptr<BufferWrapper> read_buffer_;
135 
136   bool in_message_ = false;
137 
138   base::WeakPtrFactory<SmallMessageSocket> weak_factory_;
139 
140   DISALLOW_COPY_AND_ASSIGN(SmallMessageSocket);
141 };
142 
143 }  // namespace chromecast
144 
145 #endif  // CHROMECAST_NET_SMALL_MESSAGE_SOCKET_H_
146