WebSocket++
0.8.3-dev
C++ websocket client/server library
|
Yes, but not globally.
Handlers assigned to endpoints will be automatically copied to the connections created by that endpoint. Changing a handler on an endpoint will only affect future connections.
Once a particular connection is created, it's handlers can be changed individually by calling the set_*_handler
methods. Once changed, all future events of that type for that connection will use the new handler.
To remove a handler that was previously set, call the set method with nullptr
or NULL
.
Yes. The validate
handler is called after the initial handshake has been recieved but before WebSocket++ has responded. This gives you the opportunity to inspect the incoming connection request, its headers, origin, subprotocols, and the remote endpoint IP. Return true
from the validate handler to accept the connection and false
to reject it.
To set a custom HTTP error message for your rejection, use websocketpp::connection::set_status
and (optionally) websocketpp::connection::set_body()
to set the HTTP status code and error message body text. If you do not set body text a message will be generated automatically based on the status code.
WebSocket connections may offer a particular subprotocol they want to use. The WebSocket protocol does not define the meaning or interpretation of the subprotocol. This interpretation is left up to the individual application endpoints.
WebSocket++ servers can read the requested subprotocols during the validate
handler by calling websocketpp::connection::get_requested_subprotocols
. The list is ordered by client priority. You may optionally choose one of these subprotocols with websocketpp::connection::select_subprotocol
. The handshake will then complete and let the client know which one was chosen. If you do not choose any, the "blank"/empty/none subprotocol will be used.
WebSocket++ clients can add a subprotocol to an outgoing connection by calling websocketpp::connection::add_subprotocol
before calling websocketpp::client::connect
. The order of adding will be interpreted as the order of preference.
In both caases, after the connection has been established, the selected subprotocol is available via the websocketpp::connection::get_subprotocol
method.
Note: some browsers will allow the connection to continue if they requested a subprotocol and your server doesn't select one. Others will reject the connection.
The Asio transport based clients and servers use the Asio library's underlying io_service
to handle asyncronous networking operations. The standard behavior of the io_service is to run until there are no async operations left and then return. WebSocket++, when using the Asio transport, behaves like a standard Asio application. If you want your WebSocket++/Asio based program to stop network operations and cleanly close all sockets you will want to do the following:
websocketpp::transport::asio::endpoint::stop_listening
to initiate the closing of the server listening socket.websocketpp::transport::asio::endpoint::start_perpetual
, disable it with websocketpp::transport::asio::endpoint::stop_perpetual
.websocketpp::endpoint::close
or websocketpp::connection::close
on all currently outstanding connections. This will initiate the WebSocket closing handshake for these connectionsio_service::run
method will exit cleanly and automatically when all operations are complete.WARNING: Asio's io_service
has a method called stop
. WebSocket++ wraps this method as websocketpp::transport::asio::endpoint::stop
. While this operation has a benign sounding name, it is a powerful and destructive operation that should only be used in special cases. If you are using io_service::stop
or endpoint::stop
without a very good reason your program is likely broken and may exhibit erratic behavior. Specifically, io_service::stop
stops the processing of events entirely. This does not give current operations (such as socket closing handshakes) the opportunity to finish. It will leave your sockets in a dangling state that may invoke operating system level timeouts or other errors.
Special cases:
start_perpetual
method it will prevent the io_service from exiting even if it has nothing to do. This is useful if you want a client endpoint to idle in the background to allow new connections to be formed on demand rather than generating a new endpoint for each.io_service
those operations may keep the io_service
open even after all WebSocket++ operations have completed.poll
/poll_one
/run_one
or otherwise manually driving the io_service
event loop you may need to adjust usage to make sure you are correctly recognizing the "done with work" and "not done but idling / `io_service::work`" cases.Sometimes, not generally though, because there isn’t a way to check if a TCP connection is valid.
You can try upgrading your hdl to a full connection_ptr using websocketpp::endpoint::get_con_from_hdl
. If this fails, the hdl is definitely invalid. If it succeeds it may or may not be. The only way to tell definitively is to try and send something (either a message or a ping).
If you handle errors from methods like send, ping, close, etc correctly then you shouldn’t have to worry about accidentally sending to dead connections. The send/ping/pong/close methods will set or throw a specific error in the case that you tried to send something but the connection was closed/gone/etc.
Normally, for security purposes, operating systems prevent programs from listening on sockets created by other programs. When your program crashes and restarts, the new instance is a different program from the perspective of the operating system. As such it can’t listen on the socket address/port that the previous program was using until after a timeout occurs to make sure the old program was done with it.
The first step for handling this is to make sure that you provide a method (signal handler, admin websocket message, etc) to perform a clean server shutdown. There is a question elsewhere in this FAQ that describes the steps necessary for this.
The clean close strategy won't help in the case of crashes or other abnormal closures. An option to consider for these cases is the use of the SO_REUSEADDR socket option. This instructs the OS to not request an exclusive lock on the socket. This means that after your program crashes the replacement you start can immediately listen on that address/port combo again.
Please note: how this works exactly depends on your operating system. Additionally, not exclusively locking your listening socket could allow hijacking by other programs if you are running in a shared resource environment. For development this is generally no problem. For a production environment, think carefully about the security model. websocketpp::transport::asio::endpoint::set_reuse_addr
is the method to do this. You must specify this setting before calling websocketpp::transport::asio::endpoint::listen
.
When supported by the remote endpoint, WebSocket++ allows reading and sending messages in the two formats specified in RFC6455, UTF8 text and binary. WebSocket++ performs UTF8 validation on all outgoing text messages to ensure that they meet the specification. Binary messages do not have any additional processing and their interpretation is left entirely to the library user.
To determine the type of an incoming message, use websocketpp::message_buffer::message::get_opcode
. The relevant return values are websocketpp::frame::opcode::text
and websocketpp::frame::opcode::binary
. There is no difference in how payloads are retrieved between these modes, only in how WebSocket++ validated the contents and how the library user is to interpret the data.
To specify the type of an outgoing message, use the frame opcode values listed above as the second op parameter for websocketpp::connection::send
. There are two relevant overloads of send. One that takes a std::string
and defaults to op=text. The other that takes a void const *
and a size_t
length and defaults to op=binary. Note: You can send binary messages via the string overload and text messages via the void * overload. In the case that you are manually building a message buffer rather than using the automatic send member functions, you can pass the opcode in as a parameter to the message buffer constructor or user the websocketpp::message_buffer::message::set_opcode
member function to set or re-set it later.
Yes. WebSocket++ only uses Boost features as polyfills for C++11 language features and libraries. If you have a C++11 compiler and standard library you can use WebSocket++ without Boost. In most cases setting your build environment to use the C++11 (or later) language dialect is sufficient to enable this mode of use.
With less common compilers (and sometimes very recently release compilers) there may be specific issues with certain libraries that aren't automatically detected by the library. For these situations there are additional defines available to fine tune which C++11 libraries and features are used. TODO: more details about them.
For the iostream/raw transport the C++11 standard library is sufficient. For the Asio based transports, there is no C++11 library that provides the networking capabilaties that Asio does. As such even with a C++11 build system, you will need a standalone copy of Asio to use if Boost Asio is not available.
MinGW users who want to avoid Boost should also consult the nearby question about MinGW compatibility.
Yes. The process is the same as used with standalone Asio itself. Define ASIO_STANDALONE
before including Asio or WebSocket++ headers. You will need to download a copy of the Asio headers separately (http://www.think-async.com) and make sure they are in your build system's include path.
Yes. When using the iostream/raw transport, there are no TLS features and OpenSSL is not required. When using the Asio transport TLS features are optional. You only need OpenSSL if you want to use TLS. You can only make or recieve encrypted connections (https/wss) if you have enabled TLS features.
Whether an Asio endpoint uses TLS or not is determined by its config template parameter. The default bundled websocketpp::config::asio
and websocketpp::config::asio_client
configs do not support TLS, the websocketpp::config::asio_tls
and websocketpp::config::asio_tls_client
do.
The <websocketpp/config/asio.hpp>
and <websocketpp/config/asio_client.hpp>
headers will include both the TLS and non-TLS varients of their respective configs and require the presence of OpenSSL. The <websocketpp/config/asio_no_tls.hpp>
and <websocketpp/config/asio_no_tls_client.hpp>
headers will include only the non-TLS configs and do not require OpenSSL.
Mac OS X ships a severely outdated version of the OpenSSL library. To securely use TLS with WebSocket++ on OS X you will need to install a modern version of OpenSSL via homebrew or compiling from source.
Generally, yes. Note that in C++11 mode MinGW does not currently support the C++11 STL <thread>
library. WebSocket++ requires a thread/mutex library. Options include Boost thread (the default when a compatible C++11 <thread>
can't be found) or mingw-std-threads
(https://github.com/meganz/mingw-std-threads) by including those headers and defining _WEBSOCKETPP_MINGW_THREAD_
.
These versions of the library require a custom config to use the permessage-deflate extension. Here is a minimal example of such a custom config. You can also integrate these lines into an existing custom config.
Note that in these versions there is no fine grained control over which connections are compressed or not. Clients will request compression with the default settings and use it if the server supports it. Servers will accept whatever parameters clients request.
Outgoing messages by default will be compressed if compression was auto-negotiated during the handshake. There is an option to force a specific message to be sent uncompressed even if compression was negotiated. This may be useful for sending data that you know to be compressed already (images, zip files, etc).
Server Example
Client Example
Yes. The library will automatically detect and terminate connections that violate the WebSocket protocol. In cases where the library believes the remote endpoint to be malicious or sufficiently broken to be unlikely to understand or process the closing handshake, it will be omited.
If your application detects conditions above the protocol level that you believe to be malicious, for example, if you recognize an IP from a known denial of service attack, you can close the connection with two different levels of urgency. Use the standard websocketpp::endpoint::close
or websocketpp::connection::close
methods with one of the following special close codes:
websocketpp::close::status::omit_handshake
: Omits the closing handshake, but cleanly closes the TCP connection.websocketpp::close::status::force_tcp_drop
: Forcibly drop the TCP connection.Please note that usage of these disconnect methods results in a violation of the WebSocket protocol and may have negative reprocusions for the remote endpoint with respect to network timeouts. Please use caution when using them.
Your build system may be confused about whether it is supposed to be using boost::chrono
or std::chrono
. Boost automatically detects this setup on some compilers but not others. Defining BOOST_ASIO_HAS_STD_CHRONO
can help. See http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/overview/cpp2011/chrono.html for more details.