summaryrefslogtreecommitdiffstats
path: root/Source/cmConnection.h
blob: ce2d2dc2aa182e6c26eb9a34ba492e36e8264bf0 (plain)
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
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
   file Copyright.txt or https://cmake.org/licensing for details.  */

#pragma once

#include "cmConfigure.h" // IWYU pragma: keep

#include "cmUVHandlePtr.h"
#include "cm_uv.h"

#include <cstddef>
#include <memory>
#include <string>

class cmServerBase;

/***
 * Given a sequence of bytes with any kind of buffering, instances of this
 * class arrange logical chunks according to whatever the use case is for
 * the connection.
 */
class cmConnectionBufferStrategy
{
public:
  virtual ~cmConnectionBufferStrategy();

  /***
   * Called whenever with an active raw buffer. If a logical chunk
   * becomes available, that chunk is returned and that portion is
   * removed from the rawBuffer
   *
   * @param rawBuffer in/out parameter. Receive buffer; the buffer strategy is
   * free to manipulate this buffer anyway it needs to.
   *
   * @return Next chunk from the stream. Returns the empty string if a chunk
   * isn't ready yet. Users of this interface should repeatedly call this
   * function until an empty string is returned since its entirely possible
   * multiple chunks come in a single raw buffer.
   */
  virtual std::string BufferMessage(std::string& rawBuffer) = 0;

  /***
   * Called to properly buffer an outgoing message.
   *
   * @param rawBuffer Message to format in the correct way
   *
   * @return Formatted message
   */
  virtual std::string BufferOutMessage(const std::string& rawBuffer) const
  {
    return rawBuffer;
  };
  /***
   * Resets the internal state of the buffering
   */
  virtual void clear();

  // TODO: There should be a callback / flag set for errors
};

class cmConnection
{
  CM_DISABLE_COPY(cmConnection)

public:
  cmConnection() {}

  virtual void WriteData(const std::string& data) = 0;

  virtual ~cmConnection();

  virtual bool OnConnectionShuttingDown();

  virtual bool IsOpen() const = 0;

  virtual void SetServer(cmServerBase* s);

  virtual void ProcessRequest(const std::string& request);

  virtual bool OnServeStart(std::string* pString);

protected:
  cmServerBase* Server = nullptr;
};

/***
 * Abstraction of a connection; ties in event callbacks from libuv and notifies
 * the server when appropriate
 */
class cmEventBasedConnection : public cmConnection
{

public:
  /***
   * @param bufferStrategy If no strategy is given, it will process the raw
   * chunks as they come in. The connection
   * owns the pointer given.
   */
  cmEventBasedConnection(cmConnectionBufferStrategy* bufferStrategy = nullptr);

  virtual void Connect(uv_stream_t* server);

  virtual void ReadData(const std::string& data);

  bool IsOpen() const override;

  void WriteData(const std::string& data) override;
  bool OnConnectionShuttingDown() override;

  virtual void OnDisconnect(int errorCode);

  static void on_close(uv_handle_t* handle);

  template <typename T>
  static void on_close_delete(uv_handle_t* handle)
  {
    delete reinterpret_cast<T*>(handle);
  }

protected:
  cm::uv_stream_ptr WriteStream;

  std::string RawReadBuffer;

  std::unique_ptr<cmConnectionBufferStrategy> BufferStrategy;

  static void on_read(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf);

  static void on_write(uv_write_t* req, int status);

  static void on_new_connection(uv_stream_t* stream, int status);

  static void on_alloc_buffer(uv_handle_t* handle, size_t suggested_size,
                              uv_buf_t* buf);
};