From f54fb0669b39cc54885ba44ae846e7057d53401c Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Thu, 17 Dec 2015 07:29:51 -0500 Subject: [PATCH] more docs --- docs/manual.dox | 7 +- docs/tutorials.dox | 10 ++ tutorials/utility_client/utility_client.md | 103 ++++++++++----------- tutorials/utility_server/step1.cpp | 71 ++++++++++++++ tutorials/utility_server/step2.cpp | 82 ++++++++++++++++ 5 files changed, 219 insertions(+), 54 deletions(-) create mode 100644 docs/tutorials.dox create mode 100644 tutorials/utility_server/step1.cpp create mode 100644 tutorials/utility_server/step2.cpp diff --git a/docs/manual.dox b/docs/manual.dox index 34f5d2b..77e06f9 100644 --- a/docs/manual.dox +++ b/docs/manual.dox @@ -4,7 +4,7 @@ WebSocket++ is a C++ library that can be used to implement WebSocket functionali WebSocket++ does not intend to be used alone as a web application framework or full featured web services platform. As such the components, examples, and performance tuning are geared towards operation as a WebSocket client or server. There are some minimal convenience features that stray from this (for example the ability to respond to HTTP requests other than WebSocket Upgrades) but these are not the focus of the project. In particular WebSocket++ does not intend to implement any non-WebSocket related fallback options (ajax / long polling / comet / etc). -In order to remain compact and improve portability, the WebSocket++ project strives to reduce or eliminate external dependencies where possible and appropriate. WebSocket++ core has no dependencies other than the C++11 STL. For non-C++11 compilers the Boost libraries provide drop in polyfills for the C++11 functionality used. +In order to remain compact and improve portability, the WebSocket++ project strives to reduce or eliminate external dependencies where possible and appropriate. WebSocket++ core has no dependencies other than the C++11 standard library. For non-C++11 compilers the Boost libraries provide drop in polyfills for the C++11 functionality used. WebSocket++ implements a pluggable data transport component. The default component allows reduced functionality by using STL iostream or raw byte shuffling via reading and writing char buffers. This component has no non-STL dependencies and can be used in a C++11 environment without Boost. Also included is an Asio based transport component that provides full featured network client/server functionality. This component requires either Boost Asio or a C++11 compiler and standalone Asio. As an advanced option, WebSocket++ supports custom transport layers if you want to provide your own using another library. @@ -12,7 +12,10 @@ In order to accommodate the wide variety of use cases WebSocket++ has collected, - \subpage getting_started "Getting Started" - \subpage faq "FAQ" -- \subpage reference.handlers "Handler Reference" +- \subpage tutorials "Tutorials" +- \subpage md_changelog "Change Log / Version History" +- Reference + - \subpage reference.handlers "Handler Reference" */ diff --git a/docs/tutorials.dox b/docs/tutorials.dox new file mode 100644 index 0000000..8751e97 --- /dev/null +++ b/docs/tutorials.dox @@ -0,0 +1,10 @@ +/** \page tutorials Tutorials + +These tutorials are works in progress, some are more complete than others. + +- \subpage md_tutorials_utility_client_utility_client +- \subpage md_tutorials_utility_server_utility_server +- \subpage md_tutorials_broadcast_tutorial_broadcast_tutorial +- \subpage md_tutorials_chat_tutorial_chat_tutorial + +*/ diff --git a/tutorials/utility_client/utility_client.md b/tutorials/utility_client/utility_client.md index 1a25afb..696113d 100644 --- a/tutorials/utility_client/utility_client.md +++ b/tutorials/utility_client/utility_client.md @@ -61,7 +61,7 @@ Connections do not maintain a link back to their associated endpoint. Endpoints WebSocket++ endpoints are built by combining an endpoint role with an endpoint config. There are two different types of endpoint roles, one each for the client and server roles in a WebSocket session. This is a client tutorial so we will use the client role `websocketpp::client` which is provided by the `` header. -> ###### Terminology: Endpoint Config +> ##### Terminology: Endpoint Config > WebSocket++ endpoints have a group of settings that may be configured at compile time via the `config` template parameter. A config is a struct that contains types and static constants that are used to produce an endpoint with specific properties. Depending on which config is being used the endpoint will have different methods available and may have additional third party dependencies. The endpoint role takes a template parameter called `config` that is used to configure the behavior of endpoint at compile time. For this example we are going to use a default config provided by the library called `asio_client`, provided by ``. This is a client config that uses boost::asio to provide network transport and does not support TLS based security. Later on we will discuss how to introduce TLS based security into a WebSocket++ application, more about the other stock configs, and how to build your own custom configs. @@ -78,7 +78,7 @@ In addition to the new headers, boost::asio depends on the `boost_system` shared `clang++ step2.cpp -lboost_system` #### Code so far -```cpp +~~~{.cpp} #include #include @@ -110,8 +110,7 @@ int main() { return 0; } - -``` +~~~ ### Step 3 @@ -119,7 +118,7 @@ _Create endpoint wrapper object that handles initialization and setting up the b In order to process user input while network processing occurs in the background we are going to use a separate thread for the WebSocket++ processing loop. This leaves the main thread free to process foreground user input. In order to enable simple RAII style resource management for our thread and endpoint we will use a wrapper object that configures them both in its constructor. -> ###### Terminology: websocketpp::lib namespace +> ##### Terminology: websocketpp::lib namespace > WebSocket++ is designed to be used with a C++11 standard library. As this is not universally available in popular build systems the Boost libraries may be used as polyfills for the C++11 standard library in C++98 build environments. The `websocketpp::lib` namespace is used by the library and its associated examples to abstract away the distinctions between the two. `websocketpp::lib::shared_ptr` will evaluate to `std::shared_ptr` in a C++11 environment and `boost::shared_ptr` otherwise. > > This tutorial uses the `websocketpp::lib` wrappers because it doesn't know what the build environment of the reader is. For your applications, unless you are interested in similar portability, are free to use the boost or std versions of these types directly. @@ -129,21 +128,21 @@ In order to process user input while network processing occurs in the background Within the `websocket_endpoint` constructor several things happen: First, we set the endpoint logging behavior to silent by clearing all of the access and error logging channels. [TODO: link to more information about logging] -```cpp +~~~{.cpp} m_endpoint.clear_access_channels(websocketpp::log::alevel::all); m_endpoint.clear_error_channels(websocketpp::log::elevel::all); -``` +~~~ Next, we initialize the transport system underlying the endpoint and set it to perpetual mode. In perpetual mode the endpoint's processing loop will not exit automatically when it has no connections. This is important because we want this endpoint to remain active while our application is running and process requests for new WebSocket connections on demand as we need them. Both of these methods are specific to the asio transport. They will not be necessary or present in endpoints that use a non-asio config. -```cpp +~~~{.cpp} m_endpoint.init_asio(); m_endpoint.start_perpetual(); -``` +~~~ Finally, we launch a thread to run the `run` method of our client endpoint. While the endpoint is running it will process connection tasks (read and deliver incoming messages, frame and send outgoing messages, etc). Because it is running in perpetual mode, when there are no connections active it will wait for a new connection. -```cpp +~~~{.cpp} m_thread.reset(new websocketpp::lib::thread(&client::run, &m_endpoint)); -``` +~~~ #### Build @@ -163,7 +162,7 @@ Now that our client endpoint template is actually instantiated a few more linker #### Code so far -```cpp +~~~{.cpp} #include #include @@ -215,7 +214,7 @@ int main() { return 0; } -``` +~~~ ### Step 4 @@ -234,14 +233,14 @@ The `websocket_endpoint` object has gained some new data members and methods. It #### The connect method A new WebSocket connection is initiated via a three step process. First, a connection request is created by `endpoint::get_connection(uri)`. Next, the connection request is configured. Lastly, the connection request is submitted back to the endpoint via `endpoint::connect()` which adds it to the queue of new connections to make. -> ###### Terminology `connection_ptr` +> ##### Terminology `connection_ptr` > WebSocket++ keeps track of connection related resources using a reference counted shared pointer. The type of this pointer is `endpoint::connection_ptr`. A `connection_ptr` allows direct access to information about the connection and allows changing connection settings. Because of this direct access and their internal resource management role within the library it is not safe for end applications to use `connection_ptr` except in the specific circumstances detailed below. > > **When is it safe to use `connection_ptr`?** > - After `endpoint::get_connection(...)` and before `endpoint::connect()`: `get_connection` returns a `connection_ptr`. It is safe to use this pointer to configure your new connection. Once you submit the connection to `connect` you may no longer use the `connection_ptr` and should discard it immediately for optimal memory management. > - During a handler: WebSocket++ allows you to register hooks / callbacks / event handlers for specific events that happen during a connection's lifetime. During the invocation of one of these handlers the library guarantees that it is safe to use a `connection_ptr` for the connection associated with the currently running handler. -> ###### Terminology `connection_hdl` +> ##### Terminology `connection_hdl` > Because of the limited thread safety of the `connection_ptr` the library also provides a more flexible connection identifier, the `connection_hdl`. The `connection_hdl` has type `websocketpp::connection_hdl` and it is defined in ``. Note that unlike `connection_ptr` this is not dependent on the type or config of the endpoint. Code that simply stores or transmits `connection_hdl` but does not use them can include only the header above and can treat its hdls like values. > > Connection handles are not used directly. They are used by endpoint methods to identify the target of the desired action. For example, the endpoint method that sends a new message will take as a parameter the hdl of the connection to send the message to. @@ -267,15 +266,15 @@ A new WebSocket connection is initiated via a three step process. First, a conne If connection creation succeeds, the next sequential connection ID is generated and a `connection_metadata` object is inserted into the connection list under that ID. Initially the metadata object stores the connection ID, the `connection_hdl`, and the URI the connection was opened to. -```cpp +~~~{.cpp} int new_id = m_next_id++; metadata_ptr metadata(new connection_metadata(new_id, con->get_handle(), uri)); m_connection_list[new_id] = metadata; -``` +~~~ Next, the connection request is configured. For this step the only configuration we will do is setting up a few default handlers. Later on we will return and demonstrate some more detailed configuration that can happen here (setting user agents, origin, proxies, custom headers, subprotocols, etc). -> ###### Terminology: Registering handlers +> ##### Terminology: Registering handlers > WebSocket++ provides a number of execution points where you can register to have a handler run. Which of these points are available to your endpoint will depend on its config. TLS handlers will not exist on non-TLS endpoints for example. A complete list of handlers can be found at http://www.zaphoyd.com/websocketpp/manual/reference/handler-list. > > Handlers can be registered at the endpoint level and at the connection level. Endpoint handlers are copied into new connections as they are created. Changing an endpoint handler will affect only future connections. Handlers registered at the connection level will be bound to that specific connection only. @@ -292,14 +291,14 @@ In this example we are going to set connection specific handlers that are bound Lets look at the parameters being sent to bind in detail: -```cpp +~~~{.cpp} con->set_open_handler(websocketpp::lib::bind( &connection_metadata::on_open, metadata, &m_endpoint, websocketpp::lib::placeholders::_1 )); -``` +~~~ `&connection_metadata::on_open` is the address of the `on_open` member function of the `connection_metadata` class. `metadata_ptr` is a pointer to the `connection_metadata` object associated with this class. It will be used as the object on which the `on_open` member function will be called. `&m_endpoint` is the address of the endpoint in use. This parameter will be passed as-is to the `on_open` method. Lastly, `websocketpp::lib::placeholders::_1` is a placeholder indicating that the bound function should take one additional argument to be filled in at a later time. WebSocket++ will fill in this placeholder with the `connection_hdl` when it invokes the handler. @@ -315,7 +314,7 @@ The fail handler we registered, `connection_metadata::on_fail`, sets the status Two new commands have been set up. "connect [uri]" will pass the URI to the `websocket_endpoint` connect method and report an error or the connection ID of the new connection. "show [connection id]" will retrieve and print out the metadata associated with that connection. The help text has been updated accordingly. -```cpp +~~~{.cpp} } else if (input.substr(0,7) == "connect") { int id = endpoint.connect(input.substr(8)); if (id != -1) { @@ -331,7 +330,7 @@ Two new commands have been set up. "connect [uri]" will pass the URI to the `web std::cout << "> Unknown connection id " << id << std::endl; } } -``` +~~~ #### Build @@ -339,7 +338,7 @@ There are no changes to the build instructions from step 3 #### Run -``` +~~~ Enter Command: connect not a websocket uri > Connect initialization error: invalid uri Enter Command: show 0 @@ -358,11 +357,11 @@ Enter Command: show 1 > Status: Failed > Remote Server: Apache > Error/close reason: Invalid HTTP status. -``` +~~~ #### Code so far -```cpp +~~~{.cpp} #include #include @@ -525,7 +524,7 @@ int main() { return 0; } -``` +~~~ ### Step 5 @@ -535,7 +534,7 @@ This step adds a command that allows you to close a WebSocket connection and adj #### Getting connection close information out of WebSocket++ -> ###### Terminology: WebSocket close codes & reasons +> ##### Terminology: WebSocket close codes & reasons > The WebSocket close handshake involves an exchange of optional machine readable close codes and human readable reason strings. Each endpoint sends independent close details. The codes are short integers. The reasons are UTF8 text strings of at most 125 characters. More details about valid close code ranges and the meaning of each code can be found at https://tools.ietf.org/html/rfc6455#section-7.4 The `websocketpp::close::status` namespace contains named constants for all of the IANA defined close codes. It also includes free functions to determine whether a value is reserved or invalid and to convert a code to a human readable text representation. @@ -554,7 +553,7 @@ During the close handler call WebSocket++ connections offer the following method The `connection_metadata::on_close` method is added. This method retrieves the close code and reason from the closing handshake and stores it in the local error reason field. -```cpp +~~~{.cpp} void on_close(client * c, websocketpp::connection_hdl hdl) { m_status = "Closed"; client::connection_ptr con = c->get_con_from_hdl(hdl); @@ -564,7 +563,7 @@ void on_close(client * c, websocketpp::connection_hdl hdl) { << "), close reason: " << con->get_remote_close_reason(); m_error_reason = s.str(); } -``` +~~~ Similarly to `on_open` and `on_fail`, `websocket_endpoint::connect` registers this close handler when a new connection is made. @@ -572,7 +571,7 @@ Similarly to `on_open` and `on_fail`, `websocket_endpoint::connect` registers th This method starts by looking up the given connection ID in the connection list. Next a close request is sent to the connection's handle with the specified WebSocket close code. This is done by calling `endpoint::close`. This is a thread safe method that is used to asynchronously dispatch a close signal to the connection with the given handle. When the operation is complete the connection's close handler will be triggered. -```cpp +~~~{.cpp} void close(int id, websocketpp::close::status::value code) { websocketpp::lib::error_code ec; @@ -587,7 +586,7 @@ void close(int id, websocketpp::close::status::value code) { std::cout << "> Error initiating close: " << ec.message() << std::endl; } } -``` +~~~ #### Add close option to the command loop and help message @@ -595,7 +594,7 @@ A close option is added to the command loop. It takes a connection ID and option An entry is also added to the help system to describe how the new command may be used. -```cpp +~~~{.cpp} else if (input.substr(0,5) == "close") { std::stringstream ss(input); @@ -609,7 +608,7 @@ else if (input.substr(0,5) == "close") { endpoint.close(id, close_code, reason); } -``` +~~~ #### Close all outstanding connections in `websocket_endpoint` destructor @@ -617,7 +616,7 @@ Until now quitting the program left outstanding connections and the WebSocket++ The destructor for `websocket_endpoint` now stops perpetual mode (so the run thread exits after the last connection is closed) and iterates through the list of open connections and requests a clean close for each. Finally, the run thread is joined which causes the program to wait until those connection closes complete. -```cpp +~~~{.cpp} ~websocket_endpoint() { m_endpoint.stop_perpetual(); @@ -639,7 +638,7 @@ The destructor for `websocket_endpoint` now stops perpetual mode (so the run thr m_thread->join(); } -``` +~~~ #### Build @@ -647,7 +646,7 @@ There are no changes to the build instructions from step 4 #### Run -``` +~~~ Enter Command: connect ws://localhost:9002 > Created connection with id 0 Enter Command: close 0 1001 example message @@ -662,7 +661,7 @@ Enter Command: close 1 1006 > Error initiating close: Invalid close code used Enter Command: quit > Closing connection 1 -``` +~~~ ### Step 6 @@ -670,7 +669,7 @@ _Sending and receiving messages_ This step adds a command to send a message on a given connection and updates the show command to print a transcript of all sent and received messages for that connection. -> ###### Terminology: WebSocket message types (opcodes) +> ##### Terminology: WebSocket message types (opcodes) > WebSocket messages have types indicated by their opcode. The protocol currently specifies two different opcodes for data messages, text and binary. Text messages represent UTF8 text and will be validated as such. Binary messages represent raw binary bytes and are passed through directly with no validation. > > WebSocket++ provides the values `websocketpp::frame::opcode::text` and `websocketpp::frame::opcode::binary` that can be used to direct how outgoing messages should be sent and to check how incoming messages are formatted. @@ -698,7 +697,7 @@ The third overload, `connection_hdl hdl, message_ptr msg`, takes a WebSocket++ ` Like the close method, send will start by looking up the given connection ID in the connection list. Next a send request is sent to the connection's handle with the specified WebSocket message and the text opcode. Finally, we record the sent message with our connection metadata object so later our show connection command can print a list of messages sent. -```cpp +~~~{.cpp} void send(int id, std::string message) { websocketpp::lib::error_code ec; @@ -716,13 +715,13 @@ void send(int id, std::string message) { metadata_it->second->record_sent_message(message); } -``` +~~~ #### Add send option to the command loop and help message A send option is added to the command loop. It takes a connection ID and a text message to send. An entry is also added to the help system to describe how the new command may be used. -```cpp +~~~{.cpp} else if (input.substr(0,4) == "send") { std::stringstream ss(input); @@ -735,28 +734,28 @@ else if (input.substr(0,4) == "send") { endpoint.send(id, message); } -``` +~~~ #### Add glue to `connection_metadata` for storing sent messages In order to store messages sent on this connection some code is added to `connection_metadata`. This includes a new data member `std::vector m_messages` to keep track of all messages sent and received as well as a method for adding a sent message in that list: -```cpp +~~~{.cpp} void record_sent_message(std::string message) { m_messages.push_back(">> " + message); } -``` +~~~ Finally the connection metadata output operator is updated to also print a list of processed messages: -```cpp +~~~{.cpp} out << "> Messages Processed: (" << data.m_messages.size() << ") \n"; std::vector::const_iterator it; for (it = data.m_messages.begin(); it != data.m_messages.end(); ++it) { out << *it << "\n"; } -``` +~~~ #### Receiving Messages @@ -766,7 +765,7 @@ Messages are received by registering a message handler. This handler will be cal The message receiving behave that we are implementing will be to collect all messages sent and received and to print them in order when the show connection command is run. The sent messages are already being added to that list. Now we add a message handler that pushes received messages to the list as well. Text messages are pushed as-is. Binary messages are first converted to printable hexadecimal format. -```cpp +~~~{.cpp} void on_message(websocketpp::connection_hdl hdl, client::message_ptr msg) { if (msg->get_opcode() == websocketpp::frame::opcode::text) { m_messages.push_back(msg->get_payload()); @@ -774,18 +773,18 @@ void on_message(websocketpp::connection_hdl hdl, client::message_ptr msg) { m_messages.push_back(websocketpp::utility::to_hex(msg->get_payload())); } } -``` +~~~ In order to have this handler called when new messages are received we also register it with our connection. Note that unlike most other handlers, the message handler has two parameters and thus needs two placeholders. -```cpp +~~~{.cpp} con->set_message_handler(websocketpp::lib::bind( &connection_metadata::on_message, metadata_ptr, websocketpp::lib::placeholders::_1, websocketpp::lib::placeholders::_2 )); -``` +~~~ #### Build @@ -795,7 +794,7 @@ There are no changes to the build instructions from step 5 In this example run we are connecting to the WebSocket++ example echo_server. This server will repeat any message we send back to it. You can also try testing this with the echo server at `ws://echo.websocket.org` with similar results. -``` +~~~ Enter Command: connect ws://localhost:9002 > Created connection with id 0 Enter Command: send 0 example message @@ -807,7 +806,7 @@ Enter Command: show 0 > Messages Processed: (2) >> example message << example message -``` +~~~ ### Step 7 diff --git a/tutorials/utility_server/step1.cpp b/tutorials/utility_server/step1.cpp new file mode 100644 index 0000000..c0e4643 --- /dev/null +++ b/tutorials/utility_server/step1.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2015, Peter Thorson. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the WebSocket++ Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// **NOTE:** This file is a snapshot of the WebSocket++ utility server tutorial. +// Additional related material can be found in the tutorials/utility_server +// directory of the WebSocket++ repository. + +// The ASIO_STANDALONE define is necessary to use the standalone version of Asio. +// Remove if you are using Boost Asio. +#define ASIO_STANDALONE + +#include +#include + +#include + +typedef websocketpp::server server; + +class utility_server { +public: + utility_server() { + // Set logging settings + m_endpoint.set_error_channels(websocketpp::log::elevel::all); + m_endpoint.set_access_channels(websocketpp::log::alevel::all ^ websocketpp::log::alevel::frame_payload); + + // Initialize Asio + m_endpoint.init_asio(); + } + + void run() { + // Listen on port 9002 + m_endpoint.listen(9002); + + // Queues a connection accept operation + m_endpoint.start_accept(); + + // Start the Asio io_service run loop + m_endpoint.run(); + } +private: + server m_endpoint; +}; + +int main() { + utility_server s; + s.run(); + return 0; +} diff --git a/tutorials/utility_server/step2.cpp b/tutorials/utility_server/step2.cpp new file mode 100644 index 0000000..a2815bb --- /dev/null +++ b/tutorials/utility_server/step2.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2015, Peter Thorson. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the WebSocket++ Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// **NOTE:** This file is a snapshot of the WebSocket++ utility server tutorial. +// Additional related material can be found in the tutorials/utility_server +// directory of the WebSocket++ repository. + +// The ASIO_STANDALONE define is necessary to use the standalone version of Asio. +// Remove if you are using Boost Asio. +#define ASIO_STANDALONE + +#include +#include + +#include + +typedef websocketpp::server server; + +class utility_server { +public: + utility_server() { + // Set logging settings + m_endpoint.set_error_channels(websocketpp::log::elevel::all); + m_endpoint.set_access_channels(websocketpp::log::alevel::all ^ websocketpp::log::alevel::frame_payload); + + // Initialize Asio + m_endpoint.init_asio(); + + // Set the default message handler to the echo handler + m_endpoint.set_message_handler(std::bind( + &utility_server::echo_handler, this, + std::placeholders::_1, std::placeholders::_2 + )); + } + + void echo_handler(websocketpp::connection_hdl hdl, server::message_ptr msg) { + // write a new message + m_endpoint.send(hdl, msg->get_payload(), msg->get_opcode()); + } + + void run() { + // Listen on port 9002 + m_endpoint.listen(9002); + + // Queues a connection accept operation + m_endpoint.start_accept(); + + // Start the Asio io_service run loop + m_endpoint.run(); + } +private: + server m_endpoint; +}; + +int main() { + utility_server s; + s.run(); + return 0; +}