aboutsummaryrefslogtreecommitdiff
path: root/include/lldb/Core/Communication.h
blob: 7e8209d7d9c653c906c6380f12c4fb460dc80bb9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
//===-- Communication.h -----------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#ifndef liblldb_Communication_h_
#define liblldb_Communication_h_

// C Includes
// C++ Includes
#include <string>

// Other libraries and framework includes
// Project includes
#include "lldb/lldb-private.h"
#include "lldb/Core/Broadcaster.h"
#include "lldb/Core/Error.h"
#include "lldb/Host/Mutex.h"
#include "lldb/lldb-private.h"

namespace lldb_private {

//----------------------------------------------------------------------
/// @class Communication Communication.h "lldb/Core/Communication.h"
/// @brief An abstract communications class.
///
/// Communication is an class that handles data communication
/// between two data sources. It uses a Connection class to do the
/// real communication. This approach has a couple of advantages: it
/// allows a single instance of this class to be used even though its
/// connection can change. Connections could negotiate for different
/// connections based on abilities like starting with Bluetooth and
/// negotiating up to WiFi if available. It also allows this class to be
/// subclassed by any interfaces that don't want to give bytes but want
/// to validate and give out packets. This can be done by overriding:
///
/// AppendBytesToCache (const uint8_t *src, size_t src_len, bool broadcast);
///
/// Communication inherits from Broadcaster which means it can be
/// used in conjunction with Listener to wait for multiple broadcaster
/// objects and multiple events from each of those objects.
/// Communication defines a set of pre-defined event bits (see
/// enumerations definitions that start with "eBroadcastBit" below).
///
/// There are two modes in which communications can occur:
///     @li single-threaded
///     @li multi-threaded
///
/// In single-threaded mode, all reads and writes happen synchronously
/// on the calling thread.
///
/// In multi-threaded mode, a read thread is spawned that continually
/// reads data and caches any received bytes. To start the read thread
/// clients call:
///
///     bool Communication::StartReadThread (Error *);
///
/// If true is returned a read thread has been spawned that will
/// continually execute a call to the pure virtual DoRead function:
///
///     size_t Communication::ReadFromConnection (void *, size_t, uint32_t);
///
/// When bytes are received the data gets cached in \a m_bytes and this
/// class will broadcast a \b eBroadcastBitReadThreadGotBytes event.
/// Clients that want packet based communication should override
/// AppendBytesToCache. The subclasses can choose to call the
/// built in AppendBytesToCache with the \a broadcast parameter set to
/// false. This will cause the \b eBroadcastBitReadThreadGotBytes event
/// not get broadcast, and then the subclass can post a \b
/// eBroadcastBitPacketAvailable event when a full packet of data has
/// been received.
///
/// If the connection is disconnected a \b eBroadcastBitDisconnected
/// event gets broadcast. If the read thread exits a \b
/// eBroadcastBitReadThreadDidExit event will be broadcast. Clients
/// can also post a \b eBroadcastBitReadThreadShouldExit event to this
/// object which will cause the read thread to exit.
//----------------------------------------------------------------------
class Communication : public Broadcaster
{
public:
    enum {
        eBroadcastBitDisconnected           = (1 << 0), ///< Sent when the communications connection is lost.
        eBroadcastBitReadThreadGotBytes     = (1 << 1), ///< Sent by the read thread when bytes become available.
        eBroadcastBitReadThreadDidExit      = (1 << 2), ///< Sent by the read thread when it exits to inform clients.
        eBroadcastBitReadThreadShouldExit   = (1 << 3), ///< Sent by clients that need to cancel the read thread.
        eBroadcastBitPacketAvailable        = (1 << 4), ///< Sent when data received makes a complete packet.
        kLoUserBroadcastBit                 = (1 << 16),///< Subclasses can used bits 31:16 for any needed events.
        kHiUserBroadcastBit                 = (1 << 31),
        eAllEventBits                       = 0xffffffff
    };

    typedef void (*ReadThreadBytesReceived) (void *baton, const void *src, size_t src_len);


    //------------------------------------------------------------------
    /// Construct the Communication object with the specified name for
    /// the Broadcaster that this object inherits from.
    ///
    /// @param[in] broadcaster_name
    ///     The name of the broadcaster object.  This name should be as
    ///     complete as possible to uniquely identify this object. The
    ///     broadcaster name can be updated after the connect function
    ///     is called.
    //------------------------------------------------------------------
    Communication(const char * broadcaster_name);

    //------------------------------------------------------------------
    /// Destructor.
    ///
    /// The destructor is virtual since this class gets subclassed.
    //------------------------------------------------------------------
    virtual
    ~Communication();

    void
    Clear ();

    //------------------------------------------------------------------
    /// Connect using the current connection by passing \a url to its
    /// connect function.
    /// string.
    ///
    /// @param[in] url
    ///     A string that contains all information needed by the
    ///     subclass to connect to another client.
    ///
    /// @return
    ///     \b True if the connect succeeded, \b false otherwise. The
    ///     internal error object should be filled in with an
    ///     appropriate value based on the result of this function.
    ///
    /// @see Error& Communication::GetError ();
    /// @see bool Connection::Connect (const char *url);
    //------------------------------------------------------------------
    lldb::ConnectionStatus
    Connect (const char *url, Error *error_ptr);

    //------------------------------------------------------------------
    /// Disconnect the communications connection if one is currently
    /// connected.
    ///
    /// @return
    ///     \b True if the disconnect succeeded, \b false otherwise. The
    ///     internal error object should be filled in with an
    ///     appropriate value based on the result of this function.
    ///
    /// @see Error& Communication::GetError ();
    /// @see bool Connection::Disconnect ();
    //------------------------------------------------------------------
    lldb::ConnectionStatus
    Disconnect (Error *error_ptr = NULL);

    //------------------------------------------------------------------
    /// Check if the connection is valid.
    ///
    /// @return
    ///     \b True if this object is currently connected, \b false
    ///     otherwise.
    //------------------------------------------------------------------
    bool
    IsConnected () const;

    bool
    HasConnection () const;
    
    lldb_private::Connection *
    GetConnection ()
    {
        return m_connection_sp.get();
    }
    //------------------------------------------------------------------
    /// Read bytes from the current connection.
    ///
    /// If no read thread is running, this function call the
    /// connection's Connection::Read(...) function to get any available.
    ///
    /// If a read thread has been started, this function will check for
    /// any cached bytes that have already been read and return any
    /// currently available bytes. If no bytes are cached, it will wait
    /// for the bytes to become available by listening for the \a
    /// eBroadcastBitReadThreadGotBytes event. If this function consumes
    /// all of the bytes in the cache, it will reset the
    /// \a eBroadcastBitReadThreadGotBytes event bit.
    ///
    /// @param[in] dst
    ///     A destination buffer that must be at least \a dst_len bytes
    ///     long.
    ///
    /// @param[in] dst_len
    ///     The number of bytes to attempt to read, and also the max
    ///     number of bytes that can be placed into \a dst.
    ///
    /// @param[in] timeout_usec
    ///     A timeout value in micro-seconds.
    ///
    /// @return
    ///     The number of bytes actually read.
    ///
    /// @see size_t Connection::Read (void *, size_t);
    //------------------------------------------------------------------
    size_t
    Read (void *dst, 
          size_t dst_len, 
          uint32_t timeout_usec, 
          lldb::ConnectionStatus &status, 
          Error *error_ptr);
    
    //------------------------------------------------------------------
    /// The actual write function that attempts to write to the
    /// communications protocol.
    ///
    /// Subclasses must override this function.
    ///
    /// @param[in] src
    ///     A source buffer that must be at least \a src_len bytes
    ///     long.
    ///
    /// @param[in] src_len
    ///     The number of bytes to attempt to write, and also the
    ///     number of bytes are currently available in \a src.
    ///
    /// @return
    ///     The number of bytes actually Written.
    //------------------------------------------------------------------
    size_t
    Write (const void *src, 
           size_t src_len, 
           lldb::ConnectionStatus &status,
           Error *error_ptr);
    
    //------------------------------------------------------------------
    /// Sets the connection that it to be used by this class.
    ///
    /// By making a communication class that uses different connections
    /// it allows a single communication interface to negotiate and
    /// change its connection without any interruption to the client.
    /// It also allows the Communication class to be subclassed for
    /// packet based communication.
    ///
    /// @param[in] connection
    ///     A connection that this class will own and destroy.
    ///
    /// @see
    ///     class Connection
    //------------------------------------------------------------------
    void
    SetConnection (Connection *connection);

    //------------------------------------------------------------------
    /// Starts a read thread whose sole purpose it to read bytes from
    /// the current connection. This function will call connection's
    /// read function:
    ///
    /// size_t Connection::Read (void *, size_t);
    ///
    /// When bytes are read and cached, this function will call:
    ///
    /// Communication::AppendBytesToCache (const uint8_t * bytes, size_t len, bool broadcast);
    ///
    /// Subclasses should override this function if they wish to override
    /// the default action of caching the bytes and broadcasting a \b
    /// eBroadcastBitReadThreadGotBytes event.
    ///
    /// @return
    ///     \b True if the read thread was successfully started, \b
    ///     false otherwise.
    ///
    /// @see size_t Connection::Read (void *, size_t);
    /// @see void Communication::AppendBytesToCache (const uint8_t * bytes, size_t len, bool broadcast);
    //------------------------------------------------------------------
    virtual bool
    StartReadThread (Error *error_ptr = NULL);

    //------------------------------------------------------------------
    /// Stops the read thread by cancelling it.
    ///
    /// @return
    ///     \b True if the read thread was successfully canceled, \b
    ///     false otherwise.
    //------------------------------------------------------------------
    virtual bool
    StopReadThread (Error *error_ptr = NULL);

    virtual bool
    JoinReadThread (Error *error_ptr = NULL);
    //------------------------------------------------------------------
    /// Checks if there is a currently running read thread.
    ///
    /// @return
    ///     \b True if the read thread is running, \b false otherwise.
    //------------------------------------------------------------------
    bool
    ReadThreadIsRunning ();

    //------------------------------------------------------------------
    /// The static read thread function. This function will call
    /// the "DoRead" function continuously and wait for data to become
    /// available. When data is received it will append the available
    /// data to the internal cache and broadcast a
    /// \b eBroadcastBitReadThreadGotBytes event.
    ///
    /// @param[in] comm_ptr
    ///     A pointer to an instance of this class.
    ///
    /// @return
    ///     \b NULL.
    ///
    /// @see void Communication::ReadThreadGotBytes (const uint8_t *, size_t);
    //------------------------------------------------------------------
    static lldb::thread_result_t
    ReadThread (lldb::thread_arg_t comm_ptr);

    void
    SetReadThreadBytesReceivedCallback (ReadThreadBytesReceived callback,
                                        void *callback_baton);

    static const char *
    ConnectionStatusAsCString (lldb::ConnectionStatus status);

    bool
    GetCloseOnEOF () const
    { 
        return m_close_on_eof;
    }

    void
    SetCloseOnEOF (bool b)
    { 
        m_close_on_eof = b;
    }

    static ConstString &GetStaticBroadcasterClass ();

    virtual ConstString &GetBroadcasterClass() const
    {
        return GetStaticBroadcasterClass();
    }

private:
    //------------------------------------------------------------------
    // For Communication only
    //------------------------------------------------------------------
    DISALLOW_COPY_AND_ASSIGN (Communication);


protected:
    lldb::ConnectionSP m_connection_sp; ///< The connection that is current in use by this communications class.
    lldb::thread_t m_read_thread; ///< The read thread handle in case we need to cancel the thread.
    bool m_read_thread_enabled;
    std::string m_bytes;    ///< A buffer to cache bytes read in the ReadThread function.
    Mutex m_bytes_mutex;    ///< A mutex to protect multi-threaded access to the cached bytes.
    Mutex m_write_mutex;    ///< Don't let multiple threads write at the same time...
    ReadThreadBytesReceived m_callback;
    void *m_callback_baton;
    bool m_close_on_eof;

    size_t
    ReadFromConnection (void *dst, 
                        size_t dst_len, 
                        uint32_t timeout_usec,
                        lldb::ConnectionStatus &status, 
                        Error *error_ptr);
    //------------------------------------------------------------------
    /// Append new bytes that get read from the read thread into the
    /// internal object byte cache. This will cause a \b
    /// eBroadcastBitReadThreadGotBytes event to be broadcast if \a
    /// broadcast is true.
    ///
    /// Subclasses can override this function in order to inspect the
    /// received data and check if a packet is available.
    ///
    /// Subclasses can also still call this function from the
    /// overridden method to allow the caching to correctly happen and
    /// suppress the broadcasting of the \a eBroadcastBitReadThreadGotBytes
    /// event by setting \a broadcast to false.
    ///
    /// @param[in] src
    ///     A source buffer that must be at least \a src_len bytes
    ///     long.
    ///
    /// @param[in] src_len
    ///     The number of bytes to append to the cache.
    //------------------------------------------------------------------
    virtual void
    AppendBytesToCache (const uint8_t *src, size_t src_len, bool broadcast, lldb::ConnectionStatus status);

    //------------------------------------------------------------------
    /// Get any available bytes from our data cache. If this call
    /// empties the data cache, the \b eBroadcastBitReadThreadGotBytes event
    /// will be reset to signify no more bytes are available.
    ///
    /// @param[in] dst
    ///     A destination buffer that must be at least \a dst_len bytes
    ///     long.
    ///
    /// @param[in] dst_len
    ///     The number of bytes to attempt to read from the cache,
    ///     and also the max number of bytes that can be placed into
    ///     \a dst.
    ///
    /// @return
    ///     The number of bytes extracted from the data cache.
    //------------------------------------------------------------------
    size_t
    GetCachedBytes (void *dst, size_t dst_len);
};

} // namespace lldb_private

#endif  // liblldb_Communication_h_