refactor: remove Boost dependency (#176)

- add the standalone ASIO as a replacement for Boost ASIO
- add Catch++ as a replacement for Boost Test framework
- remove dependency on Boost DateTime and Boost Lexical Cast
This commit is contained in:
Sepehr Laal 2017-09-10 12:01:26 -07:00 committed by Damien Arrachequesne
parent 6063cb1d61
commit af68bf3067
No known key found for this signature in database
GPG Key ID: 544D14663E7F7CF0
16 changed files with 250 additions and 288 deletions

6
.gitmodules vendored
View File

@ -4,3 +4,9 @@
[submodule "lib/rapidjson"]
path = lib/rapidjson
url = https://github.com/miloyip/rapidjson.git
[submodule "lib/asio"]
path = lib/asio
url = https://github.com/chriskohlhoff/asio.git
[submodule "lib/catch"]
path = lib/catch
url = https://github.com/philsquared/Catch.git

View File

@ -5,14 +5,13 @@ compiler:
before_install:
- sudo apt-get install clang git libssl-dev
- sudo add-apt-repository -y ppa:boost-latest/ppa
- sudo add-apt-repository -y ppa:kubuntu-ppa/backports
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test -y
- sudo apt-get update -yqq
- sudo apt-get install -y libboost1.55-dev libboost-system1.55-dev libboost-date-time1.55-dev libboost-random1.55-dev
- sudo apt-get install -y cmake g++-4.8
- sed -i -e 's/cmake_minimum_required(VERSION 3.1.0/cmake_minimum_required(VERSION 2.8.12/' ./CMakeLists.txt
script:
- cmake -D CMAKE_CXX_FLAGS=-std=c++11 .
- cmake -D CMAKE_CXX_FLAGS=-std=c++11 -D BUILD_UNIT_TESTS=ON .
- make
- make test
- make install

View File

@ -1,21 +0,0 @@
## Boost setup
1. Download boost from [boost.org](http://www.boost.org/).
1. Unpack boost to some place.
1. Run either .\bootstrap.bat (on Windows), or ./bootstrap.sh (on other operating systems) under boost folder.
## Boost build (Build the necessary subset only)
#### Windows (or other mainstream desktop platforms shall work too):
Run with following script will build the necessary subset:
```bash
bjam install --prefix="<your boost install folder>" --with-system --with-date_time --with-random link=static runtime-link=shared threading=multi
```
Optionally You can merge all output .lib files into a fat one,especially if you're not using cmake.
In output folder, run:
```bash
lib.exe /OUT:boost.lib *
```

View File

@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR)
PROJECT(sioclient)
option(BUILD_SHARED_LIBS "Build the shared library" OFF)
option(Boost_USE_STATIC_LIBS "Use Boost static version" ON)
option(BUILD_UNIT_TESTS "Builds unit tests target" OFF)
set(MAJOR 1)
set(MINOR 6)
@ -16,27 +16,32 @@ MESSAGE(SEND_ERROR "CMAKE_BUILD_TYPE must be either Release or Debug")
return()
endif()
set(BOOST_VER "1.55.0" CACHE STRING "boost version" )
set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME OFF)
find_package(Boost ${BOOST_VER} REQUIRED COMPONENTS system date_time random)
aux_source_directory(${CMAKE_CURRENT_LIST_DIR}/src ALL_SRC)
aux_source_directory(${CMAKE_CURRENT_LIST_DIR}/src/internal ALL_SRC)
file(GLOB ALL_HEADERS ${CMAKE_CURRENT_LIST_DIR}/src/*.h )
set(SIO_INCLUDEDIR ${CMAKE_CURRENT_LIST_DIR})
add_definitions(
# These will force ASIO to compile without Boost
-DBOOST_DATE_TIME_NO_LIB
-DBOOST_REGEX_NO_LIB
-DASIO_STANDALONE
# These will force WebsocketPP to compile with C++11
-D_WEBSOCKETPP_CPP11_STL_
-D_WEBSOCKETPP_CPP11_FUNCTIONAL_
)
add_library(sioclient ${ALL_SRC})
target_include_directories(sioclient PRIVATE ${Boost_INCLUDE_DIRS}
target_include_directories(sioclient PRIVATE
${CMAKE_CURRENT_LIST_DIR}/src
${CMAKE_CURRENT_LIST_DIR}/lib/websocketpp
${CMAKE_CURRENT_LIST_DIR}/lib/rapidjson/include
${CMAKE_CURRENT_LIST_DIR}/lib/asio/asio/include
)
set_property(TARGET sioclient PROPERTY CXX_STANDARD 11)
set_property(TARGET sioclient PROPERTY CXX_STANDARD_REQUIRED ON)
target_link_libraries(sioclient PRIVATE ${Boost_LIBRARIES})
if(BUILD_SHARED_LIBS)
set_target_properties(sioclient
PROPERTIES
@ -49,16 +54,17 @@ list(APPEND TARGET_LIBRARIES sioclient)
find_package(OpenSSL)
if(OPENSSL_FOUND)
add_library(sioclient_tls ${ALL_SRC})
target_include_directories(sioclient_tls PRIVATE ${Boost_INCLUDE_DIRS}
target_include_directories(sioclient_tls PRIVATE
${CMAKE_CURRENT_LIST_DIR}/src
${CMAKE_CURRENT_LIST_DIR}/lib/websocketpp
${CMAKE_CURRENT_LIST_DIR}/lib/rapidjson/include
${CMAKE_CURRENT_LIST_DIR}/lib/asio/asio/include
${OPENSSL_INCLUDE_DIR}
)
set_property(TARGET sioclient_tls PROPERTY CXX_STANDARD 11)
set_property(TARGET sioclient_tls PROPERTY CXX_STANDARD_REQUIRED ON)
target_link_libraries(sioclient_tls PRIVATE ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} )
target_link_libraries(sioclient_tls PRIVATE ${OPENSSL_LIBRARIES} )
target_compile_definitions(sioclient_tls PRIVATE -DSIO_TLS)
if(BUILD_SHARED_LIBS)
set_target_properties(sioclient_tls
@ -79,6 +85,8 @@ install(TARGETS ${TARGET_LIBRARIES}
DESTINATION "${CMAKE_CURRENT_LIST_DIR}/build/lib/${CMAKE_BUILD_TYPE}"
)
install(FILES ${Boost_LIBRARIES}
DESTINATION "${CMAKE_CURRENT_LIST_DIR}/build/lib/${CMAKE_BUILD_TYPE}"
)
if(BUILD_UNIT_TESTS)
message(STATUS "Building with unit test support.")
enable_testing()
add_subdirectory(test)
endif()

View File

@ -1,48 +1,13 @@
## Install
### With CMake
1. Install boost, see [Boost setup](#boost_setup) section.
2. Use `git clone --recurse-submodules https://github.com/socketio/socket.io-client-cpp.git` to clone your local repo.
3. Run `cmake -DBOOST_ROOT:STRING=<your boost install folder> -DBOOST_VER:STRING=<your boost version> ./`
4. Run `make install`(if makefile generated) or open generated project (if project file generated) to build.
5. Outputs is under `./build`, link with the all static libs under `./build/lib` and include headers under `./build/include` in your client code where you want to use it.
* If you're using boost without install,you can specify `boost include dir` and `boost lib dir` separately by:
```bash
cmake
-DBOOST_INCLUDEDIR=<your boost include folder>
-DBOOST_LIBRARYDIR=<your boost lib folder>
-DBOOST_VER:STRING=<your boost version>
./
```
* CMake didn't allow merging static libraries,but they're all copied to `./build/lib`, you can DIY if you like.
1. Use `git clone --recurse-submodules https://github.com/socketio/socket.io-client-cpp.git` to clone your local repo.
2. Run `cmake ./`
3. Run `make install`(if makefile generated) or open generated project (if project file generated) to build.
4. Outputs is under `./build`, link with the all static libs under `./build/lib` and include headers under `./build/include` in your client code where you want to use it.
### Without CMake
1. Install boost, see [Boost setup](#boost_setup) section.
2. Use `git clone --recurse-submodules https://github.com/socketio/socket.io-client-cpp.git` to clone your local repo.
3. Add `<your boost install folder>/include`,`./lib/websocketpp` and `./lib/rapidjson/include` to headers search path.
4. Include all files under `./src` in your project, add `sio_client.cpp`,`sio_socket.cpp`,`internal/sio_client_impl.cpp`, `internal/sio_packet.cpp` to source list.
5. Add `<your boost install folder>/lib` to library search path, add `boost.lib`(Win32) or `-lboost`(Other) link option.
6. Include `sio_client.h` in your client code where you want to use it.
## Boost setup
1. Download boost from [boost.org](http://www.boost.org/).
1. Unpack boost to some place.
1. Run either .\bootstrap.bat (on Windows), or ./bootstrap.sh (on other operating systems) under boost folder.
## Boost build (Build the necessary subset only)
Windows (or other mainstream desktop platforms shall work too):
The following script will build the necessary subset:
```bash
bjam install --prefix="<your boost install folder>" --with-system --with-date_time --with-random link=static runtime-link=shared threading=multi
```
Optionally You can merge all output .lib files into a fat one, especially if you're not using cmake.
In output folder, run:
```bash
lib.exe /OUT:boost.lib *
```
1. Use `git clone --recurse-submodules https://github.com/socketio/socket.io-client-cpp.git` to clone your local repo.
2. Add `./lib/asio/asio/include`, `./lib/websocketpp` and `./lib/rapidjson/include` to headers search path.
3. Include all files under `./src` in your project, add `sio_client.cpp`,`sio_socket.cpp`,`internal/sio_client_impl.cpp`, `internal/sio_packet.cpp` to source list.
4. Include `sio_client.h` in your client code where you want to use it.

1
lib/asio Submodule

@ -0,0 +1 @@
Subproject commit 230c0d2ae035c5ce1292233fcab03cea0d341264

1
lib/catch Submodule

@ -0,0 +1 @@
Subproject commit 9c07718b5f779bc1405f98ca6b5b693026f6eac7

@ -1 +1 @@
Subproject commit ac5d7ea5af9734de965688b54a7860259887b537
Subproject commit 378437aecdcb1dfe62096ffd5d944bf1f640ccc3

View File

@ -7,8 +7,9 @@
//
#include "sio_client_impl.h"
#include <functional>
#include <sstream>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <chrono>
#include <mutex>
#include <cmath>
// Comment this out to disable handshake logging to stdout
@ -18,7 +19,13 @@
#define LOG(x)
#endif
using boost::posix_time::milliseconds;
#if SIO_TLS
// If using Asio's SSL support, you will also need to add this #include.
// Source: http://think-async.com/Asio/asio-1.10.6/doc/asio/using.html
// #include <asio/ssl/impl/src.hpp>
#endif
using std::chrono::milliseconds;
using namespace std;
namespace sio
@ -43,18 +50,18 @@ namespace sio
m_client.init_asio();
// Bind the clients we are using
using websocketpp::lib::placeholders::_1;
using websocketpp::lib::placeholders::_2;
m_client.set_open_handler(lib::bind(&client_impl::on_open,this,_1));
m_client.set_close_handler(lib::bind(&client_impl::on_close,this,_1));
m_client.set_fail_handler(lib::bind(&client_impl::on_fail,this,_1));
m_client.set_message_handler(lib::bind(&client_impl::on_message,this,_1,_2));
using std::placeholders::_1;
using std::placeholders::_2;
m_client.set_open_handler(std::bind(&client_impl::on_open,this,_1));
m_client.set_close_handler(std::bind(&client_impl::on_close,this,_1));
m_client.set_fail_handler(std::bind(&client_impl::on_fail,this,_1));
m_client.set_message_handler(std::bind(&client_impl::on_message,this,_1,_2));
#if SIO_TLS
m_client.set_tls_init_handler(lib::bind(&client_impl::on_tls_init,this,_1));
m_client.set_tls_init_handler(std::bind(&client_impl::on_tls_init,this,_1));
#endif
m_packet_mgr.set_decode_callback(lib::bind(&client_impl::on_decode,this,_1));
m_packet_mgr.set_decode_callback(std::bind(&client_impl::on_decode,this,_1));
m_packet_mgr.set_encode_callback(lib::bind(&client_impl::on_encode,this,_1,_2));
m_packet_mgr.set_encode_callback(std::bind(&client_impl::on_encode,this,_1,_2));
}
client_impl::~client_impl()
@ -103,8 +110,8 @@ namespace sio
m_http_headers = headers;
this->reset_states();
m_client.get_io_service().dispatch(lib::bind(&client_impl::connect_impl,this,uri,m_query_string));
m_network_thread.reset(new thread(lib::bind(&client_impl::run_loop,this)));//uri lifecycle?
m_client.get_io_service().dispatch(std::bind(&client_impl::connect_impl,this,uri,m_query_string));
m_network_thread.reset(new thread(std::bind(&client_impl::run_loop,this)));//uri lifecycle?
}
@ -142,14 +149,14 @@ namespace sio
{
m_con_state = con_closing;
this->sockets_invoke_void(&sio::socket::close);
m_client.get_io_service().dispatch(lib::bind(&client_impl::close_impl, this,close::status::normal,"End by user"));
m_client.get_io_service().dispatch(std::bind(&client_impl::close_impl, this,close::status::normal,"End by user"));
}
void client_impl::sync_close()
{
m_con_state = con_closing;
this->sockets_invoke_void(&sio::socket::close);
m_client.get_io_service().dispatch(lib::bind(&client_impl::close_impl, this,close::status::normal,"End by user"));
m_client.get_io_service().dispatch(std::bind(&client_impl::close_impl, this,close::status::normal,"End by user"));
if(m_network_thread)
{
m_network_thread->join();
@ -173,7 +180,7 @@ namespace sio
}
}
boost::asio::io_service& client_impl::get_io_service()
asio::io_service& client_impl::get_io_service()
{
return m_client.get_io_service();
}
@ -274,11 +281,11 @@ namespace sio
}
}
void client_impl::ping(const boost::system::error_code& ec)
void client_impl::ping(const asio::error_code& ec)
{
if(ec || m_con.expired())
{
if (ec != boost::asio::error::operation_aborted)
if (ec != asio::error::operation_aborted)
LOG("ping exit,con is expired?"<<m_con.expired()<<",ec:"<<ec.message()<<endl){};
return;
}
@ -290,30 +297,30 @@ namespace sio
});
if(m_ping_timer)
{
boost::system::error_code e_code;
asio::error_code e_code;
m_ping_timer->expires_from_now(milliseconds(m_ping_interval), e_code);
m_ping_timer->async_wait(lib::bind(&client_impl::ping,this,lib::placeholders::_1));
m_ping_timer->async_wait(std::bind(&client_impl::ping,this, std::placeholders::_1));
}
if(!m_ping_timeout_timer)
{
m_ping_timeout_timer.reset(new boost::asio::deadline_timer(m_client.get_io_service()));
boost::system::error_code timeout_ec;
m_ping_timeout_timer.reset(new asio::steady_timer(m_client.get_io_service()));
std::error_code timeout_ec;
m_ping_timeout_timer->expires_from_now(milliseconds(m_ping_timeout), timeout_ec);
m_ping_timeout_timer->async_wait(lib::bind(&client_impl::timeout_pong, this,lib::placeholders::_1));
m_ping_timeout_timer->async_wait(std::bind(&client_impl::timeout_pong, this, std::placeholders::_1));
}
}
void client_impl::timeout_pong(const boost::system::error_code &ec)
void client_impl::timeout_pong(const asio::error_code &ec)
{
if(ec)
{
return;
}
LOG("Pong timeout"<<endl);
m_client.get_io_service().dispatch(lib::bind(&client_impl::close_impl, this,close::status::policy_violation,"Pong timeout"));
m_client.get_io_service().dispatch(std::bind(&client_impl::close_impl, this,close::status::policy_violation,"Pong timeout"));
}
void client_impl::timeout_reconnect(boost::system::error_code const& ec)
void client_impl::timeout_reconnect(asio::error_code const& ec)
{
if(ec)
{
@ -326,7 +333,7 @@ namespace sio
this->reset_states();
LOG("Reconnecting..."<<endl);
if(m_reconnecting_listener) m_reconnecting_listener();
m_client.get_io_service().dispatch(lib::bind(&client_impl::connect_impl,this,m_base_url,m_query_string));
m_client.get_io_service().dispatch(std::bind(&client_impl::connect_impl,this,m_base_url,m_query_string));
}
}
@ -374,10 +381,10 @@ namespace sio
LOG("Reconnect for attempt:"<<m_reconn_made<<endl);
unsigned delay = this->next_delay();
if(m_reconnect_listener) m_reconnect_listener(m_reconn_made,delay);
m_reconn_timer.reset(new boost::asio::deadline_timer(m_client.get_io_service()));
boost::system::error_code ec;
m_reconn_timer.reset(new asio::steady_timer(m_client.get_io_service()));
asio::error_code ec;
m_reconn_timer->expires_from_now(milliseconds(delay), ec);
m_reconn_timer->async_wait(lib::bind(&client_impl::timeout_reconnect,this,lib::placeholders::_1));
m_reconn_timer->async_wait(std::bind(&client_impl::timeout_reconnect,this, std::placeholders::_1));
}
else
{
@ -432,10 +439,10 @@ namespace sio
LOG("Reconnect for attempt:"<<m_reconn_made<<endl);
unsigned delay = this->next_delay();
if(m_reconnect_listener) m_reconnect_listener(m_reconn_made,delay);
m_reconn_timer.reset(new boost::asio::deadline_timer(m_client.get_io_service()));
boost::system::error_code ec;
m_reconn_timer.reset(new asio::steady_timer(m_client.get_io_service()));
asio::error_code ec;
m_reconn_timer->expires_from_now(milliseconds(delay), ec);
m_reconn_timer->async_wait(lib::bind(&client_impl::timeout_reconnect,this,lib::placeholders::_1));
m_reconn_timer->async_wait(std::bind(&client_impl::timeout_reconnect,this, std::placeholders::_1));
return;
}
reason = client::close_reason_drop;
@ -450,9 +457,9 @@ namespace sio
void client_impl::on_message(connection_hdl, client_type::message_ptr msg)
{
if (m_ping_timeout_timer) {
boost::system::error_code ec;
asio::error_code ec;
m_ping_timeout_timer->expires_from_now(milliseconds(m_ping_timeout),ec);
m_ping_timeout_timer->async_wait(lib::bind(&client_impl::timeout_pong, this,lib::placeholders::_1));
m_ping_timeout_timer->async_wait(std::bind(&client_impl::timeout_pong, this, std::placeholders::_1));
}
// Parse the incoming message according to socket.IO rules
m_packet_mgr.put_payload(msg->get_payload());
@ -490,17 +497,17 @@ namespace sio
m_ping_timeout = 60000;
}
m_ping_timer.reset(new boost::asio::deadline_timer(m_client.get_io_service()));
boost::system::error_code ec;
m_ping_timer.reset(new asio::steady_timer(m_client.get_io_service()));
asio::error_code ec;
m_ping_timer->expires_from_now(milliseconds(m_ping_interval), ec);
if(ec)LOG("ec:"<<ec.message()<<endl){};
m_ping_timer->async_wait(lib::bind(&client_impl::ping,this,lib::placeholders::_1));
m_ping_timer->async_wait(std::bind(&client_impl::ping,this, std::placeholders::_1));
LOG("On handshake,sid:"<<m_sid<<",ping interval:"<<m_ping_interval<<",ping timeout"<<m_ping_timeout<<endl);
return;
}
failed:
//just close it.
m_client.get_io_service().dispatch(lib::bind(&client_impl::close_impl, this,close::status::policy_violation,"Handshake error"));
m_client.get_io_service().dispatch(std::bind(&client_impl::close_impl, this,close::status::policy_violation,"Handshake error"));
}
void client_impl::on_pong()
@ -541,13 +548,13 @@ failed:
void client_impl::on_encode(bool isBinary,shared_ptr<const string> const& payload)
{
LOG("encoded payload length:"<<payload->length()<<endl);
m_client.get_io_service().dispatch(lib::bind(&client_impl::send_impl,this,payload,isBinary?frame::opcode::binary:frame::opcode::text));
m_client.get_io_service().dispatch(std::bind(&client_impl::send_impl,this,payload,isBinary?frame::opcode::binary:frame::opcode::text));
}
void client_impl::clear_timers()
{
LOG("clear timers"<<endl);
boost::system::error_code ec;
asio::error_code ec;
if(m_ping_timeout_timer)
{
m_ping_timeout_timer->cancel(ec);
@ -570,11 +577,11 @@ failed:
#if SIO_TLS
client_impl::context_ptr client_impl::on_tls_init(connection_hdl conn)
{
context_ptr ctx = context_ptr(new boost::asio::ssl::context(boost::asio::ssl::context::tlsv1));
boost::system::error_code ec;
ctx->set_options(boost::asio::ssl::context::default_workarounds |
boost::asio::ssl::context::no_sslv2 |
boost::asio::ssl::context::single_dh_use,ec);
context_ptr ctx = context_ptr(new asio::ssl::context(asio::ssl::context::tlsv1));
asio::error_code ec;
ctx->set_options(asio::ssl::context::default_workarounds |
asio::ssl::context::no_sslv2 |
asio::ssl::context::single_dh_use,ec);
if(ec)
{
cerr<<"Init tls failed,reason:"<< ec.message()<<endl;

View File

@ -4,7 +4,6 @@
#include <cstdint>
#ifdef _WIN32
#define _WEBSOCKETPP_CPP11_THREAD_
#define BOOST_ALL_NO_LIB
//#define _WEBSOCKETPP_CPP11_RANDOM_DEVICE_
#define _WEBSOCKETPP_NO_CPP11_FUNCTIONAL_
#define INTIALIZER(__TYPE__)
@ -30,7 +29,14 @@ typedef websocketpp::config::asio_tls_client client_config;
typedef websocketpp::config::asio_client client_config;
#endif //SIO_TLS
#endif //DEBUG
#include <boost/asio/deadline_timer.hpp>
#if SIO_TLS
#include <asio/ssl/context.hpp>
#endif
#include <asio/steady_timer.hpp>
#include <asio/error_code.hpp>
#include <asio/io_service.hpp>
#include <memory>
#include <map>
@ -122,7 +128,7 @@ namespace sio
void remove_socket(std::string const& nsp);
boost::asio::io_service& get_io_service();
asio::io_service& get_io_service();
void on_socket_closed(std::string const& nsp);
@ -137,11 +143,11 @@ namespace sio
void send_impl(std::shared_ptr<const std::string> const& payload_ptr,frame::opcode::value opcode);
void ping(const boost::system::error_code& ec);
void ping(const asio::error_code& ec);
void timeout_pong(const boost::system::error_code& ec);
void timeout_pong(const asio::error_code& ec);
void timeout_reconnect(boost::system::error_code const& ec);
void timeout_reconnect(asio::error_code const& ec);
unsigned next_delay() const;
@ -171,7 +177,7 @@ namespace sio
void clear_timers();
#if SIO_TLS
typedef websocketpp::lib::shared_ptr<boost::asio::ssl::context> context_ptr;
typedef websocketpp::lib::shared_ptr<asio::ssl::context> context_ptr;
context_ptr on_tls_init(connection_hdl con);
#endif
@ -195,11 +201,11 @@ namespace sio
packet_manager m_packet_mgr;
std::unique_ptr<boost::asio::deadline_timer> m_ping_timer;
std::unique_ptr<asio::steady_timer> m_ping_timer;
std::unique_ptr<boost::asio::deadline_timer> m_ping_timeout_timer;
std::unique_ptr<asio::steady_timer> m_ping_timeout_timer;
std::unique_ptr<boost::asio::deadline_timer> m_reconn_timer;
std::unique_ptr<asio::steady_timer> m_reconn_timer;
con_state m_con_state;

View File

@ -9,7 +9,6 @@
#include <rapidjson/encodedstream.h>
#include <rapidjson/writer.h>
#include <cassert>
#include <boost/lexical_cast.hpp>
#define kBIN_PLACE_HOLDER "_placeholder"
@ -288,7 +287,7 @@ namespace sio
pos++;
if (_type == type_binary_event || _type == type_binary_ack) {
size_t score_pos = payload_ptr.find('-');
_pending_buffers = boost::lexical_cast<unsigned>(payload_ptr.substr(pos,score_pos - pos));
_pending_buffers = static_cast<unsigned>(std::stoul(payload_ptr.substr(pos, score_pos - pos)));
pos = score_pos+1;
}
}
@ -328,7 +327,7 @@ namespace sio
if(pos<json_pos)//we've got pack id.
{
_pack_id = boost::lexical_cast<int>(payload_ptr.substr(pos,json_pos - pos));
_pack_id = std::stoi(payload_ptr.substr(pos,json_pos - pos));
}
if (_frame == frame_message && (_type == type_binary_event || _type == type_binary_ack)) {
//parse later when all buffers are arrived.

View File

@ -8,7 +8,6 @@
#include "internal/sio_client_impl.h"
using namespace websocketpp;
using boost::posix_time::milliseconds;
using std::stringstream;
namespace sio

View File

@ -1,10 +1,12 @@
#include "sio_socket.h"
#include "internal/sio_packet.h"
#include "internal/sio_client_impl.h"
#include <boost/asio/deadline_timer.hpp>
#include <boost/system/error_code.hpp>
#include <asio/steady_timer.hpp>
#include <asio/error_code.hpp>
#include <queue>
#include <chrono>
#include <cstdarg>
#include <functional>
#if DEBUG || _DEBUG
#define LOG(x) std::cout << x
@ -157,7 +159,7 @@ namespace sio
void ack(int msgId,string const& name,message::list const& ack_message);
void timeout_connection(const boost::system::error_code &ec);
void timeout_connection(const asio::error_code &ec);
void send_connect();
@ -178,7 +180,7 @@ namespace sio
error_listener m_error_listener;
std::unique_ptr<boost::asio::deadline_timer> m_connection_timer;
std::unique_ptr<asio::steady_timer> m_connection_timer;
std::queue<packet> m_packet_queue;
@ -273,9 +275,9 @@ namespace sio
}
packet p(packet::type_connect,m_nsp);
m_client->send(p);
m_connection_timer.reset(new boost::asio::deadline_timer(m_client->get_io_service()));
boost::system::error_code ec;
m_connection_timer->expires_from_now(boost::posix_time::milliseconds(20000), ec);
m_connection_timer.reset(new asio::steady_timer(m_client->get_io_service()));
asio::error_code ec;
m_connection_timer->expires_from_now(std::chrono::milliseconds(20000), ec);
m_connection_timer->async_wait(std::bind(&socket::impl::timeout_connection,this, std::placeholders::_1));
}
@ -289,11 +291,11 @@ namespace sio
if(!m_connection_timer)
{
m_connection_timer.reset(new boost::asio::deadline_timer(m_client->get_io_service()));
m_connection_timer.reset(new asio::steady_timer(m_client->get_io_service()));
}
boost::system::error_code ec;
m_connection_timer->expires_from_now(boost::posix_time::milliseconds(3000), ec);
m_connection_timer->async_wait(lib::bind(&socket::impl::on_close, this));
asio::error_code ec;
m_connection_timer->expires_from_now(std::chrono::milliseconds(3000), ec);
m_connection_timer->async_wait(std::bind(&socket::impl::on_close, this));
}
}
@ -475,7 +477,7 @@ namespace sio
if(m_error_listener)m_error_listener(err_message);
}
void socket::impl::timeout_connection(const boost::system::error_code &ec)
void socket::impl::timeout_connection(const asio::error_code &ec)
{
NULL_GUARD(m_client);
if(ec)

View File

@ -1,9 +1,9 @@
cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR)
include(${CMAKE_CURRENT_SOURCE_DIR}/../CMakeLists.txt)
find_package(Boost ${BOOST_VER} REQUIRED COMPONENTS unit_test_framework)
add_executable(sio_test sio_test.cpp)
set_property(TARGET sio_test PROPERTY CXX_STANDARD 11)
set_property(TARGET sio_test PROPERTY CXX_STANDARD_REQUIRED ON)
target_link_libraries(sioclient PRIVATE ${Boost_LIBRARIES})
target_link_libraries(sio_test sioclient)
target_include_directories(sio_test PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../src" ${Boost_INCLUDE_DIRS} )
target_include_directories(sio_test PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/../lib/catch/include"
"${CMAKE_CURRENT_SOURCE_DIR}/../src"
)
add_test(sioclient_test sio_test)

View File

@ -1,18 +0,0 @@
You need have your boost unpacked on your disk, at least staged following modules:
* system
* date_time
* random
* unit_test_framework
Then use following instruction to gen makefile or VS project.
```bash
cmake -DBOOST_LIBRARYDIR=`<your boost static libs path>` -DBOOST_INCLUDEDIR=`<your boost include path>` -DBOOST_VER:STRING=`<your boost version>` -DCMAKE_BUILD_TYPE=Debug ./
```
Then run `make` or open by VS.
For example I've installed boost 1.57.0 at `D:\boost_1_57_0` and staged the static lib at `D\boost_1_57_0\build\lib` then the command should be:
```bash
cmake -DBOOST_LIBRARYDIR=D:\boost_1_57_0\build\lib -DBOOST_INCLUDEDIR=D:\boost_1_57_0 -DBOOST_VER:STRING=1.57.0 -DCMAKE_BUILD_TYPE=Debug ./
```
In this case(Windows) CMake will create a VS project under `./test` folder. Open in VS and run it.

View File

@ -10,65 +10,66 @@
#include <iostream>
#include <thread>
#define BOOST_TEST_MODULE sio_test
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file
#include "catch.hpp"
#include <boost/test/unit_test.hpp>
#ifndef _WIN32
#include "json.hpp" //nlohmann::json cannot build in MSVC
#endif
using namespace sio;
BOOST_AUTO_TEST_SUITE(test_packet)
BOOST_AUTO_TEST_CASE( test_packet_construct_1 )
TEST_CASE( "test_packet_construct_1" )
{
packet p("/nsp",nullptr,1001,true);
BOOST_CHECK(p.get_frame() == packet::frame_message);
BOOST_CHECK(p.get_message() == nullptr);
BOOST_CHECK(p.get_nsp() == std::string("/nsp"));
BOOST_CHECK(p.get_pack_id() == 1001);
CHECK(p.get_frame() == packet::frame_message);
CHECK(p.get_message() == nullptr);
CHECK(p.get_nsp() == std::string("/nsp"));
CHECK(p.get_pack_id() == 1001);
}
BOOST_AUTO_TEST_CASE( test_packet_construct_2 )
TEST_CASE( "test_packet_construct_2" )
{
packet p(packet::frame_ping);
BOOST_CHECK(p.get_frame() == packet::frame_ping);
BOOST_CHECK(p.get_message() == nullptr);
BOOST_CHECK(p.get_nsp() == std::string(""));
BOOST_CHECK(p.get_pack_id() == 0xFFFFFFFF);
CHECK(p.get_frame() == packet::frame_ping);
CHECK(p.get_message() == nullptr);
CHECK(p.get_nsp() == std::string(""));
CHECK(p.get_pack_id() == 0xFFFFFFFF);
}
BOOST_AUTO_TEST_CASE( test_packet_construct_3 )
TEST_CASE( "test_packet_construct_3" )
{
packet p(packet::type_connect,"/nsp",nullptr);
BOOST_CHECK(p.get_frame() == packet::frame_message);
BOOST_CHECK(p.get_type() == packet::type_connect);
BOOST_CHECK(p.get_message() == nullptr);
BOOST_CHECK(p.get_nsp() == std::string("/nsp"));
BOOST_CHECK(p.get_pack_id() == 0xFFFFFFFF);
CHECK(p.get_frame() == packet::frame_message);
CHECK(p.get_type() == packet::type_connect);
CHECK(p.get_message() == nullptr);
CHECK(p.get_nsp() == std::string("/nsp"));
CHECK(p.get_pack_id() == 0xFFFFFFFF);
}
BOOST_AUTO_TEST_CASE( test_packet_accept_1 )
TEST_CASE( "test_packet_accept_1" )
{
packet p(packet::type_connect,"/nsp",nullptr);
std::string payload;
std::vector<std::shared_ptr<const std::string> > buffers;
p.accept(payload,buffers);
BOOST_CHECK(buffers.size() == 0);
BOOST_CHECK_MESSAGE(payload == "40/nsp",std::string("outputing payload:")+payload);
CHECK(buffers.size() == 0);
CHECK(payload == "40/nsp");
INFO("outputing payload:" << payload)
}
BOOST_AUTO_TEST_CASE( test_packet_accept_2 )
TEST_CASE( "test_packet_accept_2" )
{
packet p(packet::frame_ping);
std::string payload;
std::vector<std::shared_ptr<const std::string> > buffers;
p.accept(payload,buffers);
BOOST_CHECK(buffers.size() == 0);
BOOST_CHECK_MESSAGE(payload == "2",std::string("outputing payload:")+payload);
CHECK(buffers.size() == 0);
CHECK(payload == "2");
INFO("outputing payload:" << payload)
}
BOOST_AUTO_TEST_CASE( test_packet_accept_3 )
TEST_CASE( "test_packet_accept_3" )
{
message::ptr array = array_message::create();
array->get_vector().push_back(string_message::create("event"));
@ -77,13 +78,14 @@ BOOST_AUTO_TEST_CASE( test_packet_accept_3 )
std::string payload;
std::vector<std::shared_ptr<const std::string> > buffers;
p.accept(payload,buffers);
BOOST_CHECK(p.get_type() == packet::type_ack);
BOOST_CHECK(buffers.size() == 0);
BOOST_CHECK_MESSAGE(payload == "43/nsp,1001[\"event\",\"text\"]",std::string("outputing payload:")+payload);
CHECK(p.get_type() == packet::type_ack);
CHECK(buffers.size() == 0);
CHECK(payload == "43/nsp,1001[\"event\",\"text\"]");
INFO("outputing payload:" << payload)
}
#ifndef _WIN32
BOOST_AUTO_TEST_CASE( test_packet_accept_4 )
TEST_CASE( "test_packet_accept_4" )
{
message::ptr binObj = object_message::create();
binObj->get_map()["desc"] = string_message::create("Bin of 100 bytes");
@ -98,132 +100,138 @@ BOOST_AUTO_TEST_CASE( test_packet_accept_4 )
std::string payload;
std::vector<std::shared_ptr<const std::string> > buffers;
p.accept(payload,buffers);
BOOST_CHECK(p.get_type() == packet::type_binary_event);
BOOST_REQUIRE(buffers.size() == 2);
CHECK(p.get_type() == packet::type_binary_event);
REQUIRE(buffers.size() == 2);
size_t json_start = payload.find("{");
BOOST_REQUIRE(json_start!=std::string::npos);
REQUIRE(json_start!=std::string::npos);
std::string header = payload.substr(0,json_start);
BOOST_CHECK_MESSAGE(header=="452-/nsp,1001",std::string("outputing payload header:")+header);
CHECK(header=="452-/nsp,1001");
INFO("outputing payload:" << payload)
std::string json = payload.substr(json_start);
nlohmann::json j = nlohmann::json::parse(json);
BOOST_CHECK_MESSAGE(j["desc"].get<std::string>() == "Bin of 100 bytes", std::string("outputing payload desc:") + j["desc"].get<std::string>());
BOOST_CHECK_MESSAGE((bool)j["bin1"]["_placeholder"] , std::string("outputing payload bin1:") + j["bin1"].dump());
BOOST_CHECK_MESSAGE((bool)j["bin2"]["_placeholder"] , std::string("outputing payload bin2:") + j["bin2"].dump());
CHECK(j["desc"].get<std::string>() == "Bin of 100 bytes");
INFO("outputing payload desc::" << j["desc"].get<std::string>())
CHECK((bool)j["bin1"]["_placeholder"]);
INFO("outputing payload bin1:" << j["bin1"].dump())
CHECK((bool)j["bin2"]["_placeholder"]);
INFO("outputing payload bin2:" << j["bin2"].dump())
int bin1Num = j["bin1"]["num"].get<int>();
char numchar[] = {0,0};
numchar[0] = bin1Num+'0';
BOOST_CHECK_MESSAGE(buffers[bin1Num]->length()==101 , std::string("outputing payload bin1 num:")+numchar);
BOOST_CHECK(buffers[bin1Num]->at(50)==0 && buffers[bin1Num]->at(0) == packet::frame_message);
CHECK(buffers[bin1Num]->length()==101);
INFO("outputing payload bin1 num:" << numchar)
CHECK(buffers[bin1Num]->at(50)==0);
CHECK(buffers[bin1Num]->at(0) == packet::frame_message);
int bin2Num = j["bin2"]["num"].get<int>();
numchar[0] = bin2Num+'0';
BOOST_CHECK_MESSAGE(buffers[bin2Num]->length()==51 , std::string("outputing payload bin2 num:") + numchar);
BOOST_CHECK(buffers[bin2Num]->at(25)==1 && buffers[bin2Num]->at(0) == packet::frame_message);
CHECK(buffers[bin2Num]->length()==51);
INFO("outputing payload bin2 num:" << numchar)
CHECK(buffers[bin2Num]->at(25)==1);
CHECK(buffers[bin2Num]->at(0) == packet::frame_message);
}
#endif
BOOST_AUTO_TEST_CASE( test_packet_parse_1 )
TEST_CASE( "test_packet_parse_1" )
{
packet p;
bool hasbin = p.parse("42/nsp,1001[\"event\",\"text\"]");
BOOST_CHECK(!hasbin);
BOOST_CHECK(p.get_frame() == packet::frame_message);
BOOST_CHECK(p.get_type() == packet::type_event);
BOOST_CHECK(p.get_nsp() == "/nsp");
BOOST_CHECK(p.get_pack_id() == 1001);
BOOST_CHECK(p.get_message()->get_flag() == message::flag_array);
BOOST_REQUIRE(p.get_message()->get_vector()[0]->get_flag() == message::flag_string);
BOOST_CHECK(p.get_message()->get_vector()[0]->get_string() == "event");
BOOST_REQUIRE(p.get_message()->get_vector()[1]->get_flag() == message::flag_string);
BOOST_CHECK(p.get_message()->get_vector()[1]->get_string() == "text");
CHECK(!hasbin);
CHECK(p.get_frame() == packet::frame_message);
CHECK(p.get_type() == packet::type_event);
CHECK(p.get_nsp() == "/nsp");
CHECK(p.get_pack_id() == 1001);
CHECK(p.get_message()->get_flag() == message::flag_array);
REQUIRE(p.get_message()->get_vector()[0]->get_flag() == message::flag_string);
CHECK(p.get_message()->get_vector()[0]->get_string() == "event");
REQUIRE(p.get_message()->get_vector()[1]->get_flag() == message::flag_string);
CHECK(p.get_message()->get_vector()[1]->get_string() == "text");
hasbin = p.parse("431111[\"ack\",{\"count\":5}]");
BOOST_CHECK(!hasbin);
BOOST_CHECK(p.get_frame() == packet::frame_message);
BOOST_CHECK(p.get_type() == packet::type_ack);
BOOST_CHECK(p.get_pack_id() == 1111);
BOOST_CHECK(p.get_nsp() == "/");
BOOST_CHECK(p.get_message()->get_flag() == message::flag_array);
BOOST_REQUIRE(p.get_message()->get_vector()[0]->get_flag() == message::flag_string);
BOOST_CHECK(p.get_message()->get_vector()[0]->get_string() == "ack");
BOOST_REQUIRE(p.get_message()->get_vector()[1]->get_flag() == message::flag_object);
BOOST_CHECK(p.get_message()->get_vector()[1]->get_map()["count"]->get_int() == 5);
CHECK(!hasbin);
CHECK(p.get_frame() == packet::frame_message);
CHECK(p.get_type() == packet::type_ack);
CHECK(p.get_pack_id() == 1111);
CHECK(p.get_nsp() == "/");
CHECK(p.get_message()->get_flag() == message::flag_array);
REQUIRE(p.get_message()->get_vector()[0]->get_flag() == message::flag_string);
CHECK(p.get_message()->get_vector()[0]->get_string() == "ack");
REQUIRE(p.get_message()->get_vector()[1]->get_flag() == message::flag_object);
CHECK(p.get_message()->get_vector()[1]->get_map()["count"]->get_int() == 5);
}
BOOST_AUTO_TEST_CASE( test_packet_parse_2 )
TEST_CASE( "test_packet_parse_2" )
{
packet p;
bool hasbin = p.parse("3");
BOOST_CHECK(!hasbin);
BOOST_CHECK(p.get_frame() == packet::frame_pong);
BOOST_CHECK(!p.get_message());
BOOST_CHECK(p.get_nsp() == "/");
BOOST_CHECK(p.get_pack_id() == -1);
CHECK(!hasbin);
CHECK(p.get_frame() == packet::frame_pong);
CHECK(!p.get_message());
CHECK(p.get_nsp() == "/");
CHECK(p.get_pack_id() == -1);
hasbin = p.parse("2");
BOOST_CHECK(!hasbin);
BOOST_CHECK(p.get_frame() == packet::frame_ping);
BOOST_CHECK(!p.get_message());
BOOST_CHECK(p.get_nsp() == "/");
BOOST_CHECK(p.get_pack_id() == -1);
CHECK(!hasbin);
CHECK(p.get_frame() == packet::frame_ping);
CHECK(!p.get_message());
CHECK(p.get_nsp() == "/");
CHECK(p.get_pack_id() == -1);
}
BOOST_AUTO_TEST_CASE( test_packet_parse_3 )
TEST_CASE( "test_packet_parse_3" )
{
packet p;
bool hasbin = p.parse("40/nsp");
BOOST_CHECK(!hasbin);
BOOST_CHECK(p.get_type() == packet::type_connect);
BOOST_CHECK(p.get_frame() == packet::frame_message);
BOOST_CHECK(p.get_nsp() == "/nsp");
BOOST_CHECK(p.get_pack_id() == -1);
BOOST_CHECK(!p.get_message());
CHECK(!hasbin);
CHECK(p.get_type() == packet::type_connect);
CHECK(p.get_frame() == packet::frame_message);
CHECK(p.get_nsp() == "/nsp");
CHECK(p.get_pack_id() == -1);
CHECK(!p.get_message());
p.parse("40");
BOOST_CHECK(p.get_type() == packet::type_connect);
BOOST_CHECK(p.get_nsp() == "/");
BOOST_CHECK(p.get_pack_id() == -1);
BOOST_CHECK(!p.get_message());
CHECK(p.get_type() == packet::type_connect);
CHECK(p.get_nsp() == "/");
CHECK(p.get_pack_id() == -1);
CHECK(!p.get_message());
p.parse("44\"error\"");
BOOST_CHECK(p.get_type() == packet::type_error);
BOOST_CHECK(p.get_nsp() == "/");
BOOST_CHECK(p.get_pack_id() == -1);
BOOST_CHECK(p.get_message()->get_flag() == message::flag_string);
CHECK(p.get_type() == packet::type_error);
CHECK(p.get_nsp() == "/");
CHECK(p.get_pack_id() == -1);
CHECK(p.get_message()->get_flag() == message::flag_string);
p.parse("44/nsp,\"error\"");
BOOST_CHECK(p.get_type() == packet::type_error);
BOOST_CHECK(p.get_nsp() == "/nsp");
BOOST_CHECK(p.get_pack_id() == -1);
BOOST_CHECK(p.get_message()->get_flag() == message::flag_string);
CHECK(p.get_type() == packet::type_error);
CHECK(p.get_nsp() == "/nsp");
CHECK(p.get_pack_id() == -1);
CHECK(p.get_message()->get_flag() == message::flag_string);
}
BOOST_AUTO_TEST_CASE( test_packet_parse_4 )
TEST_CASE( "test_packet_parse_4" )
{
packet p;
bool hasbin = p.parse("452-/nsp,101[\"bin_event\",[{\"_placeholder\":true,\"num\":1},{\"_placeholder\":true,\"num\":0},\"text\"]]");
BOOST_CHECK(hasbin);
CHECK(hasbin);
char buf[101];
buf[0] = packet::frame_message;
memset(buf+1,0,100);
std::string bufstr(buf,101);
std::string bufstr2(buf,51);
BOOST_CHECK(p.parse_buffer(bufstr));
BOOST_CHECK(!p.parse_buffer(bufstr2));
CHECK(p.parse_buffer(bufstr));
CHECK(!p.parse_buffer(bufstr2));
BOOST_CHECK(p.get_frame() == packet::frame_message);
BOOST_CHECK(p.get_nsp() == "/nsp");
BOOST_CHECK(p.get_pack_id() == 101);
CHECK(p.get_frame() == packet::frame_message);
CHECK(p.get_nsp() == "/nsp");
CHECK(p.get_pack_id() == 101);
message::ptr msg = p.get_message();
BOOST_REQUIRE(msg&&msg->get_flag() == message::flag_array);
BOOST_CHECK(msg->get_vector()[0]->get_string() == "bin_event");
REQUIRE(msg);
REQUIRE(msg->get_flag() == message::flag_array);
CHECK(msg->get_vector()[0]->get_string() == "bin_event");
message::ptr array = msg->get_vector()[1];
BOOST_REQUIRE(array->get_flag() == message::flag_array);
BOOST_REQUIRE(array->get_vector()[0]->get_flag() == message::flag_binary);
BOOST_REQUIRE(array->get_vector()[1]->get_flag() == message::flag_binary);
BOOST_REQUIRE(array->get_vector()[2]->get_flag() == message::flag_string);
BOOST_CHECK(array->get_vector()[0]->get_binary()->size() == 50);
BOOST_CHECK(array->get_vector()[1]->get_binary()->size() == 100);
BOOST_CHECK(array->get_vector()[2]->get_string() == "text");
REQUIRE(array->get_flag() == message::flag_array);
REQUIRE(array->get_vector()[0]->get_flag() == message::flag_binary);
REQUIRE(array->get_vector()[1]->get_flag() == message::flag_binary);
REQUIRE(array->get_vector()[2]->get_flag() == message::flag_string);
CHECK(array->get_vector()[0]->get_binary()->size() == 50);
CHECK(array->get_vector()[1]->get_binary()->size() == 100);
CHECK(array->get_vector()[2]->get_string() == "text");
}
BOOST_AUTO_TEST_SUITE_END()