hello

./code/hello/Makefile
 1CXXFLAGS := -DASIO_STANDALONE
 2CXXFLAGS += -I/ceph-fj/fangjun/software/asio/include
 3CXXFLAGS += -I/ceph-fj/fangjun/software/websocketpp/include
 4CXXFLAGS += -std=c++14
 5LDFLAGS += -pthread
 6
 7main: main.o uri.o
 8	$(CXX) -o $@ $^ $(LDFLAGS)
 9
10%.o: %.cc
11	$(CXX) -c $(CXXFLAGS) -o $@ $<
12
13clean:
14	$(RM) *.o main
./code/hello/main.cc
  1#include "websocketpp/client.hpp"
  2#include "websocketpp/config/asio_no_tls_client.hpp"
  3#include <assert.h>
  4#include <iostream>
  5#include <memory>
  6#include <string>
  7#include <thread>
  8
  9using client = websocketpp::client<websocketpp::config::asio_client>;
 10
 11class connection_metadata {
 12public:
 13  using ptr = std::shared_ptr<connection_metadata>;
 14  connection_metadata(int32_t id, websocketpp::connection_hdl hdl,
 15                      std::string uri)
 16      : m_id(id), m_hdl(hdl), m_status("Connecting"), m_uri(uri),
 17        m_server("N/A") {}
 18  void on_open(client *c, websocketpp::connection_hdl hdl) {
 19    m_status = "Open";
 20    client::connection_ptr con = c->get_con_from_hdl(hdl);
 21    m_server = con->get_response_header("Server");
 22
 23    // the type of con->get_response() is defined in
 24    // websocketpp/http/response.hpp
 25    assert(con->get_response().get_version() == "HTTP/1.1");
 26#if 0
 27    // header_list is a std::map<std::string, std::string>
 28    auto header_list = con->get_response().get_headers();
 29    for (const auto &it : header_list) {
 30      std::cout << it.first << ": " << it.second << "\n";
 31    }
 32    /*
 33    Connection: upgrade
 34    Date: Wed, 05 Oct 2022 11:33:39 GMT
 35    Sec-WebSocket-Accept: QvLQVaiZn5YWerU3s15SuDWypjo=
 36    Server: nginx
 37    Upgrade: websocket
 38     */
 39#endif
 40    assert(con->get_response().get_body() == "");
 41  }
 42
 43  void on_fail(client *c, websocketpp::connection_hdl hdl) {
 44    m_status = "Failed";
 45    client::connection_ptr con = c->get_con_from_hdl(hdl);
 46    m_server = con->get_response_header("Server");
 47    m_error_reason = con->get_ec().message();
 48  }
 49
 50  void on_close(client *c, websocketpp::connection_hdl hdl) {
 51    m_status = "Closed";
 52    client::connection_ptr con = c->get_con_from_hdl(hdl);
 53    std::ostringstream os;
 54    os << "close code: " << con->get_remote_close_code() << " ("
 55       << websocketpp::close::status::get_string(con->get_remote_close_code())
 56       << "), close reason: " << con->get_remote_close_reason();
 57    m_error_reason = os.str();
 58  }
 59
 60  websocketpp::connection_hdl get_hdl() const { return m_hdl; }
 61  int32_t get_id() const { return m_id; }
 62  const std::string &get_status() const { return m_status; }
 63
 64  friend std::ostream &operator<<(std::ostream &out,
 65                                  const connection_metadata &data);
 66
 67private:
 68  int32_t m_id;
 69  websocketpp::connection_hdl m_hdl;
 70  std::string m_status;
 71  std::string m_uri;
 72  std::string m_server;
 73  std::string m_error_reason;
 74};
 75
 76std::ostream &operator<<(std::ostream &out, const connection_metadata &data) {
 77  out << "> URI: " << data.m_uri << "\n"
 78      << "> Status: " << data.m_status << "> Remote Server: "
 79      << (data.m_server.empty() ? "None Specified" : data.m_server) << "\n"
 80      << "> Error/close reason: "
 81      << (data.m_error_reason.empty() ? "N/A" : data.m_error_reason);
 82  return out;
 83}
 84
 85class websocket_endpoint {
 86public:
 87  websocket_endpoint() : m_next_id(0) {
 88    m_endpoint.clear_access_channels(websocketpp::log::alevel::all);
 89    m_endpoint.clear_error_channels(websocketpp::log::elevel::all);
 90
 91    m_endpoint.init_asio();
 92    m_endpoint.start_perpetual();
 93
 94    m_thread.reset(new std::thread(&client::run, &m_endpoint));
 95  }
 96
 97  ~websocket_endpoint() {
 98    m_endpoint.stop_perpetual();
 99    for (auto it = m_connection_list.begin(); it != m_connection_list.end();
100         ++it) {
101      if (it->second->get_status() != "Open") {
102        continue;
103      }
104
105      std::cout << "> Closing connection " << it->second->get_id() << std::endl;
106      websocketpp::lib::error_code ec;
107      m_endpoint.close(it->second->get_hdl(),
108                       websocketpp::close::status::going_away, "", ec);
109      if (ec) {
110        std::cout << "> Error closing connection " << it->second->get_id()
111                  << ": " << ec.message() << std::endl;
112      }
113    }
114    m_thread->join();
115  }
116
117  int32_t connect(std::string uri) {
118    websocketpp::lib::error_code ec;
119    client::connection_ptr con = m_endpoint.get_connection(uri, ec);
120    if (ec) {
121      std::cout << "> Connect initialization error: " << ec.message()
122                << std::endl;
123      return -1;
124    }
125    int32_t new_id = m_next_id++;
126    connection_metadata::ptr metadata_ptr(
127        new connection_metadata(new_id, con->get_handle(), uri));
128    m_connection_list[new_id] = metadata_ptr;
129
130    // see websocketpp/connection.hpp
131    con->set_open_handler(
132        [metadata_ptr = metadata_ptr, this](websocketpp::connection_hdl hdl) {
133          metadata_ptr->on_open(&m_endpoint, hdl);
134        });
135
136    // see websocketpp/connection.hpp
137    con->set_fail_handler(
138        [metadata_ptr = metadata_ptr, this](websocketpp::connection_hdl hdl) {
139          metadata_ptr->on_fail(&m_endpoint, hdl);
140        });
141
142    con->set_close_handler(
143        [metadata_ptr = metadata_ptr, this](websocketpp::connection_hdl hdl) {
144          metadata_ptr->on_close(&m_endpoint, hdl);
145        });
146
147    m_endpoint.connect(con);
148
149    return new_id;
150  }
151
152  connection_metadata::ptr get_metadata(int32_t id) const {
153    auto metadata_it = m_connection_list.find(id);
154    if (metadata_it == m_connection_list.end()) {
155      return connection_metadata::ptr();
156    } else {
157      return metadata_it->second;
158    }
159  }
160
161  void close(int32_t id, websocketpp::close::status::value code,
162             const std::string &reason = "") {
163    websocketpp::lib::error_code ec;
164    auto metadata_it = m_connection_list.find(id);
165    if (metadata_it == m_connection_list.end()) {
166      std::cout << "> No connection found with id " << id << std::endl;
167      return;
168    }
169
170    m_endpoint.close(metadata_it->second->get_hdl(), code, reason, ec);
171    if (ec) {
172      std::cout << "> Error initiating close: " << ec.message() << std::endl;
173    }
174  }
175
176private:
177  client m_endpoint;
178  std::shared_ptr<std::thread> m_thread;
179  std::map<int32_t, connection_metadata::ptr> m_connection_list;
180  int32_t m_next_id;
181};
182
183void test_uri();
184
185int main() {
186  test_uri();
187  // return 0;
188
189  bool done = false;
190  std::string input;
191  websocket_endpoint endponit;
192
193  while (true) {
194    std::cout << "Enter command: ";
195    std::getline(std::cin, input);
196    if (input == "quit") {
197      done = true;
198    } else if (input == "help") {
199      std::cout << "\nCommand List:\n"
200                << "connect <ws uri>\n"
201                << "show <connection_id>\n"
202                << "close <connection_id> <close_code> <close_reason>\n"
203                << "help: Display the help and exit\n"
204                << "quit: Exit the program\n"
205                << "\n";
206    } else if (input.substr(0, 7) == "connect") {
207      int32_t id = endponit.connect(input.substr(8));
208      if (id != -1) {
209        std::cout << "Created connection with id " << id << "\n";
210      }
211    } else if (input.substr(0, 5) == "close") {
212      std::stringstream ss(input);
213      std::string cmd;
214      int32_t id;
215      int32_t close_code = websocketpp::close::status::normal;
216      std::string reason;
217      ss >> cmd >> id >> close_code;
218      std::getline(ss, reason);
219      endponit.close(id, close_code, reason);
220    } else if (input.substr(0, 4) == "show") {
221      int32_t id = atoi(input.substr(5).c_str());
222      connection_metadata::ptr metadata = endponit.get_metadata(id);
223      if (metadata) {
224        std::cout << *metadata << std::endl;
225      } else {
226        std::cout << "Unknown connection id " << id << std::endl;
227      }
228    } else {
229      std::cout << "Unrecognized command\n";
230    }
231    if (done)
232      break;
233  }
234  return 0;
235}
236// connect ws://websocket-echo.com
237// close 0 1001 example message
./code/hello/uri.cc
 1#include "websocketpp/uri.hpp"
 2#include <assert.h>
 3#include <iostream>
 4
 5static void check_valid_ipv4() {
 6  std::string s = "10.192.168.1";
 7  bool b = websocketpp::uri_helper::ipv4_literal(s.begin(), s.end());
 8  assert(b == true);
 9
10  s = "256.192.168.1";
11  b = websocketpp::uri_helper::ipv4_literal(s.begin(), s.end());
12  assert(b == false);
13}
14
15static void check_uri() {
16  websocketpp::uri uri("ws://localhost:81");
17  assert(uri.str() == "ws://localhost:81/");
18  assert(uri.get_valid() == true);
19  assert(uri.is_ipv6_literal() == false);
20  assert(uri.get_secure() == false);
21  assert(uri.get_scheme() == "ws");
22  assert(uri.get_host() == "localhost");
23  assert(uri.get_port() == 81);
24  assert(uri.get_port_str() == "81");
25  assert(uri.get_host_port() == "localhost:81");
26  assert(uri.get_authority() == "localhost:81");
27  assert(uri.get_resource() == "/");
28  assert(uri.get_query() == "");
29}
30
31static void check_uri2() {
32  websocketpp::uri uri("wss://localhost/foo/bar?hello=12");
33  assert(uri.str() == "wss://localhost/foo/bar?hello=12");
34  assert(uri.get_valid() == true);
35  assert(uri.is_ipv6_literal() == false);
36  assert(uri.get_secure() == true);
37  assert(uri.get_scheme() == "wss");
38  assert(uri.get_host() == "localhost");
39  assert(uri.get_port() == 443);
40  assert(uri.get_port_str() == "443");
41  assert(uri.get_host_port() == "localhost");
42  assert(uri.get_authority() == "localhost:443");
43  assert(uri.get_resource() == "/foo/bar?hello=12");
44  assert(uri.get_query() == "hello=12");
45}
46
47void test_uri() {
48  check_valid_ipv4();
49  check_uri();
50  check_uri2();
51}