Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 51a692ffcc | |||
| 0195101f31 | |||
| 37d611e267 | |||
| 9d585b635e | |||
| 3770302154 | |||
| e5b87e66bc | |||
| 186ae090c6 | |||
| ec28725873 | |||
| 4f7470840e | |||
| 6c6977e48f | |||
| 23501149e0 | |||
| 511930ac89 |
@@ -1,18 +0,0 @@
|
||||
# Lineendings
|
||||
*.sln eol=crlf
|
||||
*.vcproj eol=crlf
|
||||
*.vcxproj* eol=crlf
|
||||
|
||||
# Whitespace rules
|
||||
# strict (no trailing, no tabs)
|
||||
*.cpp whitespace=trailing-space,space-before-tab,tab-in-indent,cr-at-eol
|
||||
*.hpp whitespace=trailing-space,space-before-tab,tab-in-indent,cr-at-eol
|
||||
*.c whitespace=trailing-space,space-before-tab,tab-in-indent,cr-at-eol
|
||||
*.h whitespace=trailing-space,space-before-tab,tab-in-indent,cr-at-eol
|
||||
|
||||
# normal (no trailing)
|
||||
*.sql whitespace=trailing-space,space-before-tab,cr-at-eol
|
||||
*.txt whitespace=trailing-space,space-before-tab,cr-at-eol
|
||||
|
||||
# special files which must ignore whitespace
|
||||
*.patch whitespace=-trailing-space
|
||||
+3
-55
@@ -1,7 +1,3 @@
|
||||
# make .git* files visible to git
|
||||
!.gitignore
|
||||
!.gitattributes
|
||||
|
||||
.DS_Store
|
||||
|
||||
#vim stuff
|
||||
@@ -10,32 +6,10 @@
|
||||
|
||||
*.o
|
||||
*.so
|
||||
*.so.?
|
||||
*.so.?.?.?
|
||||
*.a
|
||||
*.dylib
|
||||
lib/*
|
||||
|
||||
# CMake
|
||||
*.cmake
|
||||
*.dir
|
||||
CMakeFiles
|
||||
INSTALL.*
|
||||
ZERO_CHECK.*
|
||||
CMakeCache.txt
|
||||
install_manifest.txt
|
||||
|
||||
# Windows/Visual Studio
|
||||
*.vcproj*
|
||||
*.sln
|
||||
*.suo
|
||||
*.ncb
|
||||
*/Debug/*
|
||||
*/*/Debug/*
|
||||
*/Release/*
|
||||
*/*/Release/*
|
||||
*/RelWithDebInfo/*
|
||||
*/*/RelWithDebInfo/*
|
||||
*.dylib.?.?.?
|
||||
|
||||
objs_shared/
|
||||
objs_static/
|
||||
@@ -44,37 +18,11 @@ examples/chat_server/chat_server
|
||||
examples/echo_server/echo_server
|
||||
examples/chat_client/chat_client
|
||||
examples/echo_client/echo_client
|
||||
|
||||
test/basic/tests
|
||||
libwebsocketpp.dylib.0.1.0
|
||||
|
||||
websocketpp.xcodeproj/xcuserdata/*
|
||||
websocketpp.xcodeproj/project.xcworkspace/xcuserdata/*
|
||||
policy_based_notes.hpp
|
||||
|
||||
examples/echo_server_tls/echo_server_tls
|
||||
|
||||
examples/fuzzing_client/fuzzing_client
|
||||
|
||||
examples/stress_client/stress_client
|
||||
|
||||
examples/broadcast_server_tls/broadcast_server
|
||||
|
||||
test/basic/perf
|
||||
|
||||
examples/echo_server_tls/echo_server_tls
|
||||
|
||||
examples/concurrent_server/concurrent_server
|
||||
|
||||
examples/fuzzing_server_tls/fuzzing_server
|
||||
|
||||
examples/wsperf/wsperf
|
||||
|
||||
.sconsign.dblite
|
||||
|
||||
build/
|
||||
doxygen/
|
||||
examples/wsperf/wsperf_client
|
||||
|
||||
*.out
|
||||
|
||||
*.log
|
||||
examples/echo_server/echo_server_old
|
||||
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
language: cpp
|
||||
compiler:
|
||||
- gcc
|
||||
before_install:
|
||||
- sudo apt-get install libboost-regex1.48-dev libboost-system1.48-dev libboost-thread1.48-dev libboost-test1.48-dev libboost-random1.48-dev -y
|
||||
env:
|
||||
global:
|
||||
- BOOST_INCLUDES=/usr/include
|
||||
- BOOST_LIBS=/usr/lib
|
||||
script: scons -j 2 && scons test
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- permessage-deflate
|
||||
- experimental
|
||||
- 0.3.x-cmake
|
||||
notifications:
|
||||
recipients:
|
||||
- travis@zaphoyd.com
|
||||
email:
|
||||
on_success: change
|
||||
on_failure: always
|
||||
-237
@@ -1,237 +0,0 @@
|
||||
|
||||
############ Setup project and cmake
|
||||
|
||||
# Project name
|
||||
project (websocketpp)
|
||||
|
||||
# Minimum cmake requirement. We should require a quite recent
|
||||
# cmake for the dependency find macros etc. to be up to date.
|
||||
cmake_minimum_required (VERSION 2.6)
|
||||
|
||||
set (WEBSOCKETPP_MAJOR_VERSION 0)
|
||||
set (WEBSOCKETPP_MINOR_VERSION 3)
|
||||
set (WEBSOCKETPP_PATCH_VERSION 0)
|
||||
set (WEBSOCKETPP_VERSION ${WEBSOCKETPP_MAJOR_VERSION}.${WEBSOCKETPP_MINOR_VERSION}.${WEBSOCKETPP_PATCH_VERSION})
|
||||
|
||||
set(INSTALL_INCLUDE_DIR include CACHE PATH "Installation directory for header files")
|
||||
if (WIN32 AND NOT CYGWIN)
|
||||
set (DEF_INSTALL_CMAKE_DIR cmake)
|
||||
else ()
|
||||
set (DEF_INSTALL_CMAKE_DIR lib/cmake/websocketpp)
|
||||
endif ()
|
||||
set (INSTALL_CMAKE_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE PATH "Installation directory for CMake files")
|
||||
|
||||
# Make relative paths absolute (needed later on)
|
||||
foreach (p INCLUDE CMAKE)
|
||||
set (var INSTALL_${p}_DIR)
|
||||
if (NOT IS_ABSOLUTE "${${var}}")
|
||||
set (${var} "${CMAKE_INSTALL_PREFIX}/${${var}}")
|
||||
endif ()
|
||||
endforeach ()
|
||||
|
||||
# Set CMake library search policy
|
||||
if (COMMAND cmake_policy)
|
||||
cmake_policy (SET CMP0003 NEW)
|
||||
cmake_policy (SET CMP0005 NEW)
|
||||
endif ()
|
||||
|
||||
# Disable unnecessary build types
|
||||
set (CMAKE_CONFIGURATION_TYPES "Release;RelWithDebInfo;Debug" CACHE STRING "Configurations" FORCE)
|
||||
|
||||
# Include our cmake macros
|
||||
set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
|
||||
include (CMakeHelpers)
|
||||
|
||||
############ Paths
|
||||
|
||||
set (WEBSOCKETPP_ROOT ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
set (WEBSOCKETPP_INCLUDE ${WEBSOCKETPP_ROOT}/websocketpp)
|
||||
set (WEBSOCKETPP_BUILD_ROOT ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set (WEBSOCKETPP_BIN ${WEBSOCKETPP_BUILD_ROOT}/bin)
|
||||
set (WEBSOCKETPP_LIB ${WEBSOCKETPP_BUILD_ROOT}/lib)
|
||||
|
||||
# CMake install step prefix. I assume linux users want the prefix to
|
||||
# be the default /usr or /usr/local so this is only adjusted on Windows.
|
||||
# - Windows: Build the INSTALL project in your solution file.
|
||||
# - Linux/OSX: make install.
|
||||
if (MSVC)
|
||||
set (CMAKE_INSTALL_PREFIX "${WEBSOCKETPP_ROOT}/install")
|
||||
endif ()
|
||||
|
||||
############ Build customization
|
||||
|
||||
# Override from command line "CMake -D<OPTION>=TRUE/FALSE/0/1/ON/OFF"
|
||||
option (ENABLE_CPP11 "Build websocketpp with CPP11 features enabled." TRUE)
|
||||
option (BUILD_EXAMPLES "Build websocketpp examples." FALSE)
|
||||
option (BUILD_TESTS "Build websocketpp tests." FALSE)
|
||||
|
||||
if (BUILD_TESTS OR BUILD_EXAMPLES)
|
||||
|
||||
############ Compiler specific setup
|
||||
|
||||
set (WEBSOCKETPP_PLATFORM_LIBS "")
|
||||
set (WEBSOCKETPP_PLATFORM_TSL_LIBS "")
|
||||
set (WEBSOCKETPP_BOOST_LIBS "")
|
||||
|
||||
# VC9 and C++11 reasoning
|
||||
if (ENABLE_CPP11 AND MSVC AND MSVC90)
|
||||
message("* Detected Visual Studio 9 2008, disabling C++11 support.")
|
||||
set (ENABLE_CPP11 FALSE)
|
||||
endif ()
|
||||
|
||||
# Detect clang. Not officially reported by cmake.
|
||||
execute_process(COMMAND "${CMAKE_CXX_COMPILER}" "-v" ERROR_VARIABLE CXX_VER_STDERR)
|
||||
if ("${CXX_VER_STDERR}" MATCHES ".*clang.*")
|
||||
set (CMAKE_COMPILER_IS_CLANGXX 1)
|
||||
endif ()
|
||||
|
||||
# C++11 defines
|
||||
if (ENABLE_CPP11)
|
||||
add_definitions (-D_WEBSOCKETPP_CPP11_STL_)
|
||||
endif ()
|
||||
|
||||
# Visual studio
|
||||
if (MSVC)
|
||||
set (WEBSOCKETPP_BOOST_LIBS system thread)
|
||||
set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /GL /Gy /GF /Ox /Ob2 /Ot /Oi /MP /arch:SSE2 /fp:fast")
|
||||
set (CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG /INCREMENTAL:NO /OPT:REF /OPT:ICF")
|
||||
add_definitions (/W3 /wd4996 /wd4995 /wd4355)
|
||||
add_definitions (-DUNICODE -D_UNICODE)
|
||||
add_definitions (-D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS)
|
||||
add_definitions (-DNOMINMAX)
|
||||
endif ()
|
||||
|
||||
# g++
|
||||
if (CMAKE_COMPILER_IS_GNUCXX)
|
||||
set (WEBSOCKETPP_PLATFORM_LIBS pthread rt)
|
||||
set (WEBSOCKETPP_PLATFORM_TSL_LIBS ssl crypto)
|
||||
set (WEBSOCKETPP_BOOST_LIBS system thread)
|
||||
set (CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-std=c++0x")
|
||||
if (NOT APPLE)
|
||||
add_definitions (-DNDEBUG -Wall -Wcast-align) # todo: should we use CMAKE_C_FLAGS for these?
|
||||
endif ()
|
||||
|
||||
# Try to detect version. Note: Not tested!
|
||||
execute_process (COMMAND ${CMAKE_CXX_COMPILER} "-dumpversion" OUTPUT_VARIABLE GCC_VERSION)
|
||||
if ("${GCC_VERSION}" STRGREATER "4.4.0")
|
||||
message("* C++11 support partially enabled due to GCC version ${GCC_VERSION}")
|
||||
set (WEBSOCKETPP_BOOST_LIBS system thread)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
# clang
|
||||
if (CMAKE_COMPILER_IS_CLANGXX)
|
||||
if (NOT APPLE)
|
||||
set (WEBSOCKETPP_PLATFORM_LIBS pthread rt)
|
||||
else()
|
||||
set (WEBSOCKETPP_PLATFORM_LIBS pthread)
|
||||
endif()
|
||||
set (WEBSOCKETPP_PLATFORM_TSL_LIBS ssl crypto)
|
||||
set (WEBSOCKETPP_BOOST_LIBS system thread)
|
||||
set (CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-std=c++0x -stdlib=libc++") # todo: is libc++ really needed here?
|
||||
if (NOT APPLE)
|
||||
add_definitions (-DNDEBUG -Wall -Wno-padded) # todo: should we use CMAKE_C_FLAGS for these?
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
# OSX, can override above.
|
||||
if (APPLE)
|
||||
add_definitions (-DNDEBUG -Wall)
|
||||
endif ()
|
||||
|
||||
if (BUILD_EXAMPLES)
|
||||
list (APPEND WEBSOCKETPP_BOOST_LIBS random)
|
||||
endif()
|
||||
|
||||
############ Dependencies
|
||||
|
||||
# Set BOOST_ROOT env variable or pass with cmake -DBOOST_ROOT=path.
|
||||
# BOOST_ROOT can also be defined by a previous run from cmake cache.
|
||||
if (NOT "$ENV{BOOST_ROOT_CPP11}" STREQUAL "")
|
||||
# Scons documentation for BOOST_ROOT_CPP11:
|
||||
# "look for optional second boostroot compiled with clang's libc++ STL library
|
||||
# this prevents warnings/errors when linking code built with two different
|
||||
# incompatible STL libraries."
|
||||
file (TO_CMAKE_PATH "$ENV{BOOST_ROOT_CPP11}" BOOST_ROOT)
|
||||
set (BOOST_ROOT ${BOOST_ROOT} CACHE PATH "BOOST_ROOT dependency path" FORCE)
|
||||
endif ()
|
||||
if ("${BOOST_ROOT}" STREQUAL "")
|
||||
file (TO_CMAKE_PATH "$ENV{BOOST_ROOT}" BOOST_ROOT)
|
||||
# Cache BOOST_ROOT for runs that do not define $ENV{BOOST_ROOT}.
|
||||
set (BOOST_ROOT ${BOOST_ROOT} CACHE PATH "BOOST_ROOT dependency path" FORCE)
|
||||
endif ()
|
||||
|
||||
message ("* Configuring Boost")
|
||||
message (STATUS "-- Using BOOST_ROOT")
|
||||
message (STATUS " " ${BOOST_ROOT})
|
||||
|
||||
if (MSVC)
|
||||
set (Boost_USE_MULTITHREADED TRUE)
|
||||
set (Boost_USE_STATIC_LIBS TRUE)
|
||||
else ()
|
||||
set (Boost_USE_MULTITHREADED FALSE)
|
||||
set (Boost_USE_STATIC_LIBS FALSE)
|
||||
endif ()
|
||||
|
||||
set (Boost_FIND_REQUIRED TRUE)
|
||||
set (Boost_FIND_QUIETLY TRUE)
|
||||
set (Boost_DEBUG FALSE)
|
||||
set (Boost_USE_MULTITHREADED TRUE)
|
||||
set (Boost_ADDITIONAL_VERSIONS "1.39.0" "1.40.0" "1.41.0" "1.42.0" "1.43.0" "1.44.0" "1.46.1") # todo: someone who knows better spesify these!
|
||||
|
||||
find_package (Boost 1.39.0 COMPONENTS "${WEBSOCKETPP_BOOST_LIBS}")
|
||||
|
||||
if (Boost_FOUND)
|
||||
# Boost is a project wide global dependency.
|
||||
include_directories (${Boost_INCLUDE_DIRS})
|
||||
link_directories (${Boost_LIBRARY_DIRS})
|
||||
|
||||
# Pretty print status
|
||||
message (STATUS "-- Include Directories")
|
||||
foreach (include_dir ${Boost_INCLUDE_DIRS})
|
||||
message (STATUS " " ${include_dir})
|
||||
endforeach ()
|
||||
message (STATUS "-- Library Directories")
|
||||
foreach (library_dir ${Boost_LIBRARY_DIRS})
|
||||
message (STATUS " " ${library_dir})
|
||||
endforeach ()
|
||||
message (STATUS "-- Libraries")
|
||||
foreach (boost_lib ${Boost_LIBRARIES})
|
||||
message (STATUS " " ${boost_lib})
|
||||
endforeach ()
|
||||
message ("")
|
||||
else ()
|
||||
message (FATAL_ERROR "Failed to find required dependency: boost")
|
||||
endif ()
|
||||
|
||||
find_package(OpenSSL)
|
||||
endif()
|
||||
|
||||
############ Add projects
|
||||
|
||||
# Add main library
|
||||
add_subdirectory (websocketpp)
|
||||
|
||||
# Add examples
|
||||
if (BUILD_EXAMPLES)
|
||||
add_subdirectory (examples)
|
||||
endif ()
|
||||
|
||||
# Add tests
|
||||
if (BUILD_TESTS)
|
||||
add_subdirectory (test)
|
||||
endif ()
|
||||
|
||||
print_used_build_config()
|
||||
|
||||
export (PACKAGE websocketpp)
|
||||
|
||||
configure_file (websocketpp-config.cmake.in "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/websocketpp-config.cmake" @ONLY)
|
||||
configure_file (websocketpp-configVersion.cmake.in "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/websocketpp-configVersion.cmake" @ONLY)
|
||||
|
||||
# Install the websocketpp-config.cmake and websocketpp-configVersion.cmake
|
||||
install (FILES
|
||||
"${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/websocketpp-config.cmake"
|
||||
"${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/websocketpp-configVersion.cmake"
|
||||
DESTINATION "${INSTALL_CMAKE_DIR}" COMPONENT dev)
|
||||
|
||||
@@ -1,145 +0,0 @@
|
||||
Main Library:
|
||||
|
||||
Copyright (c) 2013, 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.
|
||||
|
||||
Bundled Libraries:
|
||||
|
||||
****** Base 64 Library (base64/base64.hpp) ******
|
||||
base64.hpp is a repackaging of the base64.cpp and base64.h files into a
|
||||
single header suitable for use as a header only library. This conversion was
|
||||
done by Peter Thorson (webmaster@zaphoyd.com) in 2012. All modifications to
|
||||
the code are redistributed under the same license as the original, which is
|
||||
listed below.
|
||||
|
||||
base64.cpp and base64.h
|
||||
|
||||
Copyright (C) 2004-2008 René Nyffenegger
|
||||
|
||||
This source code is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the author be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this source code must not be misrepresented; you must not
|
||||
claim that you wrote the original source code. If you use this source code
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original source code.
|
||||
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
René Nyffenegger rene.nyffenegger@adp-gmbh.ch
|
||||
|
||||
****** SHA1 Library (sha1/sha1.hpp) ******
|
||||
sha1.hpp is a repackaging of the sha1.cpp and sha1.h files from the shallsha1
|
||||
library (http://code.google.com/p/smallsha1/) into a single header suitable for
|
||||
use as a header only library. This conversion was done by Peter Thorson
|
||||
(webmaster@zaphoyd.com) in 2013. All modifications to the code are redistributed
|
||||
under the same license as the original, which is listed below.
|
||||
|
||||
Copyright (c) 2011, Micael Hildenborg
|
||||
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 Micael Hildenborg 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 Micael Hildenborg ''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 Micael Hildenborg 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.
|
||||
|
||||
****** MD5 Library (common/md5.hpp) ******
|
||||
md5.hpp is a reformulation of the md5.h and md5.c code from
|
||||
http://www.opensource.apple.com/source/cups/cups-59/cups/md5.c to allow it to
|
||||
function as a component of a header only library. This conversion was done by
|
||||
Peter Thorson (webmaster@zaphoyd.com) in 2012 for the WebSocket++ project. The
|
||||
changes are released under the same license as the original (listed below)
|
||||
|
||||
Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved.
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
L. Peter Deutsch
|
||||
ghost@aladdin.com
|
||||
|
||||
****** UTF8 Validation logic (utf8_validation.hpp) ******
|
||||
utf8_validation.hpp is adapted from code originally written by Bjoern Hoehrmann
|
||||
<bjoern@hoehrmann.de>. See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for
|
||||
details.
|
||||
|
||||
The original license:
|
||||
|
||||
Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,205 @@
|
||||
################################################################################
|
||||
#
|
||||
# Copyright (c) 2011, 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.
|
||||
#
|
||||
# This Makefile was derived from a similar one included in the libjson project
|
||||
# It's authors were Jonathan Wallace and Bernhard Fluehmann.
|
||||
|
||||
|
||||
objects = websocket_server_session.o websocket_client_session.o websocket_session.o websocket_server.o websocket_client.o websocket_frame.o \
|
||||
network_utilities.o sha1.o base64.o
|
||||
|
||||
libs = -lboost_system -lboost_date_time -lboost_regex -lboost_random
|
||||
|
||||
OS=$(shell uname)
|
||||
|
||||
# Defaults
|
||||
ifeq ($(OS), Darwin)
|
||||
cxxflags_default = -c -O2 -DNDEBUG
|
||||
else
|
||||
cxxflags_default = -c -O2 -DNDEBUG
|
||||
endif
|
||||
cxxflags_small = -c
|
||||
cxxflags_debug = -c -g
|
||||
cxxflags_shared = -f$(PIC)
|
||||
libname = libwebsocketpp
|
||||
libname_hdr = websocketpp
|
||||
libname_debug = $(libname)
|
||||
suffix_shared = so
|
||||
suffix_shared_darwin = dylib
|
||||
suffix_static = a
|
||||
major_version = 0
|
||||
minor_version = 1.0
|
||||
objdir = objs
|
||||
|
||||
# Variables
|
||||
prefix ?= /usr/local
|
||||
exec_prefix ?= $(prefix)
|
||||
libdir ?= lib
|
||||
includedir ?= include
|
||||
srcdir ?= src
|
||||
CXX ?= c++
|
||||
AR ?= ar
|
||||
PIC ?= PIC
|
||||
BUILD_TYPE ?= default
|
||||
SHARED ?= 1
|
||||
|
||||
ifneq ($(OS),Darwin)
|
||||
ldconfig = ldconfig
|
||||
else
|
||||
ldconfig =
|
||||
endif
|
||||
|
||||
# Internal Variables
|
||||
inst_path = $(exec_prefix)/$(libdir)
|
||||
include_path = $(prefix)/$(includedir)
|
||||
|
||||
# BUILD_TYPE specific settings
|
||||
ifeq ($(BUILD_TYPE), debug)
|
||||
CXXFLAGS := $(cxxflags_debug) $(CXXFLAGS_EXTRA)
|
||||
libname := $(libname_debug)
|
||||
else
|
||||
CXXFLAGS := $(cxxflags_default) $(CXXFLAGS_EXTRA)
|
||||
endif
|
||||
|
||||
# SHARED specific settings
|
||||
ifeq ($(SHARED), 1)
|
||||
ifeq ($(OS), Darwin)
|
||||
libname_shared = $(libname).$(suffix_shared_darwin)
|
||||
else
|
||||
libname_shared = $(libname).$(suffix_shared)
|
||||
endif
|
||||
libname_shared_major_version = $(libname_shared).$(major_version)
|
||||
lib_target = $(libname_shared_major_version).$(minor_version)
|
||||
objdir := $(objdir)_shared
|
||||
CXXFLAGS := $(CXXFLAGS) $(cxxflags_shared)
|
||||
else
|
||||
lib_target = $(libname).$(suffix_static)
|
||||
objdir := $(objdir)_static
|
||||
endif
|
||||
|
||||
# Phony targets
|
||||
.PHONY: all banner installdirs install install_headers clean uninstall \
|
||||
uninstall_headers
|
||||
|
||||
# Targets
|
||||
all: banner $(lib_target)
|
||||
@echo "============================================================"
|
||||
@echo "Done"
|
||||
@echo "============================================================"
|
||||
|
||||
banner:
|
||||
@echo "============================================================"
|
||||
@echo "libwebsocketpp version: "$(major_version).$(minor_version) "target: "$(target) "OS: "$(OS)
|
||||
@echo "============================================================"
|
||||
|
||||
installdirs: banner
|
||||
mkdir -p $(objdir)
|
||||
|
||||
# Libraries
|
||||
ifeq ($(SHARED),1)
|
||||
$(lib_target): banner installdirs $(addprefix $(objdir)/, $(objects))
|
||||
@echo "Link "
|
||||
cd $(objdir) ; \
|
||||
if test "$(OS)" = "Darwin" ; then \
|
||||
$(CXX) -dynamiclib $(libs) $(LDFLAGS) -Wl,-dylib_install_name -Wl,$(libname_shared_major_version) -o $@ $(objects) ; \
|
||||
else \
|
||||
$(CXX) -shared $(libs) $(LDFLAGS) -Wl,-soname,$(libname_shared_major_version) -o $@ $(objects) ; \
|
||||
fi ; \
|
||||
mv -f $@ ../
|
||||
@echo "Link: Done"
|
||||
else
|
||||
$(lib_target): banner installdirs $(addprefix $(objdir)/, $(objects))
|
||||
@echo "Archive"
|
||||
cd $(objdir) ; \
|
||||
$(AR) -cvq $@ $(objects) ; \
|
||||
mv -f $@ ../
|
||||
@echo "Archive: Done"
|
||||
endif
|
||||
|
||||
# Compile object files
|
||||
$(objdir)/sha1.o: $(srcdir)/sha1/sha1.cpp installdirs
|
||||
$(CXX) $< -o $@ $(CXXFLAGS)
|
||||
|
||||
$(objdir)/base64.o: $(srcdir)/base64/base64.cpp installdirs
|
||||
$(CXX) $< -o $@ $(CXXFLAGS)
|
||||
|
||||
$(objdir)/%.o: $(srcdir)/%.cpp installdirs
|
||||
$(CXX) $< -o $@ $(CXXFLAGS)
|
||||
|
||||
ifeq ($(SHARED),1)
|
||||
install: banner install_headers $(lib_target)
|
||||
@echo "Install shared library"
|
||||
cp -f ./$(lib_target) $(inst_path)
|
||||
cd $(inst_path) ; \
|
||||
ln -sf $(lib_target) $(libname_shared_major_version) ; \
|
||||
ln -sf $(libname_shared_major_version) $(libname_shared)
|
||||
$(ldconfig)
|
||||
@echo "Install shared library: Done."
|
||||
else
|
||||
install: banner install_headers $(lib_target)
|
||||
@echo "Install static library"
|
||||
cp -f ./$(lib_target) $(inst_path)
|
||||
@echo "Install static library: Done."
|
||||
endif
|
||||
|
||||
install_headers: banner
|
||||
@echo "Install header files"
|
||||
mkdir -p $(include_path)/$(libname_hdr)
|
||||
# cp -f ./*.hpp $(include_path)/$(libname_hdr)
|
||||
cp -f ./$(srcdir)/*.hpp $(include_path)/$(libname_hdr)
|
||||
mkdir -p $(include_path)/$(libname_hdr)/base64
|
||||
cp -f ./$(srcdir)/base64/base64.h $(include_path)/$(libname_hdr)/base64
|
||||
mkdir -p $(include_path)/$(libname_hdr)/sha1
|
||||
cp -f ./$(srcdir)/sha1/sha1.h $(include_path)/$(libname_hdr)/sha1
|
||||
chmod -R a+r $(include_path)/$(libname_hdr)
|
||||
find $(include_path)/$(libname_hdr) -type d -exec chmod a+x {} \;
|
||||
@echo "Install header files: Done."
|
||||
|
||||
clean: banner
|
||||
@echo "Clean library and object folder"
|
||||
rm -rf $(objdir)
|
||||
rm -f $(lib_target)
|
||||
@echo "Clean library and object folder: Done"
|
||||
|
||||
ifeq ($(SHARED),1)
|
||||
uninstall: banner uninstall_headers
|
||||
@echo "Uninstall shared library"
|
||||
rm -f $(inst_path)/$(libname_shared)
|
||||
rm -f $(inst_path)/$(libname_shared_major_version)
|
||||
rm -f $(inst_path)/$(lib_target)
|
||||
ldconfig
|
||||
@echo "Uninstall shared library: Done"
|
||||
else
|
||||
uninstall: banner uninstall_headers
|
||||
@echo "Uninstall static library"
|
||||
rm -f $(inst_path)/$(lib_target)
|
||||
@echo "Uninstall static library: Done"
|
||||
endif
|
||||
|
||||
uninstall_headers: banner
|
||||
@echo "Uninstall header files"
|
||||
rm -rf $(include_path)/$(libname)
|
||||
@echo "Uninstall header files: Done"
|
||||
-236
@@ -1,236 +0,0 @@
|
||||
import os, sys, commands
|
||||
env = Environment(ENV = os.environ)
|
||||
|
||||
# figure out a better way to configure this
|
||||
if os.environ.has_key('CXX'):
|
||||
env['CXX'] = os.environ['CXX']
|
||||
|
||||
if os.environ.has_key('DEBUG'):
|
||||
env['DEBUG'] = os.environ['DEBUG']
|
||||
|
||||
if os.environ.has_key('CXXFLAGS'):
|
||||
#env['CXXFLAGS'] = os.environ['CXXFLAGS']
|
||||
env.Append(CXXFLAGS = os.environ['CXXFLAGS'])
|
||||
|
||||
if os.environ.has_key('LINKFLAGS'):
|
||||
#env['LDFLAGS'] = os.environ['LDFLAGS']
|
||||
env.Append(LINKFLAGS = os.environ['LINKFLAGS'])
|
||||
|
||||
## Boost
|
||||
##
|
||||
## Note: You need to either set BOOSTROOT to the root of a stock Boost distribution
|
||||
## or set BOOST_INCLUDES and BOOST_LIBS if Boost comes with your OS distro e.g. and
|
||||
## needs BOOST_INCLUDES=/usr/include/boost and BOOST_LIBS=/usr/lib like Ubuntu.
|
||||
##
|
||||
if os.environ.has_key('BOOSTROOT'):
|
||||
os.environ['BOOST_ROOT'] = os.environ['BOOSTROOT']
|
||||
|
||||
if os.environ.has_key('BOOST_ROOT'):
|
||||
env['BOOST_INCLUDES'] = os.environ['BOOST_ROOT']
|
||||
env['BOOST_LIBS'] = os.path.join(os.environ['BOOST_ROOT'], 'stage', 'lib')
|
||||
elif os.environ.has_key('BOOST_INCLUDES') and os.environ.has_key('BOOST_LIBS'):
|
||||
env['BOOST_INCLUDES'] = os.environ['BOOST_INCLUDES']
|
||||
env['BOOST_LIBS'] = os.environ['BOOST_LIBS']
|
||||
else:
|
||||
raise SCons.Errors.UserError, "Neither BOOST_ROOT, nor BOOST_INCLUDES + BOOST_LIBS was set!"
|
||||
|
||||
if os.environ.has_key('WSPP_ENABLE_CPP11'):
|
||||
env['WSPP_ENABLE_CPP11'] = True
|
||||
else:
|
||||
env['WSPP_ENABLE_CPP11'] = False
|
||||
|
||||
boost_linkshared = False
|
||||
|
||||
def boostlibs(libnames,localenv):
|
||||
if localenv['PLATFORM'].startswith('win'):
|
||||
# Win/VC++ supports autolinking. nothing to do.
|
||||
# http://www.boost.org/doc/libs/1_49_0/more/getting_started/windows.html#auto-linking
|
||||
return []
|
||||
else:
|
||||
libs = []
|
||||
prefix = localenv['SHLIBPREFIX'] if boost_linkshared else localenv['LIBPREFIX']
|
||||
suffix = localenv['SHLIBSUFFIX'] if boost_linkshared else localenv['LIBSUFFIX']
|
||||
for name in libnames:
|
||||
lib = File(os.path.join(localenv['BOOST_LIBS'], '%sboost_%s%s' % (prefix, name, suffix)))
|
||||
libs.append(lib)
|
||||
return libs
|
||||
|
||||
if env['PLATFORM'].startswith('win'):
|
||||
env.Append(CPPDEFINES = ['WIN32',
|
||||
'NDEBUG',
|
||||
'WIN32_LEAN_AND_MEAN',
|
||||
'_WIN32_WINNT=0x0600',
|
||||
'_CONSOLE',
|
||||
'BOOST_TEST_DYN_LINK',
|
||||
'NOMINMAX',
|
||||
'_WEBSOCKETPP_CPP11_MEMORY_',
|
||||
'_WEBSOCKETPP_CPP11_FUNCTIONAL_'])
|
||||
arch_flags = '/arch:SSE2'
|
||||
opt_flags = '/Ox /Oi /fp:fast'
|
||||
warn_flags = '/W3 /wd4996 /wd4995 /wd4355'
|
||||
env['CCFLAGS'] = '%s /EHsc /GR /GS- /MD /nologo %s %s' % (warn_flags, arch_flags, opt_flags)
|
||||
env['LINKFLAGS'] = '/INCREMENTAL:NO /MANIFEST /NOLOGO /OPT:REF /OPT:ICF /MACHINE:X86'
|
||||
elif env['PLATFORM'] == 'posix':
|
||||
if env.has_key('DEBUG'):
|
||||
env.Append(CCFLAGS = ['-g', '-O0'])
|
||||
else:
|
||||
env.Append(CPPDEFINES = ['NDEBUG'])
|
||||
env.Append(CCFLAGS = ['-O1', '-fomit-frame-pointer'])
|
||||
env.Append(CCFLAGS = ['-Wall'])
|
||||
#env['LINKFLAGS'] = ''
|
||||
elif env['PLATFORM'] == 'darwin':
|
||||
if env.has_key('DEBUG'):
|
||||
env.Append(CCFLAGS = ['-g', '-O0'])
|
||||
else:
|
||||
env.Append(CPPDEFINES = ['NDEBUG'])
|
||||
env.Append(CCFLAGS = ['-O1', '-fomit-frame-pointer'])
|
||||
env.Append(CCFLAGS = ['-Wall'])
|
||||
#env['LINKFLAGS'] = ''
|
||||
|
||||
if env['PLATFORM'].startswith('win'):
|
||||
#env['LIBPATH'] = env['BOOST_LIBS']
|
||||
pass
|
||||
else:
|
||||
env['LIBPATH'] = ['/usr/lib',
|
||||
'/usr/local/lib'] #, env['BOOST_LIBS']
|
||||
|
||||
# Compiler specific warning flags
|
||||
if env['CXX'].startswith('g++'):
|
||||
#env.Append(CCFLAGS = ['-Wconversion'])
|
||||
env.Append(CCFLAGS = ['-Wcast-align'])
|
||||
elif env['CXX'].startswith('clang++'):
|
||||
#env.Append(CCFLAGS = ['-Wcast-align'])
|
||||
#env.Append(CCFLAGS = ['-Wglobal-constructors'])
|
||||
#env.Append(CCFLAGS = ['-Wconversion'])
|
||||
env.Append(CCFLAGS = ['-Wno-padded'])
|
||||
|
||||
# Wpadded
|
||||
# Wsign-conversion
|
||||
|
||||
platform_libs = []
|
||||
tls_libs = []
|
||||
|
||||
tls_build = False
|
||||
|
||||
if env['PLATFORM'] == 'posix':
|
||||
platform_libs = ['pthread', 'rt']
|
||||
tls_libs = ['ssl', 'crypto']
|
||||
tls_build = True
|
||||
elif env['PLATFORM'] == 'darwin':
|
||||
tls_libs = ['ssl', 'crypto']
|
||||
tls_build = True
|
||||
elif env['PLATFORM'].startswith('win'):
|
||||
# Win/VC++ supports autolinking. nothing to do.
|
||||
pass
|
||||
|
||||
## Append WebSocket++ path
|
||||
env.Append(CPPPATH = ['#'])
|
||||
|
||||
##### Set up C++11 environment
|
||||
polyfill_libs = [] # boost libraries used as drop in replacements for incomplete
|
||||
# C++11 STL implementations
|
||||
env_cpp11 = env.Clone ()
|
||||
|
||||
if env_cpp11['CXX'].startswith('g++'):
|
||||
# TODO: check g++ version
|
||||
GCC_VERSION = commands.getoutput(env_cpp11['CXX'] + ' -dumpversion')
|
||||
|
||||
if GCC_VERSION > "4.4.0":
|
||||
print "C++11 build environment partially enabled"
|
||||
env_cpp11.Append(WSPP_CPP11_ENABLED = "true",CXXFLAGS = ['-std=c++0x'],TOOLSET = ['g++'],CPPDEFINES = ['_WEBSOCKETPP_CPP11_STL_'])
|
||||
else:
|
||||
print "C++11 build environment is not supported on this version of G++"
|
||||
elif env_cpp11['CXX'].startswith('clang++'):
|
||||
print "C++11 build environment enabled"
|
||||
env_cpp11.Append(WSPP_CPP11_ENABLED = "true",CXXFLAGS = ['-std=c++0x','-stdlib=libc++'],LINKFLAGS = ['-stdlib=libc++'],TOOLSET = ['clang++'],CPPDEFINES = ['_WEBSOCKETPP_CPP11_STL_'])
|
||||
|
||||
# look for optional second boostroot compiled with clang's libc++ STL library
|
||||
# this prevents warnings/errors when linking code built with two different
|
||||
# incompatible STL libraries.
|
||||
if os.environ.has_key('BOOST_ROOT_CPP11'):
|
||||
env_cpp11['BOOST_INCLUDES'] = os.environ['BOOST_ROOT_CPP11']
|
||||
env_cpp11['BOOST_LIBS'] = os.path.join(os.environ['BOOST_ROOT_CPP11'], 'stage', 'lib')
|
||||
elif os.environ.has_key('BOOST_INCLUDES_CPP11') and os.environ.has_key('BOOST_LIBS_CPP11'):
|
||||
env_cpp11['BOOST_INCLUDES'] = os.environ['BOOST_INCLUDES_CPP11']
|
||||
env_cpp11['BOOST_LIBS'] = os.environ['BOOST_LIBS_CPP11']
|
||||
else:
|
||||
print "C++11 build environment disabled"
|
||||
|
||||
# if the build system is known to allow the isystem modifier for library include
|
||||
# values then use it for the boost libraries. Otherwise just add them to the
|
||||
# regular CPPPATH values.
|
||||
if env['CXX'].startswith('g++') or env['CXX'].startswith('clang'):
|
||||
env.Append(CPPFLAGS = '-isystem ' + env['BOOST_INCLUDES'])
|
||||
else:
|
||||
env.Append(CPPPATH = [env['BOOST_INCLUDES']])
|
||||
env.Append(LIBPATH = [env['BOOST_LIBS']])
|
||||
|
||||
# if the build system is known to allow the isystem modifier for library include
|
||||
# values then use it for the boost libraries. Otherwise just add them to the
|
||||
# regular CPPPATH values.
|
||||
if env_cpp11['CXX'].startswith('g++') or env_cpp11['CXX'].startswith('clang'):
|
||||
env_cpp11.Append(CPPFLAGS = '-isystem ' + env_cpp11['BOOST_INCLUDES'])
|
||||
else:
|
||||
env_cpp11.Append(CPPPATH = [env_cpp11['BOOST_INCLUDES']])
|
||||
env_cpp11.Append(LIBPATH = [env_cpp11['BOOST_LIBS']])
|
||||
|
||||
releasedir = 'build/release/'
|
||||
debugdir = 'build/debug/'
|
||||
testdir = 'build/test/'
|
||||
builddir = releasedir
|
||||
|
||||
Export('env')
|
||||
Export('env_cpp11')
|
||||
Export('platform_libs')
|
||||
Export('boostlibs')
|
||||
Export('tls_libs')
|
||||
Export('polyfill_libs')
|
||||
|
||||
## END OF CONFIG !!
|
||||
|
||||
## TARGETS:
|
||||
|
||||
if not env['PLATFORM'].startswith('win'):
|
||||
# Unit tests, add test folders with SConscript files to to_test list.
|
||||
to_test = ['utility','http','logger','random','processors','message_buffer','extension','transport/iostream','transport/asio','roles','endpoint','connection','transport'] #,'http','processors','connection'
|
||||
|
||||
for t in to_test:
|
||||
new_tests = SConscript('#/test/'+t+'/SConscript',variant_dir = testdir + t, duplicate = 0)
|
||||
for a in new_tests:
|
||||
new_alias = Alias('test', [a], a.abspath)
|
||||
AlwaysBuild(new_alias)
|
||||
|
||||
# Main test application
|
||||
#main = SConscript('#/examples/dev/SConscript',variant_dir = builddir + 'dev',duplicate = 0)
|
||||
|
||||
# echo_server
|
||||
echo_server = SConscript('#/examples/echo_server/SConscript',variant_dir = builddir + 'echo_server',duplicate = 0)
|
||||
|
||||
# echo_server_tls
|
||||
if tls_build:
|
||||
echo_server_tls = SConscript('#/examples/echo_server_tls/SConscript',variant_dir = builddir + 'echo_server_tls',duplicate = 0)
|
||||
|
||||
# broadcast_server
|
||||
broadcast_server = SConscript('#/examples/broadcast_server/SConscript',variant_dir = builddir + 'broadcast_server',duplicate = 0)
|
||||
|
||||
# testee_server
|
||||
testee_server = SConscript('#/examples/testee_server/SConscript',variant_dir = builddir + 'testee_server',duplicate = 0)
|
||||
|
||||
# testee_client
|
||||
testee_client = SConscript('#/examples/testee_client/SConscript',variant_dir = builddir + 'testee_client',duplicate = 0)
|
||||
|
||||
# utility_client
|
||||
utility_client = SConscript('#/examples/utility_client/SConscript',variant_dir = builddir + 'utility_client',duplicate = 0)
|
||||
|
||||
# subprotocol_server
|
||||
subprotocol_server = SConscript('#/examples/subprotocol_server/SConscript',variant_dir = builddir + 'subprotocol_server',duplicate = 0)
|
||||
|
||||
if not env['PLATFORM'].startswith('win'):
|
||||
# iostream_server
|
||||
iostream_server = SConscript('#/examples/iostream_server/SConscript',variant_dir = builddir + 'iostream_server',duplicate = 0)
|
||||
|
||||
# telemetry_client
|
||||
telemetry_client = SConscript('#/examples/telemetry_client/SConscript',variant_dir = builddir + 'telemetry_client',duplicate = 0)
|
||||
|
||||
# print_server
|
||||
print_server = SConscript('#/examples/print_server/SConscript',variant_dir = builddir + 'print_server',duplicate = 0)
|
||||
@@ -1,83 +0,0 @@
|
||||
HEAD
|
||||
- Adds URI method to extract query string from URI. Thank you Banaan for code.
|
||||
#298
|
||||
- Numerous performance improvements. Including: tuned default buffer sizes based
|
||||
on profiling, caching of handler binding for async reads/writes, non-malloc
|
||||
allocators for read/write handlers, disabling of a number of questionably
|
||||
useful range sanity checks in tight inner loops.
|
||||
- Adds a compile time switch to asio transport config to disable certain
|
||||
multithreading features (some locks, asio strands)
|
||||
|
||||
0.3.0-alpha4 - 2013-10-11
|
||||
- HTTP requests ending normally are no longer logged as errors. Thank you Banaan
|
||||
for reporting. #294
|
||||
- Eliminates spurious expired timers in certain error conditions. Thank you
|
||||
Banaan for reporting. #295
|
||||
- Consolidates all bundled library licenses into the COPYING file. #294
|
||||
- Updates bundled sha1 library to one with a cleaner interface and more
|
||||
straight-forward license. Thank you lotodore for reporting and Evgeni Golov
|
||||
for reviewing. #294
|
||||
- Re-introduces strands to asio transport, allowing `io_service` thread pools to
|
||||
be used (with some limitations).
|
||||
- Removes endpoint code that kept track of a connection list that was never used
|
||||
anywhere. Removes a lock and reduces connection creation/deletion complexity
|
||||
from O(log n) to O(1) in the number of connections.
|
||||
- A number of internal changes to transport APIs
|
||||
- Deprecates iostream transport `readsome` in favor of `read_some` which is more
|
||||
consistent with the naming of the rest of the library.
|
||||
- Adds preliminary signaling to iostream transport of eof and fatal transport
|
||||
errors
|
||||
- Updates transport code to use shared pointers rather than raw pointers to
|
||||
prevent asio from retaining pointers to connection methods after the
|
||||
connection goes out of scope. #293 Thank you otaras for reporting.
|
||||
- Fixes an issue where custom headers couldn't be set for client connections
|
||||
Thank you Jerry Win and Wolfram Schroers for reporting.
|
||||
- Fixes a compile error on visual studio when using interrupts. Thank you Javier
|
||||
Rey Neira for reporting this.
|
||||
- Adds new 1012 and 1013 close codes per IANA registry
|
||||
- Add `set_remote_endpoint` method to iostream transport.
|
||||
- Add `set_secure` method to iostream transport.
|
||||
- Fix typo in .gitattributes file. Thank you jstarasov for reporting this. #280
|
||||
- Add missing locale include. Thank you Toninoso for reporting this. #281
|
||||
- Refactors `asio_transport` endpoint and adds full documentation and exception
|
||||
free varients of all methods.
|
||||
- Removes `asio_transport` endpoint method cancel(). Use `stop_listen()` instead
|
||||
- Wrap internal `io_service` `run_one()` method
|
||||
- Suppress error when trying to shut down a connection that was already closed
|
||||
|
||||
0.3.0-alpha3 - 2013-07-16
|
||||
- Minor refactor to bundled sha1 library
|
||||
- HTTP header comparisons are now case insensitive. #220, #275
|
||||
- Refactors URI to be exception free and not use regular expressions. This
|
||||
eliminates the dependency on boost or C++11 regex libraries allowing native
|
||||
C++11 usage on GCC 4.4 and higher and significantly reduces staticly built
|
||||
binary sizes.
|
||||
- Updates handling of Server and User-Agent headers to better handle custom
|
||||
settings and allow suppression of these headers for security purposes.
|
||||
- Fix issue where pong timeout handler always fired. Thank you Steven Klassen
|
||||
for reporting this bug.
|
||||
- Add ping and pong endpoint wrapper methods
|
||||
- Add `get_request()` pass through method to connection to allow calling methods
|
||||
specific to the HTTP policy in use.
|
||||
- Fix issue compile error with `WEBSOCKETPP_STRICT_MASKING` enabled and another
|
||||
issue where `WEBSOCKETPP_STRICT_MASKING` was not applied to incoming messages.
|
||||
Thank you Petter Norby for reporting and testing these bugs. #264
|
||||
- Add additional macro guards for use with boost_config. Thank you breyed
|
||||
for testing and code. #261
|
||||
|
||||
0.3.0-alpha2 - 2013-06-09
|
||||
- Fix a regression that caused servers being sent two close frames in a row
|
||||
to end a connection uncleanly. #259
|
||||
- Fix a regression that caused spurious frames following a legitimate close
|
||||
frames to erroneously trigger handlers. #258
|
||||
- Change default HTTP response error code when no http_handler is defined from
|
||||
500/Internal Server Error to 426/Upgrade Required
|
||||
- Remove timezone from logger timestamp to work around issues with the Windows
|
||||
implimentation of strftime. Thank you breyed for testing and code. #257
|
||||
- Switch integer literals to char literals to improve VCPP compatibility.
|
||||
Thank you breyed for testing and code. #257
|
||||
- Add MSVCPP warning suppression for the bundled SHA1 library. Thank you breyed
|
||||
for testing and code. #257
|
||||
|
||||
0.3.0-alpha1 - 2013-06-09
|
||||
- Initial Release
|
||||
@@ -1,78 +0,0 @@
|
||||
|
||||
# Print build configuration
|
||||
macro (print_used_build_config)
|
||||
message ("\n=========== Used Build Configuration =============\n")
|
||||
message (STATUS "ENABLE_CPP11 = " ${ENABLE_CPP11})
|
||||
message (STATUS "BUILD_EXAMPLES = " ${BUILD_EXAMPLES})
|
||||
message (STATUS "BUILD_TESTS = " ${BUILD_TESTS})
|
||||
message ("")
|
||||
message (STATUS "WEBSOCKETPP_ROOT = " ${WEBSOCKETPP_ROOT})
|
||||
message (STATUS "WEBSOCKETPP_BIN = " ${WEBSOCKETPP_BIN})
|
||||
message (STATUS "WEBSOCKETPP_LIB = " ${WEBSOCKETPP_LIB})
|
||||
message (STATUS "Install prefix = " ${CMAKE_INSTALL_PREFIX})
|
||||
message ("")
|
||||
message (STATUS "WEBSOCKETPP_BOOST_LIBS = ${WEBSOCKETPP_BOOST_LIBS}")
|
||||
message (STATUS "WEBSOCKETPP_PLATFORM_LIBS = ${WEBSOCKETPP_PLATFORM_LIBS}")
|
||||
message (STATUS "WEBSOCKETPP_PLATFORM_TSL_LIBS = ${WEBSOCKETPP_PLATFORM_TSL_LIBS}")
|
||||
message ("")
|
||||
endmacro ()
|
||||
|
||||
# Adds the given folder_name into the source files of the current project.
|
||||
# Use this macro when your module contains .cpp and .h files in several subdirectories.
|
||||
# Your sources variable needs to be WSPP_SOURCE_FILES and headers variable WSPP_HEADER_FILES.
|
||||
macro(add_source_folder folder_name)
|
||||
file(GLOB H_FILES_IN_FOLDER_${folder_name} ${folder_name}/*.hpp ${folder_name}/*.h)
|
||||
file(GLOB CPP_FILES_IN_FOLDER_${folder_name} ${folder_name}/*.cpp ${folder_name}/*.c)
|
||||
source_group("Header Files\\${folder_name}" FILES ${H_FILES_IN_FOLDER_${folder_name}})
|
||||
source_group("Source Files\\${folder_name}" FILES ${CPP_FILES_IN_FOLDER_${folder_name}})
|
||||
set(WSPP_HEADER_FILES ${WSPP_HEADER_FILES} ${H_FILES_IN_FOLDER_${folder_name}})
|
||||
set(WSPP_SOURCE_FILES ${WSPP_SOURCE_FILES} ${CPP_FILES_IN_FOLDER_${folder_name}})
|
||||
endmacro()
|
||||
|
||||
# Initialize target.
|
||||
macro (init_target NAME)
|
||||
set (TARGET_NAME ${NAME})
|
||||
message ("** " ${TARGET_NAME})
|
||||
|
||||
# Include our own module path. This makes #include "x.h"
|
||||
# work in project subfolders to include the main directory headers.
|
||||
include_directories (${CMAKE_CURRENT_SOURCE_DIR})
|
||||
endmacro ()
|
||||
|
||||
# Build executable for executables
|
||||
macro (build_executable TARGET_NAME)
|
||||
set (TARGET_LIB_TYPE "EXECUTABLE")
|
||||
message (STATUS "-- Build Type:")
|
||||
message (STATUS " " ${TARGET_LIB_TYPE})
|
||||
|
||||
add_executable (${TARGET_NAME} ${ARGN})
|
||||
|
||||
include_directories (${WEBSOCKETPP_ROOT} ${WEBSOCKETPP_INCLUDE})
|
||||
|
||||
set_target_properties (${TARGET_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${WEBSOCKETPP_BIN})
|
||||
set_target_properties (${TARGET_NAME} PROPERTIES DEBUG_POSTFIX d)
|
||||
endmacro ()
|
||||
|
||||
# Finalize target for all types
|
||||
macro (final_target)
|
||||
if ("${TARGET_LIB_TYPE}" STREQUAL "EXECUTABLE")
|
||||
install (TARGETS ${TARGET_NAME}
|
||||
RUNTIME DESTINATION "bin"
|
||||
CONFIGURATIONS ${CMAKE_CONFIGURATION_TYPES})
|
||||
endif ()
|
||||
|
||||
# install headers, directly from current source dir and look for subfolders with headers
|
||||
file (GLOB_RECURSE TARGET_INSTALL_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.hpp)
|
||||
foreach (hppfile ${TARGET_INSTALL_HEADERS})
|
||||
get_filename_component (currdir ${hppfile} PATH)
|
||||
install (FILES ${hppfile} DESTINATION "include/${TARGET_NAME}/${currdir}")
|
||||
endforeach()
|
||||
endmacro ()
|
||||
|
||||
macro (link_boost)
|
||||
target_link_libraries (${TARGET_NAME} ${Boost_LIBRARIES})
|
||||
endmacro ()
|
||||
|
||||
macro (link_openssl)
|
||||
target_link_libraries (${TARGET_NAME} ${OPENSSL_SSL_LIBRARY} ${OPENSSL_CRYPTO_LIBRARY})
|
||||
endmacro ()
|
||||
@@ -1,52 +0,0 @@
|
||||
#include <set>
|
||||
|
||||
#include <websocketpp/config/asio_no_tls.hpp>
|
||||
#include <websocketpp/server.hpp>
|
||||
|
||||
typedef websocketpp::server<websocketpp::config::asio> server;
|
||||
|
||||
using websocketpp::connection_hdl;
|
||||
using websocketpp::lib::placeholders::_1;
|
||||
using websocketpp::lib::placeholders::_2;
|
||||
using websocketpp::lib::bind;
|
||||
|
||||
class broadcast_server {
|
||||
public:
|
||||
broadcast_server() {
|
||||
m_server.init_asio();
|
||||
|
||||
m_server.set_open_handler(bind(&broadcast_server::on_open,this,::_1));
|
||||
m_server.set_close_handler(bind(&broadcast_server::on_close,this,::_1));
|
||||
m_server.set_message_handler(bind(&broadcast_server::on_message,this,::_1,::_2));
|
||||
}
|
||||
|
||||
void on_open(connection_hdl hdl) {
|
||||
m_connections.insert(hdl);
|
||||
}
|
||||
|
||||
void on_close(connection_hdl hdl) {
|
||||
m_connections.erase(hdl);
|
||||
}
|
||||
|
||||
void on_message(connection_hdl hdl, server::message_ptr msg) {
|
||||
for (auto it : m_connections) {
|
||||
m_server.send(it,msg);
|
||||
}
|
||||
}
|
||||
|
||||
void run(uint16_t port) {
|
||||
m_server.listen(port);
|
||||
m_server.start_accept();
|
||||
m_server.run();
|
||||
}
|
||||
private:
|
||||
typedef std::set<connection_hdl,std::owner_less<connection_hdl>> con_list;
|
||||
|
||||
server m_server;
|
||||
con_list m_connections;
|
||||
};
|
||||
|
||||
int main() {
|
||||
broadcast_server server;
|
||||
server.run(9002);
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
#include <thread>
|
||||
|
||||
#include <websocketpp/config/asio_no_tls.hpp>
|
||||
#include <websocketpp/server.hpp>
|
||||
|
||||
typedef websocketpp::server<websocketpp::config::asio> server;
|
||||
|
||||
using websocketpp::connection_hdl;
|
||||
|
||||
class count_server {
|
||||
public:
|
||||
count_server() : m_count(0) {
|
||||
m_server.init_asio();
|
||||
|
||||
m_server.set_open_handler(bind(&count_server::on_open,this,_1));
|
||||
m_server.set_close_handler(bind(&count_server::on_close,this,_1));
|
||||
}
|
||||
|
||||
void on_open(connection_hdl hdl) {
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
m_connections.insert(hdl);
|
||||
}
|
||||
|
||||
void on_close(connection_hdl hdl) {
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
m_connections.erase(hdl);
|
||||
}
|
||||
|
||||
void count() {
|
||||
while (1) {
|
||||
sleep(1);
|
||||
m_count++;
|
||||
|
||||
std::stringstream ss;
|
||||
ss << m_count;
|
||||
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
for (auto it : m_connections) {
|
||||
m_server.send(it,ss.str(),websocketpp::frame::opcode::text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void run(uint16_t port) {
|
||||
m_server.listen(port);
|
||||
m_server.start_accept();
|
||||
m_server.run();
|
||||
}
|
||||
private:
|
||||
typedef std::set<connection_hdl,std::owner_less<connection_hdl>> con_list;
|
||||
|
||||
int m_count;
|
||||
server m_server;
|
||||
con_list m_connections;
|
||||
std::mutex m_mutex;
|
||||
};
|
||||
|
||||
int main() {
|
||||
count_server server;
|
||||
std::thread t(std::bind(&count_server::count,&server));
|
||||
server.run(9002);
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
file (GLOB SDIRS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *)
|
||||
foreach (SUBDIR ${SDIRS})
|
||||
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/CMakeLists.txt")
|
||||
add_subdirectory (${SUBDIR})
|
||||
endif ()
|
||||
endforeach ()
|
||||
@@ -1,88 +0,0 @@
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <exception>
|
||||
#include <websocketpp/config/asio_no_tls.hpp>
|
||||
#include <websocketpp/server.hpp>
|
||||
|
||||
typedef websocketpp::server<websocketpp::config::asio> server;
|
||||
|
||||
using websocketpp::connection_hdl;
|
||||
using websocketpp::lib::placeholders::_1;
|
||||
using websocketpp::lib::placeholders::_2;
|
||||
using websocketpp::lib::bind;
|
||||
|
||||
struct connection_data {
|
||||
int sessionid;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
class print_server {
|
||||
public:
|
||||
print_server() : m_next_sessionid(1) {
|
||||
m_server.init_asio();
|
||||
|
||||
m_server.set_open_handler(bind(&print_server::on_open,this,::_1));
|
||||
m_server.set_close_handler(bind(&print_server::on_close,this,::_1));
|
||||
m_server.set_message_handler(bind(&print_server::on_message,this,::_1,::_2));
|
||||
}
|
||||
|
||||
void on_open(connection_hdl hdl) {
|
||||
connection_data data;
|
||||
|
||||
data.sessionid = m_next_sessionid++;
|
||||
data.name = "";
|
||||
|
||||
m_connections[hdl] = data;
|
||||
}
|
||||
|
||||
void on_close(connection_hdl hdl) {
|
||||
connection_data& data = get_data_from_hdl(hdl);
|
||||
|
||||
std::cout << "Closing connection " << data.name
|
||||
<< " with sessionid " << data.sessionid << std::endl;
|
||||
|
||||
m_connections.erase(hdl);
|
||||
}
|
||||
|
||||
void on_message(connection_hdl hdl, server::message_ptr msg) {
|
||||
connection_data& data = get_data_from_hdl(hdl);
|
||||
|
||||
if (data.name == "") {
|
||||
data.name = msg->get_payload();
|
||||
std::cout << "Setting name of connection with sessionid "
|
||||
<< data.sessionid << " to " << data.name << std::endl;
|
||||
} else {
|
||||
std::cout << "Got a message from connection " << data.name
|
||||
<< " with sessionid " << data.sessionid << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
connection_data& get_data_from_hdl(connection_hdl hdl) {
|
||||
auto it = m_connections.find(hdl);
|
||||
|
||||
if (it == m_connections.end()) {
|
||||
// this connection is not in the list. This really shouldn't happen
|
||||
// and probably means something else is wrong.
|
||||
throw std::invalid_argument("No data available for session");
|
||||
}
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void run(uint16_t port) {
|
||||
m_server.listen(port);
|
||||
m_server.start_accept();
|
||||
m_server.run();
|
||||
}
|
||||
private:
|
||||
typedef std::map<connection_hdl,connection_data,std::owner_less<connection_hdl>> con_list;
|
||||
|
||||
int m_next_sessionid;
|
||||
server m_server;
|
||||
con_list m_connections;
|
||||
};
|
||||
|
||||
int main() {
|
||||
print_server server;
|
||||
server.run(9002);
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
## Broadcast Server example
|
||||
##
|
||||
|
||||
Import('env')
|
||||
Import('env_cpp11')
|
||||
Import('boostlibs')
|
||||
Import('platform_libs')
|
||||
Import('polyfill_libs')
|
||||
|
||||
env = env.Clone ()
|
||||
env_cpp11 = env_cpp11.Clone ()
|
||||
|
||||
prgs = []
|
||||
|
||||
# if a C++11 environment is available build using that, otherwise use boost
|
||||
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
|
||||
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env_cpp11.Program('broadcast_server', ["broadcast_server.cpp"], LIBS = ALL_LIBS)
|
||||
else:
|
||||
ALL_LIBS = boostlibs(['system','thread'],env) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env.Program('broadcast_server', ["broadcast_server.cpp"], LIBS = ALL_LIBS)
|
||||
|
||||
Return('prgs')
|
||||
@@ -1,158 +0,0 @@
|
||||
#include <websocketpp/config/asio_no_tls.hpp>
|
||||
|
||||
#include <websocketpp/server.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
/*#include <boost/thread.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>*/
|
||||
#include <websocketpp/common/thread.hpp>
|
||||
|
||||
typedef websocketpp::server<websocketpp::config::asio> server;
|
||||
|
||||
using websocketpp::connection_hdl;
|
||||
using websocketpp::lib::placeholders::_1;
|
||||
using websocketpp::lib::placeholders::_2;
|
||||
using websocketpp::lib::bind;
|
||||
|
||||
using websocketpp::lib::thread;
|
||||
using websocketpp::lib::mutex;
|
||||
using websocketpp::lib::unique_lock;
|
||||
using websocketpp::lib::condition_variable;
|
||||
|
||||
/* on_open insert connection_hdl into channel
|
||||
* on_close remove connection_hdl from channel
|
||||
* on_message queue send to all channels
|
||||
*/
|
||||
|
||||
enum action_type {
|
||||
SUBSCRIBE,
|
||||
UNSUBSCRIBE,
|
||||
MESSAGE
|
||||
};
|
||||
|
||||
struct action {
|
||||
action(action_type t, connection_hdl h) : type(t), hdl(h) {}
|
||||
action(action_type t, server::message_ptr m) : type(t), msg(m) {}
|
||||
|
||||
action_type type;
|
||||
websocketpp::connection_hdl hdl;
|
||||
server::message_ptr msg;
|
||||
};
|
||||
|
||||
class broadcast_server {
|
||||
public:
|
||||
broadcast_server() {
|
||||
// Initialize Asio Transport
|
||||
m_server.init_asio();
|
||||
|
||||
// Register handler callbacks
|
||||
m_server.set_open_handler(bind(&broadcast_server::on_open,this,::_1));
|
||||
m_server.set_close_handler(bind(&broadcast_server::on_close,this,::_1));
|
||||
m_server.set_message_handler(bind(&broadcast_server::on_message,this,::_1,::_2));
|
||||
}
|
||||
|
||||
void run(uint16_t port) {
|
||||
// listen on specified port
|
||||
m_server.listen(port);
|
||||
|
||||
// Start the server accept loop
|
||||
m_server.start_accept();
|
||||
|
||||
// Start the ASIO io_service run loop
|
||||
try {
|
||||
m_server.run();
|
||||
} catch (const std::exception & e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
} catch (websocketpp::lib::error_code e) {
|
||||
std::cout << e.message() << std::endl;
|
||||
} catch (...) {
|
||||
std::cout << "other exception" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void on_open(connection_hdl hdl) {
|
||||
unique_lock<mutex> lock(m_action_lock);
|
||||
//std::cout << "on_open" << std::endl;
|
||||
m_actions.push(action(SUBSCRIBE,hdl));
|
||||
lock.unlock();
|
||||
m_action_cond.notify_one();
|
||||
}
|
||||
|
||||
void on_close(connection_hdl hdl) {
|
||||
unique_lock<mutex> lock(m_action_lock);
|
||||
//std::cout << "on_close" << std::endl;
|
||||
m_actions.push(action(UNSUBSCRIBE,hdl));
|
||||
lock.unlock();
|
||||
m_action_cond.notify_one();
|
||||
}
|
||||
|
||||
void on_message(connection_hdl hdl, server::message_ptr msg) {
|
||||
// queue message up for sending by processing thread
|
||||
unique_lock<mutex> lock(m_action_lock);
|
||||
//std::cout << "on_message" << std::endl;
|
||||
m_actions.push(action(MESSAGE,msg));
|
||||
lock.unlock();
|
||||
m_action_cond.notify_one();
|
||||
}
|
||||
|
||||
void process_messages() {
|
||||
while(1) {
|
||||
unique_lock<mutex> lock(m_action_lock);
|
||||
|
||||
while(m_actions.empty()) {
|
||||
m_action_cond.wait(lock);
|
||||
}
|
||||
|
||||
action a = m_actions.front();
|
||||
m_actions.pop();
|
||||
|
||||
lock.unlock();
|
||||
|
||||
if (a.type == SUBSCRIBE) {
|
||||
unique_lock<mutex> lock(m_connection_lock);
|
||||
m_connections.insert(a.hdl);
|
||||
} else if (a.type == UNSUBSCRIBE) {
|
||||
unique_lock<mutex> lock(m_connection_lock);
|
||||
m_connections.erase(a.hdl);
|
||||
} else if (a.type == MESSAGE) {
|
||||
unique_lock<mutex> lock(m_connection_lock);
|
||||
|
||||
con_list::iterator it;
|
||||
for (it = m_connections.begin(); it != m_connections.end(); ++it) {
|
||||
m_server.send(*it,a.msg);
|
||||
}
|
||||
} else {
|
||||
// undefined.
|
||||
}
|
||||
}
|
||||
}
|
||||
private:
|
||||
typedef std::set<connection_hdl,std::owner_less<connection_hdl>> con_list;
|
||||
|
||||
server m_server;
|
||||
con_list m_connections;
|
||||
std::queue<action> m_actions;
|
||||
|
||||
mutex m_action_lock;
|
||||
mutex m_connection_lock;
|
||||
condition_variable m_action_cond;
|
||||
};
|
||||
|
||||
int main() {
|
||||
try {
|
||||
broadcast_server server;
|
||||
|
||||
// Start a thread to run the processing loop
|
||||
thread t(bind(&broadcast_server::process_messages,&server));
|
||||
|
||||
// Run the asio loop with the main thread
|
||||
server.run(9002);
|
||||
|
||||
t.join();
|
||||
|
||||
} catch (std::exception & e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
CFLAGS = -O2
|
||||
LDFLAGS =
|
||||
|
||||
CXX ?= c++
|
||||
SHARED ?= "1"
|
||||
|
||||
ifeq ($(SHARED), 1)
|
||||
LDFLAGS := $(LDFLAGS) -lboost_system -lboost_thread -lwebsocketpp
|
||||
else
|
||||
LDFLAGS := $(LDFLAGS) -lboost_system -lboost_thread -lboost_date_time -lboost_regex -lboost_random ../../libwebsocketpp.a
|
||||
endif
|
||||
|
||||
chat_client: chat_client.o chat_client_handler.o
|
||||
$(CXX) $(CFLAGS) $^ -o $@ $(LDFLAGS)
|
||||
|
||||
%.o: %.cpp
|
||||
$(CXX) -c $(CFLAGS) -o $@ $^
|
||||
|
||||
# cleanup by removing generated files
|
||||
#
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f *.o chat_client
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2011, 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:
|
||||
@@ -11,10 +11,10 @@
|
||||
* * 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
|
||||
*
|
||||
* 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;
|
||||
@@ -22,28 +22,57 @@
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*/
|
||||
//#define BOOST_TEST_DYN_LINK
|
||||
#define BOOST_TEST_MODULE transport_asio_base
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include "chat_client_handler.hpp"
|
||||
|
||||
#include "../../src/websocketpp.hpp"
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <websocketpp/transport/asio/base.hpp>
|
||||
using boost::asio::ip::tcp;
|
||||
using namespace websocketchat;
|
||||
|
||||
BOOST_AUTO_TEST_CASE( blank_error ) {
|
||||
websocketpp::lib::error_code ec;
|
||||
int main(int argc, char* argv[]) {
|
||||
std::string uri;
|
||||
|
||||
if (argc != 2) {
|
||||
std::cout << "Usage: `chat_client ws_uri`" << std::endl;
|
||||
} else {
|
||||
uri = argv[1];
|
||||
}
|
||||
|
||||
chat_client_handler_ptr c(new chat_client_handler());
|
||||
|
||||
try {
|
||||
boost::asio::io_service io_service;
|
||||
|
||||
websocketpp::client_ptr client(new websocketpp::client(io_service,c));
|
||||
|
||||
client->init();
|
||||
|
||||
BOOST_CHECK( !ec );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( asio_error ) {
|
||||
using websocketpp::transport::asio::error::make_error_code;
|
||||
using websocketpp::transport::asio::error::general;
|
||||
|
||||
websocketpp::lib::error_code ec = make_error_code(general);
|
||||
|
||||
BOOST_CHECK( ec == general );
|
||||
BOOST_CHECK( ec.value() == 1 );
|
||||
client->set_header("User Agent","WebSocket++/2011-09-25");
|
||||
client->add_subprotocol("com.zaphoyd.websocketpp.chat");
|
||||
|
||||
client->set_origin("http://zaphoyd.com");
|
||||
|
||||
client->connect(uri);
|
||||
|
||||
boost::thread t(boost::bind(&boost::asio::io_service::run, &io_service));
|
||||
|
||||
char line[512];
|
||||
while (std::cin.getline(line, 512)) {
|
||||
c->send(line);
|
||||
}
|
||||
|
||||
t.join();
|
||||
} catch (std::exception& e) {
|
||||
std::cerr << "Exception: " << e.what() << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<script type="text/javascript" src="jquery-1.6.3.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
var ws;
|
||||
var url;
|
||||
|
||||
$(document).ready(init);
|
||||
|
||||
function init() {
|
||||
$(document).keypress(function(event) {
|
||||
if ( event.which == 13 ) {
|
||||
event.preventDefault();
|
||||
send();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function connect() {
|
||||
url = $("#server_url").val();
|
||||
console.log(url);
|
||||
|
||||
if ("WebSocket" in window) {
|
||||
ws = new WebSocket(url);
|
||||
} else if ("MozWebSocket" in window) {
|
||||
ws = new MozWebSocket(url);
|
||||
} else {
|
||||
chat_message("This Browser does not support WebSockets");
|
||||
return;
|
||||
}
|
||||
ws.onopen = function(e) {
|
||||
chat_message("A connection to "+url+" has been opened.");
|
||||
|
||||
$("#server_url").attr("disabled",true);
|
||||
$("#toggle_connect").html("Disconnect");
|
||||
};
|
||||
|
||||
ws.onerror = function(e) {
|
||||
chat_message("An error occured, see console log for more details.");
|
||||
console.log(e);
|
||||
};
|
||||
|
||||
ws.onclose = function(e) {
|
||||
chat_message("The connection to "+url+" was closed.");
|
||||
};
|
||||
|
||||
ws.onmessage = function(e) {
|
||||
var message = JSON.parse(e.data);
|
||||
|
||||
if (message.type == "msg") {
|
||||
chat_message(message.value,message.sender);
|
||||
} else if (message.type == "participants") {
|
||||
var o = "<ul>";
|
||||
for (var p in message.value) {
|
||||
o += "<li>"+message.value[p]+"</li>";
|
||||
}
|
||||
o += "</ul>";
|
||||
$("#participants").html(o);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function chat_message(message,sender) {
|
||||
if (arguments.length == 1) {
|
||||
sender = "";
|
||||
}
|
||||
|
||||
var style;
|
||||
|
||||
if (sender == "") {
|
||||
style = "client";
|
||||
} else if (sender == "server") {
|
||||
style = "server";
|
||||
sender = "["+sender+"]";
|
||||
} else {
|
||||
style = "message";
|
||||
sender = "["+sender+"]";
|
||||
}
|
||||
|
||||
$("#messages").append("<span class='"+style+"'><span class='sender'>"+sender+"</span> <span class='msg'>"+message+"</span></span><br />");
|
||||
$("#messages").prop({ scrollTop: $("#messages").prop("scrollHeight") });
|
||||
}
|
||||
|
||||
function disconnect() {
|
||||
ws.close();
|
||||
$("#server_url").removeAttr("disabled");
|
||||
$("#toggle_connect").html("Connect");
|
||||
$("#participants").html("");
|
||||
}
|
||||
|
||||
function toggle_connect() {
|
||||
if ($("#server_url").attr("disabled") != "disabled") {
|
||||
connect();
|
||||
} else {
|
||||
disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
function send() {
|
||||
if (ws === undefined || ws.readyState != 1) {
|
||||
chat_message("Websocket is not avaliable for writing");
|
||||
return;
|
||||
}
|
||||
|
||||
ws.send($("#msg").val());
|
||||
$("#msg").val("");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
body,html {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
height: 100%;
|
||||
background-color: #999;
|
||||
font-family: sans-serif;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
|
||||
}
|
||||
|
||||
#controls {
|
||||
padding: 4px;
|
||||
float:right;
|
||||
width: 300px;
|
||||
|
||||
}
|
||||
|
||||
input {
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
#messages {
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
#messages .client {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
#messages .server {
|
||||
color: yellow;
|
||||
}
|
||||
|
||||
#messages .message {
|
||||
color: white;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<div id="controls">
|
||||
<div id="server">
|
||||
<input type="text" name="server_url" id="server_url" value="ws://thor-websocket.zaphoyd.net:9000/chat" />
|
||||
<button id="toggle_connect" onclick="toggle_connect();">Connect</button>
|
||||
</div>
|
||||
|
||||
<div id="message_input"><input type="text" name="msg" id="msg" value="Hello World!" />
|
||||
<button onclick="send();">Send</button></div>
|
||||
<h3>Chat Participants</h3>
|
||||
<div id="participants"></div>
|
||||
</div>
|
||||
<div id="messages"></div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "chat_client_handler.hpp"
|
||||
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
|
||||
using websocketchat::chat_client_handler;
|
||||
using websocketpp::client_session_ptr;
|
||||
|
||||
void chat_client_handler::on_open(session_ptr s) {
|
||||
// not sure if anything needs to happen here.
|
||||
m_session = s;
|
||||
|
||||
std::cout << "Successfully connected" << std::endl;
|
||||
}
|
||||
|
||||
void chat_client_handler::on_close(session_ptr s) {
|
||||
// not sure if anything needs to happen here either.
|
||||
|
||||
m_session = client_session_ptr();
|
||||
|
||||
std::cout << "client was disconnected" << std::endl;
|
||||
}
|
||||
|
||||
void chat_client_handler::on_message(session_ptr s,const std::string &msg) {
|
||||
//std::cout << "message from server: " << msg << std::endl;
|
||||
|
||||
decode_server_msg(msg);
|
||||
}
|
||||
|
||||
// CLIENT API
|
||||
// client api methods will be called from outside the io_service.run thread
|
||||
// they need to be careful to not touch unsyncronized member variables.
|
||||
|
||||
void chat_client_handler::send(const std::string &msg) {
|
||||
if (!m_session) {
|
||||
std::cerr << "Error: no connected session" << std::endl;
|
||||
return;
|
||||
}
|
||||
m_session->io_service().post(boost::bind(&chat_client_handler::do_send, this, msg));
|
||||
}
|
||||
|
||||
void chat_client_handler::close() {
|
||||
if (!m_session) {
|
||||
std::cerr << "Error: no connected session" << std::endl;
|
||||
return;
|
||||
}
|
||||
m_session->io_service().post(boost::bind(&chat_client_handler::do_close,this));
|
||||
}
|
||||
|
||||
// END CLIENT API
|
||||
|
||||
void chat_client_handler::do_send(const std::string &msg) {
|
||||
if (!m_session) {
|
||||
std::cerr << "Error: no connected session" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// check for local commands
|
||||
if (msg == "/list") {
|
||||
std::cout << "list all participants" << std::endl;
|
||||
} else if (msg == "/close") {
|
||||
do_close();
|
||||
} else {
|
||||
m_session->send(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void chat_client_handler::do_close() {
|
||||
if (!m_session) {
|
||||
std::cerr << "Error: no connected session" << std::endl;
|
||||
return;
|
||||
}
|
||||
m_session->close(websocketpp::session::CLOSE_STATUS_GOING_AWAY,"");
|
||||
}
|
||||
|
||||
// {"type":"participants","value":[<participant>,...]}
|
||||
// {"type":"msg","sender":"<sender>","value":"<msg>" }
|
||||
void chat_client_handler::decode_server_msg(const std::string &msg) {
|
||||
// for messages of type participants, erase and rebuild m_participants
|
||||
// for messages of type msg, print out message
|
||||
|
||||
// NOTE: The chat server was written with the intention of the client having a built in
|
||||
// JSON parser. To keep external dependencies low for this demonstration chat client I am
|
||||
// parsing the server messages by hand.
|
||||
|
||||
std::string::size_type start = 9;
|
||||
std::string::size_type end;
|
||||
|
||||
if (msg.substr(0,start) != "{\"type\":\"") {
|
||||
// ignore
|
||||
std::cout << "invalid message" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (msg.substr(start,15) == "msg\",\"sender\":\"") {
|
||||
// parse message
|
||||
std::string sender;
|
||||
std::string message;
|
||||
|
||||
start += 15;
|
||||
|
||||
end = msg.find("\"",start);
|
||||
while (end != std::string::npos) {
|
||||
if (msg[end-1] == '\\') {
|
||||
sender += msg.substr(start,end-start-1) + "\"";
|
||||
start = end+1;
|
||||
end = msg.find("\"",start);
|
||||
} else {
|
||||
sender += msg.substr(start,end-start);
|
||||
start = end;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (msg.substr(start,11) != "\",\"value\":\"") {
|
||||
std::cout << "invalid message" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
start += 11;
|
||||
|
||||
end = msg.find("\"",start);
|
||||
while (end != std::string::npos) {
|
||||
if (msg[end-1] == '\\') {
|
||||
message += msg.substr(start,end-start-1) + "\"";
|
||||
start = end+1;
|
||||
end = msg.find("\"",start);
|
||||
} else {
|
||||
message += msg.substr(start,end-start);
|
||||
start = end;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "[" << sender << "] " << message << std::endl;
|
||||
} else if (msg.substr(start,23) == "participants\",\"value\":[") {
|
||||
// parse participants
|
||||
std::cout << "participants message" << std::endl;
|
||||
} else {
|
||||
// unknown message type
|
||||
std::cout << "unknown message" << std::endl;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CHAT_CLIENT_HANDLER_HPP
|
||||
#define CHAT_CLIENT_HANDLER_HPP
|
||||
|
||||
// com.zaphoyd.websocketpp.chat protocol
|
||||
//
|
||||
// client messages:
|
||||
// alias [UTF8 text, 16 characters max]
|
||||
// msg [UTF8 text]
|
||||
//
|
||||
// server messages:
|
||||
// {"type":"msg","sender":"<sender>","value":"<msg>" }
|
||||
// {"type":"participants","value":[<participant>,...]}
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include "../../src/websocketpp.hpp"
|
||||
#include "../../src/websocket_connection_handler.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <queue>
|
||||
|
||||
using websocketpp::session_ptr;
|
||||
|
||||
namespace websocketchat {
|
||||
|
||||
class chat_client_handler : public websocketpp::connection_handler {
|
||||
public:
|
||||
chat_client_handler() {}
|
||||
virtual ~chat_client_handler() {}
|
||||
|
||||
// ignored for clients?
|
||||
void validate(session_ptr s) {}
|
||||
|
||||
// connection to chat room complete
|
||||
void on_open(session_ptr s);
|
||||
|
||||
// connection to chat room closed
|
||||
void on_close(session_ptr s);
|
||||
|
||||
// got a new message from server
|
||||
void on_message(session_ptr s,const std::string &msg);
|
||||
|
||||
// ignore messages
|
||||
void on_message(session_ptr s,const std::vector<unsigned char> &data) {}
|
||||
|
||||
// CLIENT API
|
||||
void send(const std::string &msg);
|
||||
void close();
|
||||
|
||||
private:
|
||||
// Client API internal
|
||||
void do_send(const std::string &msg);
|
||||
void do_close();
|
||||
|
||||
void decode_server_msg(const std::string &msg);
|
||||
|
||||
// list of other chat participants
|
||||
std::set<std::string> m_participants;
|
||||
std::queue<std::string> m_msg_queue;
|
||||
session_ptr m_session;
|
||||
};
|
||||
|
||||
typedef boost::shared_ptr<chat_client_handler> chat_client_handler_ptr;
|
||||
|
||||
}
|
||||
#endif // CHAT_CLIENT_HANDLER_HPP
|
||||
+4
File diff suppressed because one or more lines are too long
@@ -0,0 +1,23 @@
|
||||
CFLAGS = -O2
|
||||
LDFLAGS =
|
||||
|
||||
CXX ?= c++
|
||||
SHARED ?= "1"
|
||||
|
||||
ifeq ($(SHARED), 1)
|
||||
LDFLAGS := $(LDFLAGS) -lboost_system -lboost_date_time -lwebsocketpp
|
||||
else
|
||||
LDFLAGS := $(LDFLAGS) -lboost_system -lboost_date_time -lboost_regex -lboost_random -lboost_program_options ../../libwebsocketpp.a
|
||||
endif
|
||||
|
||||
chat_server: chat_server.o chat.o
|
||||
$(CXX) $(CFLAGS) $^ -o $@ $(LDFLAGS)
|
||||
|
||||
%.o: %.cpp
|
||||
$(CXX) -c $(CFLAGS) -o $@ $^
|
||||
|
||||
# cleanup by removing generated files
|
||||
#
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f *.o chat_server
|
||||
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "chat.hpp"
|
||||
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
|
||||
using websocketchat::chat_server_handler;
|
||||
using websocketpp::session_ptr;
|
||||
|
||||
void chat_server_handler::validate(session_ptr client) {
|
||||
std::stringstream err;
|
||||
|
||||
// We only know about the chat resource
|
||||
if (client->get_resource() != "/chat") {
|
||||
err << "Request for unknown resource " << client->get_resource();
|
||||
throw(websocketpp::handshake_error(err.str(),404));
|
||||
}
|
||||
|
||||
// Require specific origin example
|
||||
if (client->get_origin() != "http://zaphoyd.com") {
|
||||
err << "Request from unrecognized origin: " << client->get_origin();
|
||||
throw(websocketpp::handshake_error(err.str(),403));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void chat_server_handler::on_open(session_ptr client) {
|
||||
std::cout << "client " << client << " joined the lobby." << std::endl;
|
||||
m_connections.insert(std::pair<session_ptr,std::string>(client,get_con_id(client)));
|
||||
|
||||
// send user list and signon message to all clients
|
||||
send_to_all(serialize_state());
|
||||
client->send(encode_message("server","Welcome, use the /alias command to set a name, /help for a list of other commands."));
|
||||
send_to_all(encode_message("server",m_connections[client]+" has joined the chat."));
|
||||
}
|
||||
|
||||
void chat_server_handler::on_close(session_ptr client) {
|
||||
std::map<session_ptr,std::string>::iterator it = m_connections.find(client);
|
||||
|
||||
if (it == m_connections.end()) {
|
||||
// this client has already disconnected, we can ignore this.
|
||||
// this happens during certain types of disconnect where there is a
|
||||
// deliberate "soft" disconnection preceeding the "hard" socket read
|
||||
// fail or disconnect ack message.
|
||||
return;
|
||||
}
|
||||
|
||||
std::cout << "client " << client << " left the lobby." << std::endl;
|
||||
|
||||
const std::string alias = it->second;
|
||||
m_connections.erase(it);
|
||||
|
||||
// send user list and signoff message to all clients
|
||||
send_to_all(serialize_state());
|
||||
send_to_all(encode_message("server",alias+" has left the chat."));
|
||||
}
|
||||
|
||||
void chat_server_handler::on_message(session_ptr client,const std::string &msg) {
|
||||
std::cout << "message from client " << client << ": " << msg << std::endl;
|
||||
|
||||
|
||||
|
||||
// check for special command messages
|
||||
if (msg == "/help") {
|
||||
// print command list
|
||||
client->send(encode_message("server","avaliable commands:<br /> /help - show this help<br /> /alias foo - set alias to foo",false));
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg.substr(0,7) == "/alias ") {
|
||||
std::string response;
|
||||
std::string alias;
|
||||
|
||||
if (msg.size() == 7) {
|
||||
response = "You must enter an alias.";
|
||||
client->send(encode_message("server",response));
|
||||
return;
|
||||
} else {
|
||||
alias = msg.substr(7);
|
||||
}
|
||||
|
||||
response = m_connections[client] + " is now known as "+alias;
|
||||
|
||||
// store alias pre-escaped so we don't have to do this replacing every time this
|
||||
// user sends a message
|
||||
|
||||
// escape JSON characters
|
||||
boost::algorithm::replace_all(alias,"\\","\\\\");
|
||||
boost::algorithm::replace_all(alias,"\"","\\\"");
|
||||
|
||||
// escape HTML characters
|
||||
boost::algorithm::replace_all(alias,"&","&");
|
||||
boost::algorithm::replace_all(alias,"<","<");
|
||||
boost::algorithm::replace_all(alias,">",">");
|
||||
|
||||
m_connections[client] = alias;
|
||||
|
||||
// set alias
|
||||
send_to_all(serialize_state());
|
||||
send_to_all(encode_message("server",response));
|
||||
return;
|
||||
}
|
||||
|
||||
// catch other slash commands
|
||||
if (msg[0] == '/') {
|
||||
client->send(encode_message("server","unrecognized command"));
|
||||
return;
|
||||
}
|
||||
|
||||
// create JSON message to send based on msg
|
||||
send_to_all(encode_message(m_connections[client],msg));
|
||||
}
|
||||
|
||||
// {"type":"participants","value":[<participant>,...]}
|
||||
std::string chat_server_handler::serialize_state() {
|
||||
std::stringstream s;
|
||||
|
||||
s << "{\"type\":\"participants\",\"value\":[";
|
||||
|
||||
std::map<session_ptr,std::string>::iterator it;
|
||||
|
||||
for (it = m_connections.begin(); it != m_connections.end(); it++) {
|
||||
s << "\"" << (*it).second << "\"";
|
||||
if (++it != m_connections.end()) {
|
||||
s << ",";
|
||||
}
|
||||
it--;
|
||||
}
|
||||
|
||||
s << "]}";
|
||||
|
||||
return s.str();
|
||||
}
|
||||
|
||||
// {"type":"msg","sender":"<sender>","value":"<msg>" }
|
||||
std::string chat_server_handler::encode_message(std::string sender,std::string msg,bool escape) {
|
||||
std::stringstream s;
|
||||
|
||||
// escape JSON characters
|
||||
boost::algorithm::replace_all(msg,"\\","\\\\");
|
||||
boost::algorithm::replace_all(msg,"\"","\\\"");
|
||||
|
||||
// escape HTML characters
|
||||
if (escape) {
|
||||
boost::algorithm::replace_all(msg,"&","&");
|
||||
boost::algorithm::replace_all(msg,"<","<");
|
||||
boost::algorithm::replace_all(msg,">",">");
|
||||
}
|
||||
|
||||
s << "{\"type\":\"msg\",\"sender\":\"" << sender
|
||||
<< "\",\"value\":\"" << msg << "\"}";
|
||||
|
||||
return s.str();
|
||||
}
|
||||
|
||||
std::string chat_server_handler::get_con_id(session_ptr s) {
|
||||
std::stringstream endpoint;
|
||||
endpoint << s->socket().remote_endpoint();
|
||||
return endpoint.str();
|
||||
}
|
||||
|
||||
void chat_server_handler::send_to_all(std::string data) {
|
||||
std::map<session_ptr,std::string>::iterator it;
|
||||
for (it = m_connections.begin(); it != m_connections.end(); it++) {
|
||||
(*it).first->send(data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CHAT_HPP
|
||||
#define CHAT_HPP
|
||||
|
||||
// com.zaphoyd.websocketpp.chat protocol
|
||||
//
|
||||
// client messages:
|
||||
// alias [UTF8 text, 16 characters max]
|
||||
// msg [UTF8 text]
|
||||
//
|
||||
// server messages:
|
||||
// {"type":"msg","sender":"<sender>","value":"<msg>" }
|
||||
// {"type":"participants","value":[<participant>,...]}
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include "../../src/websocketpp.hpp"
|
||||
#include "../../src/websocket_connection_handler.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace websocketchat {
|
||||
|
||||
class chat_server_handler : public websocketpp::connection_handler {
|
||||
public:
|
||||
chat_server_handler() {}
|
||||
virtual ~chat_server_handler() {}
|
||||
|
||||
void validate(websocketpp::session_ptr client);
|
||||
|
||||
// add new connection to the lobby
|
||||
void on_open(websocketpp::session_ptr client);
|
||||
|
||||
// someone disconnected from the lobby, remove them
|
||||
void on_close(websocketpp::session_ptr client);
|
||||
|
||||
void on_message(websocketpp::session_ptr client,const std::string &msg);
|
||||
|
||||
// lobby will ignore binary messages
|
||||
void on_message(websocketpp::session_ptr client,
|
||||
const std::vector<unsigned char> &data) {}
|
||||
private:
|
||||
std::string serialize_state();
|
||||
std::string encode_message(std::string sender,std::string msg,bool escape = true);
|
||||
std::string get_con_id(websocketpp::session_ptr s);
|
||||
|
||||
void send_to_all(std::string data);
|
||||
|
||||
// list of outstanding connections
|
||||
std::map<websocketpp::session_ptr,std::string> m_connections;
|
||||
};
|
||||
|
||||
typedef boost::shared_ptr<chat_server_handler> chat_server_handler_ptr;
|
||||
|
||||
}
|
||||
#endif // CHAT_HPP
|
||||
@@ -0,0 +1,177 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<script type="text/javascript" src="jquery-1.6.3.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
var ws;
|
||||
var url;
|
||||
|
||||
$(document).ready(init);
|
||||
|
||||
function init() {
|
||||
$(document).keypress(function(event) {
|
||||
if ( event.which == 13 ) {
|
||||
event.preventDefault();
|
||||
send();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function connect() {
|
||||
url = $("#server_url").val();
|
||||
console.log(url);
|
||||
|
||||
if ("WebSocket" in window) {
|
||||
ws = new WebSocket(url);
|
||||
} else if ("MozWebSocket" in window) {
|
||||
ws = new MozWebSocket(url);
|
||||
} else {
|
||||
chat_message("This Browser does not support WebSockets");
|
||||
return;
|
||||
}
|
||||
ws.onopen = function(e) {
|
||||
chat_message("A connection to "+url+" has been opened.");
|
||||
|
||||
$("#server_url").attr("disabled",true);
|
||||
$("#toggle_connect").html("Disconnect");
|
||||
};
|
||||
|
||||
ws.onerror = function(e) {
|
||||
chat_message("An error occured, see console log for more details.");
|
||||
console.log(e);
|
||||
};
|
||||
|
||||
ws.onclose = function(e) {
|
||||
chat_message("The connection to "+url+" was closed.");
|
||||
};
|
||||
|
||||
ws.onmessage = function(e) {
|
||||
var message = JSON.parse(e.data);
|
||||
|
||||
if (message.type == "msg") {
|
||||
chat_message(message.value,message.sender);
|
||||
} else if (message.type == "participants") {
|
||||
var o = "<ul>";
|
||||
for (var p in message.value) {
|
||||
o += "<li>"+message.value[p]+"</li>";
|
||||
}
|
||||
o += "</ul>";
|
||||
$("#participants").html(o);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function chat_message(message,sender) {
|
||||
if (arguments.length == 1) {
|
||||
sender = "";
|
||||
}
|
||||
|
||||
var style;
|
||||
|
||||
if (sender == "") {
|
||||
style = "client";
|
||||
} else if (sender == "server") {
|
||||
style = "server";
|
||||
sender = "["+sender+"]";
|
||||
} else {
|
||||
style = "message";
|
||||
sender = "["+sender+"]";
|
||||
}
|
||||
|
||||
$("#messages").append("<span class='"+style+"'><span class='sender'>"+sender+"</span> <span class='msg'>"+message+"</span></span><br />");
|
||||
$("#messages").prop({ scrollTop: $("#messages").prop("scrollHeight") });
|
||||
}
|
||||
|
||||
function disconnect() {
|
||||
ws.close();
|
||||
$("#server_url").removeAttr("disabled");
|
||||
$("#toggle_connect").html("Connect");
|
||||
$("#participants").html("");
|
||||
}
|
||||
|
||||
function toggle_connect() {
|
||||
if ($("#server_url").attr("disabled") != "disabled") {
|
||||
connect();
|
||||
} else {
|
||||
disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
function send() {
|
||||
if (ws === undefined || ws.readyState != 1) {
|
||||
chat_message("Websocket is not avaliable for writing");
|
||||
return;
|
||||
}
|
||||
|
||||
ws.send($("#msg").val());
|
||||
$("#msg").val("");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
body,html {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
height: 100%;
|
||||
background-color: #999;
|
||||
font-family: sans-serif;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
|
||||
}
|
||||
|
||||
#controls {
|
||||
padding: 4px;
|
||||
float:right;
|
||||
width: 300px;
|
||||
|
||||
}
|
||||
|
||||
input {
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
#messages {
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
#messages .client {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
#messages .server {
|
||||
color: yellow;
|
||||
}
|
||||
|
||||
#messages .message {
|
||||
color: white;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<div id="controls">
|
||||
<div id="server">
|
||||
<input type="text" name="server_url" id="server_url" value="ws://thor-websocket.zaphoyd.net:9000/chat" />
|
||||
<button id="toggle_connect" onclick="toggle_connect();">Connect</button>
|
||||
</div>
|
||||
|
||||
<div id="message_input"><input type="text" name="msg" id="msg" value="Hello World!" />
|
||||
<button onclick="send();">Send</button></div>
|
||||
<h3>Chat Participants</h3>
|
||||
<div id="participants"></div>
|
||||
</div>
|
||||
<div id="messages"></div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2011, 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:
|
||||
@@ -11,10 +11,10 @@
|
||||
* * 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
|
||||
*
|
||||
* 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;
|
||||
@@ -22,51 +22,63 @@
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*/
|
||||
//#define BOOST_TEST_DYN_LINK
|
||||
#define BOOST_TEST_MODULE message
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include "chat.hpp"
|
||||
|
||||
#include "../../src/websocketpp.hpp"
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include <websocketpp/message_buffer/message.hpp>
|
||||
using boost::asio::ip::tcp;
|
||||
using namespace websocketchat;
|
||||
|
||||
template <typename message>
|
||||
struct stub {
|
||||
typedef websocketpp::lib::weak_ptr<stub> weak_ptr;
|
||||
typedef websocketpp::lib::shared_ptr<stub> ptr;
|
||||
|
||||
stub() : recycled(false) {}
|
||||
|
||||
bool recycle(message * msg) {
|
||||
this->recycled = true;
|
||||
return false;
|
||||
int main(int argc, char* argv[]) {
|
||||
std::string host = "localhost";
|
||||
short port = 9003;
|
||||
std::string full_host;
|
||||
|
||||
if (argc == 3) {
|
||||
// TODO: input validation?
|
||||
host = argv[1];
|
||||
port = atoi(argv[2]);
|
||||
}
|
||||
|
||||
bool recycled;
|
||||
};
|
||||
|
||||
BOOST_AUTO_TEST_CASE( basic_size_check ) {
|
||||
typedef websocketpp::message_buffer::message<stub> message_type;
|
||||
typedef stub<message_type> stub_type;
|
||||
|
||||
stub_type::ptr s(new stub_type());
|
||||
message_type::ptr msg(new message_type(s,websocketpp::frame::opcode::TEXT,500));
|
||||
|
||||
BOOST_CHECK(msg->get_payload().capacity() >= 500);
|
||||
|
||||
std::stringstream temp;
|
||||
|
||||
temp << host << ":" << port;
|
||||
full_host = temp.str();
|
||||
|
||||
|
||||
chat_server_handler_ptr chat_handler(new chat_server_handler());
|
||||
|
||||
try {
|
||||
boost::asio::io_service io_service;
|
||||
tcp::endpoint endpoint(tcp::v6(), port);
|
||||
|
||||
websocketpp::server_ptr server(
|
||||
new websocketpp::server(io_service,endpoint,chat_handler)
|
||||
);
|
||||
|
||||
// setup server settings
|
||||
server->add_host(host);
|
||||
server->add_host(full_host);
|
||||
// Chat server should only be receiving small text messages, reduce max
|
||||
// message size limit slightly to save memory, improve performance, and
|
||||
// guard against DoS attacks.
|
||||
server->set_max_message_size(0xFFFF); // 64KiB
|
||||
|
||||
// start the server
|
||||
server->start_accept();
|
||||
|
||||
std::cout << "Starting chat server on " << full_host << std::endl;
|
||||
|
||||
io_service.run();
|
||||
} catch (std::exception& e) {
|
||||
std::cerr << "Exception: " << e.what() << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( recycle ) {
|
||||
typedef websocketpp::message_buffer::message<stub> message_type;
|
||||
typedef stub<message_type> stub_type;
|
||||
|
||||
stub_type::ptr s(new stub_type());
|
||||
message_type::ptr msg(new message_type(s,websocketpp::frame::opcode::TEXT,500));
|
||||
|
||||
BOOST_CHECK(s->recycled == false);
|
||||
BOOST_CHECK(msg->recycle() == false);
|
||||
BOOST_CHECK(s->recycled == true);
|
||||
}
|
||||
|
||||
+4
File diff suppressed because one or more lines are too long
@@ -1,18 +0,0 @@
|
||||
## Main development example
|
||||
##
|
||||
|
||||
Import('env')
|
||||
Import('env_cpp11')
|
||||
Import('boostlibs')
|
||||
Import('platform_libs')
|
||||
Import('polyfill_libs')
|
||||
|
||||
env_cpp11 = env_cpp11.Clone ()
|
||||
|
||||
prgs = []
|
||||
|
||||
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
|
||||
BOOST_LIBS_CPP11 = boostlibs(['unit_test_framework','system','timer','chrono'],env_cpp11) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env_cpp11.Program('main', ["main.cpp"], LIBS = BOOST_LIBS_CPP11)
|
||||
|
||||
Return('prgs')
|
||||
@@ -1,200 +0,0 @@
|
||||
//#ifndef _WEBSOCKETPP_CPP11_STL_
|
||||
// #define _WEBSOCKETPP_CPP11_STL_
|
||||
//#endif
|
||||
|
||||
#include <random>
|
||||
#include <boost/timer/timer.hpp>
|
||||
|
||||
#include <websocketpp/config/core.hpp>
|
||||
|
||||
//#include <websocketpp/security/none.hpp>
|
||||
|
||||
//#include <websocketpp/concurrency/none.hpp>
|
||||
//#include <websocketpp/concurrency/stl.hpp>
|
||||
|
||||
//#include <websocketpp/transport/iostream.hpp>
|
||||
#include <websocketpp/server.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
//typedef websocketpp::concurrency::stl concurrency;
|
||||
//typedef websocketpp::transport::iostream<concurrency> transport;
|
||||
//typedef websocketpp::server<concurrency,transport> server;
|
||||
typedef websocketpp::server<websocketpp::config::core> server;
|
||||
|
||||
/*class handler : public server::handler {
|
||||
bool validate(connection_ptr con) {
|
||||
std::cout << "handler validate" << std::endl;
|
||||
if (con->get_origin() != "http://www.example.com") {
|
||||
con->set_status(websocketpp::http::status_code::FORBIDDEN);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void http(connection_ptr con) {
|
||||
std::cout << "handler http" << std::endl;
|
||||
}
|
||||
|
||||
void on_load(connection_ptr con, ptr old_handler) {
|
||||
std::cout << "handler on_load" << std::endl;
|
||||
}
|
||||
void on_unload(connection_ptr con, ptr new_handler) {
|
||||
std::cout << "handler on_unload" << std::endl;
|
||||
}
|
||||
|
||||
void on_open(connection_ptr con) {
|
||||
std::cout << "handler on_open" << std::endl;
|
||||
}
|
||||
void on_fail(connection_ptr con) {
|
||||
std::cout << "handler on_fail" << std::endl;
|
||||
}
|
||||
|
||||
void on_message(connection_ptr con, message_ptr msg) {
|
||||
std::cout << "handler on_message" << std::endl;
|
||||
|
||||
|
||||
}
|
||||
|
||||
void on_close(connection_ptr con) {
|
||||
std::cout << "handler on_close" << std::endl;
|
||||
}
|
||||
};*/
|
||||
|
||||
int main() {
|
||||
typedef websocketpp::message_buffer::message<websocketpp::message_buffer::alloc::con_msg_manager>
|
||||
message_type;
|
||||
typedef websocketpp::message_buffer::alloc::con_msg_manager<message_type>
|
||||
con_msg_man_type;
|
||||
|
||||
con_msg_man_type::ptr manager(new con_msg_man_type());
|
||||
|
||||
size_t foo = 1024;
|
||||
|
||||
message_type::ptr input = manager->get_message(websocketpp::frame::opcode::TEXT,foo);
|
||||
message_type::ptr output = manager->get_message(websocketpp::frame::opcode::TEXT,foo);
|
||||
websocketpp::frame::masking_key_type key;
|
||||
|
||||
std::random_device dev;
|
||||
|
||||
|
||||
|
||||
key.i = 0x12345678;
|
||||
|
||||
double m = 18094238402394.0824923;
|
||||
|
||||
/*std::cout << "Some Math" << std::endl;
|
||||
{
|
||||
boost::timer::auto_cpu_timer t;
|
||||
|
||||
for (int i = 0; i < foo; i++) {
|
||||
m /= 1.001;
|
||||
}
|
||||
|
||||
}*/
|
||||
|
||||
std::cout << m << std::endl;
|
||||
|
||||
std::cout << "Random Gen" << std::endl;
|
||||
{
|
||||
boost::timer::auto_cpu_timer t;
|
||||
|
||||
input->get_raw_payload().replace(0,foo,foo,'\0');
|
||||
output->get_raw_payload().replace(0,foo,foo,'\0');
|
||||
}
|
||||
|
||||
std::cout << "Out of place accelerated" << std::endl;
|
||||
{
|
||||
boost::timer::auto_cpu_timer t;
|
||||
|
||||
websocketpp::frame::word_mask_exact(reinterpret_cast<uint8_t*>(const_cast<char*>(input->get_raw_payload().data())), reinterpret_cast<uint8_t*>(const_cast<char*>(output->get_raw_payload().data())), foo, key);
|
||||
}
|
||||
|
||||
std::cout << websocketpp::utility::to_hex(input->get_payload().c_str(),20) << std::endl;
|
||||
std::cout << websocketpp::utility::to_hex(output->get_payload().c_str(),20) << std::endl;
|
||||
|
||||
input->get_raw_payload().replace(0,foo,foo,'\0');
|
||||
output->get_raw_payload().replace(0,foo,foo,'\0');
|
||||
|
||||
std::cout << "In place accelerated" << std::endl;
|
||||
{
|
||||
boost::timer::auto_cpu_timer t;
|
||||
|
||||
websocketpp::frame::word_mask_exact(reinterpret_cast<uint8_t*>(const_cast<char*>(input->get_raw_payload().data())), reinterpret_cast<uint8_t*>(const_cast<char*>(input->get_raw_payload().data())), foo, key);
|
||||
}
|
||||
|
||||
std::cout << websocketpp::utility::to_hex(input->get_payload().c_str(),20) << std::endl;
|
||||
std::cout << websocketpp::utility::to_hex(output->get_payload().c_str(),20) << std::endl;
|
||||
|
||||
input->get_raw_payload().replace(0,foo,foo,'\0');
|
||||
output->get_raw_payload().replace(0,foo,foo,'\0');
|
||||
std::cout << "Out of place byte by byte" << std::endl;
|
||||
{
|
||||
boost::timer::auto_cpu_timer t;
|
||||
|
||||
websocketpp::frame::byte_mask(input->get_raw_payload().begin(), input->get_raw_payload().end(), output->get_raw_payload().begin(), key);
|
||||
}
|
||||
|
||||
std::cout << websocketpp::utility::to_hex(input->get_payload().c_str(),20) << std::endl;
|
||||
std::cout << websocketpp::utility::to_hex(output->get_payload().c_str(),20) << std::endl;
|
||||
|
||||
input->get_raw_payload().replace(0,foo,foo,'\0');
|
||||
output->get_raw_payload().replace(0,foo,foo,'\0');
|
||||
std::cout << "In place byte by byte" << std::endl;
|
||||
{
|
||||
boost::timer::auto_cpu_timer t;
|
||||
|
||||
websocketpp::frame::byte_mask(input->get_raw_payload().begin(), input->get_raw_payload().end(), input->get_raw_payload().begin(), key);
|
||||
}
|
||||
|
||||
std::cout << websocketpp::utility::to_hex(input->get_payload().c_str(),20) << std::endl;
|
||||
std::cout << websocketpp::utility::to_hex(output->get_payload().c_str(),20) << std::endl;
|
||||
|
||||
input->get_raw_payload().replace(0,foo,foo,'a');
|
||||
output->get_raw_payload().replace(0,foo,foo,'b');
|
||||
std::cout << "Copy" << std::endl;
|
||||
{
|
||||
boost::timer::auto_cpu_timer t;
|
||||
|
||||
std::copy(input->get_raw_payload().begin(), input->get_raw_payload().end(), output->get_raw_payload().begin());
|
||||
}
|
||||
|
||||
std::cout << websocketpp::utility::to_hex(input->get_payload().c_str(),20) << std::endl;
|
||||
std::cout << websocketpp::utility::to_hex(output->get_payload().c_str(),20) << std::endl;
|
||||
|
||||
/*server::handler::ptr h(new handler());
|
||||
|
||||
server test_server(h);
|
||||
server::connection_ptr con;
|
||||
|
||||
std::stringstream output;
|
||||
|
||||
test_server.register_ostream(&output);
|
||||
|
||||
con = test_server.get_connection();
|
||||
|
||||
con->start();
|
||||
|
||||
//foo.handle_accept(con,true);
|
||||
|
||||
std::stringstream input;
|
||||
input << "GET / HTTP/1.1\r\nHost: www.example.com\r\nConnection: upgrade\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 13\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\nOrigin: http://www.example.com\r\n\r\n";
|
||||
//input << "GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n";
|
||||
input >> *con;
|
||||
|
||||
std::stringstream input2;
|
||||
input2 << "messageabc2";
|
||||
input2 >> *con;
|
||||
|
||||
std::stringstream input3;
|
||||
input3 << "messageabc3";
|
||||
input3 >> *con;
|
||||
|
||||
std::stringstream input4;
|
||||
input4 << "close";
|
||||
input4 >> *con;
|
||||
|
||||
std::cout << "connection output:" << std::endl;
|
||||
std::cout << output.str() << std::endl;*/
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
CFLAGS = -O2
|
||||
LDFLAGS =
|
||||
|
||||
CXX ?= c++
|
||||
SHARED ?= "1"
|
||||
|
||||
ifeq ($(SHARED), 1)
|
||||
LDFLAGS := $(LDFLAGS) -lboost_system -lboost_thread -lwebsocketpp
|
||||
else
|
||||
LDFLAGS := $(LDFLAGS) -lboost_system -lboost_thread -lboost_date_time -lboost_regex -lboost_random -lboost_program_options ../../libwebsocketpp.a
|
||||
endif
|
||||
|
||||
echo_client: echo_client.o echo_client_handler.o
|
||||
$(CXX) $(CFLAGS) $^ -o $@ $(LDFLAGS)
|
||||
|
||||
%.o: %.cpp
|
||||
$(CXX) -c $(CFLAGS) -o $@ $^
|
||||
|
||||
# cleanup by removing generated files
|
||||
#
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f *.o echo_client
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "echo_client_handler.hpp"
|
||||
|
||||
#include "../../src/websocketpp.hpp"
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using boost::asio::ip::tcp;
|
||||
using namespace websocketecho;
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
std::string uri;
|
||||
|
||||
/*if (argc != 2) {
|
||||
std::cout << "Usage: `echo_client test_url`" << std::endl;
|
||||
} else {
|
||||
uri = argv[1];
|
||||
}*/
|
||||
|
||||
echo_client_handler_ptr c(new echo_client_handler());
|
||||
|
||||
try {
|
||||
boost::asio::io_service io_service;
|
||||
|
||||
websocketpp::client_ptr client(new websocketpp::client(io_service,c));
|
||||
|
||||
client->init();
|
||||
client->set_header("User Agent","WebSocket++/2011-10-27");
|
||||
|
||||
client->connect("ws://localhost:9001/getCaseCount");
|
||||
io_service.run();
|
||||
|
||||
std::cout << "case count: " << c->m_case_count << std::endl;
|
||||
|
||||
for (int i = 1; i <= c->m_case_count; i++) {
|
||||
io_service.reset();
|
||||
|
||||
client->set_alog_level(websocketpp::ALOG_OFF);
|
||||
client->set_elog_level(websocketpp::LOG_OFF);
|
||||
|
||||
client->init();
|
||||
client->set_header("User Agent","WebSocket++/2011-10-27");
|
||||
|
||||
|
||||
std::stringstream url;
|
||||
|
||||
url << "ws://localhost:9001/runCase?case=" << i << "&agent=\"WebSocket++Snapshot/2011-10-27\"";
|
||||
|
||||
client->connect(url.str());
|
||||
|
||||
io_service.run();
|
||||
}
|
||||
|
||||
std::cout << "done" << std::endl;
|
||||
|
||||
} catch (std::exception& e) {
|
||||
std::cerr << "Exception: " << e.what() << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2011, 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:
|
||||
@@ -11,10 +11,10 @@
|
||||
* * 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
|
||||
*
|
||||
* 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;
|
||||
@@ -22,36 +22,35 @@
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "connection_tu2.hpp"
|
||||
#include "echo_client_handler.hpp"
|
||||
|
||||
void echo_func(server* s, websocketpp::connection_hdl hdl, message_ptr msg) {
|
||||
s->send(hdl, msg->get_payload(), msg->get_opcode());
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
|
||||
using websocketecho::echo_client_handler;
|
||||
using websocketpp::client_session_ptr;
|
||||
|
||||
void echo_client_handler::on_open(session_ptr s) {
|
||||
std::cout << " Successfully connected (handshake complete): " << s->get_resource() << std::endl;
|
||||
}
|
||||
|
||||
std::string run_server_test(std::string input) {
|
||||
server test_server;
|
||||
return run_server_test(test_server,input);
|
||||
void echo_client_handler::on_close(session_ptr s) {
|
||||
std::cout << " client was disconnected (WS state is now CLOSED)" << std::endl;
|
||||
}
|
||||
|
||||
std::string run_server_test(server & s, std::string input) {
|
||||
server::connection_ptr con;
|
||||
std::stringstream output;
|
||||
|
||||
s.clear_access_channels(websocketpp::log::alevel::all);
|
||||
s.clear_error_channels(websocketpp::log::elevel::all);
|
||||
|
||||
s.register_ostream(&output);
|
||||
|
||||
con = s.get_connection();
|
||||
con->start();
|
||||
|
||||
std::stringstream channel;
|
||||
|
||||
channel << input;
|
||||
channel >> *con;
|
||||
|
||||
return output.str();
|
||||
void echo_client_handler::on_message(session_ptr s,const std::string &msg) {
|
||||
if (s->get_resource() == "/getCaseCount") {
|
||||
std::cout << "Detected " << msg << " test cases." << std::endl;
|
||||
m_case_count = atoi(msg.c_str());
|
||||
} else {
|
||||
s->send(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void echo_client_handler::on_message(session_ptr s,
|
||||
const std::vector<unsigned char> &data) {
|
||||
s->send(data);
|
||||
}
|
||||
@@ -11,10 +11,10 @@
|
||||
* * 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
|
||||
*
|
||||
* 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;
|
||||
@@ -22,52 +22,56 @@
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*/
|
||||
//#define BOOST_TEST_DYN_LINK
|
||||
#define BOOST_TEST_MODULE utility
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#ifndef ECHO_CLIENT_HANDLER_HPP
|
||||
#define ECHO_CLIENT_HANDLER_HPP
|
||||
|
||||
// com.zaphoyd.websocketpp.chat protocol
|
||||
//
|
||||
// client messages:
|
||||
// alias [UTF8 text, 16 characters max]
|
||||
// msg [UTF8 text]
|
||||
//
|
||||
// server messages:
|
||||
// {"type":"msg","sender":"<sender>","value":"<msg>" }
|
||||
// {"type":"participants","value":[<participant>,...]}
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include "../../src/websocketpp.hpp"
|
||||
#include "../../src/websocket_connection_handler.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <queue>
|
||||
|
||||
#include <websocketpp/utilities.hpp>
|
||||
using websocketpp::session_ptr;
|
||||
|
||||
BOOST_AUTO_TEST_SUITE ( utility )
|
||||
namespace websocketecho {
|
||||
|
||||
BOOST_AUTO_TEST_CASE( substr_found ) {
|
||||
std::string haystack = "abc123";
|
||||
std::string needle = "abc";
|
||||
class echo_client_handler : public websocketpp::connection_handler {
|
||||
public:
|
||||
echo_client_handler() : m_case_count(0) {}
|
||||
virtual ~echo_client_handler() {}
|
||||
|
||||
// connection to chat room complete
|
||||
void on_open(session_ptr s);
|
||||
|
||||
// connection to chat room closed
|
||||
void on_close(session_ptr sn);
|
||||
|
||||
// got a new message from server
|
||||
void on_message(session_ptr s,const std::string &msg);
|
||||
|
||||
// ignore messages
|
||||
void on_message(session_ptr s,const std::vector<unsigned char> &data);
|
||||
|
||||
int m_case_count;
|
||||
};
|
||||
|
||||
typedef boost::shared_ptr<echo_client_handler> echo_client_handler_ptr;
|
||||
|
||||
BOOST_CHECK(websocketpp::utility::ci_find_substr(haystack,needle) ==haystack.begin());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( substr_found_ci ) {
|
||||
std::string haystack = "abc123";
|
||||
std::string needle = "aBc";
|
||||
|
||||
BOOST_CHECK(websocketpp::utility::ci_find_substr(haystack,needle) ==haystack.begin());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( substr_not_found ) {
|
||||
std::string haystack = "abd123";
|
||||
std::string needle = "abcd";
|
||||
|
||||
BOOST_CHECK(websocketpp::utility::ci_find_substr(haystack,needle) == haystack.end());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( to_lower ) {
|
||||
std::string in = "AbCd";
|
||||
|
||||
BOOST_CHECK_EQUAL(websocketpp::utility::to_lower(in), "abcd");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( string_replace_all ) {
|
||||
std::string source = "foo \"bar\" baz";
|
||||
std::string dest = "foo \\\"bar\\\" baz";
|
||||
|
||||
using websocketpp::utility::string_replace_all;
|
||||
BOOST_CHECK_EQUAL(string_replace_all(source,"\"","\\\""),dest);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
#endif // ECHO_CLIENT_HANDLER_HPP
|
||||
@@ -1,10 +0,0 @@
|
||||
|
||||
file (GLOB SOURCE_FILES *.cpp)
|
||||
file (GLOB HEADER_FILES *.hpp)
|
||||
|
||||
init_target (echo_server)
|
||||
|
||||
build_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})
|
||||
|
||||
link_boost ()
|
||||
final_target ()
|
||||
@@ -0,0 +1,23 @@
|
||||
CFLAGS = -O2
|
||||
LDFLAGS =
|
||||
|
||||
CXX ?= c++
|
||||
SHARED ?= "1"
|
||||
|
||||
ifeq ($(SHARED), 1)
|
||||
LDFLAGS := $(LDFLAGS) -lboost_system -lboost_date_time -lwebsocketpp
|
||||
else
|
||||
LDFLAGS := $(LDFLAGS) -lboost_system -lboost_date_time -lboost_regex -lboost_random -lboost_program_options ../../libwebsocketpp.a
|
||||
endif
|
||||
|
||||
echo_server: echo_server.o echo.o
|
||||
$(CXX) $(CFLAGS) $^ -o $@ $(LDFLAGS)
|
||||
|
||||
%.o: %.cpp
|
||||
$(CXX) -c $(CFLAGS) -o $@ $^
|
||||
|
||||
# cleanup by removing generated files
|
||||
#
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f *.o echo_server
|
||||
@@ -1,23 +0,0 @@
|
||||
## Main development example
|
||||
##
|
||||
|
||||
Import('env')
|
||||
Import('env_cpp11')
|
||||
Import('boostlibs')
|
||||
Import('platform_libs')
|
||||
Import('polyfill_libs')
|
||||
|
||||
env = env.Clone ()
|
||||
env_cpp11 = env_cpp11.Clone ()
|
||||
|
||||
prgs = []
|
||||
|
||||
# if a C++11 environment is available build using that, otherwise use boost
|
||||
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
|
||||
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env_cpp11.Program('echo_server', ["echo_server.cpp"], LIBS = ALL_LIBS)
|
||||
else:
|
||||
ALL_LIBS = boostlibs(['system'],env) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env.Program('echo_server', ["echo_server.cpp"], LIBS = ALL_LIBS)
|
||||
|
||||
Return('prgs')
|
||||
@@ -11,10 +11,10 @@
|
||||
* * 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
|
||||
*
|
||||
* 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;
|
||||
@@ -22,16 +22,20 @@
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*/
|
||||
//#define BOOST_TEST_DYN_LINK
|
||||
#define BOOST_TEST_MODULE extension
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <string>
|
||||
#include "echo.hpp"
|
||||
|
||||
#include <websocketpp/extensions/extension.hpp>
|
||||
using websocketecho::echo_server_handler;
|
||||
|
||||
BOOST_AUTO_TEST_CASE( blank ) {
|
||||
BOOST_CHECK( true );
|
||||
void echo_server_handler::validate(websocketpp::session_ptr client) {}
|
||||
|
||||
void echo_server_handler::on_message(websocketpp::session_ptr client, const std::string &msg) {
|
||||
client->send(msg);
|
||||
}
|
||||
|
||||
void echo_server_handler::on_message(websocketpp::session_ptr client,
|
||||
const std::vector<unsigned char> &data) {
|
||||
client->send(data);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2011, 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:
|
||||
@@ -11,10 +11,10 @@
|
||||
* * 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
|
||||
*
|
||||
* 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;
|
||||
@@ -22,42 +22,44 @@
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBSOCKETPP_LOGGER_STUB_HPP
|
||||
#define WEBSOCKETPP_LOGGER_STUB_HPP
|
||||
#ifndef ECHO_SERVER_HANDLER_HPP
|
||||
#define ECHO_SERVER_HANDLER_HPP
|
||||
#include "../../src/websocketpp.hpp"
|
||||
#include "../../src/websocket_connection_handler.hpp"
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <websocketpp/common/cpp11.hpp>
|
||||
#include <websocketpp/logger/levels.hpp>
|
||||
using websocketpp::session_ptr;
|
||||
|
||||
namespace websocketpp {
|
||||
namespace log {
|
||||
namespace websocketecho {
|
||||
|
||||
/// Stub logger that ignores all input
|
||||
class stub {
|
||||
class echo_server_handler : public websocketpp::connection_handler {
|
||||
public:
|
||||
explicit stub(std::ostream * out) {}
|
||||
stub(level c, std::ostream * out) {}
|
||||
_WEBSOCKETPP_CONSTEXPR_TOKEN_ stub() {}
|
||||
|
||||
void set_channels(level channels) {}
|
||||
void clear_channels(level channels) {}
|
||||
|
||||
void write(level channel, std::string const & msg) {}
|
||||
void write(level channel, char const * msg) {}
|
||||
|
||||
_WEBSOCKETPP_CONSTEXPR_TOKEN_ bool static_test(level channel) const {
|
||||
return false;
|
||||
}
|
||||
bool dynamic_test(level channel) {
|
||||
return false;
|
||||
}
|
||||
echo_server_handler() {}
|
||||
virtual ~echo_server_handler() {}
|
||||
|
||||
// The echo server allows all domains is protocol free.
|
||||
void validate(session_ptr client);
|
||||
|
||||
// an echo server is stateless.
|
||||
// The handler has no need to keep track of connected clients.
|
||||
void on_fail(session_ptr client) {}
|
||||
void on_open(session_ptr client) {}
|
||||
void on_close(session_ptr client) {}
|
||||
|
||||
// both text and binary messages are echoed back to the sending client.
|
||||
void on_message(session_ptr client,const std::string &msg);
|
||||
void on_message(session_ptr client,
|
||||
const std::vector<unsigned char> &data);
|
||||
};
|
||||
|
||||
} // log
|
||||
} // websocketpp
|
||||
typedef boost::shared_ptr<echo_server_handler> echo_server_handler_ptr;
|
||||
|
||||
#endif // WEBSOCKETPP_LOGGER_STUB_HPP
|
||||
}
|
||||
|
||||
#endif // ECHO_SERVER_HANDLER_HPP
|
||||
@@ -0,0 +1,94 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
var ws;
|
||||
var url;
|
||||
|
||||
function connect() {
|
||||
url = document.getElementById("server_url").value;
|
||||
console.log(url);
|
||||
|
||||
if ("WebSocket" in window) {
|
||||
ws = new WebSocket(url);
|
||||
} else if ("MozWebSocket" in window) {
|
||||
ws = new MozWebSocket(url);
|
||||
} else {
|
||||
document.getElementById("messages").innerHTML += "This Browser does not support WebSockets<br />";
|
||||
return;
|
||||
}
|
||||
ws.onopen = function(e) {
|
||||
document.getElementById("messages").innerHTML += "Client: A connection to "+ws.URL+" has been opened.<br />";
|
||||
|
||||
document.getElementById("server_url").disabled = true;
|
||||
document.getElementById("toggle_connect").innerHTML = "Disconnect";
|
||||
};
|
||||
|
||||
ws.onerror = function(e) {
|
||||
document.getElementById("messages").innerHTML += "Client: An error occured, see console log for more details.<br />";
|
||||
console.log(e);
|
||||
};
|
||||
|
||||
ws.onclose = function(e) {
|
||||
document.getElementById("messages").innerHTML += "Client: The connection to "+url+" was closed.<br />";
|
||||
};
|
||||
|
||||
ws.onmessage = function(e) {
|
||||
document.getElementById("messages").innerHTML += "Server: "+e.data+"<br />";
|
||||
};
|
||||
}
|
||||
|
||||
function disconnect() {
|
||||
ws.close();
|
||||
document.getElementById("server_url").disabled = false;
|
||||
document.getElementById("toggle_connect").innerHTML = "Connect";
|
||||
}
|
||||
|
||||
function toggle_connect() {
|
||||
if (document.getElementById("server_url").disabled === false) {
|
||||
connect();
|
||||
} else {
|
||||
disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
function send() {
|
||||
if (ws === undefined || ws.readyState != 1) {
|
||||
document.getElementById("messages").innerHTML += "Client: Websocket is not avaliable for writing<br />";
|
||||
return;
|
||||
}
|
||||
|
||||
ws.send(document.getElementById("msg").value);
|
||||
document.getElementById("msg").value = "";
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
body,html {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
#controls {
|
||||
float:right;
|
||||
background-color: #999;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<div id="controls">
|
||||
<div id="server">
|
||||
<input type="text" name="server_url" id="server_url" value="ws://localhost:5000" />
|
||||
<button id="toggle_connect" onclick="toggle_connect();">Connect</button>
|
||||
</div>
|
||||
|
||||
<div id="message_input"><input type="text" name="msg" id="msg" value="Hello World!" />
|
||||
<button onclick="send();">Send</button></div>
|
||||
</div>
|
||||
<div id="messages"></div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBSOCKETPP_ECHO_SERVER_HANDLER_HPP
|
||||
#define WEBSOCKETPP_ECHO_SERVER_HANDLER_HPP
|
||||
|
||||
class echo_handler : public server::handler {
|
||||
void on_message(connection_ptr con, std::string msg) {
|
||||
con->write(msg);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // WEBSOCKETPP_ECHO_SERVER_HANDLER_HPP
|
||||
@@ -1,60 +1,90 @@
|
||||
#include <websocketpp/config/asio_no_tls.hpp>
|
||||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <websocketpp/server.hpp>
|
||||
#include "echo.hpp"
|
||||
|
||||
#include "../../src/websocketpp.hpp"
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
typedef websocketpp::server<websocketpp::config::asio> server;
|
||||
|
||||
using websocketpp::lib::placeholders::_1;
|
||||
using websocketpp::lib::placeholders::_2;
|
||||
using websocketpp::lib::bind;
|
||||
|
||||
// pull out the type of messages sent by our config
|
||||
typedef server::message_ptr message_ptr;
|
||||
|
||||
// Define a callback to handle incoming messages
|
||||
void on_message(server* s, websocketpp::connection_hdl hdl, message_ptr msg) {
|
||||
std::cout << "on_message called with hdl: " << hdl.lock().get()
|
||||
<< " and message: " << msg->get_payload()
|
||||
<< std::endl;
|
||||
|
||||
try {
|
||||
s->send(hdl, msg->get_payload(), msg->get_opcode());
|
||||
} catch (const websocketpp::lib::error_code& e) {
|
||||
std::cout << "Echo failed because: " << e
|
||||
<< "(" << e.message() << ")" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
// Create a server endpoint
|
||||
server echo_server;
|
||||
using boost::asio::ip::tcp;
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
std::string host = "localhost";
|
||||
short port = 9002;
|
||||
std::string full_host;
|
||||
|
||||
if (argc == 3) {
|
||||
// TODO: input validation?
|
||||
host = argv[1];
|
||||
port = atoi(argv[2]);
|
||||
}
|
||||
|
||||
std::stringstream temp;
|
||||
|
||||
temp << host << ":" << port;
|
||||
full_host = temp.str();
|
||||
|
||||
websocketecho::echo_server_handler_ptr echo_handler(new websocketecho::echo_server_handler());
|
||||
|
||||
try {
|
||||
// Set logging settings
|
||||
echo_server.set_access_channels(websocketpp::log::alevel::all);
|
||||
echo_server.clear_access_channels(websocketpp::log::alevel::frame_payload);
|
||||
|
||||
// Initialize ASIO
|
||||
echo_server.init_asio();
|
||||
|
||||
// Register our message handler
|
||||
echo_server.set_message_handler(bind(&on_message,&echo_server,::_1,::_2));
|
||||
|
||||
// Listen on port 9002
|
||||
echo_server.listen(9002);
|
||||
|
||||
// Start the server accept loop
|
||||
echo_server.start_accept();
|
||||
|
||||
// Start the ASIO io_service run loop
|
||||
echo_server.run();
|
||||
} catch (const std::exception & e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
} catch (websocketpp::lib::error_code e) {
|
||||
std::cout << e.message() << std::endl;
|
||||
} catch (...) {
|
||||
std::cout << "other exception" << std::endl;
|
||||
}
|
||||
boost::asio::io_service io_service;
|
||||
tcp::endpoint endpoint(tcp::v6(), port);
|
||||
|
||||
websocketpp::server_ptr server(
|
||||
new websocketpp::server(io_service,endpoint,echo_handler)
|
||||
);
|
||||
|
||||
//server->parse_command_line(argc, argv);
|
||||
|
||||
|
||||
|
||||
// setup server settings
|
||||
//server->set_alog_level(websocketpp::ALOG_OFF);
|
||||
//server->set_elog_level(websocketpp::LOG_OFF);
|
||||
|
||||
server->add_host(host);
|
||||
server->add_host(full_host);
|
||||
|
||||
// bump up max message size to maximum since we may be using the echo
|
||||
// server to test performance and protocol extremes.
|
||||
server->set_max_message_size(websocketpp::frame::PAYLOAD_64BIT_LIMIT);
|
||||
|
||||
// start the server
|
||||
server->start_accept();
|
||||
|
||||
std::cout << "Starting echo server on " << full_host << std::endl;
|
||||
|
||||
// start asio
|
||||
io_service.run();
|
||||
} catch (std::exception& e) {
|
||||
std::cerr << "Exception: " << e.what() << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Executable
BIN
Binary file not shown.
@@ -1,15 +0,0 @@
|
||||
|
||||
file (GLOB SOURCE_FILES *.cpp)
|
||||
file (GLOB HEADER_FILES *.hpp)
|
||||
|
||||
|
||||
if (OPENSSL_FOUND)
|
||||
|
||||
init_target (echo_server_tls)
|
||||
|
||||
build_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})
|
||||
|
||||
link_boost ()
|
||||
link_openssl()
|
||||
final_target ()
|
||||
endif()
|
||||
@@ -1,24 +0,0 @@
|
||||
## Main development example
|
||||
##
|
||||
|
||||
Import('env')
|
||||
Import('env_cpp11')
|
||||
Import('boostlibs')
|
||||
Import('platform_libs')
|
||||
Import('polyfill_libs')
|
||||
Import('tls_libs')
|
||||
|
||||
env = env.Clone ()
|
||||
env_cpp11 = env_cpp11.Clone ()
|
||||
|
||||
prgs = []
|
||||
|
||||
# if a C++11 environment is available build using that, otherwise use boost
|
||||
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
|
||||
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs] + [tls_libs]
|
||||
prgs += env_cpp11.Program('echo_server_tls', ["echo_server_tls.cpp"], LIBS = ALL_LIBS)
|
||||
else:
|
||||
ALL_LIBS = boostlibs(['system'],env) + [platform_libs] + [polyfill_libs] + [tls_libs]
|
||||
prgs += env.Program('echo_server_tls', ["echo_server_tls.cpp"], LIBS = ALL_LIBS)
|
||||
|
||||
Return('prgs')
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBSOCKETPP_ECHO_SERVER_HANDLER_HPP
|
||||
#define WEBSOCKETPP_ECHO_SERVER_HANDLER_HPP
|
||||
|
||||
class echo_handler : public server::handler {
|
||||
void on_message(connection_ptr con, std::string msg) {
|
||||
con->write(msg);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // WEBSOCKETPP_ECHO_SERVER_HANDLER_HPP
|
||||
@@ -1,72 +0,0 @@
|
||||
#include <websocketpp/config/asio.hpp>
|
||||
|
||||
#include <websocketpp/server.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
typedef websocketpp::server<websocketpp::config::asio_tls> server;
|
||||
|
||||
using websocketpp::lib::placeholders::_1;
|
||||
using websocketpp::lib::placeholders::_2;
|
||||
using websocketpp::lib::bind;
|
||||
|
||||
// pull out the type of messages sent by our config
|
||||
typedef websocketpp::config::asio::message_type::ptr message_ptr;
|
||||
typedef websocketpp::lib::shared_ptr<boost::asio::ssl::context> context_ptr;
|
||||
|
||||
void on_message(server* s, websocketpp::connection_hdl hdl, message_ptr msg) {
|
||||
std::cout << "on_message called with hdl: " << hdl.lock().get()
|
||||
<< " and message: " << msg->get_payload()
|
||||
<< std::endl;
|
||||
|
||||
try {
|
||||
s->send(hdl, msg->get_payload(), msg->get_opcode());
|
||||
} catch (const websocketpp::lib::error_code& e) {
|
||||
std::cout << "Echo failed because: " << e
|
||||
<< "(" << e.message() << ")" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
std::string get_password() {
|
||||
return "test";
|
||||
}
|
||||
|
||||
context_ptr on_tls_init(websocketpp::connection_hdl hdl) {
|
||||
std::cout << "on_tls_init called with hdl: " << hdl.lock().get() << std::endl;
|
||||
context_ptr ctx(new boost::asio::ssl::context(boost::asio::ssl::context::tlsv1));
|
||||
|
||||
try {
|
||||
ctx->set_options(boost::asio::ssl::context::default_workarounds |
|
||||
boost::asio::ssl::context::no_sslv2 |
|
||||
boost::asio::ssl::context::single_dh_use);
|
||||
ctx->set_password_callback(bind(&get_password));
|
||||
ctx->use_certificate_chain_file("server.pem");
|
||||
ctx->use_private_key_file("server.pem", boost::asio::ssl::context::pem);
|
||||
} catch (std::exception& e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
int main() {
|
||||
// Create a server endpoint
|
||||
server echo_server;
|
||||
|
||||
// Initialize ASIO
|
||||
echo_server.init_asio();
|
||||
|
||||
// Register our message handler
|
||||
echo_server.set_message_handler(bind(&on_message,&echo_server,::_1,::_2));
|
||||
echo_server.set_tls_init_handler(bind(&on_tls_init,::_1));
|
||||
|
||||
|
||||
// Listen on port 9002
|
||||
echo_server.listen(9002);
|
||||
|
||||
// Start the server accept loop
|
||||
echo_server.start_accept();
|
||||
|
||||
// Start the ASIO io_service run loop
|
||||
echo_server.run();
|
||||
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
Proc-Type: 4,ENCRYPTED
|
||||
DEK-Info: DES-EDE3-CBC,A0ED66EF872A48A9
|
||||
|
||||
gXuvKojXzApVhhPVNdRliiajbC4PtwQG5c8TA7JADLgwOR7o9t6KtXEr37bDRpvB
|
||||
9aO9P+SJaK5OOp3XKPGthOdqv+tvCRTlmzmC8GjPLBX389DWT2xoGu7JkGwDtdSm
|
||||
rnF49Rlp5bfjpACk5xKNiKeDo1CWfeEJzw9Kto0g+5eMaEdors64oPzjXs3geA2g
|
||||
TxCJSHv9qSX6++pCLKKCUTbyzidAxV/Zb0AAubt5V40QKqX4HhSwwstFnTaX3tlb
|
||||
3QOdY+y04VIkM6d7qN5W8M7NzRkMpZ1qBpQcUMpkhQcRzWP2wub5AAff9D2GntRd
|
||||
4Dz1vn3u41U3Okdr0CNj+iH7byCzuokoAhk6ZQEN6WB+GTpGgfBXdtUZrfpb0MKm
|
||||
UNYP5AF2AmUqJRXhViTDVtu/V2tHF3LGuNT+W2Dz+spFZEq0byEO0N858eR0dikc
|
||||
6jOASvNQbSwD0+mkgBC1gXKKU3ngj2gpJUwljeACdWFd8N2egrZfyI05CmX7vPNC
|
||||
NXbs7k2buWNdjP4/D8IM+HDVidWzQa/kG/qokXKqllem9Egg37lUucwnP3cX2/Hw
|
||||
U2mfaBWzeZtqc+GqRp08rYIql+Reai3sUYlQMnNk01prVY47UQb+dxuqjaxGV5Xx
|
||||
Xkx0s2mfQnNRjL4S7Hjhqelufi6GpkCQ2EGsPpA+6K1ztZ0ame9Q2BE1SXeM/6vU
|
||||
rxT5nRrCxueyXAyQSGcqMX9//gSeK8WWBqG/c1IAMVDa0NWrJeOJhSziE+ta3B0m
|
||||
bHAPBY6vh0iB3lLdRlbUOPbC6R1TpxMOs+6Vbs2+OTifFpvOVymEoZq/nroyg68P
|
||||
vn5uCKogwWA7o8EArf/UTlIwWJmH9bgILdZKld4wMel2HQg16RDzm+mEXAJi52a/
|
||||
FC+fgfphdxltmUJ+rqOyR4AHULjaTWUQqTIB6sdlzgmES1nXAiE71zX//KFqomar
|
||||
O60SPPk3C1bs0x5DsvmGJa8SIfDhyd+D7NPyqwEKqrZsaotYGklNkfqxa6pa8mrc
|
||||
ejxquW1PK4FvBk26+osu5a90Jih0PcQM7DUMMr2WHdTiMSXWAiK2ToYF8Itt25Qv
|
||||
Cd0CsSYw9CJkXNr1u1+mObheaY9QYOmztnSJLy4ZO2JsMhqNwuAueIcwmhXOREq7
|
||||
kzlnGMgJcuSeAS/OBNj8Zgx0c7QQ0kzc+YmnOCsqoMtPsu/CsXJ4iJiM3Tki/2jT
|
||||
bywrTiQwE6R3a/87GREOREX+WLicZBWX3k9/4tBL5XSe1p5wPpuIRQUDvAGNfNHP
|
||||
JN7kujDF4SehilF1qtvCygAwvxHFDj+EwhXKNDKJzoZZIM15rAk3k92n2j6nz1qH
|
||||
a3xOU05yydOlO6F6w51I1QoDddmkzCRNB0TeO3D6rekHsCK1aDWmC+qRcm2ZFtVz
|
||||
sY6fdZN2NEmMQokIh9Opi1f8CSYSizPESMzdu2SF0xVO9n/IGIkn1ksK04O2BZo0
|
||||
X3LBPHLfCRsQNY1eF17bj07fYU2oPZKs/XzJiwxkqK6LFvpeAVaYrtg9fqRO/UVe
|
||||
QhUIj3BL550ocEpa15xLehLrmwzYiW5zwGjSHQ4EgZluGLCwyKGTh4QswEJRA9Rt
|
||||
-----END RSA PRIVATE KEY-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIE0DCCA7igAwIBAgIJAM5MuKJezXq0MA0GCSqGSIb3DQEBBQUAMIGgMQswCQYD
|
||||
VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xGDAW
|
||||
BgNVBAoTD1phcGhveWQgU3R1ZGlvczEUMBIGA1UECxMLV2ViU29ja2V0KysxFjAU
|
||||
BgNVBAMTDVBldGVyIFRob3Jzb24xJDAiBgkqhkiG9w0BCQEWFXdlYm1hc3RlckB6
|
||||
YXBob3lkLmNvbTAeFw0xMTExMTUyMTIwMDZaFw0xMjExMTQyMTIwMDZaMIGgMQsw
|
||||
CQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28x
|
||||
GDAWBgNVBAoTD1phcGhveWQgU3R1ZGlvczEUMBIGA1UECxMLV2ViU29ja2V0Kysx
|
||||
FjAUBgNVBAMTDVBldGVyIFRob3Jzb24xJDAiBgkqhkiG9w0BCQEWFXdlYm1hc3Rl
|
||||
ckB6YXBob3lkLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANR0
|
||||
tdwAnIB8I9qRZ7QbzEWY95RpM7GIn0u/9oH90PzdHiE0rXSkKT+yw3XUzH0iw5t0
|
||||
5dEwSC+srSP5Vm4cA6kXc94agVVaPW89tGcdP4fHptCruSrzQsDXELCPl5UUvMpA
|
||||
YUcGisdXYPN/EeOoqb9wKWxoW5mREsyyeWWS89fYN5qU/d0QpbSvEWghqLbL/ZS2
|
||||
hOlXT9LufOeA+vHiV1/T/h5xC7ecIH02YDQw1EnqxbPmkLPcWThztLS9FiufNDRM
|
||||
Rhcoaj2b9VDHvDwdbeA0T5v5qNdG34LaapYOelxzQMOtM0f9Dgqehodyxl2qm9mR
|
||||
lq432dlOEzDnVCPNHwECAwEAAaOCAQkwggEFMB0GA1UdDgQWBBTTPKfNMnKOykhv
|
||||
+vKS7vql5JsMyzCB1QYDVR0jBIHNMIHKgBTTPKfNMnKOykhv+vKS7vql5JsMy6GB
|
||||
pqSBozCBoDELMAkGA1UEBhMCVVMxETAPBgNVBAgTCElsbGlub2lzMRAwDgYDVQQH
|
||||
EwdDaGljYWdvMRgwFgYDVQQKEw9aYXBob3lkIFN0dWRpb3MxFDASBgNVBAsTC1dl
|
||||
YlNvY2tldCsrMRYwFAYDVQQDEw1QZXRlciBUaG9yc29uMSQwIgYJKoZIhvcNAQkB
|
||||
FhV3ZWJtYXN0ZXJAemFwaG95ZC5jb22CCQDOTLiiXs16tDAMBgNVHRMEBTADAQH/
|
||||
MA0GCSqGSIb3DQEBBQUAA4IBAQB+SH0s/hrv5VYqgX6SNLzxdSLvCVsUkCdTpxwY
|
||||
wOJ84XmYcXDMhKDtZqLtOtN6pfEwVusFlC9mkieuunztCnWNmsSG83RuljJPjFSi
|
||||
1d4Id4bKEQkQ4cfnjoHKivRrViWLnxuNnLzC6tpyGH/35kKWhhr6T58AXerFgVw3
|
||||
mHvLPTr1DuhdAZA0ZuvuseVAFFAjI3RetSySwHJE3ak8KswDVfLi6E3XxMVsIWTS
|
||||
/iFsC2WwoZQlljya2V/kRYIhu+uCdqJ01wunn2BvmURPSgr4GTBF0FQ9JGpNbXxM
|
||||
TAU7oQJgyFc5sCcuEgPTO0dWVQTvdZVgay4tkmduKDRkmJBF
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,87 +0,0 @@
|
||||
#include <iostream>
|
||||
#include <websocketpp/config/asio_no_tls.hpp>
|
||||
#include <websocketpp/server.hpp>
|
||||
|
||||
struct connection_data {
|
||||
int sessionid;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
struct custom_config : public websocketpp::config::asio {
|
||||
// pull default settings from our core config
|
||||
typedef websocketpp::config::asio core;
|
||||
|
||||
typedef core::concurrency_type concurrency_type;
|
||||
typedef core::request_type request_type;
|
||||
typedef core::response_type response_type;
|
||||
typedef core::message_type message_type;
|
||||
typedef core::con_msg_manager_type con_msg_manager_type;
|
||||
typedef core::endpoint_msg_manager_type endpoint_msg_manager_type;
|
||||
typedef core::alog_type alog_type;
|
||||
typedef core::elog_type elog_type;
|
||||
typedef core::rng_type rng_type;
|
||||
typedef core::transport_type transport_type;
|
||||
typedef core::endpoint_base endpoint_base;
|
||||
|
||||
// Set a custom connection_base class
|
||||
typedef connection_data connection_base;
|
||||
};
|
||||
|
||||
typedef websocketpp::server<custom_config> server;
|
||||
typedef server::connection_ptr connection_ptr;
|
||||
|
||||
using websocketpp::connection_hdl;
|
||||
using websocketpp::lib::placeholders::_1;
|
||||
using websocketpp::lib::placeholders::_2;
|
||||
using websocketpp::lib::bind;
|
||||
|
||||
class print_server {
|
||||
public:
|
||||
print_server() : m_next_sessionid(1) {
|
||||
m_server.init_asio();
|
||||
|
||||
m_server.set_open_handler(bind(&print_server::on_open,this,::_1));
|
||||
m_server.set_close_handler(bind(&print_server::on_close,this,::_1));
|
||||
m_server.set_message_handler(bind(&print_server::on_message,this,::_1,::_2));
|
||||
}
|
||||
|
||||
void on_open(connection_hdl hdl) {
|
||||
connection_ptr con = m_server.get_con_from_hdl(hdl);
|
||||
|
||||
con->sessionid = m_next_sessionid++;
|
||||
}
|
||||
|
||||
void on_close(connection_hdl hdl) {
|
||||
connection_ptr con = m_server.get_con_from_hdl(hdl);
|
||||
|
||||
std::cout << "Closing connection " << con->name
|
||||
<< " with sessionid " << con->sessionid << std::endl;
|
||||
}
|
||||
|
||||
void on_message(connection_hdl hdl, server::message_ptr msg) {
|
||||
connection_ptr con = m_server.get_con_from_hdl(hdl);
|
||||
|
||||
if (con->name == "") {
|
||||
con->name = msg->get_payload();
|
||||
std::cout << "Setting name of connection with sessionid "
|
||||
<< con->sessionid << " to " << con->name << std::endl;
|
||||
} else {
|
||||
std::cout << "Got a message from connection " << con->name
|
||||
<< " with sessionid " << con->sessionid << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void run(uint16_t port) {
|
||||
m_server.listen(port);
|
||||
m_server.start_accept();
|
||||
m_server.run();
|
||||
}
|
||||
private:
|
||||
int m_next_sessionid;
|
||||
server m_server;
|
||||
};
|
||||
|
||||
int main() {
|
||||
print_server server;
|
||||
server.run(9002);
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
#include <iostream>
|
||||
|
||||
#include <websocketpp/config/asio_no_tls.hpp>
|
||||
#include <websocketpp/server.hpp>
|
||||
|
||||
typedef websocketpp::server<websocketpp::config::asio> server;
|
||||
|
||||
using websocketpp::connection_hdl;
|
||||
using websocketpp::lib::placeholders::_1;
|
||||
using websocketpp::lib::placeholders::_2;
|
||||
using websocketpp::lib::bind;
|
||||
using websocketpp::lib::ref;
|
||||
|
||||
void custom_on_msg(server & s, connection_hdl hdl, server::message_ptr msg) {
|
||||
std::cout << "Message sent to custom handler" << std::endl;
|
||||
}
|
||||
|
||||
void default_on_msg(server & s, connection_hdl hdl, server::message_ptr msg) {
|
||||
std::cout << "Message sent to default handler" << std::endl;
|
||||
|
||||
if (msg->get_payload() == "upgrade") {
|
||||
// Upgrade our connection_hdl to a full connection_ptr
|
||||
server::connection_ptr con = s.get_con_from_hdl(hdl);
|
||||
|
||||
// Change the on message handler for this connection only to
|
||||
// custom_on_mesage
|
||||
con->set_message_handler(bind(&custom_on_msg,ref(s),::_1,::_2));
|
||||
std::cout << "Upgrading connection to custom handler" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
server s;
|
||||
|
||||
s.set_message_handler(bind(&default_on_msg,ref(s),::_1,::_2));
|
||||
|
||||
s.init_asio();
|
||||
s.listen(9002);
|
||||
s.start_accept();
|
||||
|
||||
s.run();
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
## iostream server example
|
||||
##
|
||||
|
||||
Import('env')
|
||||
Import('env_cpp11')
|
||||
Import('boostlibs')
|
||||
Import('platform_libs')
|
||||
Import('polyfill_libs')
|
||||
|
||||
env = env.Clone ()
|
||||
env_cpp11 = env_cpp11.Clone ()
|
||||
|
||||
prgs = []
|
||||
|
||||
# if a C++11 environment is available build using that, otherwise use boost
|
||||
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
|
||||
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env_cpp11.Program('iostream_server', ["iostream_server.cpp"], LIBS = ALL_LIBS)
|
||||
else:
|
||||
ALL_LIBS = boostlibs(['system'],env) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env.Program('iostream_server', ["iostream_server.cpp"], LIBS = ALL_LIBS)
|
||||
|
||||
Return('prgs')
|
||||
@@ -1,93 +0,0 @@
|
||||
#include <websocketpp/config/core.hpp>
|
||||
|
||||
#include <websocketpp/server.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
typedef websocketpp::server<websocketpp::config::core> server;
|
||||
|
||||
using websocketpp::lib::placeholders::_1;
|
||||
using websocketpp::lib::placeholders::_2;
|
||||
using websocketpp::lib::bind;
|
||||
|
||||
// pull out the type of messages sent by our config
|
||||
typedef server::message_ptr message_ptr;
|
||||
|
||||
// Define a callback to handle incoming messages
|
||||
void on_message(server* s, websocketpp::connection_hdl hdl, message_ptr msg) {
|
||||
if (msg->get_opcode() == websocketpp::frame::opcode::text) {
|
||||
s->get_alog().write(websocketpp::log::alevel::app,
|
||||
"Text Message Received: "+msg->get_payload());
|
||||
} else {
|
||||
s->get_alog().write(websocketpp::log::alevel::app,
|
||||
"Binary Message Received: "+websocketpp::utility::to_hex(msg->get_payload()));
|
||||
}
|
||||
|
||||
try {
|
||||
s->send(hdl, msg->get_payload(), msg->get_opcode());
|
||||
} catch (const websocketpp::lib::error_code& e) {
|
||||
s->get_alog().write(websocketpp::log::alevel::app,
|
||||
"Echo Failed: "+e.message());
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
server s;
|
||||
std::ofstream log;
|
||||
|
||||
try {
|
||||
// set up access channels to only log interesting things
|
||||
s.clear_access_channels(websocketpp::log::alevel::all);
|
||||
s.set_access_channels(websocketpp::log::alevel::connect);
|
||||
s.set_access_channels(websocketpp::log::alevel::disconnect);
|
||||
s.set_access_channels(websocketpp::log::alevel::app);
|
||||
|
||||
// Log to a file rather than stdout, as we are using stdout for real
|
||||
// output
|
||||
log.open("output.log");
|
||||
s.get_alog().set_ostream(&log);
|
||||
s.get_elog().set_ostream(&log);
|
||||
|
||||
// print all output to stdout
|
||||
s.register_ostream(&std::cout);
|
||||
|
||||
// Register our message handler
|
||||
s.set_message_handler(bind(&on_message,&s,::_1,::_2));
|
||||
|
||||
server::connection_ptr con = s.get_connection();
|
||||
|
||||
con->start();
|
||||
|
||||
// C++ iostream's don't support the idea of asynchronous i/o. As such
|
||||
// there are two input strategies demonstrated here. Buffered I/O will
|
||||
// read from stdin in chunks until EOF. This works very well for
|
||||
// replaying canned connections as would be done in automated testing.
|
||||
//
|
||||
// If the server is being used live however, assuming input is being
|
||||
// piped from elsewhere in realtime, this strategy will result in small
|
||||
// messages being buffered forever. The non-buffered strategy below
|
||||
// reads characters from stdin one at a time. This is inefficient and
|
||||
// for more serious uses should be replaced with a platform specific
|
||||
// asyncronous i/o technique like select, poll, IOCP, etc
|
||||
bool buffered_io = false;
|
||||
|
||||
if (buffered_io) {
|
||||
std::cin >> *con;
|
||||
con->eof();
|
||||
} else {
|
||||
char a;
|
||||
while(std::cin.get(a)) {
|
||||
con->read_some(&a,1);
|
||||
}
|
||||
con->eof();
|
||||
}
|
||||
} catch (const std::exception & e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
} catch (websocketpp::lib::error_code e) {
|
||||
std::cout << e.message() << std::endl;
|
||||
} catch (...) {
|
||||
std::cout << "other exception" << std::endl;
|
||||
}
|
||||
log.close();
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
|
||||
file (GLOB SOURCE_FILES *.cpp)
|
||||
file (GLOB HEADER_FILES *.hpp)
|
||||
|
||||
init_target (print_server)
|
||||
|
||||
build_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})
|
||||
|
||||
link_boost ()
|
||||
final_target ()
|
||||
@@ -1,23 +0,0 @@
|
||||
## Print server example
|
||||
##
|
||||
|
||||
Import('env')
|
||||
Import('env_cpp11')
|
||||
Import('boostlibs')
|
||||
Import('platform_libs')
|
||||
Import('polyfill_libs')
|
||||
|
||||
env = env.Clone ()
|
||||
env_cpp11 = env_cpp11.Clone ()
|
||||
|
||||
prgs = []
|
||||
|
||||
# if a C++11 environment is available build using that, otherwise use boost
|
||||
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
|
||||
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env_cpp11.Program('print_server', ["print_server.cpp"], LIBS = ALL_LIBS)
|
||||
else:
|
||||
ALL_LIBS = boostlibs(['system'],env) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env.Program('print_server', ["print_server.cpp"], LIBS = ALL_LIBS)
|
||||
|
||||
Return('prgs')
|
||||
@@ -1,22 +0,0 @@
|
||||
#include <iostream>
|
||||
|
||||
#include <websocketpp/config/asio_no_tls.hpp>
|
||||
#include <websocketpp/server.hpp>
|
||||
|
||||
typedef websocketpp::server<websocketpp::config::asio> server;
|
||||
|
||||
void on_message(websocketpp::connection_hdl hdl, server::message_ptr msg) {
|
||||
std::cout << msg->get_payload() << std::endl;
|
||||
}
|
||||
|
||||
int main() {
|
||||
server print_server;
|
||||
|
||||
print_server.set_message_handler(&on_message);
|
||||
|
||||
print_server.init_asio();
|
||||
print_server.listen(9002);
|
||||
print_server.start_accept();
|
||||
|
||||
print_server.run();
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
#include <set>
|
||||
#include <websocketpp/config/asio_no_tls.hpp>
|
||||
#include <websocketpp/server.hpp>
|
||||
|
||||
typedef websocketpp::server<websocketpp::config::asio> server;
|
||||
|
||||
using websocketpp::connection_hdl;
|
||||
using websocketpp::lib::placeholders::_1;
|
||||
using websocketpp::lib::placeholders::_2;
|
||||
using websocketpp::lib::bind;
|
||||
|
||||
class broadcast_server {
|
||||
public:
|
||||
broadcast_server() {
|
||||
m_server.init_asio();
|
||||
|
||||
m_server.set_open_handler(bind(&broadcast_server::on_open,this,::_1));
|
||||
m_server.set_close_handler(bind(&broadcast_server::on_close,this,::_1));
|
||||
m_server.set_message_handler(bind(&broadcast_server::on_message,this,::_1,::_2));
|
||||
}
|
||||
|
||||
void on_open(connection_hdl hdl) {
|
||||
m_connections.insert(hdl);
|
||||
}
|
||||
|
||||
void on_close(connection_hdl hdl) {
|
||||
m_connections.erase(hdl);
|
||||
}
|
||||
|
||||
void on_message(connection_hdl hdl, server::message_ptr msg) {
|
||||
for (auto it : m_connections) {
|
||||
m_server.send(it,msg);
|
||||
}
|
||||
}
|
||||
|
||||
void run(uint16_t port) {
|
||||
m_server.listen(port);
|
||||
m_server.start_accept();
|
||||
m_server.run();
|
||||
}
|
||||
private:
|
||||
typedef std::set<connection_hdl,std::owner_less<connection_hdl>> con_list;
|
||||
|
||||
server m_server;
|
||||
con_list m_connections;
|
||||
};
|
||||
|
||||
int main() {
|
||||
broadcast_server server;
|
||||
server.run(9002);
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
|
||||
file (GLOB SOURCE_FILES *.cpp)
|
||||
file (GLOB HEADER_FILES *.hpp)
|
||||
|
||||
init_target (sip_client)
|
||||
|
||||
build_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})
|
||||
|
||||
link_boost ()
|
||||
final_target ()
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
|
||||
|
||||
Checkout the project from git
|
||||
|
||||
At the top level, run cmake:
|
||||
|
||||
cmake -G 'Unix Makefiles' \
|
||||
-D BUILD_EXAMPLES=ON \
|
||||
-D WEBSOCKETPP_ROOT=/tmp/cm1 \
|
||||
-D ENABLE_CPP11=OFF .
|
||||
|
||||
and then make the example:
|
||||
|
||||
make -C examples/sip_client
|
||||
|
||||
Now run it:
|
||||
|
||||
bin/sip_client ws://ws-server:80
|
||||
|
||||
It has been tested against the repro SIP proxy from reSIProcate
|
||||
|
||||
http://www.resiprocate.org/WebRTC_and_SIP_Over_WebSockets
|
||||
@@ -1,23 +0,0 @@
|
||||
## SIP client example
|
||||
##
|
||||
|
||||
Import('env')
|
||||
Import('env_cpp11')
|
||||
Import('boostlibs')
|
||||
Import('platform_libs')
|
||||
Import('polyfill_libs')
|
||||
|
||||
env = env.Clone ()
|
||||
env_cpp11 = env_cpp11.Clone ()
|
||||
|
||||
prgs = []
|
||||
|
||||
# if a C++11 environment is avaliable build using that, otherwise use boost
|
||||
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
|
||||
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env_cpp11.Program('sip_client', ["sip_client.cpp"], LIBS = ALL_LIBS)
|
||||
else:
|
||||
ALL_LIBS = boostlibs(['system','random'],env) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env.Program('sip_client', ["sip_client.cpp"], LIBS = ALL_LIBS)
|
||||
|
||||
Return('prgs')
|
||||
@@ -1,88 +0,0 @@
|
||||
#include <condition_variable>
|
||||
|
||||
#include <websocketpp/config/asio_no_tls_client.hpp>
|
||||
|
||||
#include <websocketpp/client.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
typedef websocketpp::client<websocketpp::config::asio_client> client;
|
||||
|
||||
using websocketpp::lib::placeholders::_1;
|
||||
using websocketpp::lib::placeholders::_2;
|
||||
using websocketpp::lib::bind;
|
||||
|
||||
// pull out the type of messages sent by our config
|
||||
typedef websocketpp::config::asio_client::message_type::ptr message_ptr;
|
||||
|
||||
// Create a server endpoint
|
||||
client sip_client;
|
||||
|
||||
|
||||
bool received;
|
||||
|
||||
void on_open(client* c, websocketpp::connection_hdl hdl) {
|
||||
// now it is safe to use the connection
|
||||
std::cout << "connection ready" << std::endl;
|
||||
|
||||
received=false;
|
||||
// Send a SIP OPTIONS message to the server:
|
||||
std::string SIP_msg="OPTIONS sip:carol@chicago.com SIP/2.0\r\nVia: SIP/2.0/WS df7jal23ls0d.invalid;rport;branch=z9hG4bKhjhs8ass877\r\nMax-Forwards: 70\r\nTo: <sip:carol@chicago.com>\r\nFrom: Alice <sip:alice@atlanta.com>;tag=1928301774\r\nCall-ID: a84b4c76e66710\r\nCSeq: 63104 OPTIONS\r\nContact: <sip:alice@pc33.atlanta.com>\r\nAccept: application/sdp\r\nContent-Length: 0\r\n\r\n";
|
||||
sip_client.send(hdl, SIP_msg.c_str(), websocketpp::frame::opcode::text);
|
||||
}
|
||||
|
||||
void on_message(client* c, websocketpp::connection_hdl hdl, message_ptr msg) {
|
||||
client::connection_ptr con = sip_client.get_con_from_hdl(hdl);
|
||||
|
||||
std::cout << "Received a reply:" << std::endl;
|
||||
fwrite(msg->get_payload().c_str(), msg->get_payload().size(), 1, stdout);
|
||||
received=true;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
|
||||
std::string uri = "ws://localhost:9001";
|
||||
|
||||
if (argc == 2) {
|
||||
uri = argv[1];
|
||||
}
|
||||
|
||||
try {
|
||||
// We expect there to be a lot of errors, so suppress them
|
||||
sip_client.clear_access_channels(websocketpp::log::alevel::all);
|
||||
sip_client.clear_error_channels(websocketpp::log::elevel::all);
|
||||
|
||||
// Initialize ASIO
|
||||
sip_client.init_asio();
|
||||
|
||||
// Register our handlers
|
||||
sip_client.set_open_handler(bind(&on_open,&sip_client,::_1));
|
||||
sip_client.set_message_handler(bind(&on_message,&sip_client,::_1,::_2));
|
||||
|
||||
websocketpp::lib::error_code ec;
|
||||
client::connection_ptr con = sip_client.get_connection(uri, ec);
|
||||
|
||||
// Specify the SIP subprotocol:
|
||||
con->add_subprotocol("sip");
|
||||
|
||||
sip_client.connect(con);
|
||||
|
||||
// Start the ASIO io_service run loop
|
||||
sip_client.run();
|
||||
|
||||
while(!received) {
|
||||
boost::this_thread::sleep(boost::posix_time::milliseconds(100));
|
||||
}
|
||||
|
||||
std::cout << "done" << std::endl;
|
||||
|
||||
} catch (const std::exception & e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
} catch (websocketpp::lib::error_code e) {
|
||||
std::cout << e.message() << std::endl;
|
||||
} catch (...) {
|
||||
std::cout << "other exception" << std::endl;
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
## Main development example
|
||||
##
|
||||
|
||||
Import('env')
|
||||
Import('env_cpp11')
|
||||
Import('boostlibs')
|
||||
Import('platform_libs')
|
||||
Import('polyfill_libs')
|
||||
|
||||
env = env.Clone ()
|
||||
env_cpp11 = env_cpp11.Clone ()
|
||||
|
||||
prgs = []
|
||||
|
||||
# if a C++11 environment is available build using that, otherwise use boost
|
||||
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
|
||||
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env_cpp11.Program('subprotocol_server', ["subprotocol_server.cpp"], LIBS = ALL_LIBS)
|
||||
else:
|
||||
ALL_LIBS = boostlibs(['system'],env) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env.Program('subprotocol_server', ["subprotocol_server.cpp"], LIBS = ALL_LIBS)
|
||||
|
||||
Return('prgs')
|
||||
@@ -1,52 +0,0 @@
|
||||
#include <iostream>
|
||||
|
||||
#include <websocketpp/config/asio_no_tls.hpp>
|
||||
#include <websocketpp/server.hpp>
|
||||
|
||||
typedef websocketpp::server<websocketpp::config::asio> server;
|
||||
|
||||
using websocketpp::connection_hdl;
|
||||
using websocketpp::lib::placeholders::_1;
|
||||
using websocketpp::lib::placeholders::_2;
|
||||
using websocketpp::lib::bind;
|
||||
using websocketpp::lib::ref;
|
||||
|
||||
|
||||
bool validate(server & s, connection_hdl hdl) {
|
||||
server::connection_ptr con = s.get_con_from_hdl(hdl);
|
||||
|
||||
std::cout << "Cache-Control: " << con->get_request_header("Cache-Control") << std::endl;
|
||||
|
||||
const std::vector<std::string> & subp_requests = con->get_requested_subprotocols();
|
||||
std::vector<std::string>::const_iterator it;
|
||||
|
||||
for (it = subp_requests.begin(); it != subp_requests.end(); ++it) {
|
||||
std::cout << "Requested: " << *it << std::endl;
|
||||
}
|
||||
|
||||
if (subp_requests.size() > 0) {
|
||||
con->select_subprotocol(subp_requests[0]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main() {
|
||||
try {
|
||||
server s;
|
||||
|
||||
s.set_validate_handler(bind(&validate,ref(s),::_1));
|
||||
|
||||
s.init_asio();
|
||||
s.listen(9005);
|
||||
s.start_accept();
|
||||
|
||||
s.run();
|
||||
} catch (const std::exception & e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
} catch (websocketpp::lib::error_code e) {
|
||||
std::cout << e.message() << std::endl;
|
||||
} catch (...) {
|
||||
std::cout << "other exception" << std::endl;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
|
||||
file (GLOB SOURCE_FILES *.cpp)
|
||||
file (GLOB HEADER_FILES *.hpp)
|
||||
|
||||
init_target (telemetry_client)
|
||||
|
||||
build_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})
|
||||
|
||||
link_boost ()
|
||||
final_target ()
|
||||
@@ -1,23 +0,0 @@
|
||||
## Telemetry client example
|
||||
##
|
||||
|
||||
Import('env')
|
||||
Import('env_cpp11')
|
||||
Import('boostlibs')
|
||||
Import('platform_libs')
|
||||
Import('polyfill_libs')
|
||||
|
||||
env = env.Clone ()
|
||||
env_cpp11 = env_cpp11.Clone ()
|
||||
|
||||
prgs = []
|
||||
|
||||
# if a C++11 environment is available build using that, otherwise use boost
|
||||
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
|
||||
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env_cpp11.Program('telemetry_client', ["telemetry_client.cpp"], LIBS = ALL_LIBS)
|
||||
else:
|
||||
ALL_LIBS = boostlibs(['system','random'],env) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env.Program('telemetry_client', ["telemetry_client.cpp"], LIBS = ALL_LIBS)
|
||||
|
||||
Return('prgs')
|
||||
@@ -1,156 +0,0 @@
|
||||
#include <websocketpp/config/asio_no_tls_client.hpp>
|
||||
#include <websocketpp/client.hpp>
|
||||
|
||||
// This header pulls in the WebSocket++ abstracted thread support that will
|
||||
// select between boost::thread and std::thread based on how the build system
|
||||
// is configured.
|
||||
#include <websocketpp/common/thread.hpp>
|
||||
|
||||
/**
|
||||
* The telemetry client connects to a WebSocket server and sends a message every
|
||||
* second containing an integer count. This example can be used as the basis for
|
||||
* programs where a client connects and pushes data for logging, stress/load
|
||||
* testing, etc.
|
||||
*/
|
||||
class telemetry_client {
|
||||
public:
|
||||
typedef websocketpp::client<websocketpp::config::asio_client> client;
|
||||
typedef websocketpp::lib::lock_guard<websocketpp::lib::mutex> scoped_lock;
|
||||
|
||||
telemetry_client() : m_open(false),m_done(false) {
|
||||
// set up access channels to only log interesting things
|
||||
m_client.clear_access_channels(websocketpp::log::alevel::all);
|
||||
m_client.set_access_channels(websocketpp::log::alevel::connect);
|
||||
m_client.set_access_channels(websocketpp::log::alevel::disconnect);
|
||||
m_client.set_access_channels(websocketpp::log::alevel::app);
|
||||
|
||||
// Initialize the Asio transport policy
|
||||
m_client.init_asio();
|
||||
|
||||
// Bind the handlers we are using
|
||||
using websocketpp::lib::placeholders::_1;
|
||||
using websocketpp::lib::bind;
|
||||
m_client.set_open_handler(bind(&telemetry_client::on_open,this,::_1));
|
||||
m_client.set_close_handler(bind(&telemetry_client::on_close,this,::_1));
|
||||
m_client.set_fail_handler(bind(&telemetry_client::on_fail,this,::_1));
|
||||
}
|
||||
|
||||
// This method will block until the connection is complete
|
||||
void run(const std::string & uri) {
|
||||
// Create a new connection to the given URI
|
||||
websocketpp::lib::error_code ec;
|
||||
client::connection_ptr con = m_client.get_connection(uri, ec);
|
||||
if (ec) {
|
||||
m_client.get_alog().write(websocketpp::log::alevel::app,
|
||||
"Get Connection Error: "+ec.message());
|
||||
return;
|
||||
}
|
||||
|
||||
// Grab a handle for this connection so we can talk to it in a thread
|
||||
// safe manor after the event loop starts.
|
||||
m_hdl = con->get_handle();
|
||||
|
||||
// Queue the connection. No DNS queries or network connections will be
|
||||
// made until the io_service event loop is run.
|
||||
m_client.connect(con);
|
||||
|
||||
// Create a thread to run the ASIO io_service event loop
|
||||
websocketpp::lib::thread asio_thread(&client::run, &m_client);
|
||||
|
||||
// Create a thread to run the telemetry loop
|
||||
websocketpp::lib::thread telemetry_thread(&telemetry_client::telemetry_loop,this);
|
||||
|
||||
asio_thread.join();
|
||||
telemetry_thread.join();
|
||||
}
|
||||
|
||||
// The open handler will signal that we are ready to start sending telemetry
|
||||
void on_open(websocketpp::connection_hdl hdl) {
|
||||
m_client.get_alog().write(websocketpp::log::alevel::app,
|
||||
"Connection opened, starting telemetry!");
|
||||
|
||||
scoped_lock guard(m_lock);
|
||||
m_open = true;
|
||||
}
|
||||
|
||||
// The close handler will signal that we should stop sending telemetry
|
||||
void on_close(websocketpp::connection_hdl hdl) {
|
||||
m_client.get_alog().write(websocketpp::log::alevel::app,
|
||||
"Connection closed, stopping telemetry!");
|
||||
|
||||
scoped_lock guard(m_lock);
|
||||
m_done = true;
|
||||
}
|
||||
|
||||
// The fail handler will signal that we should stop sending telemetry
|
||||
void on_fail(websocketpp::connection_hdl hdl) {
|
||||
m_client.get_alog().write(websocketpp::log::alevel::app,
|
||||
"Connection failed, stopping telemetry!");
|
||||
|
||||
scoped_lock guard(m_lock);
|
||||
m_done = true;
|
||||
}
|
||||
|
||||
void telemetry_loop() {
|
||||
uint64_t count = 0;
|
||||
std::stringstream val;
|
||||
websocketpp::lib::error_code ec;
|
||||
|
||||
while(1) {
|
||||
bool wait = false;
|
||||
|
||||
{
|
||||
scoped_lock guard(m_lock);
|
||||
// If the connection has been closed, stop generating telemetry
|
||||
if (m_done) {break;}
|
||||
|
||||
// If the connection hasn't been opened yet wait a bit and retry
|
||||
if (!m_open) {
|
||||
wait = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (wait) {
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
val.str("");
|
||||
val << "count is " << count++;
|
||||
|
||||
m_client.get_alog().write(websocketpp::log::alevel::app, val.str());
|
||||
m_client.send(m_hdl,val.str(),websocketpp::frame::opcode::text,ec);
|
||||
|
||||
// The most likely error that we will get is that the connection is
|
||||
// not in the right state. Usually this means we tried to send a
|
||||
// message to a connection that was closed or in the process of
|
||||
// closing. While many errors here can be easily recovered from,
|
||||
// in this simple example, we'll stop the telemetry loop.
|
||||
if (ec) {
|
||||
m_client.get_alog().write(websocketpp::log::alevel::app,
|
||||
"Send Error: "+ec.message());
|
||||
break;
|
||||
}
|
||||
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
private:
|
||||
client m_client;
|
||||
websocketpp::connection_hdl m_hdl;
|
||||
websocketpp::lib::mutex m_lock;
|
||||
bool m_open;
|
||||
bool m_done;
|
||||
};
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
telemetry_client c;
|
||||
|
||||
std::string uri = "ws://localhost:9002";
|
||||
|
||||
if (argc == 2) {
|
||||
uri = argv[1];
|
||||
}
|
||||
|
||||
c.run(uri);
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
|
||||
file (GLOB SOURCE_FILES *.cpp)
|
||||
file (GLOB HEADER_FILES *.hpp)
|
||||
|
||||
init_target (testee_client)
|
||||
|
||||
build_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})
|
||||
|
||||
link_boost ()
|
||||
final_target ()
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
## Autobahn test client example
|
||||
##
|
||||
|
||||
Import('env')
|
||||
Import('env_cpp11')
|
||||
Import('boostlibs')
|
||||
Import('platform_libs')
|
||||
Import('polyfill_libs')
|
||||
|
||||
env = env.Clone ()
|
||||
env_cpp11 = env_cpp11.Clone ()
|
||||
|
||||
prgs = []
|
||||
|
||||
# if a C++11 environment is available build using that, otherwise use boost
|
||||
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
|
||||
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env_cpp11.Program('testee_client', ["testee_client.cpp"], LIBS = ALL_LIBS)
|
||||
else:
|
||||
ALL_LIBS = boostlibs(['system','random'],env) + [platform_libs] + [polyfill_libs]
|
||||
prgs += env.Program('testee_client', ["testee_client.cpp"], LIBS = ALL_LIBS)
|
||||
|
||||
Return('prgs')
|
||||
@@ -1,84 +0,0 @@
|
||||
#include <websocketpp/config/asio_no_tls_client.hpp>
|
||||
|
||||
#include <websocketpp/client.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
typedef websocketpp::client<websocketpp::config::asio_client> client;
|
||||
|
||||
using websocketpp::lib::placeholders::_1;
|
||||
using websocketpp::lib::placeholders::_2;
|
||||
using websocketpp::lib::bind;
|
||||
|
||||
// pull out the type of messages sent by our config
|
||||
typedef websocketpp::config::asio_client::message_type::ptr message_ptr;
|
||||
|
||||
int case_count = 0;
|
||||
|
||||
void on_message(client* c, websocketpp::connection_hdl hdl, message_ptr msg) {
|
||||
client::connection_ptr con = c->get_con_from_hdl(hdl);
|
||||
|
||||
if (con->get_resource() == "/getCaseCount") {
|
||||
std::cout << "Detected " << msg->get_payload() << " test cases."
|
||||
<< std::endl;
|
||||
case_count = atoi(msg->get_payload().c_str());
|
||||
} else {
|
||||
c->send(hdl, msg->get_payload(), msg->get_opcode());
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
// Create a server endpoint
|
||||
client c;
|
||||
|
||||
std::string uri = "ws://localhost:9001";
|
||||
|
||||
if (argc == 2) {
|
||||
uri = argv[1];
|
||||
}
|
||||
|
||||
try {
|
||||
// We expect there to be a lot of errors, so suppress them
|
||||
c.clear_access_channels(websocketpp::log::alevel::all);
|
||||
c.clear_error_channels(websocketpp::log::elevel::all);
|
||||
|
||||
// Initialize ASIO
|
||||
c.init_asio();
|
||||
|
||||
// Register our handlers
|
||||
c.set_message_handler(bind(&on_message,&c,::_1,::_2));
|
||||
|
||||
websocketpp::lib::error_code ec;
|
||||
client::connection_ptr con = c.get_connection(uri+"/getCaseCount", ec);
|
||||
c.connect(con);
|
||||
|
||||
// Start the ASIO io_service run loop
|
||||
c.run();
|
||||
|
||||
std::cout << "case count: " << case_count << std::endl;
|
||||
|
||||
for (int i = 1; i <= case_count; i++) {
|
||||
c.reset();
|
||||
|
||||
std::stringstream url;
|
||||
|
||||
url << uri << "/runCase?case=" << i << "&agent="
|
||||
<< websocketpp::user_agent;
|
||||
|
||||
con = c.get_connection(url.str(), ec);
|
||||
|
||||
c.connect(con);
|
||||
|
||||
c.run();
|
||||
}
|
||||
|
||||
std::cout << "done" << std::endl;
|
||||
|
||||
} catch (const std::exception & e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
} catch (websocketpp::lib::error_code e) {
|
||||
std::cout << e.message() << std::endl;
|
||||
} catch (...) {
|
||||
std::cout << "other exception" << std::endl;
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
## Autobahn Testee Server
|
||||
##
|
||||
|
||||
Import('env')
|
||||
Import('env_cpp11')
|
||||
Import('boostlibs')
|
||||
Import('platform_libs')
|
||||
Import('polyfill_libs')
|
||||
Import('tls_libs')
|
||||
|
||||
env = env.Clone ()
|
||||
env_cpp11 = env_cpp11.Clone ()
|
||||
|
||||
prgs = []
|
||||
|
||||
# if a C++11 environment is available build using that, otherwise use boost
|
||||
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
|
||||
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs] + [tls_libs]
|
||||
prgs += env_cpp11.Program('testee_server', ["testee_server.cpp"], LIBS = ALL_LIBS)
|
||||
else:
|
||||
ALL_LIBS = boostlibs(['system'],env) + [platform_libs] + [polyfill_libs] + [tls_libs]
|
||||
prgs += env.Program('testee_server', ["testee_server.cpp"], LIBS = ALL_LIBS)
|
||||
|
||||
Return('prgs')
|
||||
@@ -1,167 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
//#include <websocketpp/config/asio_no_tls.hpp>
|
||||
#include <websocketpp/config/asio.hpp>
|
||||
#include <websocketpp/server.hpp>
|
||||
|
||||
#include <websocketpp/message_buffer/fixed.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
typedef websocketpp::lib::shared_ptr<boost::asio::ssl::context> context_ptr;
|
||||
|
||||
std::string get_password() {
|
||||
return "test";
|
||||
}
|
||||
|
||||
context_ptr on_tls_init(websocketpp::connection_hdl hdl) {
|
||||
//std::cout << "on_tls_init called with hdl: " << hdl.lock().get() << std::endl;
|
||||
context_ptr ctx(new boost::asio::ssl::context(boost::asio::ssl::context::tlsv1));
|
||||
|
||||
try {
|
||||
ctx->set_options(boost::asio::ssl::context::default_workarounds |
|
||||
boost::asio::ssl::context::no_sslv2 |
|
||||
boost::asio::ssl::context::single_dh_use);
|
||||
ctx->set_password_callback(bind(&get_password));
|
||||
ctx->use_certificate_chain_file("server.pem");
|
||||
ctx->use_private_key_file("server.pem", boost::asio::ssl::context::pem);
|
||||
} catch (std::exception& e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
struct testee_config : public websocketpp::config::asio {
|
||||
// pull default settings from our core config
|
||||
typedef websocketpp::config::asio core;
|
||||
|
||||
typedef core::concurrency_type concurrency_type;
|
||||
typedef core::request_type request_type;
|
||||
typedef core::response_type response_type;
|
||||
typedef core::message_type message_type;
|
||||
typedef core::con_msg_manager_type con_msg_manager_type;
|
||||
typedef core::endpoint_msg_manager_type endpoint_msg_manager_type;
|
||||
|
||||
//typedef websocketpp::message_buffer::fixed::policy::message message_type;
|
||||
//typedef websocketpp::message_buffer::fixed::policy::con_msg_manager con_msg_manager_type;
|
||||
////typedef websocketpp::message_buffer::fixed::policy::con_msg_manager endpoint_msg_manager_type;
|
||||
//typedef websocketpp::message_buffer::fixed::policy::endpoint_msg_manager endpoint_msg_manager_type;
|
||||
|
||||
typedef core::alog_type alog_type;
|
||||
typedef core::elog_type elog_type;
|
||||
typedef core::rng_type rng_type;
|
||||
typedef core::endpoint_base endpoint_base;
|
||||
|
||||
static bool const enable_multithreading = true;
|
||||
|
||||
struct transport_config : public core::transport_config {
|
||||
typedef core::concurrency_type concurrency_type;
|
||||
typedef core::elog_type elog_type;
|
||||
typedef core::alog_type alog_type;
|
||||
typedef core::request_type request_type;
|
||||
typedef core::response_type response_type;
|
||||
|
||||
static bool const enable_multithreading = true;
|
||||
};
|
||||
|
||||
typedef websocketpp::transport::asio::endpoint<transport_config>
|
||||
transport_type;
|
||||
|
||||
static const websocketpp::log::level elog_level =
|
||||
websocketpp::log::elevel::none;
|
||||
static const websocketpp::log::level alog_level =
|
||||
websocketpp::log::alevel::none;
|
||||
};
|
||||
|
||||
typedef websocketpp::server<testee_config> server;
|
||||
|
||||
using websocketpp::lib::placeholders::_1;
|
||||
using websocketpp::lib::placeholders::_2;
|
||||
using websocketpp::lib::bind;
|
||||
|
||||
// pull out the type of messages sent by our config
|
||||
typedef server::message_ptr message_ptr;
|
||||
|
||||
// Define a callback to handle incoming messages
|
||||
void on_message(server* s, websocketpp::connection_hdl hdl, message_ptr msg) {
|
||||
s->send(hdl, msg->get_payload(), msg->get_opcode());
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
// Create a server endpoint
|
||||
server testee_server;
|
||||
|
||||
short port = 9002;
|
||||
size_t num_threads = 1;
|
||||
|
||||
if (argc == 3) {
|
||||
port = atoi(argv[1]);
|
||||
num_threads = atoi(argv[2]);
|
||||
}
|
||||
|
||||
try {
|
||||
// Total silence
|
||||
//testee_server.clear_access_channels(websocketpp::log::alevel::all);
|
||||
//testee_server.clear_error_channels(websocketpp::log::alevel::all);
|
||||
|
||||
// Initialize ASIO
|
||||
testee_server.init_asio();
|
||||
|
||||
// Register our message handler
|
||||
testee_server.set_message_handler(bind(&on_message,&testee_server,::_1,::_2));
|
||||
//testee_server.set_tls_init_handler(bind(&on_tls_init,::_1));
|
||||
|
||||
|
||||
// Listen on port
|
||||
testee_server.listen(port);
|
||||
|
||||
// Start the server accept loop
|
||||
testee_server.start_accept();
|
||||
|
||||
// Start the ASIO io_service run loop
|
||||
if (num_threads == 1) {
|
||||
testee_server.run();
|
||||
} else {
|
||||
typedef websocketpp::lib::shared_ptr<websocketpp::lib::thread> thread_ptr;
|
||||
std::vector<thread_ptr> ts;
|
||||
for (size_t i = 0; i < num_threads; i++) {
|
||||
ts.push_back(thread_ptr(new websocketpp::lib::thread(&server::run, &testee_server)));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < num_threads; i++) {
|
||||
ts[i]->join();
|
||||
}
|
||||
}
|
||||
} catch (const std::exception & e) {
|
||||
std::cout << "exception: " << e.what() << std::endl;
|
||||
} catch (websocketpp::lib::error_code e) {
|
||||
std::cout << "error code: " << e.message() << std::endl;
|
||||
} catch (...) {
|
||||
std::cout << "other exception" << std::endl;
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
## Utility client example
|
||||
##
|
||||
|
||||
Import('env')
|
||||
Import('env_cpp11')
|
||||
Import('boostlibs')
|
||||
Import('platform_libs')
|
||||
Import('polyfill_libs')
|
||||
Import('tls_libs')
|
||||
|
||||
env = env.Clone ()
|
||||
env_cpp11 = env_cpp11.Clone ()
|
||||
|
||||
prgs = []
|
||||
|
||||
# if a C++11 environment is available build using that, otherwise use boost
|
||||
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
|
||||
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs] + [tls_libs]
|
||||
prgs += env_cpp11.Program('utility_client', ["utility_client.cpp"], LIBS = ALL_LIBS)
|
||||
else:
|
||||
ALL_LIBS = boostlibs(['system','random'],env) + [platform_libs] + [polyfill_libs] + [tls_libs]
|
||||
prgs += env.Program('utility_client', ["utility_client.cpp"], LIBS = ALL_LIBS)
|
||||
|
||||
Return('prgs')
|
||||
@@ -1,166 +0,0 @@
|
||||
/**
|
||||
* This example is presently used as a scratch space. It may or may not be broken
|
||||
* at any given time.
|
||||
*/
|
||||
|
||||
#include <websocketpp/config/asio_client.hpp>
|
||||
|
||||
#include <websocketpp/client.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <chrono>
|
||||
|
||||
typedef websocketpp::client<websocketpp::config::asio_tls_client> client;
|
||||
|
||||
using websocketpp::lib::placeholders::_1;
|
||||
using websocketpp::lib::placeholders::_2;
|
||||
using websocketpp::lib::bind;
|
||||
|
||||
// pull out the type of messages sent by our config
|
||||
typedef websocketpp::config::asio_tls_client::message_type::ptr message_ptr;
|
||||
typedef websocketpp::lib::shared_ptr<boost::asio::ssl::context> context_ptr;
|
||||
typedef client::connection_ptr connection_ptr;
|
||||
|
||||
|
||||
|
||||
class perftest {
|
||||
public:
|
||||
typedef perftest type;
|
||||
typedef std::chrono::duration<int,std::micro> dur_type;
|
||||
|
||||
perftest () {
|
||||
m_endpoint.set_access_channels(websocketpp::log::alevel::none);
|
||||
m_endpoint.set_error_channels(websocketpp::log::elevel::none);
|
||||
|
||||
// Initialize ASIO
|
||||
m_endpoint.init_asio();
|
||||
|
||||
// Register our handlers
|
||||
m_endpoint.set_tls_init_handler(bind(&type::on_tls_init,this,::_1));
|
||||
|
||||
m_endpoint.set_tcp_pre_init_handler(bind(&type::on_tcp_pre_init,this,::_1));
|
||||
m_endpoint.set_tcp_post_init_handler(bind(&type::on_tcp_post_init,this,::_1));
|
||||
m_endpoint.set_socket_init_handler(bind(&type::on_socket_init,this,::_1));
|
||||
m_endpoint.set_message_handler(bind(&type::on_message,this,::_1,::_2));
|
||||
m_endpoint.set_open_handler(bind(&type::on_open,this,::_1));
|
||||
m_endpoint.set_close_handler(bind(&type::on_close,this,::_1));
|
||||
}
|
||||
|
||||
void start(std::string uri) {
|
||||
websocketpp::lib::error_code ec;
|
||||
client::connection_ptr con = m_endpoint.get_connection(uri, ec);
|
||||
|
||||
if (ec) {
|
||||
m_endpoint.get_alog().write(websocketpp::log::alevel::app,ec.message());
|
||||
}
|
||||
|
||||
//con->set_proxy("http://humupdates.uchicago.edu:8443");
|
||||
|
||||
m_endpoint.connect(con);
|
||||
|
||||
// Start the ASIO io_service run loop
|
||||
m_start = std::chrono::high_resolution_clock::now();
|
||||
m_endpoint.run();
|
||||
}
|
||||
|
||||
void on_tcp_pre_init(websocketpp::connection_hdl hdl) {
|
||||
m_tcp_pre_init = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
void on_tcp_post_init(websocketpp::connection_hdl hdl) {
|
||||
m_tcp_post_init = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
void on_socket_init(websocketpp::connection_hdl hdl) {
|
||||
m_socket_init = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
|
||||
context_ptr on_tls_init(websocketpp::connection_hdl hdl) {
|
||||
context_ptr ctx(new boost::asio::ssl::context(boost::asio::ssl::context::tlsv1));
|
||||
|
||||
try {
|
||||
ctx->set_options(boost::asio::ssl::context::default_workarounds |
|
||||
boost::asio::ssl::context::no_sslv2 |
|
||||
boost::asio::ssl::context::single_dh_use);
|
||||
} catch (std::exception& e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void on_open(websocketpp::connection_hdl hdl) {
|
||||
m_open = std::chrono::high_resolution_clock::now();
|
||||
|
||||
client::connection_ptr con = m_endpoint.get_con_from_hdl(hdl);
|
||||
|
||||
m_msg = con->get_message(websocketpp::frame::opcode::text,64);
|
||||
m_msg->append_payload(std::string(60,'*'));
|
||||
m_msg_count = 1;
|
||||
|
||||
//m_message_stamps.reserve(1000);
|
||||
|
||||
m_con_start = std::chrono::high_resolution_clock::now();
|
||||
|
||||
m_endpoint.send(hdl, m_msg);
|
||||
//m_endpoint.send(hdl, "", websocketpp::frame::opcode::text);
|
||||
}
|
||||
void on_message(websocketpp::connection_hdl hdl, message_ptr msg) {
|
||||
if (m_msg_count == 1000) {
|
||||
m_message = std::chrono::high_resolution_clock::now();
|
||||
m_endpoint.close(hdl,websocketpp::close::status::going_away,"");
|
||||
} else {
|
||||
m_msg_count++;
|
||||
m_endpoint.send(hdl, m_msg);
|
||||
}
|
||||
}
|
||||
void on_close(websocketpp::connection_hdl hdl) {
|
||||
m_close = std::chrono::high_resolution_clock::now();
|
||||
|
||||
|
||||
|
||||
std::cout << "Socket Init: " << std::chrono::duration_cast<dur_type>(m_socket_init-m_start).count() << std::endl;
|
||||
std::cout << "TCP Pre Init: " << std::chrono::duration_cast<dur_type>(m_tcp_pre_init-m_start).count() << std::endl;
|
||||
std::cout << "TCP Post Init: " << std::chrono::duration_cast<dur_type>(m_tcp_post_init-m_start).count() << std::endl;
|
||||
std::cout << "Open: " << std::chrono::duration_cast<dur_type>(m_open-m_start).count() << std::endl;
|
||||
std::cout << "Start: " << std::chrono::duration_cast<dur_type>(m_con_start-m_start).count() << std::endl;
|
||||
std::cout << "Message: " << std::chrono::duration_cast<dur_type>(m_message-m_start).count() << std::endl;
|
||||
std::cout << "Close: " << std::chrono::duration_cast<dur_type>(m_close-m_start).count() << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "Message: " << std::chrono::duration_cast<dur_type>(m_message-m_con_start).count() << std::endl;
|
||||
std::cout << "Close: " << std::chrono::duration_cast<dur_type>(m_close-m_message).count() << std::endl;
|
||||
}
|
||||
private:
|
||||
client m_endpoint;
|
||||
|
||||
client::message_ptr m_msg;
|
||||
size_t m_msg_count;
|
||||
|
||||
std::chrono::high_resolution_clock::time_point m_start;
|
||||
std::chrono::high_resolution_clock::time_point m_tcp_pre_init;
|
||||
std::chrono::high_resolution_clock::time_point m_tcp_post_init;
|
||||
std::chrono::high_resolution_clock::time_point m_socket_init;
|
||||
|
||||
std::vector<std::chrono::high_resolution_clock::time_point> m_message_stamps;
|
||||
|
||||
std::chrono::high_resolution_clock::time_point m_con_start;
|
||||
std::chrono::high_resolution_clock::time_point m_open;
|
||||
std::chrono::high_resolution_clock::time_point m_message;
|
||||
std::chrono::high_resolution_clock::time_point m_close;
|
||||
};
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
std::string uri = "wss://echo.websocket.org";
|
||||
|
||||
if (argc == 2) {
|
||||
uri = argv[1];
|
||||
}
|
||||
|
||||
try {
|
||||
perftest endpoint;
|
||||
endpoint.start(uri);
|
||||
} catch (const std::exception & e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
} catch (websocketpp::lib::error_code e) {
|
||||
std::cout << e.message() << std::endl;
|
||||
} catch (...) {
|
||||
std::cout << "other exception" << std::endl;
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
Copyright (c) 2011, 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.
|
||||
@@ -1,45 +0,0 @@
|
||||
WebSocket++ (0.3.0-alpha4)
|
||||
==========================
|
||||
|
||||
WebSocket++ is a header only C++ library that implements RFC6455 The WebSocket
|
||||
Protocol. It allows integrating WebSocket client and server functionality into
|
||||
C++ programs. It uses interchangeable network transport modules including one
|
||||
based on C++ iostreams and one based on Boost Asio.
|
||||
|
||||
Major Features
|
||||
==============
|
||||
* Full support for RFC6455
|
||||
* Partial support for Hixie 76 / Hybi 00, 07-17 draft specs (server only)
|
||||
* Message/event based interface
|
||||
* Supports secure WebSockets (TLS), IPv6, and explicit proxies.
|
||||
* Flexible dependency management (C++11 Standard Library or Boost)
|
||||
* Interchangeable network transport modules (iostream and Boost Asio)
|
||||
* Portable/cross platform (Posix/Windows, 32/64bit, Intel/ARM/PPC)
|
||||
* Thread-safe
|
||||
|
||||
Get Involved
|
||||
============
|
||||
|
||||
[](https://travis-ci.org/zaphoyd/websocketpp)
|
||||
|
||||
**Project Website**
|
||||
http://www.zaphoyd.com/websocketpp/
|
||||
|
||||
**User Manual**
|
||||
http://www.zaphoyd.com/websocketpp/manual/
|
||||
|
||||
**GitHub Repository**
|
||||
https://github.com/zaphoyd/websocketpp/
|
||||
|
||||
**Announcements Mailing List**
|
||||
http://groups.google.com/group/websocketpp-announcements/
|
||||
|
||||
**IRC Channel**
|
||||
#websocketpp (freenode)
|
||||
|
||||
**Discussion / Development / Support Mailing List / Forum**
|
||||
http://groups.google.com/group/websocketpp/
|
||||
|
||||
Author
|
||||
======
|
||||
Peter Thorson - websocketpp@zaphoyd.com
|
||||
+348
@@ -0,0 +1,348 @@
|
||||
How to use this library
|
||||
|
||||
WebSocket++ is a C++ websocket server library implemented using the Boost Asio networking stack. It is designed to provide a simple interface.
|
||||
|
||||
Built on Asio's proactor asynchronous event loop.
|
||||
|
||||
Building a program using WebSocket++ has two parts
|
||||
1. Implement a connection handler.
|
||||
This is done by subclassing websocketpp::connection_handler. Each websocket connection is attached to a connection handler.
|
||||
The handler implements the following methods:
|
||||
|
||||
validate:
|
||||
Called after the client handshake is received but before the connection is accepted. Allows cookie authentication, origin checking, subprotocol negotiation, etc.
|
||||
|
||||
connect:
|
||||
Called when the connection has been established and writes are allowed.
|
||||
|
||||
disconnect:
|
||||
Called when the connection has been disconnected.
|
||||
|
||||
message: text and binary variants
|
||||
Called when a new websocket message is received.
|
||||
|
||||
The handler has access to the following websocket session API:
|
||||
get_header
|
||||
returns the value of an HTTP header sent by the client during the handshake.
|
||||
|
||||
get_request
|
||||
returns the resource requested by the client in the handshake.
|
||||
|
||||
set_handler:
|
||||
pass responsibility for this connection to another connection handler.
|
||||
|
||||
set_http_error:
|
||||
reject the connection with a specific HTTP error.
|
||||
|
||||
add_header
|
||||
adds an HTTP header to the server handshake.
|
||||
|
||||
set_subprotocol
|
||||
selects a subprotocol for the connection.
|
||||
|
||||
send: text and binary variants
|
||||
send a websocket message.
|
||||
|
||||
ping:
|
||||
send a ping.
|
||||
|
||||
2. Start Asio's event loop with a TCP endpoint and your connection handler
|
||||
|
||||
There are two example programs in the examples directory that demonstrate this use pattern.
|
||||
One is a trivial stateless echo server, the other is a simple web based chat client.
|
||||
Both include example javascript clients. The echo server is suitable for use with automated
|
||||
testing suites such as the Autobahn test suite.
|
||||
|
||||
By default, a single connection handler object is used for all connections.
|
||||
If needs require, that default handler can either store per-connection state itself
|
||||
or create new handlers and pass off responsibility for the connection to them.
|
||||
|
||||
How to build this library
|
||||
|
||||
Build static library
|
||||
make
|
||||
|
||||
Build and install in system include directories
|
||||
make install
|
||||
|
||||
Available flags:
|
||||
- SHARED=1: build a shared instead of static library.
|
||||
- DEBUG=1: build library with no optimizations, suitable for debugging. Debug library
|
||||
is called libwebsocketpp_dbg
|
||||
- CXX=*: uses * as the c++ compiler instead of system default
|
||||
|
||||
Build tested on
|
||||
- Mac OS X 10.7 with apple gcc 4.2, macports gcc 4.6, apple llvm/clang, boost 1.47
|
||||
- Fedora 15, gcc 4.6, boost 1.46
|
||||
- Ubunutu server, gcc, boost 1.42
|
||||
|
||||
Outstanding issues
|
||||
- Acknowledgement details
|
||||
- Subprotocol negotiation interface
|
||||
- check draft 14 issues
|
||||
- session.cpp - add_header. Decide what should happen with multiple calls to
|
||||
add header with the same key
|
||||
- multiple headers of the same value
|
||||
- Better exception model
|
||||
- closing handshake reason/ error codes?
|
||||
- tests for opening/closing handshake
|
||||
- tests for utf8
|
||||
- utf8 streaming validation
|
||||
- more easily configurable frame size limit
|
||||
- Better system of handling server wide defaults (like hosts, frame limits, etc)
|
||||
|
||||
To check
|
||||
- double check bugs in autobahn (sending wrong localhost:9000 header) not
|
||||
- checking masking in the 9.x tests
|
||||
|
||||
Unimplemented features
|
||||
- SSL
|
||||
- frame or streaming based API
|
||||
- client features
|
||||
- extension negotiation interface
|
||||
|
||||
Acknowledgements
|
||||
- Boost Asio and other libraries
|
||||
- base64 library
|
||||
- sha1 library
|
||||
- htonll discussion
|
||||
- build/makefile from libjson
|
||||
|
||||
- Autobahn test suite
|
||||
- testing by Keith Brisson
|
||||
|
||||
|
||||
|
||||
API spec notes
|
||||
|
||||
|
||||
|
||||
## Server API ##
|
||||
websocketpp.hpp
|
||||
|
||||
create a websocketpp::server_ptr initialized to a new websocketpp::server object
|
||||
|
||||
the server constructor will need three things.
|
||||
- A boost::asio::io_service object to manage its async operations
|
||||
- A boost::asio::ip::tcp::endpoint to listen to for new connections
|
||||
- An object that implements the websocketpp::connection_handler interface to provide callback functions (See Handler API)
|
||||
|
||||
After construction, the server object will be in the initialization state.
|
||||
At this time you can set up server configuration options either via calling individual set option commands
|
||||
or by loading them in a batch from a configuration file.
|
||||
|
||||
The only required option is that at least one host value must be set.
|
||||
Incoming websocket connections must specify a host value that they wish to connect to
|
||||
and if the server object does not have that host value in it's list of canonical hosts it will reject the connection.
|
||||
|
||||
[note about settings that can be changed live?]
|
||||
|
||||
Once the server has been configured the way you want, call the start_accept() method.
|
||||
This will add the first async call to your io_service. If your io_service was already running,
|
||||
the server will start accepting connections immediately. If not you will need to call io_service.run() to start it.
|
||||
|
||||
Once the server has started it will accept new connections.
|
||||
A new session object will be created for each connection accepted.
|
||||
The session will perform the websocket handshake and if it is successful begin reading frames.
|
||||
The session will continue reading frames until an error occurs or a connection close frame is seen.
|
||||
The session will notify the handler that it was initialized with (see Handler API) as necessary.
|
||||
The Session API defines how a handler (or other part of the end application) can interact with the session
|
||||
(to get information about the session, send messages back to the client, etc).
|
||||
|
||||
## Client API ##
|
||||
include websocketpp.hpp
|
||||
|
||||
create a websocketpp::client_ptr initialized to a new websocketpp::client object
|
||||
|
||||
the client constructor will need:
|
||||
- A boost::asio::io_service object to manage its async operations
|
||||
- An object that implements the websocketpp::connection_handler interface to provide callback functions (See Handler API)
|
||||
|
||||
After construction, the client object will be in the initialization state.
|
||||
At this time you can set up client configuration options either via calling individual set options commands
|
||||
or by loading them in a batch from a configuration file.
|
||||
|
||||
Opening a new connection:
|
||||
Per the websocket spec, a client can only have one connection in the connecting state at a time.
|
||||
Client method new_session() will create a new session and return a shared pointer to it.
|
||||
After this point new_session will throw an exception if you attempt to call it again
|
||||
before the most recently created session has either successfully connected or failed to connect.
|
||||
new_session()
|
||||
- call websocketpp::client::new_session(). This will return a session_ptr
|
||||
|
||||
|
||||
## Handler API ##
|
||||
The handler API defines the interface that a websocketpp session will use to communicate information
|
||||
about the session state and new messages to your application.
|
||||
|
||||
A client or server must be initialized with a default handler that will be used for all sessions.
|
||||
The default handler may pass a session off to another handler as necessary.
|
||||
|
||||
A handler must implement the following methods:
|
||||
- validate(session_ptr)
|
||||
- on_fail(session_ptr)
|
||||
- on_open(session_ptr)
|
||||
- on_close(session_ptr)
|
||||
- on_message(session_ptr,const std::vector<unsigned char> &)
|
||||
- on_message(session_ptr,const std::string &)
|
||||
|
||||
validate will be called after a websocket handshake has been received and before it is accepted.
|
||||
It provides a handler with the ability to refuse a connection based on application specific logic
|
||||
(ex: restrict domains or negotiate subprotocols). To reject the connection throw a handshake_error.
|
||||
Validate is never called for client sessions.
|
||||
To refuse a client session (ex: if you do not like the set of extensions/subprotocols the server chose)
|
||||
you can close the connection immediately in the on_open member function.
|
||||
|
||||
on_fail is called whenever a session is terminated or failed before it was successfully established.
|
||||
This happens if there is an error during the handshake process or if the server refused the connection.
|
||||
|
||||
on_fail will be the last time a session calls its handler.
|
||||
If your application will need information from `session` after this function you should either
|
||||
save the session_ptr somewhere or copy the data out.
|
||||
|
||||
on_open is called after the websocket session has been successfully established and is in the OPEN state.
|
||||
The session is now available to send messages and will begin reading frames
|
||||
and calling the on_message/on_close/on_error callbacks.
|
||||
A client may reject the connection by closing the session at this point.
|
||||
|
||||
on_close is called whenever an open session is closed for any reason.
|
||||
This can be due to either endpoint requesting a connection close or an error occurring.
|
||||
Information about why the session was closed can be extracted from the session itself.
|
||||
on_close will be the last time a session calls its handler.
|
||||
If your application will need information from `session` after this function you should either
|
||||
save the session_ptr somewhere or copy the data out.
|
||||
|
||||
on_message (binary version) will be called when a binary message is received.
|
||||
Message data is passed as a vector of bytes (unsigned char).
|
||||
Data will not be available after this callback ends so the handler must either
|
||||
completely process the message or copy it somewhere else for processing later.
|
||||
|
||||
TODO: Notes about thread safety
|
||||
|
||||
|
||||
## Session API ##
|
||||
The Session API allows a handler to look up information about a session
|
||||
as well as interact with that session (send messages, close the connection, etc).
|
||||
|
||||
Session pointers are returned with every handler callback as well as every call to websocketpp::client::connect.
|
||||
|
||||
|
||||
Handler Interface:
|
||||
- set_handler(connection_handler_ptr)
|
||||
|
||||
Handshake Interface:
|
||||
For the client these methods are valid after the server's handshake has been received.
|
||||
This is guaranteed to be the case by the time `on_open` is called.
|
||||
|
||||
For the server these methods are valid after the client's handshake has been received.
|
||||
This is guaranteed to be the case by the time `validate` is called.
|
||||
|
||||
- const std::string& get_subprotocol() const;
|
||||
- const std::string& get_resource() const;
|
||||
- const std::string& get_origin() const;
|
||||
- std::string get_client_header(const std::string&) const;
|
||||
- std::string get_server_header(const std::string&) const;
|
||||
- const std::vector<std::string>& get_extensions() const;
|
||||
- unsigned int get_version() const;
|
||||
|
||||
Frame Interface
|
||||
- void send(const std::string &);
|
||||
- void send(const std::vector<unsigned char> &);
|
||||
- void ping(const std::string &);
|
||||
- void pong(const std::string &);
|
||||
|
||||
These methods are valid only for open connections. They will throw an exception if called from any other state.
|
||||
|
||||
WebSocket++ does not queue messages. As such only one send operation can be occurring at once.
|
||||
TODO: failure behavior. OPTIONS:
|
||||
- send will throw a `session_busy` exception if busy
|
||||
- send will return true/false
|
||||
- a callback could be defined letting the handler know that it is safe to write again.
|
||||
|
||||
Session Interface
|
||||
- void close(uint16_t status,const std::string &reason);
|
||||
- bool is_server() const;
|
||||
|
||||
|
||||
|
||||
|
||||
--------------------------------
|
||||
screwing around with a policy based refactoring
|
||||
--------------------------------
|
||||
|
||||
template<class WebSocketRole,class Logger>
|
||||
class endpoint : public WebSocketRole, Logger {
|
||||
public:
|
||||
endpoint(connection_handler_ptr);
|
||||
|
||||
size_t get_connected_client_count() const;
|
||||
|
||||
void set_endpoint(const tcp::endpoint& endpoint); // asio::bind
|
||||
|
||||
private:
|
||||
std::list<session_ptr> m_connections;
|
||||
connection_handler_ptr m_handler;
|
||||
|
||||
boost::asio::io_service m_io_service;
|
||||
tcp::acceptor m_acceptor;
|
||||
}
|
||||
|
||||
class server_interface {
|
||||
public:
|
||||
void add_host(const std::string &host);
|
||||
void remove_host(const std::string &host);
|
||||
bool validate_host(const std::string &host) const;
|
||||
|
||||
void set_max_message_size(uint64_t size);
|
||||
bool validate_message_size(uint64_t size) const;
|
||||
|
||||
void start() {
|
||||
// start_accept()
|
||||
// io_service.run()
|
||||
}
|
||||
private:
|
||||
void start_accept();
|
||||
void handle_accept(session_ptr session, const boost::system::error_code&)
|
||||
|
||||
std::set<std::string> m_hosts;
|
||||
uint64_t m_max_message_size;
|
||||
}
|
||||
|
||||
class client_interface {
|
||||
public:
|
||||
session_ptr connect(const std::string &url);
|
||||
protected:
|
||||
|
||||
private:
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class HandshakePolicy>
|
||||
class session : public HandshakePolicy {
|
||||
public:
|
||||
session();
|
||||
private:
|
||||
|
||||
}
|
||||
|
||||
namespace websocketpp {
|
||||
namespace handshake {
|
||||
|
||||
/* a handshake policy must define:
|
||||
void on_connect();
|
||||
bool is_server() const;
|
||||
|
||||
*/
|
||||
|
||||
class server {
|
||||
|
||||
}
|
||||
|
||||
class client {
|
||||
|
||||
}
|
||||
|
||||
} // handshake
|
||||
} // websocketpp
|
||||
-44
@@ -1,44 +0,0 @@
|
||||
Complete & Tested:
|
||||
- Server and client roles pass all Autobahn v0.5.9 test suite tests strictly
|
||||
- Streaming UTF8 validation
|
||||
- random number generation
|
||||
- iostream based transport
|
||||
- C++11 support
|
||||
- LLVM/Clang support
|
||||
- GCC support
|
||||
- 64 bit support
|
||||
- 32 bit support
|
||||
- Logging
|
||||
- Client role
|
||||
- message_handler
|
||||
- ping_handler
|
||||
- pong_handler
|
||||
- open_handler
|
||||
- close_handler
|
||||
- echo_server & echo_server_tls
|
||||
|
||||
Implimented, needs more testing
|
||||
- TLS support
|
||||
- External io_service support
|
||||
- socket_init_handler
|
||||
- tls_init_handler
|
||||
- tcp_init_handler
|
||||
- exception/error handling
|
||||
- Subprotocol negotiation
|
||||
- Hybi 00/Hixie 76 legacy protocol support
|
||||
- Performance tuning
|
||||
- Outgoing Proxy Support
|
||||
- PowerPC support
|
||||
- Visual Studio / Windows support
|
||||
- Timeouts
|
||||
- CMake build/install support
|
||||
|
||||
- validate_handler
|
||||
- http_handler
|
||||
|
||||
Future feature roadmap
|
||||
- Extension support
|
||||
- permessage_compress extension
|
||||
- Message buffer pool
|
||||
- flow control
|
||||
- tutorials & documentation
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
base64.cpp and base64.h
|
||||
|
||||
Copyright (C) 2004-2008 René Nyffenegger
|
||||
|
||||
This source code is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the author be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this source code must not be misrepresented; you must not
|
||||
claim that you wrote the original source code. If you use this source code
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original source code.
|
||||
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
René Nyffenegger rene.nyffenegger@adp-gmbh.ch
|
||||
|
||||
*/
|
||||
|
||||
#include "base64.h"
|
||||
#include <iostream>
|
||||
|
||||
static const std::string base64_chars =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789+/";
|
||||
|
||||
|
||||
static inline bool is_base64(unsigned char c) {
|
||||
return (isalnum(c) || (c == '+') || (c == '/'));
|
||||
}
|
||||
|
||||
std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) {
|
||||
std::string ret;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
unsigned char char_array_3[3];
|
||||
unsigned char char_array_4[4];
|
||||
|
||||
while (in_len--) {
|
||||
char_array_3[i++] = *(bytes_to_encode++);
|
||||
if (i == 3) {
|
||||
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
||||
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
|
||||
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
|
||||
char_array_4[3] = char_array_3[2] & 0x3f;
|
||||
|
||||
for(i = 0; (i <4) ; i++)
|
||||
ret += base64_chars[char_array_4[i]];
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (i)
|
||||
{
|
||||
for(j = i; j < 3; j++)
|
||||
char_array_3[j] = '\0';
|
||||
|
||||
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
||||
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
|
||||
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
|
||||
char_array_4[3] = char_array_3[2] & 0x3f;
|
||||
|
||||
for (j = 0; (j < i + 1); j++)
|
||||
ret += base64_chars[char_array_4[j]];
|
||||
|
||||
while((i++ < 3))
|
||||
ret += '=';
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
std::string base64_decode(std::string const& encoded_string) {
|
||||
size_t in_len = encoded_string.size();
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int in_ = 0;
|
||||
unsigned char char_array_4[4], char_array_3[3];
|
||||
std::string ret;
|
||||
|
||||
while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
|
||||
char_array_4[i++] = encoded_string[in_]; in_++;
|
||||
if (i ==4) {
|
||||
for (i = 0; i <4; i++)
|
||||
char_array_4[i] = base64_chars.find(char_array_4[i]);
|
||||
|
||||
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
|
||||
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
|
||||
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
|
||||
|
||||
for (i = 0; (i < 3); i++)
|
||||
ret += char_array_3[i];
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (i) {
|
||||
for (j = i; j <4; j++)
|
||||
char_array_4[j] = 0;
|
||||
|
||||
for (j = 0; j <4; j++)
|
||||
char_array_4[j] = base64_chars.find(char_array_4[j]);
|
||||
|
||||
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
|
||||
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
|
||||
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
|
||||
|
||||
for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
#include <string>
|
||||
|
||||
std::string base64_encode(unsigned char const* , unsigned int len);
|
||||
std::string base64_decode(std::string const& s);
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "network_utilities.hpp"
|
||||
|
||||
uint64_t htonll(uint64_t src) {
|
||||
static int typ = TYP_INIT;
|
||||
unsigned char c;
|
||||
union {
|
||||
uint64_t ull;
|
||||
unsigned char c[8];
|
||||
} x;
|
||||
if (typ == TYP_INIT) {
|
||||
x.ull = 0x01;
|
||||
typ = (x.c[7] == 0x01ULL) ? TYP_BIGE : TYP_SMLE;
|
||||
}
|
||||
if (typ == TYP_BIGE)
|
||||
return src;
|
||||
x.ull = src;
|
||||
c = x.c[0]; x.c[0] = x.c[7]; x.c[7] = c;
|
||||
c = x.c[1]; x.c[1] = x.c[6]; x.c[6] = c;
|
||||
c = x.c[2]; x.c[2] = x.c[5]; x.c[5] = c;
|
||||
c = x.c[3]; x.c[3] = x.c[4]; x.c[4] = c;
|
||||
return x.ull;
|
||||
}
|
||||
|
||||
uint64_t ntohll(uint64_t src) {
|
||||
return htonll(src);
|
||||
}
|
||||
|
||||
std::string lookup_http_error_string(int code) {
|
||||
switch (code) {
|
||||
case 400:
|
||||
return "Bad Request";
|
||||
case 401:
|
||||
return "Unauthorized";
|
||||
case 403:
|
||||
return "Forbidden";
|
||||
case 404:
|
||||
return "Not Found";
|
||||
case 405:
|
||||
return "Method Not Allowed";
|
||||
case 406:
|
||||
return "Not Acceptable";
|
||||
case 407:
|
||||
return "Proxy Authentication Required";
|
||||
case 408:
|
||||
return "Request Timeout";
|
||||
case 409:
|
||||
return "Conflict";
|
||||
case 410:
|
||||
return "Gone";
|
||||
case 411:
|
||||
return "Length Required";
|
||||
case 412:
|
||||
return "Precondition Failed";
|
||||
case 413:
|
||||
return "Request Entity Too Large";
|
||||
case 414:
|
||||
return "Request-URI Too Long";
|
||||
case 415:
|
||||
return "Unsupported Media Type";
|
||||
case 416:
|
||||
return "Requested Range Not Satisfiable";
|
||||
case 417:
|
||||
return "Expectation Failed";
|
||||
case 500:
|
||||
return "Internal Server Error";
|
||||
case 501:
|
||||
return "Not Implimented";
|
||||
case 502:
|
||||
return "Bad Gateway";
|
||||
case 503:
|
||||
return "Service Unavailable";
|
||||
case 504:
|
||||
return "Gateway Timeout";
|
||||
case 505:
|
||||
return "HTTP Version Not Supported";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
std::string lookup_ws_close_status_string(uint16_t code) {
|
||||
switch (code) {
|
||||
case 1000:
|
||||
return "Normal closure";
|
||||
case 1001:
|
||||
return "Going away";
|
||||
case 1002:
|
||||
return "Protocol error";
|
||||
case 1003:
|
||||
return "Unacceptable data";
|
||||
case 1004:
|
||||
return "Reserved";
|
||||
case 1005:
|
||||
return "No status received";
|
||||
case 1006:
|
||||
return "Abnormal closure";
|
||||
case 1007:
|
||||
return "Invalid message data";
|
||||
case 1008:
|
||||
return "Policy Violation";
|
||||
case 1009:
|
||||
return "Message too large";
|
||||
case 1010:
|
||||
return "Missing required extensions";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
bool websocketpp::ws_uri::parse(const std::string& uri) {
|
||||
boost::cmatch what;
|
||||
static const boost::regex expression("(ws|wss)://([^/:\\[]+|\\[[0-9:]+\\])(:\\d{1,5})?(/[^#]*)?");
|
||||
|
||||
// TODO: should this split resource into path/query?
|
||||
|
||||
if (boost::regex_match(uri.c_str(), what, expression)) {
|
||||
if (what[1] == "wss") {
|
||||
secure = true;
|
||||
} else {
|
||||
secure = false;
|
||||
}
|
||||
|
||||
host = what[2];
|
||||
|
||||
if (what[3] == "") {
|
||||
port = (secure ? 443 : 80);
|
||||
} else {
|
||||
unsigned int t_port = atoi(std::string(what[3]).substr(1).c_str());
|
||||
|
||||
if (t_port > 65535) {
|
||||
return false;
|
||||
}
|
||||
|
||||
port = atoi(std::string(what[3]).substr(1).c_str());
|
||||
}
|
||||
|
||||
if (what[4] == "") {
|
||||
resource = "/";
|
||||
} else {
|
||||
resource = what[4];
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2011, 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:
|
||||
@@ -11,10 +11,10 @@
|
||||
* * 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
|
||||
*
|
||||
* 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;
|
||||
@@ -22,37 +22,40 @@
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBSOCKETPP_CONCURRENCY_NONE_HPP
|
||||
#define WEBSOCKETPP_CONCURRENCY_NONE_HPP
|
||||
#ifndef NETWORK_UTILITIES_HPP
|
||||
#define NETWORK_UTILITIES_HPP
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
// http://www.viva64.com/en/k/0018/
|
||||
// TODO: impliment stuff from here:
|
||||
// http://stackoverflow.com/questions/809902/64-bit-ntohl-in-c
|
||||
|
||||
#define TYP_INIT 0
|
||||
#define TYP_SMLE 1
|
||||
#define TYP_BIGE 2
|
||||
|
||||
uint64_t htonll(uint64_t src);
|
||||
uint64_t ntohll(uint64_t src);
|
||||
|
||||
std::string lookup_http_error_string(int code);
|
||||
std::string lookup_ws_close_status_string(uint16_t code);
|
||||
|
||||
namespace websocketpp {
|
||||
namespace concurrency {
|
||||
struct ws_uri {
|
||||
bool parse(const std::string& uri);
|
||||
|
||||
namespace none_impl {
|
||||
class fake_mutex {
|
||||
public:
|
||||
fake_mutex() {}
|
||||
~fake_mutex() {}
|
||||
bool secure;
|
||||
std::string host;
|
||||
uint16_t port;
|
||||
std::string resource;
|
||||
};
|
||||
}
|
||||
|
||||
class fake_lock_guard {
|
||||
public:
|
||||
explicit fake_lock_guard(fake_mutex foo) {}
|
||||
~fake_lock_guard() {}
|
||||
};
|
||||
} // namespace none_impl
|
||||
|
||||
/// Stub Concurrency policy to remove locking in single threaded projects
|
||||
class none {
|
||||
public:
|
||||
typedef none_impl::fake_mutex mutex_type;
|
||||
typedef none_impl::fake_lock_guard scoped_lock_type;
|
||||
};
|
||||
|
||||
} // namespace concurrency
|
||||
} // namespace websocketpp
|
||||
|
||||
#endif // WEBSOCKETPP_CONCURRENCY_ASYNC_HPP
|
||||
#endif // NETWORK_UTILITIES_HPP
|
||||
Executable
+41
@@ -0,0 +1,41 @@
|
||||
#
|
||||
# Makefile
|
||||
#
|
||||
# Copyright (C) 1998, 2009
|
||||
# Paul E. Jones <paulej@packetizer.com>
|
||||
# All Rights Reserved.
|
||||
#
|
||||
#############################################################################
|
||||
# $Id: Makefile 12 2009-06-22 19:34:25Z paulej $
|
||||
#############################################################################
|
||||
#
|
||||
# Description:
|
||||
# This is a makefile for UNIX to build the programs sha, shacmp, and
|
||||
# shatest
|
||||
#
|
||||
#
|
||||
|
||||
CC = g++
|
||||
|
||||
CFLAGS = -c -O2 -Wall -D_FILE_OFFSET_BITS=64
|
||||
|
||||
LIBS =
|
||||
|
||||
OBJS = sha1.o
|
||||
|
||||
all: sha shacmp shatest
|
||||
|
||||
sha: sha.o $(OBJS)
|
||||
$(CC) -o $@ sha.o $(OBJS) $(LIBS)
|
||||
|
||||
shacmp: shacmp.o $(OBJS)
|
||||
$(CC) -o $@ shacmp.o $(OBJS) $(LIBS)
|
||||
|
||||
shatest: shatest.o $(OBJS)
|
||||
$(CC) -o $@ shatest.o $(OBJS) $(LIBS)
|
||||
|
||||
%.o: %.cpp
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
|
||||
clean:
|
||||
$(RM) *.o sha shacmp shatest
|
||||
Executable
+48
@@ -0,0 +1,48 @@
|
||||
#
|
||||
# Makefile.nt
|
||||
#
|
||||
# Copyright (C) 1998, 2009
|
||||
# Paul E. Jones <paulej@packetizer.com>
|
||||
# All Rights Reserved.
|
||||
#
|
||||
#############################################################################
|
||||
# $Id: Makefile.nt 13 2009-06-22 20:20:32Z paulej $
|
||||
#############################################################################
|
||||
#
|
||||
# Description:
|
||||
# This is a makefile for Win32 to build the programs sha, shacmp, and
|
||||
# shatest
|
||||
#
|
||||
# Portability Issues:
|
||||
# Designed to work with Visual C++
|
||||
#
|
||||
#
|
||||
|
||||
.silent:
|
||||
|
||||
!include <win32.mak>
|
||||
|
||||
RM = del /q
|
||||
|
||||
LIBS = $(conlibs) setargv.obj
|
||||
|
||||
CFLAGS = -D _CRT_SECURE_NO_WARNINGS /EHsc /O2 /W3
|
||||
|
||||
OBJS = sha1.obj
|
||||
|
||||
all: sha.exe shacmp.exe shatest.exe
|
||||
|
||||
sha.exe: sha.obj $(OBJS)
|
||||
$(link) $(conflags) -out:$@ sha.obj $(OBJS) $(LIBS)
|
||||
|
||||
shacmp.exe: shacmp.obj $(OBJS)
|
||||
$(link) $(conflags) -out:$@ shacmp.obj $(OBJS) $(LIBS)
|
||||
|
||||
shatest.exe: shatest.obj $(OBJS)
|
||||
$(link) $(conflags) -out:$@ shatest.obj $(OBJS) $(LIBS)
|
||||
|
||||
.cpp.obj:
|
||||
$(cc) $(CFLAGS) $(cflags) $(cvars) $<
|
||||
|
||||
clean:
|
||||
$(RM) *.obj sha.exe shacmp.exe shatest.exe
|
||||
Executable
+14
@@ -0,0 +1,14 @@
|
||||
Copyright (C) 1998, 2009
|
||||
Paul E. Jones <paulej@packetizer.com>
|
||||
|
||||
Freeware Public License (FPL)
|
||||
|
||||
This software is licensed as "freeware." Permission to distribute
|
||||
this software in source and binary forms, including incorporation
|
||||
into other products, is hereby granted without a fee. THIS SOFTWARE
|
||||
IS PROVIDED 'AS IS' AND WITHOUT ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHOR SHALL NOT BE HELD
|
||||
LIABLE FOR ANY DAMAGES RESULTING FROM THE USE OF THIS SOFTWARE, EITHER
|
||||
DIRECTLY OR INDIRECTLY, INCLUDING, BUT NOT LIMITED TO, LOSS OF DATA
|
||||
OR DATA BEING RENDERED INACCURATE.
|
||||
Executable
+176
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* sha.cpp
|
||||
*
|
||||
* Copyright (C) 1998, 2009
|
||||
* Paul E. Jones <paulej@packetizer.com>
|
||||
* All Rights Reserved
|
||||
*
|
||||
*****************************************************************************
|
||||
* $Id: sha.cpp 13 2009-06-22 20:20:32Z paulej $
|
||||
*****************************************************************************
|
||||
*
|
||||
* Description:
|
||||
* This utility will display the message digest (fingerprint) for
|
||||
* the specified file(s).
|
||||
*
|
||||
* Portability Issues:
|
||||
* None.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#ifdef WIN32
|
||||
#include <io.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include "sha1.h"
|
||||
|
||||
/*
|
||||
* Function prototype
|
||||
*/
|
||||
void usage();
|
||||
|
||||
|
||||
/*
|
||||
* main
|
||||
*
|
||||
* Description:
|
||||
* This is the entry point for the program
|
||||
*
|
||||
* Parameters:
|
||||
* argc: [in]
|
||||
* This is the count of arguments in the argv array
|
||||
* argv: [in]
|
||||
* This is an array of filenames for which to compute message digests
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*
|
||||
* Comments:
|
||||
*
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
SHA1 sha; // SHA-1 class
|
||||
FILE *fp; // File pointer for reading files
|
||||
char c; // Character read from file
|
||||
unsigned message_digest[5]; // Message digest from "sha"
|
||||
int i; // Counter
|
||||
bool reading_stdin; // Are we reading standard in?
|
||||
bool read_stdin = false; // Have we read stdin?
|
||||
|
||||
/*
|
||||
* Check the program arguments and print usage information if -?
|
||||
* or --help is passed as the first argument.
|
||||
*/
|
||||
if (argc > 1 && (!strcmp(argv[1],"-?") || !strcmp(argv[1],"--help")))
|
||||
{
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* For each filename passed in on the command line, calculate the
|
||||
* SHA-1 value and display it.
|
||||
*/
|
||||
for(i = 0; i < argc; i++)
|
||||
{
|
||||
/*
|
||||
* We start the counter at 0 to guarantee entry into the for loop.
|
||||
* So if 'i' is zero, we will increment it now. If there is no
|
||||
* argv[1], we will use STDIN below.
|
||||
*/
|
||||
if (i == 0)
|
||||
{
|
||||
i++;
|
||||
}
|
||||
|
||||
if (argc == 1 || !strcmp(argv[i],"-"))
|
||||
{
|
||||
#ifdef WIN32
|
||||
_setmode(_fileno(stdin), _O_BINARY);
|
||||
#endif
|
||||
fp = stdin;
|
||||
reading_stdin = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(fp = fopen(argv[i],"rb")))
|
||||
{
|
||||
fprintf(stderr, "sha: unable to open file %s\n", argv[i]);
|
||||
return 2;
|
||||
}
|
||||
reading_stdin = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* We do not want to read STDIN multiple times
|
||||
*/
|
||||
if (reading_stdin)
|
||||
{
|
||||
if (read_stdin)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
read_stdin = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset the SHA1 object and process input
|
||||
*/
|
||||
sha.Reset();
|
||||
|
||||
c = fgetc(fp);
|
||||
while(!feof(fp))
|
||||
{
|
||||
sha.Input(c);
|
||||
c = fgetc(fp);
|
||||
}
|
||||
|
||||
if (!reading_stdin)
|
||||
{
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
if (!sha.Result(message_digest))
|
||||
{
|
||||
fprintf(stderr,"sha: could not compute message digest for %s\n",
|
||||
reading_stdin?"STDIN":argv[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf( "%08X %08X %08X %08X %08X - %s\n",
|
||||
message_digest[0],
|
||||
message_digest[1],
|
||||
message_digest[2],
|
||||
message_digest[3],
|
||||
message_digest[4],
|
||||
reading_stdin?"STDIN":argv[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* usage
|
||||
*
|
||||
* Description:
|
||||
* This function will display program usage information to the user.
|
||||
*
|
||||
* Parameters:
|
||||
* None.
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*
|
||||
* Comments:
|
||||
*
|
||||
*/
|
||||
void usage()
|
||||
{
|
||||
printf("usage: sha <file> [<file> ...]\n");
|
||||
printf("\tThis program will display the message digest (fingerprint)\n");
|
||||
printf("\tfor files using the Secure Hashing Algorithm (SHA-1).\n");
|
||||
}
|
||||
Executable
+589
@@ -0,0 +1,589 @@
|
||||
/*
|
||||
* sha1.cpp
|
||||
*
|
||||
* Copyright (C) 1998, 2009
|
||||
* Paul E. Jones <paulej@packetizer.com>
|
||||
* All Rights Reserved.
|
||||
*
|
||||
*****************************************************************************
|
||||
* $Id: sha1.cpp 12 2009-06-22 19:34:25Z paulej $
|
||||
*****************************************************************************
|
||||
*
|
||||
* Description:
|
||||
* This class implements the Secure Hashing Standard as defined
|
||||
* in FIPS PUB 180-1 published April 17, 1995.
|
||||
*
|
||||
* The Secure Hashing Standard, which uses the Secure Hashing
|
||||
* Algorithm (SHA), produces a 160-bit message digest for a
|
||||
* given data stream. In theory, it is highly improbable that
|
||||
* two messages will produce the same message digest. Therefore,
|
||||
* this algorithm can serve as a means of providing a "fingerprint"
|
||||
* for a message.
|
||||
*
|
||||
* Portability Issues:
|
||||
* SHA-1 is defined in terms of 32-bit "words". This code was
|
||||
* written with the expectation that the processor has at least
|
||||
* a 32-bit machine word size. If the machine word size is larger,
|
||||
* the code should still function properly. One caveat to that
|
||||
* is that the input functions taking characters and character arrays
|
||||
* assume that only 8 bits of information are stored in each character.
|
||||
*
|
||||
* Caveats:
|
||||
* SHA-1 is designed to work with messages less than 2^64 bits long.
|
||||
* Although SHA-1 allows a message digest to be generated for
|
||||
* messages of any number of bits less than 2^64, this implementation
|
||||
* only works with messages with a length that is a multiple of 8
|
||||
* bits.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "sha1.h"
|
||||
|
||||
/*
|
||||
* SHA1
|
||||
*
|
||||
* Description:
|
||||
* This is the constructor for the sha1 class.
|
||||
*
|
||||
* Parameters:
|
||||
* None.
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*
|
||||
* Comments:
|
||||
*
|
||||
*/
|
||||
SHA1::SHA1()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
/*
|
||||
* ~SHA1
|
||||
*
|
||||
* Description:
|
||||
* This is the destructor for the sha1 class
|
||||
*
|
||||
* Parameters:
|
||||
* None.
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*
|
||||
* Comments:
|
||||
*
|
||||
*/
|
||||
SHA1::~SHA1()
|
||||
{
|
||||
// The destructor does nothing
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset
|
||||
*
|
||||
* Description:
|
||||
* This function will initialize the sha1 class member variables
|
||||
* in preparation for computing a new message digest.
|
||||
*
|
||||
* Parameters:
|
||||
* None.
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*
|
||||
* Comments:
|
||||
*
|
||||
*/
|
||||
void SHA1::Reset()
|
||||
{
|
||||
Length_Low = 0;
|
||||
Length_High = 0;
|
||||
Message_Block_Index = 0;
|
||||
|
||||
H[0] = 0x67452301;
|
||||
H[1] = 0xEFCDAB89;
|
||||
H[2] = 0x98BADCFE;
|
||||
H[3] = 0x10325476;
|
||||
H[4] = 0xC3D2E1F0;
|
||||
|
||||
Computed = false;
|
||||
Corrupted = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Result
|
||||
*
|
||||
* Description:
|
||||
* This function will return the 160-bit message digest into the
|
||||
* array provided.
|
||||
*
|
||||
* Parameters:
|
||||
* message_digest_array: [out]
|
||||
* This is an array of five unsigned integers which will be filled
|
||||
* with the message digest that has been computed.
|
||||
*
|
||||
* Returns:
|
||||
* True if successful, false if it failed.
|
||||
*
|
||||
* Comments:
|
||||
*
|
||||
*/
|
||||
bool SHA1::Result(unsigned *message_digest_array)
|
||||
{
|
||||
int i; // Counter
|
||||
|
||||
if (Corrupted)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Computed)
|
||||
{
|
||||
PadMessage();
|
||||
Computed = true;
|
||||
}
|
||||
|
||||
for(i = 0; i < 5; i++)
|
||||
{
|
||||
message_digest_array[i] = H[i];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Input
|
||||
*
|
||||
* Description:
|
||||
* This function accepts an array of octets as the next portion of
|
||||
* the message.
|
||||
*
|
||||
* Parameters:
|
||||
* message_array: [in]
|
||||
* An array of characters representing the next portion of the
|
||||
* message.
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*
|
||||
* Comments:
|
||||
*
|
||||
*/
|
||||
void SHA1::Input( const unsigned char *message_array,
|
||||
unsigned length)
|
||||
{
|
||||
if (!length)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Computed || Corrupted)
|
||||
{
|
||||
Corrupted = true;
|
||||
return;
|
||||
}
|
||||
|
||||
while(length-- && !Corrupted)
|
||||
{
|
||||
Message_Block[Message_Block_Index++] = (*message_array & 0xFF);
|
||||
|
||||
Length_Low += 8;
|
||||
Length_Low &= 0xFFFFFFFF; // Force it to 32 bits
|
||||
if (Length_Low == 0)
|
||||
{
|
||||
Length_High++;
|
||||
Length_High &= 0xFFFFFFFF; // Force it to 32 bits
|
||||
if (Length_High == 0)
|
||||
{
|
||||
Corrupted = true; // Message is too long
|
||||
}
|
||||
}
|
||||
|
||||
if (Message_Block_Index == 64)
|
||||
{
|
||||
ProcessMessageBlock();
|
||||
}
|
||||
|
||||
message_array++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Input
|
||||
*
|
||||
* Description:
|
||||
* This function accepts an array of octets as the next portion of
|
||||
* the message.
|
||||
*
|
||||
* Parameters:
|
||||
* message_array: [in]
|
||||
* An array of characters representing the next portion of the
|
||||
* message.
|
||||
* length: [in]
|
||||
* The length of the message_array
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*
|
||||
* Comments:
|
||||
*
|
||||
*/
|
||||
void SHA1::Input( const char *message_array,
|
||||
unsigned length)
|
||||
{
|
||||
Input((unsigned char *) message_array, length);
|
||||
}
|
||||
|
||||
/*
|
||||
* Input
|
||||
*
|
||||
* Description:
|
||||
* This function accepts a single octets as the next message element.
|
||||
*
|
||||
* Parameters:
|
||||
* message_element: [in]
|
||||
* The next octet in the message.
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*
|
||||
* Comments:
|
||||
*
|
||||
*/
|
||||
void SHA1::Input(unsigned char message_element)
|
||||
{
|
||||
Input(&message_element, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Input
|
||||
*
|
||||
* Description:
|
||||
* This function accepts a single octet as the next message element.
|
||||
*
|
||||
* Parameters:
|
||||
* message_element: [in]
|
||||
* The next octet in the message.
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*
|
||||
* Comments:
|
||||
*
|
||||
*/
|
||||
void SHA1::Input(char message_element)
|
||||
{
|
||||
Input((unsigned char *) &message_element, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* operator<<
|
||||
*
|
||||
* Description:
|
||||
* This operator makes it convenient to provide character strings to
|
||||
* the SHA1 object for processing.
|
||||
*
|
||||
* Parameters:
|
||||
* message_array: [in]
|
||||
* The character array to take as input.
|
||||
*
|
||||
* Returns:
|
||||
* A reference to the SHA1 object.
|
||||
*
|
||||
* Comments:
|
||||
* Each character is assumed to hold 8 bits of information.
|
||||
*
|
||||
*/
|
||||
SHA1& SHA1::operator<<(const char *message_array)
|
||||
{
|
||||
const char *p = message_array;
|
||||
|
||||
while(*p)
|
||||
{
|
||||
Input(*p);
|
||||
p++;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*
|
||||
* operator<<
|
||||
*
|
||||
* Description:
|
||||
* This operator makes it convenient to provide character strings to
|
||||
* the SHA1 object for processing.
|
||||
*
|
||||
* Parameters:
|
||||
* message_array: [in]
|
||||
* The character array to take as input.
|
||||
*
|
||||
* Returns:
|
||||
* A reference to the SHA1 object.
|
||||
*
|
||||
* Comments:
|
||||
* Each character is assumed to hold 8 bits of information.
|
||||
*
|
||||
*/
|
||||
SHA1& SHA1::operator<<(const unsigned char *message_array)
|
||||
{
|
||||
const unsigned char *p = message_array;
|
||||
|
||||
while(*p)
|
||||
{
|
||||
Input(*p);
|
||||
p++;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*
|
||||
* operator<<
|
||||
*
|
||||
* Description:
|
||||
* This function provides the next octet in the message.
|
||||
*
|
||||
* Parameters:
|
||||
* message_element: [in]
|
||||
* The next octet in the message
|
||||
*
|
||||
* Returns:
|
||||
* A reference to the SHA1 object.
|
||||
*
|
||||
* Comments:
|
||||
* The character is assumed to hold 8 bits of information.
|
||||
*
|
||||
*/
|
||||
SHA1& SHA1::operator<<(const char message_element)
|
||||
{
|
||||
Input((unsigned char *) &message_element, 1);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*
|
||||
* operator<<
|
||||
*
|
||||
* Description:
|
||||
* This function provides the next octet in the message.
|
||||
*
|
||||
* Parameters:
|
||||
* message_element: [in]
|
||||
* The next octet in the message
|
||||
*
|
||||
* Returns:
|
||||
* A reference to the SHA1 object.
|
||||
*
|
||||
* Comments:
|
||||
* The character is assumed to hold 8 bits of information.
|
||||
*
|
||||
*/
|
||||
SHA1& SHA1::operator<<(const unsigned char message_element)
|
||||
{
|
||||
Input(&message_element, 1);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*
|
||||
* ProcessMessageBlock
|
||||
*
|
||||
* Description:
|
||||
* This function will process the next 512 bits of the message
|
||||
* stored in the Message_Block array.
|
||||
*
|
||||
* Parameters:
|
||||
* None.
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*
|
||||
* Comments:
|
||||
* Many of the variable names in this function, especially the single
|
||||
* character names, were used because those were the names used
|
||||
* in the publication.
|
||||
*
|
||||
*/
|
||||
void SHA1::ProcessMessageBlock()
|
||||
{
|
||||
const unsigned K[] = { // Constants defined for SHA-1
|
||||
0x5A827999,
|
||||
0x6ED9EBA1,
|
||||
0x8F1BBCDC,
|
||||
0xCA62C1D6
|
||||
};
|
||||
int t; // Loop counter
|
||||
unsigned temp; // Temporary word value
|
||||
unsigned W[80]; // Word sequence
|
||||
unsigned A, B, C, D, E; // Word buffers
|
||||
|
||||
/*
|
||||
* Initialize the first 16 words in the array W
|
||||
*/
|
||||
for(t = 0; t < 16; t++)
|
||||
{
|
||||
W[t] = ((unsigned) Message_Block[t * 4]) << 24;
|
||||
W[t] |= ((unsigned) Message_Block[t * 4 + 1]) << 16;
|
||||
W[t] |= ((unsigned) Message_Block[t * 4 + 2]) << 8;
|
||||
W[t] |= ((unsigned) Message_Block[t * 4 + 3]);
|
||||
}
|
||||
|
||||
for(t = 16; t < 80; t++)
|
||||
{
|
||||
W[t] = CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
|
||||
}
|
||||
|
||||
A = H[0];
|
||||
B = H[1];
|
||||
C = H[2];
|
||||
D = H[3];
|
||||
E = H[4];
|
||||
|
||||
for(t = 0; t < 20; t++)
|
||||
{
|
||||
temp = CircularShift(5,A) + ((B & C) | ((~B) & D)) + E + W[t] + K[0];
|
||||
temp &= 0xFFFFFFFF;
|
||||
E = D;
|
||||
D = C;
|
||||
C = CircularShift(30,B);
|
||||
B = A;
|
||||
A = temp;
|
||||
}
|
||||
|
||||
for(t = 20; t < 40; t++)
|
||||
{
|
||||
temp = CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
|
||||
temp &= 0xFFFFFFFF;
|
||||
E = D;
|
||||
D = C;
|
||||
C = CircularShift(30,B);
|
||||
B = A;
|
||||
A = temp;
|
||||
}
|
||||
|
||||
for(t = 40; t < 60; t++)
|
||||
{
|
||||
temp = CircularShift(5,A) +
|
||||
((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
|
||||
temp &= 0xFFFFFFFF;
|
||||
E = D;
|
||||
D = C;
|
||||
C = CircularShift(30,B);
|
||||
B = A;
|
||||
A = temp;
|
||||
}
|
||||
|
||||
for(t = 60; t < 80; t++)
|
||||
{
|
||||
temp = CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
|
||||
temp &= 0xFFFFFFFF;
|
||||
E = D;
|
||||
D = C;
|
||||
C = CircularShift(30,B);
|
||||
B = A;
|
||||
A = temp;
|
||||
}
|
||||
|
||||
H[0] = (H[0] + A) & 0xFFFFFFFF;
|
||||
H[1] = (H[1] + B) & 0xFFFFFFFF;
|
||||
H[2] = (H[2] + C) & 0xFFFFFFFF;
|
||||
H[3] = (H[3] + D) & 0xFFFFFFFF;
|
||||
H[4] = (H[4] + E) & 0xFFFFFFFF;
|
||||
|
||||
Message_Block_Index = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* PadMessage
|
||||
*
|
||||
* Description:
|
||||
* According to the standard, the message must be padded to an even
|
||||
* 512 bits. The first padding bit must be a '1'. The last 64 bits
|
||||
* represent the length of the original message. All bits in between
|
||||
* should be 0. This function will pad the message according to those
|
||||
* rules by filling the message_block array accordingly. It will also
|
||||
* call ProcessMessageBlock() appropriately. When it returns, it
|
||||
* can be assumed that the message digest has been computed.
|
||||
*
|
||||
* Parameters:
|
||||
* None.
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*
|
||||
* Comments:
|
||||
*
|
||||
*/
|
||||
void SHA1::PadMessage()
|
||||
{
|
||||
/*
|
||||
* Check to see if the current message block is too small to hold
|
||||
* the initial padding bits and length. If so, we will pad the
|
||||
* block, process it, and then continue padding into a second block.
|
||||
*/
|
||||
if (Message_Block_Index > 55)
|
||||
{
|
||||
Message_Block[Message_Block_Index++] = 0x80;
|
||||
while(Message_Block_Index < 64)
|
||||
{
|
||||
Message_Block[Message_Block_Index++] = 0;
|
||||
}
|
||||
|
||||
ProcessMessageBlock();
|
||||
|
||||
while(Message_Block_Index < 56)
|
||||
{
|
||||
Message_Block[Message_Block_Index++] = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Message_Block[Message_Block_Index++] = 0x80;
|
||||
while(Message_Block_Index < 56)
|
||||
{
|
||||
Message_Block[Message_Block_Index++] = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Store the message length as the last 8 octets
|
||||
*/
|
||||
Message_Block[56] = (Length_High >> 24) & 0xFF;
|
||||
Message_Block[57] = (Length_High >> 16) & 0xFF;
|
||||
Message_Block[58] = (Length_High >> 8) & 0xFF;
|
||||
Message_Block[59] = (Length_High) & 0xFF;
|
||||
Message_Block[60] = (Length_Low >> 24) & 0xFF;
|
||||
Message_Block[61] = (Length_Low >> 16) & 0xFF;
|
||||
Message_Block[62] = (Length_Low >> 8) & 0xFF;
|
||||
Message_Block[63] = (Length_Low) & 0xFF;
|
||||
|
||||
ProcessMessageBlock();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* CircularShift
|
||||
*
|
||||
* Description:
|
||||
* This member function will perform a circular shifting operation.
|
||||
*
|
||||
* Parameters:
|
||||
* bits: [in]
|
||||
* The number of bits to shift (1-31)
|
||||
* word: [in]
|
||||
* The value to shift (assumes a 32-bit integer)
|
||||
*
|
||||
* Returns:
|
||||
* The shifted value.
|
||||
*
|
||||
* Comments:
|
||||
*
|
||||
*/
|
||||
unsigned SHA1::CircularShift(int bits, unsigned word)
|
||||
{
|
||||
return ((word << bits) & 0xFFFFFFFF) | ((word & 0xFFFFFFFF) >> (32-bits));
|
||||
}
|
||||
Executable
+89
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* sha1.h
|
||||
*
|
||||
* Copyright (C) 1998, 2009
|
||||
* Paul E. Jones <paulej@packetizer.com>
|
||||
* All Rights Reserved.
|
||||
*
|
||||
*****************************************************************************
|
||||
* $Id: sha1.h 12 2009-06-22 19:34:25Z paulej $
|
||||
*****************************************************************************
|
||||
*
|
||||
* Description:
|
||||
* This class implements the Secure Hashing Standard as defined
|
||||
* in FIPS PUB 180-1 published April 17, 1995.
|
||||
*
|
||||
* Many of the variable names in this class, especially the single
|
||||
* character names, were used because those were the names used
|
||||
* in the publication.
|
||||
*
|
||||
* Please read the file sha1.cpp for more information.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _SHA1_H_
|
||||
#define _SHA1_H_
|
||||
|
||||
class SHA1
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
SHA1();
|
||||
virtual ~SHA1();
|
||||
|
||||
/*
|
||||
* Re-initialize the class
|
||||
*/
|
||||
void Reset();
|
||||
|
||||
/*
|
||||
* Returns the message digest
|
||||
*/
|
||||
bool Result(unsigned *message_digest_array);
|
||||
|
||||
/*
|
||||
* Provide input to SHA1
|
||||
*/
|
||||
void Input( const unsigned char *message_array,
|
||||
unsigned length);
|
||||
void Input( const char *message_array,
|
||||
unsigned length);
|
||||
void Input(unsigned char message_element);
|
||||
void Input(char message_element);
|
||||
SHA1& operator<<(const char *message_array);
|
||||
SHA1& operator<<(const unsigned char *message_array);
|
||||
SHA1& operator<<(const char message_element);
|
||||
SHA1& operator<<(const unsigned char message_element);
|
||||
|
||||
private:
|
||||
|
||||
/*
|
||||
* Process the next 512 bits of the message
|
||||
*/
|
||||
void ProcessMessageBlock();
|
||||
|
||||
/*
|
||||
* Pads the current message block to 512 bits
|
||||
*/
|
||||
void PadMessage();
|
||||
|
||||
/*
|
||||
* Performs a circular left shift operation
|
||||
*/
|
||||
inline unsigned CircularShift(int bits, unsigned word);
|
||||
|
||||
unsigned H[5]; // Message digest buffers
|
||||
|
||||
unsigned Length_Low; // Message length in bits
|
||||
unsigned Length_High; // Message length in bits
|
||||
|
||||
unsigned char Message_Block[64]; // 512-bit message blocks
|
||||
int Message_Block_Index; // Index into message block array
|
||||
|
||||
bool Computed; // Is the digest computed?
|
||||
bool Corrupted; // Is the message digest corruped?
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
Executable
+169
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* shacmp.cpp
|
||||
*
|
||||
* Copyright (C) 1998, 2009
|
||||
* Paul E. Jones <paulej@packetizer.com>
|
||||
* All Rights Reserved
|
||||
*
|
||||
*****************************************************************************
|
||||
* $Id: shacmp.cpp 12 2009-06-22 19:34:25Z paulej $
|
||||
*****************************************************************************
|
||||
*
|
||||
* Description:
|
||||
* This utility will compare two files by producing a message digest
|
||||
* for each file using the Secure Hashing Algorithm and comparing
|
||||
* the message digests. This function will return 0 if they
|
||||
* compare or 1 if they do not or if there is an error.
|
||||
* Errors result in a return code higher than 1.
|
||||
*
|
||||
* Portability Issues:
|
||||
* none.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "sha1.h"
|
||||
|
||||
/*
|
||||
* Return codes
|
||||
*/
|
||||
#define SHA1_COMPARE 0
|
||||
#define SHA1_NO_COMPARE 1
|
||||
#define SHA1_USAGE_ERROR 2
|
||||
#define SHA1_FILE_ERROR 3
|
||||
|
||||
/*
|
||||
* Function prototype
|
||||
*/
|
||||
void usage();
|
||||
|
||||
/*
|
||||
* main
|
||||
*
|
||||
* Description:
|
||||
* This is the entry point for the program
|
||||
*
|
||||
* Parameters:
|
||||
* argc: [in]
|
||||
* This is the count of arguments in the argv array
|
||||
* argv: [in]
|
||||
* This is an array of filenames for which to compute message digests
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*
|
||||
* Comments:
|
||||
*
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
SHA1 sha; // SHA-1 class
|
||||
FILE *fp; // File pointer for reading files
|
||||
char c; // Character read from file
|
||||
unsigned message_digest[2][5]; // Message digest for files
|
||||
int i; // Counter
|
||||
bool message_match; // Message digest match flag
|
||||
int returncode;
|
||||
|
||||
/*
|
||||
* If we have two arguments, we will assume they are filenames. If
|
||||
* we do not have to arguments, call usage() and exit.
|
||||
*/
|
||||
if (argc != 3)
|
||||
{
|
||||
usage();
|
||||
return SHA1_USAGE_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the message digests for each file
|
||||
*/
|
||||
for(i = 1; i <= 2; i++)
|
||||
{
|
||||
sha.Reset();
|
||||
|
||||
if (!(fp = fopen(argv[i],"rb")))
|
||||
{
|
||||
fprintf(stderr, "sha: unable to open file %s\n", argv[i]);
|
||||
return SHA1_FILE_ERROR;
|
||||
}
|
||||
|
||||
c = fgetc(fp);
|
||||
while(!feof(fp))
|
||||
{
|
||||
sha.Input(c);
|
||||
c = fgetc(fp);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
if (!sha.Result(message_digest[i-1]))
|
||||
{
|
||||
fprintf(stderr,"shacmp: could not compute message digest for %s\n",
|
||||
argv[i]);
|
||||
return SHA1_FILE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare the message digest values
|
||||
*/
|
||||
message_match = true;
|
||||
for(i = 0; i < 5; i++)
|
||||
{
|
||||
if (message_digest[0][i] != message_digest[1][i])
|
||||
{
|
||||
message_match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (message_match)
|
||||
{
|
||||
printf("Fingerprints match:\n");
|
||||
returncode = SHA1_COMPARE;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Fingerprints do not match:\n");
|
||||
returncode = SHA1_NO_COMPARE;
|
||||
}
|
||||
|
||||
printf( "\t%08X %08X %08X %08X %08X\n",
|
||||
message_digest[0][0],
|
||||
message_digest[0][1],
|
||||
message_digest[0][2],
|
||||
message_digest[0][3],
|
||||
message_digest[0][4]);
|
||||
printf( "\t%08X %08X %08X %08X %08X\n",
|
||||
message_digest[1][0],
|
||||
message_digest[1][1],
|
||||
message_digest[1][2],
|
||||
message_digest[1][3],
|
||||
message_digest[1][4]);
|
||||
|
||||
return returncode;
|
||||
}
|
||||
|
||||
/*
|
||||
* usage
|
||||
*
|
||||
* Description:
|
||||
* This function will display program usage information to the user.
|
||||
*
|
||||
* Parameters:
|
||||
* None.
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*
|
||||
* Comments:
|
||||
*
|
||||
*/
|
||||
void usage()
|
||||
{
|
||||
printf("usage: shacmp <file> <file>\n");
|
||||
printf("\tThis program will compare the message digests (fingerprints)\n");
|
||||
printf("\tfor two files using the Secure Hashing Algorithm (SHA-1).\n");
|
||||
}
|
||||
Executable
+149
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* shatest.cpp
|
||||
*
|
||||
* Copyright (C) 1998, 2009
|
||||
* Paul E. Jones <paulej@packetizer.com>
|
||||
* All Rights Reserved
|
||||
*
|
||||
*****************************************************************************
|
||||
* $Id: shatest.cpp 12 2009-06-22 19:34:25Z paulej $
|
||||
*****************************************************************************
|
||||
*
|
||||
* Description:
|
||||
* This file will exercise the SHA1 class and perform the three
|
||||
* tests documented in FIPS PUB 180-1.
|
||||
*
|
||||
* Portability Issues:
|
||||
* None.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include "sha1.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
/*
|
||||
* Define patterns for testing
|
||||
*/
|
||||
#define TESTA "abc"
|
||||
#define TESTB "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
|
||||
|
||||
/*
|
||||
* Function prototype
|
||||
*/
|
||||
void DisplayMessageDigest(unsigned *message_digest);
|
||||
|
||||
/*
|
||||
* main
|
||||
*
|
||||
* Description:
|
||||
* This is the entry point for the program
|
||||
*
|
||||
* Parameters:
|
||||
* None.
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*
|
||||
* Comments:
|
||||
*
|
||||
*/
|
||||
int main()
|
||||
{
|
||||
SHA1 sha;
|
||||
unsigned message_digest[5];
|
||||
|
||||
/*
|
||||
* Perform test A
|
||||
*/
|
||||
cout << endl << "Test A: 'abc'" << endl;
|
||||
|
||||
sha.Reset();
|
||||
sha << TESTA;
|
||||
|
||||
if (!sha.Result(message_digest))
|
||||
{
|
||||
cerr << "ERROR-- could not compute message digest" << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
DisplayMessageDigest(message_digest);
|
||||
cout << "Should match:" << endl;
|
||||
cout << '\t' << "A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D" << endl;
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform test B
|
||||
*/
|
||||
cout << endl << "Test B: " << TESTB << endl;
|
||||
|
||||
sha.Reset();
|
||||
sha << TESTB;
|
||||
|
||||
if (!sha.Result(message_digest))
|
||||
{
|
||||
cerr << "ERROR-- could not compute message digest" << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
DisplayMessageDigest(message_digest);
|
||||
cout << "Should match:" << endl;
|
||||
cout << '\t' << "84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1" << endl;
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform test C
|
||||
*/
|
||||
cout << endl << "Test C: One million 'a' characters" << endl;
|
||||
|
||||
sha.Reset();
|
||||
for(int i = 1; i <= 1000000; i++) sha.Input('a');
|
||||
|
||||
if (!sha.Result(message_digest))
|
||||
{
|
||||
cerr << "ERROR-- could not compute message digest" << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
DisplayMessageDigest(message_digest);
|
||||
cout << "Should match:" << endl;
|
||||
cout << '\t' << "34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F" << endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* DisplayMessageDigest
|
||||
*
|
||||
* Description:
|
||||
* Display Message Digest array
|
||||
*
|
||||
* Parameters:
|
||||
* None.
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*
|
||||
* Comments:
|
||||
*
|
||||
*/
|
||||
void DisplayMessageDigest(unsigned *message_digest)
|
||||
{
|
||||
ios::fmtflags flags;
|
||||
|
||||
cout << '\t';
|
||||
|
||||
flags = cout.setf(ios::hex|ios::uppercase,ios::basefield);
|
||||
cout.setf(ios::uppercase);
|
||||
|
||||
for(int i = 0; i < 5 ; i++)
|
||||
{
|
||||
cout << message_digest[i] << ' ';
|
||||
}
|
||||
|
||||
cout << endl;
|
||||
|
||||
cout.setf(flags);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
// Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
|
||||
// See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace utf8_validator {
|
||||
|
||||
static const int UTF8_ACCEPT = 0;
|
||||
static const int UTF8_REJECT = 1;
|
||||
|
||||
static const uint8_t utf8d[] = {
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1f
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3f
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5f
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7f
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f
|
||||
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf
|
||||
8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df
|
||||
0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef
|
||||
0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff
|
||||
0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2
|
||||
1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4
|
||||
1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6
|
||||
1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8
|
||||
};
|
||||
|
||||
uint32_t inline
|
||||
decode(uint32_t* state, uint32_t* codep, uint32_t byte) {
|
||||
uint32_t type = utf8d[byte];
|
||||
|
||||
*codep = (*state != UTF8_ACCEPT) ?
|
||||
(byte & 0x3fu) | (*codep << 6) :
|
||||
(0xff >> type) & (byte);
|
||||
|
||||
*state = utf8d[256 + *state*16 + type];
|
||||
return *state;
|
||||
}
|
||||
|
||||
} // namespace utf8_validator
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
*/
|
||||
#include "websocketpp.hpp"
|
||||
#include "websocket_client.hpp"
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using websocketpp::client;
|
||||
using boost::asio::ip::tcp;
|
||||
|
||||
client::client(boost::asio::io_service& io_service,
|
||||
websocketpp::connection_handler_ptr defc)
|
||||
: m_elog_level(LOG_OFF),
|
||||
m_alog_level(ALOG_OFF),
|
||||
m_state(CLIENT_STATE_NULL),
|
||||
m_max_message_size(DEFAULT_MAX_MESSAGE_SIZE),
|
||||
m_io_service(io_service),
|
||||
m_resolver(io_service),
|
||||
m_def_con_handler(defc) {}
|
||||
|
||||
void client::init() {
|
||||
// TODO: sanity check whether the session buffer size bound could be reduced
|
||||
m_client_session = client_session_ptr(
|
||||
new client_session(
|
||||
shared_from_this(),
|
||||
m_io_service,
|
||||
m_def_con_handler,
|
||||
m_max_message_size*2
|
||||
)
|
||||
);
|
||||
m_state = CLIENT_STATE_INITIALIZED;
|
||||
}
|
||||
|
||||
void client::connect(const std::string& uri) {
|
||||
if (m_state != CLIENT_STATE_INITIALIZED) {
|
||||
throw client_error("connect can only be called after init and before a connection has been established");
|
||||
}
|
||||
|
||||
m_client_session->set_uri(uri);
|
||||
|
||||
std::stringstream port;
|
||||
port << m_client_session->get_port();
|
||||
|
||||
|
||||
tcp::resolver::query query(m_client_session->get_host(),
|
||||
port.str());
|
||||
tcp::resolver::iterator iterator = m_resolver.resolve(query);
|
||||
|
||||
boost::asio::async_connect(m_client_session->socket(),
|
||||
iterator,boost::bind(&client::handle_connect,
|
||||
this,
|
||||
boost::asio::placeholders::error));
|
||||
m_state = CLIENT_STATE_CONNECTING;
|
||||
}
|
||||
|
||||
|
||||
void client::add_subprotocol(const std::string& p) {
|
||||
if (m_state != CLIENT_STATE_INITIALIZED) {
|
||||
throw client_error("add_protocol can only be called after init and before connect");
|
||||
}
|
||||
m_client_session->add_subprotocol(p);
|
||||
}
|
||||
|
||||
void client::set_header(const std::string& key,const std::string& val) {
|
||||
if (m_state != CLIENT_STATE_INITIALIZED) {
|
||||
throw client_error("set_header can only be called after init and before connect");
|
||||
}
|
||||
m_client_session->set_header(key,val);
|
||||
}
|
||||
|
||||
void client::set_origin(const std::string& val) {
|
||||
if (m_state != CLIENT_STATE_INITIALIZED) {
|
||||
throw client_error("set_origin can only be called after init and before connect");
|
||||
}
|
||||
m_client_session->set_origin(val);
|
||||
}
|
||||
|
||||
|
||||
void client::set_max_message_size(uint64_t val) {
|
||||
if (val > frame::PAYLOAD_64BIT_LIMIT) {
|
||||
std::stringstream err;
|
||||
err << "Invalid maximum message size: " << val;
|
||||
|
||||
// TODO: Figure out what the ideal error behavior for this method.
|
||||
// Options:
|
||||
// Throw exception
|
||||
// Log error and set value to maximum allowed
|
||||
// Log error and leave value at whatever it was before
|
||||
log(err.str(),LOG_WARN);
|
||||
//throw client_error(err.str());
|
||||
}
|
||||
m_max_message_size = val;
|
||||
}
|
||||
|
||||
bool client::test_elog_level(uint16_t level) {
|
||||
return (level >= m_elog_level);
|
||||
}
|
||||
void client::set_elog_level(uint16_t level) {
|
||||
std::stringstream msg;
|
||||
msg << "Error logging level changing from "
|
||||
<< m_elog_level << " to " << level;
|
||||
log(msg.str(),LOG_INFO);
|
||||
|
||||
m_elog_level = level;
|
||||
}
|
||||
bool client::test_alog_level(uint16_t level) {
|
||||
return ((level & m_alog_level) != 0);
|
||||
}
|
||||
void client::set_alog_level(uint16_t level) {
|
||||
if (test_alog_level(level)) {
|
||||
return;
|
||||
}
|
||||
std::stringstream msg;
|
||||
msg << "Access logging level " << level << " being set";
|
||||
access_log(msg.str(),ALOG_INFO);
|
||||
|
||||
m_alog_level |= level;
|
||||
}
|
||||
void client::unset_alog_level(uint16_t level) {
|
||||
if (!test_alog_level(level)) {
|
||||
return;
|
||||
}
|
||||
std::stringstream msg;
|
||||
msg << "Access logging level " << level << " being unset";
|
||||
access_log(msg.str(),ALOG_INFO);
|
||||
|
||||
m_alog_level &= ~level;
|
||||
}
|
||||
|
||||
bool client::validate_message_size(uint64_t val) {
|
||||
if (val > m_max_message_size) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void client::log(std::string msg,uint16_t level) {
|
||||
if (!test_elog_level(level)) {
|
||||
return;
|
||||
}
|
||||
std::cerr << "[Error Log] "
|
||||
<< boost::posix_time::to_iso_extended_string(
|
||||
boost::posix_time::second_clock::local_time())
|
||||
<< " " << msg << std::endl;
|
||||
}
|
||||
void client::access_log(std::string msg,uint16_t level) {
|
||||
if (!test_alog_level(level)) {
|
||||
return;
|
||||
}
|
||||
std::cout << "[Access Log] "
|
||||
<< boost::posix_time::to_iso_extended_string(
|
||||
boost::posix_time::second_clock::local_time())
|
||||
<< " " << msg << std::endl;
|
||||
}
|
||||
|
||||
void client::handle_connect(const boost::system::error_code& error) {
|
||||
if (!error) {
|
||||
std::stringstream err;
|
||||
err << "Successful Connection ";
|
||||
log(err.str(),LOG_ERROR);
|
||||
|
||||
std::cout << boost::posix_time::to_iso_extended_string(boost::posix_time::microsec_clock::local_time()) << " TCP established" << std::endl;
|
||||
|
||||
m_state = CLIENT_STATE_CONNECTED;
|
||||
m_client_session->on_connect();
|
||||
} else {
|
||||
std::stringstream err;
|
||||
err << "An error occurred while establishing a connection: " << error;
|
||||
|
||||
log(err.str(),LOG_ERROR);
|
||||
throw client_error(err.str());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBSOCKET_CLIENT_HPP
|
||||
#define WEBSOCKET_CLIENT_HPP
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace websocketpp {
|
||||
class client;
|
||||
typedef boost::shared_ptr<client> client_ptr;
|
||||
}
|
||||
|
||||
#include "websocketpp.hpp"
|
||||
#include "websocket_client_session.hpp"
|
||||
#include "websocket_connection_handler.hpp"
|
||||
|
||||
using boost::asio::ip::tcp;
|
||||
|
||||
namespace websocketpp {
|
||||
|
||||
class client_error : public std::exception {
|
||||
public:
|
||||
client_error(const std::string& msg)
|
||||
: m_msg(msg) {}
|
||||
~client_error() throw() {}
|
||||
|
||||
virtual const char* what() const throw() {
|
||||
return m_msg.c_str();
|
||||
}
|
||||
private:
|
||||
std::string m_msg;
|
||||
};
|
||||
|
||||
class client : public boost::enable_shared_from_this<client> {
|
||||
public:
|
||||
static const uint16_t CLIENT_STATE_NULL = 0;
|
||||
static const uint16_t CLIENT_STATE_INITIALIZED = 1;
|
||||
static const uint16_t CLIENT_STATE_CONNECTING = 2;
|
||||
static const uint16_t CLIENT_STATE_CONNECTED = 3;
|
||||
|
||||
client(boost::asio::io_service& io_service,
|
||||
connection_handler_ptr defc);
|
||||
|
||||
// INTERFACE FOR LOCAL APPLICATIONS
|
||||
|
||||
// initializes the session. Methods that affect the opening handshake
|
||||
// such as add_protocol and set_header must be called after init and
|
||||
// before connect.
|
||||
void init();
|
||||
|
||||
// starts the connection process. Should be called before
|
||||
// io_service.run(), connection process will not start until run() has
|
||||
// been called.
|
||||
void connect(const std::string& url);
|
||||
|
||||
// Adds a protocol to the opening handshake.
|
||||
// Must be called before connect
|
||||
void add_subprotocol(const std::string& p);
|
||||
|
||||
// Sets the value of the given HTTP header to be sent during the
|
||||
// opening handshake. Must be called before connect
|
||||
void set_header(const std::string& key,const std::string& val);
|
||||
|
||||
void set_origin(const std::string& val);
|
||||
|
||||
void set_max_message_size(uint64_t val);
|
||||
|
||||
// Test methods determine if a message of the given level should be
|
||||
// written. elog shows all values above the level set. alog shows only
|
||||
// the values explicitly set.
|
||||
bool test_elog_level(uint16_t level);
|
||||
void set_elog_level(uint16_t level);
|
||||
|
||||
bool test_alog_level(uint16_t level);
|
||||
void set_alog_level(uint16_t level);
|
||||
void unset_alog_level(uint16_t level);
|
||||
|
||||
// INTERFACE FOR SESSIONS
|
||||
|
||||
// Check if message size is within server's acceptable parameters
|
||||
bool validate_message_size(uint64_t val);
|
||||
|
||||
// write to the server's logs
|
||||
void log(std::string msg,uint16_t level = LOG_ERROR);
|
||||
void access_log(std::string msg,uint16_t level);
|
||||
private:
|
||||
// if no errors starts the session's read loop and returns to the
|
||||
// start_accept phase.
|
||||
void handle_connect(const boost::system::error_code& error);
|
||||
|
||||
private:
|
||||
uint16_t m_elog_level;
|
||||
uint16_t m_alog_level;
|
||||
|
||||
uint16_t m_state;
|
||||
|
||||
std::set<std::string> m_hosts;
|
||||
uint64_t m_max_message_size;
|
||||
boost::asio::io_service& m_io_service;
|
||||
tcp::resolver m_resolver;
|
||||
client_session_ptr m_client_session;
|
||||
connection_handler_ptr m_def_con_handler;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // WEBSOCKET_CLIENT_HPP
|
||||
@@ -0,0 +1,354 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "websocketpp.hpp"
|
||||
#include "websocket_client_session.hpp"
|
||||
|
||||
#include "websocket_frame.hpp"
|
||||
#include "utf8_validator/utf8_validator.hpp"
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/random.hpp>
|
||||
#include <boost/random/random_device.hpp>
|
||||
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
using websocketpp::client_session;
|
||||
|
||||
client_session::client_session (websocketpp::client_ptr c,
|
||||
boost::asio::io_service& io_service,
|
||||
websocketpp::connection_handler_ptr defc,
|
||||
uint64_t buf_size)
|
||||
: session(io_service,defc,buf_size),m_client(c) {}
|
||||
|
||||
void client_session::on_connect() {
|
||||
// TODO: section 4.1: Figure out if we have another connection to this
|
||||
// host/port pending.
|
||||
write_handshake();
|
||||
}
|
||||
|
||||
void client_session::set_uri(const std::string& uri) {
|
||||
if (!m_uri.parse(uri)) {
|
||||
throw client_error("Invalid WebSocket URI");
|
||||
}
|
||||
|
||||
if (m_uri.secure) {
|
||||
throw client_error("wss / secure connections are not supported at this time");
|
||||
}
|
||||
|
||||
m_resource = m_uri.resource;
|
||||
|
||||
std::stringstream l;
|
||||
|
||||
l << "parsed websocket url: secure: " << m_uri.secure << " host: " << m_uri.host
|
||||
<< " port (final): " << m_uri.port << " resource " << m_uri.resource;
|
||||
|
||||
log(l.str(),LOG_DEBUG);
|
||||
}
|
||||
|
||||
bool client_session::get_secure() const {
|
||||
return m_uri.secure;
|
||||
}
|
||||
|
||||
std::string client_session::get_host() const{
|
||||
return m_uri.host;
|
||||
}
|
||||
|
||||
uint16_t client_session::get_port() const {
|
||||
return m_uri.port;
|
||||
}
|
||||
|
||||
void client_session::set_header(const std::string &key,const std::string &val) {
|
||||
// TODO: prevent use of reserved headers
|
||||
m_client_headers[key] = val;
|
||||
}
|
||||
|
||||
void client_session::set_origin(const std::string& val) {
|
||||
// TODO: input validation
|
||||
m_client_origin = val;
|
||||
}
|
||||
|
||||
void client_session::add_subprotocol(const std::string &val) {
|
||||
// TODO: input validation
|
||||
m_client_subprotocols.push_back(val);
|
||||
}
|
||||
|
||||
void client_session::add_extension(const std::string& val) {
|
||||
// TODO: input validation
|
||||
m_client_extensions.push_back(val);
|
||||
}
|
||||
|
||||
void client_session::read_handshake() {
|
||||
boost::asio::async_read_until(
|
||||
m_socket,
|
||||
m_buf,
|
||||
"\r\n\r\n",
|
||||
boost::bind(
|
||||
&session::handle_read_handshake,
|
||||
shared_from_this(),
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void client_session::handle_read_handshake(const boost::system::error_code& e,
|
||||
std::size_t bytes_transferred) {
|
||||
|
||||
if (e) {
|
||||
log_error("Error reading server handshake",e);
|
||||
drop_tcp();
|
||||
return;
|
||||
}
|
||||
|
||||
// parse server handshake
|
||||
std::istream response_stream(&m_buf);
|
||||
std::string header;
|
||||
std::string::size_type end;
|
||||
|
||||
// get status line
|
||||
std::getline(response_stream, header);
|
||||
if (header[header.size()-1] == '\r') {
|
||||
header.erase(header.end()-1);
|
||||
m_server_http_request = header;
|
||||
m_raw_server_handshake += header+"\n";
|
||||
}
|
||||
|
||||
// get headers
|
||||
while (std::getline(response_stream, header) && header != "\r") {
|
||||
if (header[header.size()-1] != '\r') {
|
||||
continue; // ignore malformed header lines?
|
||||
} else {
|
||||
header.erase(header.end()-1);
|
||||
}
|
||||
|
||||
end = header.find(": ",0);
|
||||
|
||||
if (end != std::string::npos) {
|
||||
std::string h = header.substr(0,end);
|
||||
if (get_server_header(h) == "") {
|
||||
m_server_headers[h] = header.substr(end+2);
|
||||
} else {
|
||||
m_server_headers[h] += ", " + header.substr(end+2);
|
||||
}
|
||||
}
|
||||
|
||||
m_raw_server_handshake += header+"\n";
|
||||
}
|
||||
|
||||
// temporary debugging
|
||||
if (m_buf.size() > 0) {
|
||||
std::stringstream foo;
|
||||
foo << "bytes left over: " << m_buf.size();
|
||||
access_log(foo.str(), ALOG_HANDSHAKE);
|
||||
}
|
||||
|
||||
m_client->access_log(m_raw_server_handshake,ALOG_HANDSHAKE);
|
||||
|
||||
// handshake error checking
|
||||
try {
|
||||
std::stringstream err;
|
||||
std::string h;
|
||||
|
||||
// TODO: allow versions greater than 1.1
|
||||
if (m_server_http_request.substr(0,9) != "HTTP/1.1 ") {
|
||||
err << "Websocket handshake has invalid HTTP version: "
|
||||
<< m_server_http_request.substr(0,9);
|
||||
|
||||
throw(handshake_error(err.str(),400));
|
||||
}
|
||||
|
||||
// check the HTTP version
|
||||
if (m_server_http_request.substr(9,3) != "101") {
|
||||
err << "Websocket handshake ended with status "
|
||||
<< m_server_http_request.substr(9);
|
||||
|
||||
// TODO: check version header for other supported versions.
|
||||
|
||||
throw(handshake_error(err.str(),400));
|
||||
}
|
||||
|
||||
// verify the presence of required headers
|
||||
h = get_server_header("Upgrade");
|
||||
if (h == "") {
|
||||
throw(handshake_error("Required Upgrade header is missing",400));
|
||||
} else if (!boost::iequals(h,"websocket")) {
|
||||
err << "Upgrade header was \"" << h << "\" instead of \"websocket\"";
|
||||
throw(handshake_error(err.str(),400));
|
||||
}
|
||||
|
||||
h = get_server_header("Connection");
|
||||
if (h == "") {
|
||||
throw(handshake_error("Required Connection header is missing",400));
|
||||
} else if (!boost::ifind_first(h,"upgrade")) {
|
||||
err << "Connection header, \"" << h
|
||||
<< "\", does not contain required token \"upgrade\"";
|
||||
throw(handshake_error(err.str(),400));
|
||||
}
|
||||
|
||||
if (get_server_header("Sec-WebSocket-Accept") == "") {
|
||||
throw(handshake_error("Required Sec-WebSocket-Key header is missing",400));
|
||||
} else {
|
||||
// TODO: make a helper function for this.
|
||||
std::string server_key = m_client_key;
|
||||
server_key += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
||||
|
||||
SHA1 sha;
|
||||
uint32_t message_digest[5];
|
||||
|
||||
sha.Reset();
|
||||
sha << server_key.c_str();
|
||||
|
||||
if (!sha.Result(message_digest)) {
|
||||
m_client->log("Error computing handshake sha1 hash.",LOG_ERROR);
|
||||
// TODO: close behavior
|
||||
return;
|
||||
}
|
||||
|
||||
// convert sha1 hash bytes to network byte order because this sha1
|
||||
// library works on ints rather than bytes
|
||||
for (int i = 0; i < 5; i++) {
|
||||
message_digest[i] = htonl(message_digest[i]);
|
||||
}
|
||||
|
||||
server_key = base64_encode(
|
||||
reinterpret_cast<const unsigned char*>(message_digest),20);
|
||||
if (server_key != get_server_header("Sec-WebSocket-Accept")) {
|
||||
m_client->log("Server key does not match",LOG_ERROR);
|
||||
// TODO: close behavior
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (const handshake_error& e) {
|
||||
std::stringstream err;
|
||||
err << "Caught handshake exception: " << e.what();
|
||||
|
||||
m_client->access_log(e.what(),ALOG_HANDSHAKE);
|
||||
m_client->log(err.str(),LOG_ERROR);
|
||||
|
||||
// TODO: close behavior
|
||||
return;
|
||||
}
|
||||
|
||||
log_open_result();
|
||||
|
||||
m_state = STATE_OPEN;
|
||||
|
||||
if (m_local_interface) {
|
||||
m_local_interface->on_open(shared_from_this());
|
||||
}
|
||||
|
||||
reset_message();
|
||||
read_frame();
|
||||
}
|
||||
|
||||
void client_session::write_handshake() {
|
||||
// generate client handshake.
|
||||
std::string client_handshake;
|
||||
|
||||
client_handshake += "GET "+m_resource+" HTTP/1.1\r\n";
|
||||
|
||||
set_header("Upgrade","websocket");
|
||||
set_header("Connection","Upgrade");
|
||||
set_header("Sec-WebSocket-Version","13");
|
||||
|
||||
std::stringstream h;
|
||||
|
||||
h << m_uri.host << ":" << m_uri.port;
|
||||
|
||||
set_header("Host",h.str());
|
||||
|
||||
if (m_client_origin != "") {
|
||||
set_header("Origin",m_client_origin);
|
||||
}
|
||||
|
||||
// TODO: generate proper key
|
||||
m_client_key = "XO4pxrIMLnK1CEVQP9untQ==";
|
||||
|
||||
int32_t raw_key[4];
|
||||
|
||||
boost::random::random_device rng;
|
||||
boost::random::variate_generator<boost::random::random_device&, boost::random::uniform_int_distribution<> > gen(rng, boost::random::uniform_int_distribution<>(INT32_MIN,INT32_MAX));
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
raw_key[i] = gen();
|
||||
}
|
||||
|
||||
m_client_key = base64_encode(reinterpret_cast<unsigned char const*>(raw_key), 16);
|
||||
|
||||
m_client->access_log("Client key chosen: "+m_client_key, ALOG_HANDSHAKE);
|
||||
|
||||
set_header("Sec-WebSocket-Key",m_client_key);
|
||||
|
||||
|
||||
|
||||
set_header("User Agent","WebSocket++/2011-09-25");
|
||||
|
||||
header_list::iterator it;
|
||||
for (it = m_client_headers.begin(); it != m_client_headers.end(); it++) {
|
||||
client_handshake += it->first + ": " + it->second + "\r\n";
|
||||
}
|
||||
|
||||
client_handshake += "\r\n";
|
||||
|
||||
m_raw_client_handshake = client_handshake;
|
||||
|
||||
// start async write to handle_write_handshake
|
||||
boost::asio::async_write(
|
||||
m_socket,
|
||||
boost::asio::buffer(m_raw_client_handshake),
|
||||
boost::bind(
|
||||
&session::handle_write_handshake,
|
||||
shared_from_this(),
|
||||
boost::asio::placeholders::error
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void client_session::handle_write_handshake(const boost::system::error_code& error) {
|
||||
if (error) {
|
||||
log_error("Error writing handshake",error);
|
||||
drop_tcp();
|
||||
return;
|
||||
}
|
||||
|
||||
read_handshake();
|
||||
}
|
||||
|
||||
void client_session::log(const std::string& msg, uint16_t level) const {
|
||||
m_client->log(msg,level);
|
||||
}
|
||||
|
||||
void client_session::access_log(const std::string& msg, uint16_t level) const {
|
||||
m_client->access_log(msg,level);
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBSOCKET_CLIENT_SESSION_HPP
|
||||
#define WEBSOCKET_CLIENT_SESSION_HPP
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/enable_shared_from_this.hpp>
|
||||
|
||||
#if defined(WIN32)
|
||||
#include <winsock2.h>
|
||||
#else
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace websocketpp {
|
||||
class client_session;
|
||||
typedef boost::shared_ptr<client_session> client_session_ptr;
|
||||
}
|
||||
|
||||
#include "websocket_session.hpp"
|
||||
#include "websocket_client.hpp"
|
||||
|
||||
using boost::asio::ip::tcp;
|
||||
|
||||
namespace websocketpp {
|
||||
|
||||
class client_session : public session {
|
||||
public:
|
||||
client_session (client_ptr c,
|
||||
boost::asio::io_service& io_service,
|
||||
connection_handler_ptr defc,
|
||||
uint64_t buf_size);
|
||||
|
||||
/*** CLIENT INTERFACE ***/
|
||||
|
||||
// This function is called when a tcp connection has been established and
|
||||
// the connection is ready to start the opening handshake.
|
||||
void on_connect();
|
||||
|
||||
/*** HANDSHAKE INTERFACE ***/
|
||||
|
||||
void set_uri(const std::string& url);
|
||||
|
||||
bool get_secure() const;
|
||||
std::string get_host() const;
|
||||
uint16_t get_port() const;
|
||||
|
||||
// Set an HTTP header for the outgoing client handshake.
|
||||
void set_header(const std::string& key,const std::string& val);
|
||||
|
||||
// adds a subprotocol. This will result in the appropriate
|
||||
// Sec-WebSocket-Protocol header being sent with the opening connection.
|
||||
// Values will be sent in the order they were added. Servers interpret this
|
||||
// order as the preferred order.
|
||||
void add_subprotocol(const std::string &val);
|
||||
|
||||
// Sets the origin value that will be sent to the server
|
||||
void set_origin(const std::string &val);
|
||||
|
||||
// Adds an extension to the extension list. Extensions are sent in the
|
||||
// order added
|
||||
void add_extension(const std::string& val);
|
||||
|
||||
/*** SESSION INTERFACE ***/
|
||||
// see session
|
||||
bool is_server() const {return false;}
|
||||
|
||||
void log(const std::string& msg, uint16_t level) const;
|
||||
void access_log(const std::string& msg, uint16_t level) const;
|
||||
protected:
|
||||
// Opening handshake processors and callbacks.
|
||||
virtual void write_handshake();
|
||||
virtual void handle_write_handshake(const boost::system::error_code& e);
|
||||
virtual void read_handshake();
|
||||
virtual void handle_read_handshake(const boost::system::error_code& e,
|
||||
std::size_t bytes_transferred);
|
||||
|
||||
private:
|
||||
|
||||
protected:
|
||||
ws_uri m_uri;
|
||||
// url parts
|
||||
bool m_secure;
|
||||
std::string m_host;
|
||||
uint16_t m_port;
|
||||
|
||||
// handshake stuff
|
||||
std::string m_client_key;
|
||||
|
||||
// connection resources
|
||||
client_ptr m_client;
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // WEBSOCKET_CLIENT_SESSION_HPP
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBSOCKET_CONNECTION_HANDLER_HPP
|
||||
#define WEBSOCKET_CONNECTION_HANDLER_HPP
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
namespace websocketpp {
|
||||
class connection_handler;
|
||||
typedef boost::shared_ptr<connection_handler> connection_handler_ptr;
|
||||
}
|
||||
|
||||
#include "websocket_session.hpp"
|
||||
|
||||
namespace websocketpp {
|
||||
|
||||
class connection_handler {
|
||||
public:
|
||||
// validate will be called after a websocket handshake has been received and
|
||||
// before it is accepted. It provides a handler the ability to refuse a
|
||||
// connection based on application specific logic (ex: restrict domains or
|
||||
// negotiate subprotocols). To reject the connection throw a handshake_error
|
||||
//
|
||||
// Validate is never called for client sessions. To refuse a client session
|
||||
// (ex: if you do not like the set of extensions/subprotocols the server
|
||||
// chose) you can close the connection immediately in the on_open method.
|
||||
//
|
||||
// handshake_error parameters:
|
||||
// log_message - error message to send to server log
|
||||
// http_error_code - numeric HTTP error code to return to the client
|
||||
// http_error_msg - (optional) string HTTP error code to return to the
|
||||
// client (useful for returning non-standard error codes)
|
||||
virtual void validate(session_ptr session) {};
|
||||
|
||||
// on_open is called after the websocket session has been successfully
|
||||
// established and is in the OPEN state. The session is now avaliable to
|
||||
// send messages and will begin reading frames and calling the on_message/
|
||||
// on_close/on_error callbacks. A client may reject the connection by
|
||||
// closing the session at this point.
|
||||
virtual void on_open(session_ptr session) = 0;
|
||||
|
||||
// on_close is called whenever an open session is closed for any reason.
|
||||
// This can be due to either endpoint requesting a connection close or an
|
||||
// error occuring. Information about why the session was closed can be
|
||||
// extracted from the session itself.
|
||||
//
|
||||
// on_close will be the last time a session calls its handler. If your
|
||||
// application will need information from `session` after this function you
|
||||
// should either save the session_ptr somewhere or copy the data out.
|
||||
virtual void on_close(session_ptr session) = 0;
|
||||
|
||||
// on_message (binary version) will be called when a binary message is
|
||||
// recieved. Message data is passed as a vector of bytes (unsigned char).
|
||||
// data will not be avaliable after this callback ends so the handler must
|
||||
// either completely process the message or copy it somewhere else for
|
||||
// processing later.
|
||||
virtual void on_message(session_ptr session,
|
||||
const std::vector<unsigned char> &data) = 0;
|
||||
|
||||
// on_message (text version). Identical to on_message except the data
|
||||
// parameter is a string interpreted as UTF-8. WebSocket++ guarantees that
|
||||
// this string is valid UTF-8.
|
||||
virtual void on_message(session_ptr session,const std::string &msg) = 0;
|
||||
|
||||
|
||||
|
||||
// #### optional error cases ####
|
||||
|
||||
// on_fail is called whenever a session is terminated or failed before it
|
||||
// was successfully established. This happens if there is an error during
|
||||
// the handshake process or if the server refused the connection.
|
||||
//
|
||||
// on_fail will be the last time a session calls its handler. If your
|
||||
// application will need information from `session` after this function you
|
||||
// should either save the session_ptr somewhere or copy the data out.
|
||||
virtual void on_fail(session_ptr session) {};
|
||||
|
||||
// experimental
|
||||
virtual void on_ping_timeout(session_ptr session) {}
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
#endif // WEBSOCKET_CONNECTION_HANDLER_HPP
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
||||
* Copyright (c) 2011, 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:
|
||||
@@ -11,10 +11,10 @@
|
||||
* * 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
|
||||
*
|
||||
* 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;
|
||||
@@ -22,25 +22,34 @@
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBSOCKETPP_CONCURRENCY_BASIC_HPP
|
||||
#define WEBSOCKETPP_CONCURRENCY_BASIC_HPP
|
||||
#ifndef WEBSOCKET_ENDPOINT_HPP
|
||||
#define WEBSOCKET_ENDPOINT_HPP
|
||||
|
||||
#include <websocketpp/common/thread.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
namespace websocketpp {
|
||||
namespace concurrency {
|
||||
class endpoint;
|
||||
typedef boost::shared_ptr<endpoint> endpoint_ptr;
|
||||
}
|
||||
|
||||
/// Concurrency policy that uses std::mutex / boost::mutex
|
||||
class basic {
|
||||
#include "websocket_session.hpp"
|
||||
|
||||
namespace websocketpp {
|
||||
|
||||
class endpoint : public boost::enable_shared_from_this<endpoint> {
|
||||
public:
|
||||
typedef lib::mutex mutex_type;
|
||||
typedef lib::lock_guard<mutex_type> scoped_lock_type;
|
||||
virtual bool is_server() = 0;
|
||||
// log
|
||||
// access_log
|
||||
};
|
||||
|
||||
} // namespace concurrency
|
||||
} // namespace websocketpp
|
||||
|
||||
#endif // WEBSOCKETPP_CONCURRENCY_BASIC_HPP
|
||||
|
||||
}
|
||||
#endif // WEBSOCKET_ENDPOINT_HPP
|
||||
@@ -0,0 +1,591 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
*/
|
||||
#include "websocketpp.hpp"
|
||||
#include "websocket_frame.hpp"
|
||||
|
||||
#include "websocket_server.hpp"
|
||||
#include "utf8_validator/utf8_validator.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
#if defined(WIN32)
|
||||
#include <winsock2.h>
|
||||
#else
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
using websocketpp::frame;
|
||||
|
||||
|
||||
uint8_t frame::get_state() const {
|
||||
return m_state;
|
||||
}
|
||||
|
||||
uint64_t frame::get_bytes_needed() const {
|
||||
return m_bytes_needed;
|
||||
}
|
||||
|
||||
void frame::reset() {
|
||||
m_state = STATE_BASIC_HEADER;
|
||||
m_bytes_needed = BASIC_HEADER_LENGTH;
|
||||
m_degraded = false;
|
||||
m_payload.empty();
|
||||
memset(m_header,0,MAX_HEADER_LENGTH);
|
||||
}
|
||||
|
||||
// Method invariant: One of the following must always be true even in the case
|
||||
// of exceptions.
|
||||
// - m_bytes_needed > 0
|
||||
// - m-state = STATE_READY
|
||||
void frame::consume(std::istream &s) {
|
||||
try {
|
||||
switch (m_state) {
|
||||
case STATE_BASIC_HEADER:
|
||||
s.read(&m_header[BASIC_HEADER_LENGTH-m_bytes_needed],m_bytes_needed);
|
||||
|
||||
m_bytes_needed -= s.gcount();
|
||||
|
||||
if (m_bytes_needed == 0) {
|
||||
process_basic_header();
|
||||
|
||||
validate_basic_header();
|
||||
|
||||
if (m_bytes_needed > 0) {
|
||||
m_state = STATE_EXTENDED_HEADER;
|
||||
} else {
|
||||
process_extended_header();
|
||||
|
||||
if (m_bytes_needed == 0) {
|
||||
m_state = STATE_READY;
|
||||
process_payload();
|
||||
|
||||
} else {
|
||||
m_state = STATE_PAYLOAD;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case STATE_EXTENDED_HEADER:
|
||||
s.read(&m_header[get_header_len()-m_bytes_needed],m_bytes_needed);
|
||||
|
||||
m_bytes_needed -= s.gcount();
|
||||
|
||||
if (m_bytes_needed == 0) {
|
||||
process_extended_header();
|
||||
if (m_bytes_needed == 0) {
|
||||
m_state = STATE_READY;
|
||||
process_payload();
|
||||
} else {
|
||||
m_state = STATE_PAYLOAD;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case STATE_PAYLOAD:
|
||||
s.read(reinterpret_cast<char *>(&m_payload[m_payload.size()-m_bytes_needed]),
|
||||
m_bytes_needed);
|
||||
|
||||
m_bytes_needed -= s.gcount();
|
||||
|
||||
if (m_bytes_needed == 0) {
|
||||
m_state = STATE_READY;
|
||||
process_payload();
|
||||
}
|
||||
break;
|
||||
case STATE_RECOVERY:
|
||||
// Recovery state discards all bytes that are not the first byte
|
||||
// of a close frame.
|
||||
do {
|
||||
s.read(reinterpret_cast<char *>(&m_header[0]),1);
|
||||
|
||||
//std::cout << std::hex << int(static_cast<unsigned char>(m_header[0])) << " ";
|
||||
|
||||
if (int(static_cast<unsigned char>(m_header[0])) == 0x88) {
|
||||
//(BPB0_FIN && CONNECTION_CLOSE)
|
||||
m_bytes_needed--;
|
||||
m_state = STATE_BASIC_HEADER;
|
||||
break;
|
||||
}
|
||||
} while (s.gcount() > 0);
|
||||
|
||||
//std::cout << std::endl;
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/*if (s.gcount() == 0) {
|
||||
throw frame_error("consume read zero bytes",FERR_FATAL_SESSION_ERROR);
|
||||
}*/
|
||||
} catch (const frame_error& e) {
|
||||
// After this point all non-close frames must be considered garbage,
|
||||
// including the current one. Reset it and put the reading frame into
|
||||
// a recovery state.
|
||||
if (m_degraded == true) {
|
||||
throw frame_error("An error occurred while trying to gracefully recover from a less serious frame error.",FERR_FATAL_SESSION_ERROR);
|
||||
} else {
|
||||
reset();
|
||||
m_state = STATE_RECOVERY;
|
||||
m_degraded = true;
|
||||
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char* frame::get_header() {
|
||||
return m_header;
|
||||
}
|
||||
|
||||
char* frame::get_extended_header() {
|
||||
return m_header+BASIC_HEADER_LENGTH;
|
||||
}
|
||||
|
||||
unsigned int frame::get_header_len() const {
|
||||
unsigned int temp = 2;
|
||||
|
||||
if (get_masked()) {
|
||||
temp += 4;
|
||||
}
|
||||
|
||||
if (get_basic_size() == 126) {
|
||||
temp += 2;
|
||||
} else if (get_basic_size() == 127) {
|
||||
temp += 8;
|
||||
}
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
char* frame::get_masking_key() {
|
||||
if (m_state != STATE_READY) {
|
||||
throw frame_error("attempted to get masking_key before reading full header");
|
||||
}
|
||||
return m_masking_key;
|
||||
}
|
||||
|
||||
// get and set header bits
|
||||
bool frame::get_fin() const {
|
||||
return ((m_header[0] & BPB0_FIN) == BPB0_FIN);
|
||||
}
|
||||
|
||||
void frame::set_fin(bool fin) {
|
||||
if (fin) {
|
||||
m_header[0] |= BPB0_FIN;
|
||||
} else {
|
||||
m_header[0] &= (0xFF ^ BPB0_FIN);
|
||||
}
|
||||
}
|
||||
|
||||
// get and set reserved bits
|
||||
bool frame::get_rsv1() const {
|
||||
return ((m_header[0] & BPB0_RSV1) == BPB0_RSV1);
|
||||
}
|
||||
|
||||
void frame::set_rsv1(bool b) {
|
||||
if (b) {
|
||||
m_header[0] |= BPB0_RSV1;
|
||||
} else {
|
||||
m_header[0] &= (0xFF ^ BPB0_RSV1);
|
||||
}
|
||||
}
|
||||
|
||||
bool frame::get_rsv2() const {
|
||||
return ((m_header[0] & BPB0_RSV2) == BPB0_RSV2);
|
||||
}
|
||||
|
||||
void frame::set_rsv2(bool b) {
|
||||
if (b) {
|
||||
m_header[0] |= BPB0_RSV2;
|
||||
} else {
|
||||
m_header[0] &= (0xFF ^ BPB0_RSV2);
|
||||
}
|
||||
}
|
||||
|
||||
bool frame::get_rsv3() const {
|
||||
return ((m_header[0] & BPB0_RSV3) == BPB0_RSV3);
|
||||
}
|
||||
|
||||
void frame::set_rsv3(bool b) {
|
||||
if (b) {
|
||||
m_header[0] |= BPB0_RSV3;
|
||||
} else {
|
||||
m_header[0] &= (0xFF ^ BPB0_RSV3);
|
||||
}
|
||||
}
|
||||
|
||||
frame::opcode frame::get_opcode() const {
|
||||
return frame::opcode(m_header[0] & BPB0_OPCODE);
|
||||
}
|
||||
|
||||
void frame::set_opcode(frame::opcode op) {
|
||||
if (op > 0x0F) {
|
||||
throw frame_error("invalid opcode",FERR_PROTOCOL_VIOLATION);
|
||||
}
|
||||
|
||||
if (get_basic_size() > BASIC_PAYLOAD_LIMIT &&
|
||||
is_control()) {
|
||||
throw frame_error("control frames can't have large payloads",FERR_PROTOCOL_VIOLATION);
|
||||
}
|
||||
|
||||
m_header[0] &= (0xFF ^ BPB0_OPCODE); // clear op bits
|
||||
m_header[0] |= op; // set op bits
|
||||
}
|
||||
|
||||
bool frame::get_masked() const {
|
||||
return ((m_header[1] & BPB1_MASK) == BPB1_MASK);
|
||||
}
|
||||
|
||||
void frame::set_masked(bool masked) {
|
||||
if (masked) {
|
||||
m_header[1] |= BPB1_MASK;
|
||||
generate_masking_key();
|
||||
} else {
|
||||
m_header[1] &= (0xFF ^ BPB1_MASK);
|
||||
clear_masking_key();
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t frame::get_basic_size() const {
|
||||
return m_header[1] & BPB1_PAYLOAD;
|
||||
}
|
||||
|
||||
size_t frame::get_payload_size() const {
|
||||
if (m_state != STATE_READY && m_state != STATE_PAYLOAD) {
|
||||
// problem
|
||||
throw frame_error("attempted to get payload size before reading full header");
|
||||
}
|
||||
|
||||
return m_payload.size();
|
||||
}
|
||||
|
||||
uint16_t frame::get_close_status() const {
|
||||
if (get_payload_size() == 0) {
|
||||
return close::status::NO_STATUS;
|
||||
} else if (get_payload_size() >= 2) {
|
||||
char val[2];
|
||||
|
||||
val[0] = m_payload[0];
|
||||
val[1] = m_payload[1];
|
||||
|
||||
uint16_t code = ntohs(*(
|
||||
reinterpret_cast<uint16_t*>(&val[0])
|
||||
));
|
||||
|
||||
// these two codes should never be on the wire
|
||||
if (code == close::status::NO_STATUS || code == close::status::ABNORMAL_CLOSE) {
|
||||
throw frame_error("Invalid close status code on the wire");
|
||||
}
|
||||
|
||||
return code;
|
||||
} else {
|
||||
return close::status::PROTOCOL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
std::string frame::get_close_msg() const {
|
||||
if (get_payload_size() > 2) {
|
||||
uint32_t state = utf8_validator::UTF8_ACCEPT;
|
||||
uint32_t codep = 0;
|
||||
validate_utf8(&state,&codep,2);
|
||||
if (state != utf8_validator::UTF8_ACCEPT) {
|
||||
throw frame_error("Invalid UTF-8 Data",
|
||||
frame::FERR_PAYLOAD_VIOLATION);
|
||||
}
|
||||
return std::string(m_payload.begin()+2,m_payload.end());
|
||||
} else {
|
||||
return std::string();
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<unsigned char> &frame::get_payload() {
|
||||
return m_payload;
|
||||
}
|
||||
|
||||
void frame::set_payload(const std::vector<unsigned char> source) {
|
||||
set_payload_helper(source.size());
|
||||
|
||||
std::copy(source.begin(),source.end(),m_payload.begin());
|
||||
}
|
||||
void frame::set_payload(const std::string source) {
|
||||
set_payload_helper(source.size());
|
||||
|
||||
std::copy(source.begin(),source.end(),m_payload.begin());
|
||||
}
|
||||
|
||||
bool frame::is_control() const {
|
||||
return (get_opcode() > MAX_FRAME_OPCODE);
|
||||
}
|
||||
|
||||
void frame::set_payload_helper(size_t s) {
|
||||
if (s > max_payload_size) {
|
||||
throw frame_error("requested payload is over implimentation defined limit",FERR_MSG_TOO_BIG);
|
||||
}
|
||||
|
||||
// limits imposed by the websocket spec
|
||||
if (s > BASIC_PAYLOAD_LIMIT &&
|
||||
get_opcode() > MAX_FRAME_OPCODE) {
|
||||
throw frame_error("control frames can't have large payloads",FERR_PROTOCOL_VIOLATION);
|
||||
}
|
||||
|
||||
if (s <= BASIC_PAYLOAD_LIMIT) {
|
||||
m_header[1] = s;
|
||||
} else if (s <= PAYLOAD_16BIT_LIMIT) {
|
||||
m_header[1] = BASIC_PAYLOAD_16BIT_CODE;
|
||||
|
||||
// this reinterprets the second pair of bytes in m_header as a
|
||||
// 16 bit int and writes the payload size there as an integer
|
||||
// in network byte order
|
||||
*reinterpret_cast<uint16_t*>(&m_header[BASIC_HEADER_LENGTH]) = htons(s);
|
||||
} else if (s <= PAYLOAD_64BIT_LIMIT) {
|
||||
m_header[1] = BASIC_PAYLOAD_64BIT_CODE;
|
||||
*reinterpret_cast<uint64_t*>(&m_header[BASIC_HEADER_LENGTH]) = htonll(s);
|
||||
} else {
|
||||
throw frame_error("payload size limit is 63 bits",FERR_PROTOCOL_VIOLATION);
|
||||
}
|
||||
|
||||
m_payload.resize(s);
|
||||
}
|
||||
|
||||
void frame::set_status(uint16_t status,const std::string message) {
|
||||
// check for valid statuses
|
||||
if (close::status::invalid(status)) {
|
||||
std::stringstream err;
|
||||
err << "Status code " << status << " is invalid";
|
||||
throw frame_error(err.str());
|
||||
}
|
||||
|
||||
if (close::status::reserved(status)) {
|
||||
std::stringstream err;
|
||||
err << "Status code " << status << " is reserved";
|
||||
throw frame_error(err.str());
|
||||
}
|
||||
|
||||
m_payload.resize(2+message.size());
|
||||
|
||||
char val[2];
|
||||
|
||||
*reinterpret_cast<uint16_t*>(&val[0]) = htons(status);
|
||||
|
||||
m_header[1] = message.size()+2;
|
||||
|
||||
m_payload[0] = val[0];
|
||||
m_payload[1] = val[1];
|
||||
|
||||
std::copy(message.begin(),message.end(),m_payload.begin()+2);
|
||||
}
|
||||
|
||||
std::string frame::print_frame() const {
|
||||
std::stringstream f;
|
||||
|
||||
unsigned int len = get_header_len();
|
||||
|
||||
f << "frame: ";
|
||||
// print header
|
||||
for (unsigned int i = 0; i < len; i++) {
|
||||
f << std::hex << (unsigned short)m_header[i] << " ";
|
||||
}
|
||||
// print message
|
||||
if (m_payload.size() > 50) {
|
||||
f << "[payload of " << m_payload.size() << " bytes]";
|
||||
} else {
|
||||
std::vector<unsigned char>::const_iterator it;
|
||||
for (it = m_payload.begin(); it != m_payload.end(); it++) {
|
||||
f << *it;
|
||||
}
|
||||
}
|
||||
return f.str();
|
||||
}
|
||||
|
||||
void frame::process_basic_header() {
|
||||
m_bytes_needed = get_header_len() - BASIC_HEADER_LENGTH;
|
||||
}
|
||||
|
||||
void frame::process_extended_header() {
|
||||
uint8_t s = get_basic_size();
|
||||
uint64_t payload_size;
|
||||
int mask_index = BASIC_HEADER_LENGTH;
|
||||
|
||||
if (s <= BASIC_PAYLOAD_LIMIT) {
|
||||
payload_size = s;
|
||||
} else if (s == BASIC_PAYLOAD_16BIT_CODE) {
|
||||
// reinterpret the second two bytes as a 16 bit integer in network
|
||||
// byte order. Convert to host byte order and store locally.
|
||||
payload_size = ntohs(*(
|
||||
reinterpret_cast<uint16_t*>(&m_header[BASIC_HEADER_LENGTH])
|
||||
));
|
||||
|
||||
if (payload_size < s) {
|
||||
std::stringstream err;
|
||||
err << "payload length not minimally encoded. Using 16 bit form for payload size: " << payload_size;
|
||||
m_bytes_needed = payload_size;
|
||||
throw frame_error(err.str(),
|
||||
FERR_PROTOCOL_VIOLATION);
|
||||
}
|
||||
|
||||
mask_index += 2;
|
||||
} else if (s == BASIC_PAYLOAD_64BIT_CODE) {
|
||||
// reinterpret the second eight bytes as a 64 bit integer in
|
||||
// network byte order. Convert to host byte order and store.
|
||||
payload_size = ntohll(*(
|
||||
reinterpret_cast<uint64_t*>(&m_header[BASIC_HEADER_LENGTH])
|
||||
));
|
||||
|
||||
if (payload_size <= PAYLOAD_16BIT_LIMIT) {
|
||||
m_bytes_needed = payload_size;
|
||||
throw frame_error("payload length not minimally encoded",
|
||||
FERR_PROTOCOL_VIOLATION);
|
||||
}
|
||||
|
||||
mask_index += 8;
|
||||
} else {
|
||||
// shouldn't be here
|
||||
throw frame_error("invalid get_basic_size in process_extended_header");
|
||||
}
|
||||
|
||||
if (get_masked() == 0) {
|
||||
clear_masking_key();
|
||||
} else {
|
||||
// TODO: use this copy line (needs testing)
|
||||
// std::copy(m_header[mask_index],m_header[mask_index+4],m_masking_key);
|
||||
m_masking_key[0] = m_header[mask_index+0];
|
||||
m_masking_key[1] = m_header[mask_index+1];
|
||||
m_masking_key[2] = m_header[mask_index+2];
|
||||
m_masking_key[3] = m_header[mask_index+3];
|
||||
}
|
||||
|
||||
if (payload_size > max_payload_size) {
|
||||
// TODO: frame/message size limits
|
||||
throw server_error("got frame with payload greater than maximum frame buffer size.");
|
||||
}
|
||||
m_payload.resize(payload_size);
|
||||
m_bytes_needed = payload_size;
|
||||
}
|
||||
|
||||
void frame::process_payload() {
|
||||
if (get_masked()) {
|
||||
char *masking_key = &m_header[get_header_len()-4];
|
||||
|
||||
for (uint64_t i = 0; i < m_payload.size(); i++) {
|
||||
m_payload[i] = (m_payload[i] ^ masking_key[i%4]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void frame::process_payload2() {
|
||||
// unmask payload one byte at a time
|
||||
|
||||
//uint64_t key = (*((uint32_t*)m_masking_key;)) << 32;
|
||||
//key += *((uint32_t*)m_masking_key);
|
||||
|
||||
// might need to switch byte order
|
||||
uint32_t key = *((uint32_t*)m_masking_key);
|
||||
|
||||
// 4
|
||||
|
||||
uint64_t i = 0;
|
||||
uint64_t s = (m_payload.size() / 4);
|
||||
|
||||
std::cout << "s: " << s << std::endl;
|
||||
|
||||
// chunks of 4
|
||||
for (i = 0; i < s; i+=4) {
|
||||
((uint32_t*)(&m_payload[0]))[i] = (((uint32_t*)(&m_payload[0]))[i] ^ key);
|
||||
}
|
||||
|
||||
// finish the last few
|
||||
for (i = s; i < m_payload.size(); i++) {
|
||||
m_payload[i] = (m_payload[i] ^ m_masking_key[i%4]);
|
||||
}
|
||||
}
|
||||
|
||||
void frame::validate_utf8(uint32_t* state,uint32_t* codep, size_t offset) const {
|
||||
for (size_t i = offset; i < m_payload.size(); i++) {
|
||||
using utf8_validator::decode;
|
||||
|
||||
if (decode(state,codep,m_payload[i]) == utf8_validator::UTF8_REJECT) {
|
||||
throw frame_error("Invalid UTF-8 Data",FERR_PAYLOAD_VIOLATION);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void frame::validate_basic_header() const {
|
||||
// check for control frame size
|
||||
if (get_basic_size() > BASIC_PAYLOAD_LIMIT && is_control()) {
|
||||
throw frame_error("Control Frame is too large",FERR_PROTOCOL_VIOLATION);
|
||||
}
|
||||
|
||||
// check for reserved opcodes
|
||||
if (get_rsv1() || get_rsv2() || get_rsv3()) {
|
||||
throw frame_error("Reserved bit used",FERR_PROTOCOL_VIOLATION);
|
||||
}
|
||||
|
||||
// check for reserved opcodes
|
||||
opcode op = get_opcode();
|
||||
if (op > 0x02 && op < 0x08) {
|
||||
throw frame_error("Reserved opcode used",FERR_PROTOCOL_VIOLATION);
|
||||
}
|
||||
if (op > 0x0A) {
|
||||
throw frame_error("Reserved opcode used",FERR_PROTOCOL_VIOLATION);
|
||||
}
|
||||
|
||||
// check for fragmented control message
|
||||
if (is_control() && !get_fin()) {
|
||||
throw frame_error("Fragmented control message",FERR_PROTOCOL_VIOLATION);
|
||||
}
|
||||
}
|
||||
|
||||
void frame::generate_masking_key() {
|
||||
//throw "masking key generation not implimented";
|
||||
|
||||
int32_t key = m_gen();
|
||||
|
||||
//m_masking_key[0] = reinterpret_cast<char*>(&key)[0];
|
||||
//m_masking_key[1] = reinterpret_cast<char*>(&key)[1];
|
||||
//m_masking_key[2] = reinterpret_cast<char*>(&key)[2];
|
||||
//m_masking_key[3] = reinterpret_cast<char*>(&key)[3];
|
||||
|
||||
*(reinterpret_cast<int32_t *>(&m_header[get_header_len()-4])) = key;
|
||||
|
||||
//std::cout << "maskkey: " << m_masking_key << std::endl;
|
||||
|
||||
/* TODO: test and tune
|
||||
|
||||
boost::random::random_device rng;
|
||||
boost::random::uniform_int_distribution<> mask(0,UINT32_MAX);
|
||||
|
||||
*(reinterpret_cast<uint32_t *>(m_masking_key)) = mask(rng);
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
void frame::clear_masking_key() {
|
||||
// this is a no-op as clearing the mask bit also changes the get_header_len
|
||||
// method to not include these byte ranges. Whenever the masking bit is re-
|
||||
// set a new key is generated anyways.
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBSOCKET_FRAME_HPP
|
||||
#define WEBSOCKET_FRAME_HPP
|
||||
|
||||
#include "network_utilities.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
|
||||
#include <boost/random.hpp>
|
||||
#include <boost/random/random_device.hpp>
|
||||
|
||||
namespace websocketpp {
|
||||
|
||||
/* policies to abstract out
|
||||
|
||||
- random number generation
|
||||
- utf8 validation
|
||||
|
||||
*/
|
||||
|
||||
class frame {
|
||||
public:
|
||||
enum opcode_s {
|
||||
CONTINUATION_FRAME = 0x00,
|
||||
TEXT_FRAME = 0x01,
|
||||
BINARY_FRAME = 0x02,
|
||||
CONNECTION_CLOSE = 0x08,
|
||||
PING = 0x09,
|
||||
PONG = 0x0A
|
||||
};
|
||||
|
||||
typedef enum opcode_s opcode;
|
||||
|
||||
static const uint8_t MAX_FRAME_OPCODE = 0x07;
|
||||
|
||||
static const uint8_t STATE_BASIC_HEADER = 1;
|
||||
static const uint8_t STATE_EXTENDED_HEADER = 2;
|
||||
static const uint8_t STATE_PAYLOAD = 3;
|
||||
static const uint8_t STATE_READY = 4;
|
||||
static const uint8_t STATE_RECOVERY = 5;
|
||||
|
||||
static const uint16_t FERR_FATAL_SESSION_ERROR = 0; // force session end
|
||||
static const uint16_t FERR_SOFT_SESSION_ERROR = 1; // should log and ignore
|
||||
static const uint16_t FERR_PROTOCOL_VIOLATION = 2; // must end session
|
||||
static const uint16_t FERR_PAYLOAD_VIOLATION = 3; // should end session
|
||||
static const uint16_t FERR_INTERNAL_SERVER_ERROR = 4; // cleanly end session
|
||||
static const uint16_t FERR_MSG_TOO_BIG = 5;
|
||||
|
||||
// basic payload byte flags
|
||||
static const uint8_t BPB0_OPCODE = 0x0F;
|
||||
static const uint8_t BPB0_RSV3 = 0x10;
|
||||
static const uint8_t BPB0_RSV2 = 0x20;
|
||||
static const uint8_t BPB0_RSV1 = 0x40;
|
||||
static const uint8_t BPB0_FIN = 0x80;
|
||||
static const uint8_t BPB1_PAYLOAD = 0x7F;
|
||||
static const uint8_t BPB1_MASK = 0x80;
|
||||
|
||||
static const uint8_t BASIC_PAYLOAD_LIMIT = 0x7D; // 125
|
||||
static const uint8_t BASIC_PAYLOAD_16BIT_CODE = 0x7E; // 126
|
||||
static const uint16_t PAYLOAD_16BIT_LIMIT = 0xFFFF; // 2^16, 65535
|
||||
static const uint8_t BASIC_PAYLOAD_64BIT_CODE = 0x7F; // 127
|
||||
static const uint64_t PAYLOAD_64BIT_LIMIT = 0x7FFFFFFFFFFFFFFF; // 2^63
|
||||
|
||||
static const unsigned int BASIC_HEADER_LENGTH = 2;
|
||||
static const unsigned int MAX_HEADER_LENGTH = 14;
|
||||
static const uint8_t extended_header_length = 12;
|
||||
static const uint64_t max_payload_size = 100000000; // 100MB
|
||||
|
||||
// create an empty frame for writing into
|
||||
frame() : m_gen(m_rng,
|
||||
boost::random::uniform_int_distribution<>(INT32_MIN,INT32_MAX)),m_degraded(false) {
|
||||
reset();
|
||||
}
|
||||
|
||||
uint8_t get_state() const;
|
||||
uint64_t get_bytes_needed() const;
|
||||
void reset();
|
||||
|
||||
void consume(std::istream &s);
|
||||
|
||||
// get pointers to underlying buffers
|
||||
char* get_header();
|
||||
char* get_extended_header();
|
||||
unsigned int get_header_len() const;
|
||||
|
||||
char* get_masking_key();
|
||||
|
||||
// get and set header bits
|
||||
bool get_fin() const;
|
||||
void set_fin(bool fin);
|
||||
|
||||
bool get_rsv1() const;
|
||||
void set_rsv1(bool b);
|
||||
|
||||
bool get_rsv2() const;
|
||||
void set_rsv2(bool b);
|
||||
|
||||
bool get_rsv3() const;
|
||||
void set_rsv3(bool b);
|
||||
|
||||
opcode get_opcode() const;
|
||||
void set_opcode(opcode op);
|
||||
|
||||
bool get_masked() const;
|
||||
void set_masked(bool masked);
|
||||
|
||||
uint8_t get_basic_size() const;
|
||||
size_t get_payload_size() const;
|
||||
|
||||
uint16_t get_close_status() const;
|
||||
std::string get_close_msg() const;
|
||||
|
||||
std::vector<unsigned char> &get_payload();
|
||||
|
||||
void set_payload(const std::vector<unsigned char> source);
|
||||
void set_payload(const std::string source);
|
||||
void set_payload_helper(size_t s);
|
||||
|
||||
void set_status(uint16_t status,const std::string message = "");
|
||||
|
||||
bool is_control() const;
|
||||
|
||||
std::string print_frame() const;
|
||||
|
||||
// reads basic header, sets and returns m_header_bits_needed
|
||||
void process_basic_header();
|
||||
void process_extended_header();
|
||||
void process_payload();
|
||||
void process_payload2(); // experiment with more efficient masking code.
|
||||
|
||||
void validate_utf8(uint32_t* state,uint32_t* codep,size_t offset = 0) const;
|
||||
void validate_basic_header() const;
|
||||
|
||||
void generate_masking_key();
|
||||
void clear_masking_key();
|
||||
|
||||
private:
|
||||
uint8_t m_state;
|
||||
uint64_t m_bytes_needed;
|
||||
bool m_degraded;
|
||||
|
||||
char m_header[MAX_HEADER_LENGTH];
|
||||
std::vector<unsigned char> m_payload;
|
||||
|
||||
char m_masking_key[4];
|
||||
|
||||
boost::random::random_device m_rng;
|
||||
boost::random::variate_generator<boost::random::random_device&,
|
||||
boost::random::uniform_int_distribution<> >
|
||||
m_gen;
|
||||
};
|
||||
|
||||
// Exception classes
|
||||
class frame_error : public std::exception {
|
||||
public:
|
||||
frame_error(const std::string& msg,
|
||||
uint16_t code = frame::FERR_FATAL_SESSION_ERROR)
|
||||
: m_msg(msg),m_code(code) {}
|
||||
~frame_error() throw() {}
|
||||
|
||||
virtual const char* what() const throw() {
|
||||
return m_msg.c_str();
|
||||
}
|
||||
|
||||
uint16_t code() const throw() {
|
||||
return m_code;
|
||||
}
|
||||
|
||||
std::string m_msg;
|
||||
uint16_t m_code;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // WEBSOCKET_FRAME_HPP
|
||||
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "websocketpp.hpp"
|
||||
#include "websocket_server.hpp"
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using websocketpp::server;
|
||||
|
||||
server::server(boost::asio::io_service& io_service,
|
||||
const tcp::endpoint& endpoint,
|
||||
websocketpp::connection_handler_ptr defc)
|
||||
: m_elog_level(LOG_ERROR),
|
||||
m_alog_level(ALOG_CONTROL),
|
||||
m_max_message_size(DEFAULT_MAX_MESSAGE_SIZE),
|
||||
m_io_service(io_service),
|
||||
m_acceptor(io_service, endpoint),
|
||||
m_def_con_handler(defc),
|
||||
m_desc("websocketpp::server") {
|
||||
m_desc.add_options()
|
||||
("help", "produce help message")
|
||||
("host,h",po::value<std::vector<std::string> >()->multitoken()->composing(), "hostnames to listen on")
|
||||
("port,p",po::value<int>(), "port to listen on")
|
||||
;
|
||||
|
||||
}
|
||||
|
||||
void server::parse_command_line(int ac, char* av[]) {
|
||||
po::store(po::parse_command_line(ac,av, m_desc),m_vm);
|
||||
po::notify(m_vm);
|
||||
|
||||
if (m_vm.count("help") ) {
|
||||
std::cout << m_desc << std::endl;
|
||||
}
|
||||
|
||||
//m_vm["host"].as<std::string>();
|
||||
|
||||
const std::vector< std::string > &foo = m_vm["host"].as< std::vector<std::string> >();
|
||||
|
||||
for (int i = 0; i < foo.size(); i++) {
|
||||
std::cout << foo[i] << std::endl;
|
||||
}
|
||||
|
||||
//std::cout << m_vm["host"].as< std::vector<std::string> >() << std::endl;
|
||||
}
|
||||
|
||||
void server::add_host(std::string host) {
|
||||
m_hosts.insert(host);
|
||||
}
|
||||
|
||||
void server::remove_host(std::string host) {
|
||||
m_hosts.erase(host);
|
||||
}
|
||||
|
||||
|
||||
void server::set_max_message_size(uint64_t val) {
|
||||
if (val > frame::PAYLOAD_64BIT_LIMIT) {
|
||||
std::stringstream err;
|
||||
err << "Invalid maximum message size: " << val;
|
||||
|
||||
// TODO: Figure out what the ideal error behavior for this method.
|
||||
// Options:
|
||||
// Throw exception
|
||||
// Log error and set value to maximum allowed
|
||||
// Log error and leave value at whatever it was before
|
||||
log(err.str(),LOG_WARN);
|
||||
//throw server_error(err.str());
|
||||
}
|
||||
m_max_message_size = val;
|
||||
}
|
||||
|
||||
bool server::test_elog_level(uint16_t level) {
|
||||
return (level >= m_elog_level);
|
||||
}
|
||||
void server::set_elog_level(uint16_t level) {
|
||||
std::stringstream msg;
|
||||
msg << "Error logging level changing from "
|
||||
<< m_elog_level << " to " << level;
|
||||
log(msg.str(),LOG_INFO);
|
||||
|
||||
m_elog_level = level;
|
||||
}
|
||||
bool server::test_alog_level(uint16_t level) {
|
||||
return ((level & m_alog_level) != 0);
|
||||
}
|
||||
void server::set_alog_level(uint16_t level) {
|
||||
if (test_alog_level(level)) {
|
||||
return;
|
||||
}
|
||||
std::stringstream msg;
|
||||
msg << "Access logging level " << level << " being set";
|
||||
access_log(msg.str(),ALOG_INFO);
|
||||
|
||||
m_alog_level |= level;
|
||||
}
|
||||
void server::unset_alog_level(uint16_t level) {
|
||||
if (!test_alog_level(level)) {
|
||||
return;
|
||||
}
|
||||
std::stringstream msg;
|
||||
msg << "Access logging level " << level << " being unset";
|
||||
access_log(msg.str(),ALOG_INFO);
|
||||
|
||||
m_alog_level &= ~level;
|
||||
}
|
||||
|
||||
bool server::validate_host(std::string host) {
|
||||
if (m_hosts.find(host) == m_hosts.end()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool server::validate_message_size(uint64_t val) {
|
||||
if (val > m_max_message_size) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void server::log(std::string msg,uint16_t level) {
|
||||
if (!test_elog_level(level)) {
|
||||
return;
|
||||
}
|
||||
std::cerr << "[Error Log] "
|
||||
<< boost::posix_time::to_iso_extended_string(
|
||||
boost::posix_time::second_clock::local_time())
|
||||
<< " " << msg << std::endl;
|
||||
}
|
||||
void server::access_log(std::string msg,uint16_t level) {
|
||||
if (!test_alog_level(level)) {
|
||||
return;
|
||||
}
|
||||
std::cout << "[Access Log] "
|
||||
<< boost::posix_time::to_iso_extended_string(
|
||||
boost::posix_time::second_clock::local_time())
|
||||
<< " " << msg << std::endl;
|
||||
}
|
||||
|
||||
void server::start_accept() {
|
||||
// TODO: sanity check whether the session buffer size bound could be reduced
|
||||
server_session_ptr new_session(new server_session(shared_from_this(),
|
||||
m_io_service,
|
||||
m_def_con_handler,
|
||||
m_max_message_size*2));
|
||||
|
||||
m_acceptor.async_accept(
|
||||
new_session->socket(),
|
||||
boost::bind(
|
||||
&server::handle_accept,
|
||||
this,
|
||||
new_session,
|
||||
boost::asio::placeholders::error
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void server::handle_accept(websocketpp::server_session_ptr session,
|
||||
const boost::system::error_code& error) {
|
||||
|
||||
if (!error) {
|
||||
session->on_connect();
|
||||
} else {
|
||||
std::stringstream err;
|
||||
err << "Error accepting socket connection: " << error;
|
||||
|
||||
log(err.str(),LOG_ERROR);
|
||||
throw server_error(err.str());
|
||||
}
|
||||
|
||||
this->start_accept();
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBSOCKET_SERVER_HPP
|
||||
#define WEBSOCKET_SERVER_HPP
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/program_options.hpp>
|
||||
namespace po = boost::program_options;
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace websocketpp {
|
||||
class server;
|
||||
typedef boost::shared_ptr<server> server_ptr;
|
||||
}
|
||||
|
||||
#include "websocketpp.hpp"
|
||||
#include "websocket_server_session.hpp"
|
||||
#include "websocket_connection_handler.hpp"
|
||||
|
||||
using boost::asio::ip::tcp;
|
||||
|
||||
namespace websocketpp {
|
||||
|
||||
class server_error : public std::exception {
|
||||
public:
|
||||
server_error(const std::string& msg)
|
||||
: m_msg(msg) {}
|
||||
~server_error() throw() {}
|
||||
|
||||
virtual const char* what() const throw() {
|
||||
return m_msg.c_str();
|
||||
}
|
||||
private:
|
||||
std::string m_msg;
|
||||
};
|
||||
|
||||
class server : public boost::enable_shared_from_this<server> {
|
||||
public:
|
||||
server(boost::asio::io_service& io_service,
|
||||
const tcp::endpoint& endpoint,
|
||||
connection_handler_ptr defc);
|
||||
|
||||
// creates a new session object and connects the next websocket
|
||||
// connection to it.
|
||||
void start_accept();
|
||||
|
||||
// INTERFACE FOR LOCAL APPLICATIONS
|
||||
|
||||
// Add or remove a host string (host:port) to the list of acceptable
|
||||
// hosts to accept websocket connections from. Additions/deletions here
|
||||
// only affect new connections.
|
||||
void add_host(std::string host);
|
||||
void remove_host(std::string host);
|
||||
|
||||
void set_max_message_size(uint64_t val);
|
||||
|
||||
// Test methods determine if a message of the given level should be
|
||||
// written. elog shows all values above the level set. alog shows only
|
||||
// the values explicitly set.
|
||||
bool test_elog_level(uint16_t level);
|
||||
void set_elog_level(uint16_t level);
|
||||
|
||||
bool test_alog_level(uint16_t level);
|
||||
void set_alog_level(uint16_t level);
|
||||
void unset_alog_level(uint16_t level);
|
||||
|
||||
void parse_command_line(int ac, char* av[]);
|
||||
|
||||
// INTERFACE FOR SESSIONS
|
||||
|
||||
// Check if this server will respond to this host.
|
||||
bool validate_host(std::string host);
|
||||
|
||||
// Check if message size is within server's acceptable parameters
|
||||
bool validate_message_size(uint64_t val);
|
||||
|
||||
// write to the server's logs
|
||||
void log(std::string msg,uint16_t level = LOG_ERROR);
|
||||
void access_log(std::string msg,uint16_t level);
|
||||
private:
|
||||
// if no errors starts the session's read loop and returns to the
|
||||
// start_accept phase.
|
||||
void handle_accept(server_session_ptr session,
|
||||
const boost::system::error_code& error);
|
||||
|
||||
private:
|
||||
uint16_t m_elog_level;
|
||||
uint16_t m_alog_level;
|
||||
|
||||
std::set<std::string> m_hosts;
|
||||
uint64_t m_max_message_size;
|
||||
boost::asio::io_service& m_io_service;
|
||||
tcp::acceptor m_acceptor;
|
||||
connection_handler_ptr m_def_con_handler;
|
||||
|
||||
po::options_description m_desc;
|
||||
po::variables_map m_vm;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // WEBSOCKET_SERVER_HPP
|
||||
@@ -0,0 +1,362 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "websocketpp.hpp"
|
||||
#include "websocket_server_session.hpp"
|
||||
|
||||
#include "websocket_frame.hpp"
|
||||
#include "utf8_validator/utf8_validator.hpp"
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
using websocketpp::server_session;
|
||||
|
||||
server_session::server_session(websocketpp::server_ptr s,
|
||||
boost::asio::io_service& io_service,
|
||||
websocketpp::connection_handler_ptr defc,
|
||||
uint64_t buf_size)
|
||||
: session(io_service,defc,buf_size),m_server(s) {}
|
||||
|
||||
void server_session::on_connect() {
|
||||
read_handshake();
|
||||
}
|
||||
|
||||
|
||||
void server_session::set_header(const std::string &key,const std::string &val) {
|
||||
// TODO: prevent use of reserved headers;
|
||||
m_server_headers[key] = val;
|
||||
}
|
||||
|
||||
void server_session::select_subprotocol(const std::string& val) {
|
||||
std::vector<std::string>::iterator it;
|
||||
|
||||
it = std::find(m_client_subprotocols.begin(),
|
||||
m_client_subprotocols.end(),
|
||||
val);
|
||||
|
||||
if (val != "" && it == m_client_subprotocols.end()) {
|
||||
throw server_error("Attempted to choose a subprotocol not proposed by the client");
|
||||
}
|
||||
|
||||
m_server_subprotocol = val;
|
||||
}
|
||||
|
||||
void server_session::select_extension(const std::string& val) {
|
||||
if (val == "") {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::string>::iterator it;
|
||||
|
||||
it = std::find(m_client_extensions.begin(),
|
||||
m_client_extensions.end(),
|
||||
val);
|
||||
|
||||
if (it == m_client_extensions.end()) {
|
||||
throw server_error("Attempted to choose an extension not proposed by the client");
|
||||
}
|
||||
|
||||
m_server_extensions.push_back(val);
|
||||
}
|
||||
|
||||
void server_session::read_handshake() {
|
||||
m_timer.expires_from_now(boost::posix_time::seconds(5));
|
||||
|
||||
m_timer.async_wait(
|
||||
boost::bind(
|
||||
&session::handle_handshake_expired,
|
||||
shared_from_this(),
|
||||
boost::asio::placeholders::error
|
||||
)
|
||||
);
|
||||
|
||||
boost::asio::async_read_until(
|
||||
m_socket,
|
||||
m_buf,
|
||||
"\r\n\r\n",
|
||||
boost::bind(
|
||||
&session::handle_read_handshake,
|
||||
shared_from_this(),
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void server_session::handle_read_handshake(const boost::system::error_code& e,
|
||||
std::size_t bytes_transferred) {
|
||||
std::ostringstream line;
|
||||
line << &m_buf;
|
||||
m_raw_client_handshake += line.str();
|
||||
|
||||
access_log(m_raw_client_handshake,ALOG_HANDSHAKE);
|
||||
|
||||
std::vector<std::string> tokens;
|
||||
std::string::size_type start = 0;
|
||||
std::string::size_type end;
|
||||
|
||||
// Get request and parse headers
|
||||
end = m_raw_client_handshake.find("\r\n",start);
|
||||
|
||||
while(end != std::string::npos) {
|
||||
tokens.push_back(m_raw_client_handshake.substr(start, end - start));
|
||||
|
||||
start = end + 2;
|
||||
|
||||
end = m_raw_client_handshake.find("\r\n",start);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < tokens.size(); i++) {
|
||||
if (i == 0) {
|
||||
m_client_http_request = tokens[i];
|
||||
}
|
||||
|
||||
end = tokens[i].find(": ",0);
|
||||
|
||||
if (end != std::string::npos) {
|
||||
std::string h = tokens[i].substr(0,end);
|
||||
|
||||
if (get_client_header(h) == "") {
|
||||
m_client_headers[h] = tokens[i].substr(end+2);
|
||||
} else {
|
||||
m_client_headers[h] += ", " + tokens[i].substr(end+2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// handshake error checking
|
||||
try {
|
||||
std::stringstream err;
|
||||
std::string h;
|
||||
|
||||
// check the method
|
||||
if (m_client_http_request.substr(0,4) != "GET ") {
|
||||
err << "Websocket handshake has invalid method: "
|
||||
<< m_client_http_request.substr(0,4);
|
||||
|
||||
throw(handshake_error(err.str(),400));
|
||||
}
|
||||
|
||||
// check the HTTP version
|
||||
// TODO: allow versions greater than 1.1
|
||||
end = m_client_http_request.find(" HTTP/1.1",4);
|
||||
if (end == std::string::npos) {
|
||||
err << "Websocket handshake has invalid HTTP version";
|
||||
throw(handshake_error(err.str(),400));
|
||||
}
|
||||
|
||||
m_resource = m_client_http_request.substr(4,end-4);
|
||||
|
||||
// verify the presence of required headers
|
||||
h = get_client_header("Host");
|
||||
if (h == "") {
|
||||
throw(handshake_error("Required Host header is missing",400));
|
||||
} else if (!m_server->validate_host(h)) {
|
||||
err << "Host " << h << " is not one of this server's names.";
|
||||
throw(handshake_error(err.str(),400));
|
||||
}
|
||||
|
||||
h = get_client_header("Upgrade");
|
||||
if (h == "") {
|
||||
throw(handshake_error("Required Upgrade header is missing",400));
|
||||
} else if (!boost::iequals(h,"websocket")) {
|
||||
err << "Upgrade header was " << h << " instead of \"websocket\"";
|
||||
throw(handshake_error(err.str(),400));
|
||||
}
|
||||
|
||||
h = get_client_header("Connection");
|
||||
if (h == "") {
|
||||
throw(handshake_error("Required Connection header is missing",400));
|
||||
} else if (!boost::ifind_first(h,"upgrade")) {
|
||||
err << "Connection header, \"" << h
|
||||
<< "\", does not contain required token \"upgrade\"";
|
||||
throw(handshake_error(err.str(),400));
|
||||
}
|
||||
|
||||
if (get_client_header("Sec-WebSocket-Key") == "") {
|
||||
throw(handshake_error("Required Sec-WebSocket-Key header is missing",400));
|
||||
}
|
||||
|
||||
h = get_client_header("Sec-WebSocket-Version");
|
||||
if (h == "") {
|
||||
throw(handshake_error("Required Sec-WebSocket-Version header is missing",400));
|
||||
} else {
|
||||
m_version = atoi(h.c_str());
|
||||
|
||||
if (m_version != 7 && m_version != 8 && m_version != 13) {
|
||||
err << "This server doesn't support WebSocket protocol version "
|
||||
<< m_version;
|
||||
throw(handshake_error(err.str(),400));
|
||||
}
|
||||
}
|
||||
|
||||
if (m_version < 13) {
|
||||
h = get_client_header("Sec-WebSocket-Origin");
|
||||
} else {
|
||||
h = get_client_header("Origin");
|
||||
}
|
||||
|
||||
if (h != "") {
|
||||
m_client_origin = h;
|
||||
}
|
||||
|
||||
// TODO: extract subprotocols
|
||||
// TODO: extract extensions
|
||||
|
||||
// optional headers (delegated to the local interface)
|
||||
if (m_local_interface) {
|
||||
m_local_interface->validate(shared_from_this());
|
||||
}
|
||||
|
||||
m_server_http_code = 101;
|
||||
m_server_http_string = "Switching Protocols";
|
||||
} catch (const handshake_error& e) {
|
||||
std::stringstream err;
|
||||
err << "Caught handshake exception: " << e.what();
|
||||
|
||||
access_log(e.what(),ALOG_HANDSHAKE);
|
||||
log(err.str(),LOG_ERROR);
|
||||
|
||||
m_server_http_code = e.m_http_error_code;
|
||||
m_server_http_string = e.m_http_error_msg;
|
||||
}
|
||||
|
||||
write_handshake();
|
||||
}
|
||||
|
||||
void server_session::write_handshake() {
|
||||
std::stringstream h;
|
||||
|
||||
|
||||
|
||||
if (m_server_http_code == 101) {
|
||||
std::string server_key = get_client_header("Sec-WebSocket-Key");
|
||||
server_key += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
||||
|
||||
SHA1 sha;
|
||||
uint32_t message_digest[5];
|
||||
|
||||
sha.Reset();
|
||||
sha << server_key.c_str();
|
||||
|
||||
if (sha.Result(message_digest)){
|
||||
// convert sha1 hash bytes to network byte order because this sha1
|
||||
// library works on ints rather than bytes
|
||||
for (int i = 0; i < 5; i++) {
|
||||
message_digest[i] = htonl(message_digest[i]);
|
||||
}
|
||||
|
||||
server_key = base64_encode(
|
||||
reinterpret_cast<const unsigned char*>(message_digest),20);
|
||||
|
||||
// set handshake accept headers
|
||||
set_header("Sec-WebSocket-Accept",server_key);
|
||||
set_header("Upgrade","websocket");
|
||||
set_header("Connection","Upgrade");
|
||||
} else {
|
||||
log("Error computing handshake sha1 hash.",LOG_ERROR);
|
||||
m_server_http_code = 500;
|
||||
m_server_http_string = "";
|
||||
}
|
||||
}
|
||||
|
||||
// hardcoded server headers
|
||||
set_header("Server","WebSocket++/2011-09-25");
|
||||
|
||||
h << "HTTP/1.1 " << m_server_http_code << " "
|
||||
<< (m_server_http_string != "" ? m_server_http_string :
|
||||
lookup_http_error_string(m_server_http_code))
|
||||
<< "\r\n";
|
||||
|
||||
header_list::iterator it;
|
||||
for (it = m_server_headers.begin(); it != m_server_headers.end(); it++) {
|
||||
h << it->first << ": " << it->second << "\r\n";
|
||||
}
|
||||
|
||||
h << "\r\n";
|
||||
|
||||
m_raw_server_handshake = h.str();
|
||||
|
||||
// start async write to handle_write_handshake
|
||||
boost::asio::async_write(
|
||||
m_socket,
|
||||
boost::asio::buffer(m_raw_server_handshake),
|
||||
boost::bind(
|
||||
&session::handle_write_handshake,
|
||||
shared_from_this(),
|
||||
boost::asio::placeholders::error
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void server_session::handle_write_handshake(const boost::system::error_code& error) {
|
||||
if (error) {
|
||||
log_error("Error writing handshake response",error);
|
||||
drop_tcp();
|
||||
return;
|
||||
}
|
||||
|
||||
log_open_result();
|
||||
|
||||
if (m_server_http_code != 101) {
|
||||
std::stringstream err;
|
||||
err << "Handshake ended with HTTP error: " << m_server_http_code << " "
|
||||
<< (m_server_http_string != "" ? m_server_http_string : lookup_http_error_string(m_server_http_code));
|
||||
log(err.str(),LOG_ERROR);
|
||||
drop_tcp();
|
||||
// TODO: tell client that connection failed.
|
||||
return;
|
||||
}
|
||||
|
||||
m_state = STATE_OPEN;
|
||||
|
||||
// stop the handshake timer
|
||||
m_timer.cancel();
|
||||
|
||||
if (m_local_interface) {
|
||||
m_local_interface->on_open(shared_from_this());
|
||||
}
|
||||
|
||||
reset_message();
|
||||
this->read_frame();
|
||||
}
|
||||
|
||||
void server_session::log(const std::string& msg, uint16_t level) const {
|
||||
m_server->log(msg,level);
|
||||
}
|
||||
|
||||
void server_session::access_log(const std::string& msg, uint16_t level) const {
|
||||
m_server->access_log(msg,level);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user