1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2025-07-03 23:47:12 +02:00

Initial preparations for CURL and Discord integration.

This commit is contained in:
Sandu Liviu Catalin
2021-01-27 07:27:48 +02:00
parent 8257eb61d6
commit 95705e87c8
1751 changed files with 440547 additions and 854 deletions

View File

@ -0,0 +1,18 @@
# 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

94
module/Vendor/WebSocketPP/.gitignore vendored Normal file
View File

@ -0,0 +1,94 @@
# make .git* files visible to git
!.gitignore
!.gitattributes
.DS_Store
#vim stuff
*~
*.swp
*.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/*
bin/Debug
*/Release/*
*/*/Release/*
*/RelWithDebInfo/*
*/*/RelWithDebInfo/*
# explicitly allow this path with /debug/ in it
!websocketpp/transport/debug/*
objs_shared/
objs_static/
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
*.opensdf
*.sdf
*.vcxproj
*.vcxproj.filters
*.user
install
Makefile
bin
Testing/Temporary/CTestCostData.txt

282
module/Vendor/WebSocketPP/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,282 @@
############ Setup project and cmake
# 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.8.8)
############ 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.
# This must be set prior to any call to project or it will not be read correctly.
# - Windows: Build the INSTALL project in your solution file.
# - Linux/OSX: make install.
if (WIN32)
set (CMAKE_INSTALL_PREFIX "${WEBSOCKETPP_ROOT}/install" CACHE PATH "")
endif ()
############ Project name and version
set (WEBSOCKETPP_MAJOR_VERSION 0)
set (WEBSOCKETPP_MINOR_VERSION 8)
set (WEBSOCKETPP_PATCH_VERSION 2)
set (WEBSOCKETPP_VERSION ${WEBSOCKETPP_MAJOR_VERSION}.${WEBSOCKETPP_MINOR_VERSION}.${WEBSOCKETPP_PATCH_VERSION})
if(POLICY CMP0048)
cmake_policy(GET CMP0048 _version_policy)
endif()
if(_version_allowed STREQUAL NEW)
project (websocketpp VERSION ${WEBSOCKETPP_VERSION})
else()
project (websocketpp)
endif()
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
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)
############ 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)
enable_testing ()
############ Compiler specific setup
set (WEBSOCKETPP_PLATFORM_LIBS "")
set (WEBSOCKETPP_PLATFORM_TLS_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)
if (MSVC)
add_definitions (-D_WEBSOCKETPP_CPP11_FUNCTIONAL_)
add_definitions (-D_WEBSOCKETPP_CPP11_SYSTEM_ERROR_)
add_definitions (-D_WEBSOCKETPP_CPP11_RANDOM_DEVICE_)
add_definitions (-D_WEBSOCKETPP_CPP11_MEMORY_)
else()
add_definitions (-D_WEBSOCKETPP_CPP11_STL_)
endif()
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)
if (NOT APPLE)
set (WEBSOCKETPP_PLATFORM_LIBS pthread rt)
else()
set (WEBSOCKETPP_PLATFORM_LIBS pthread)
endif()
set (WEBSOCKETPP_PLATFORM_TLS_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_TLS_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()
if (BUILD_TESTS)
list (APPEND WEBSOCKETPP_BOOST_LIBS unit_test_framework)
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 ()
if (BOOST_STATIC)
set (Boost_USE_STATIC_LIBS TRUE)
endif ()
if (NOT Boost_USE_STATIC_LIBS)
add_definitions (-DBOOST_TEST_DYN_LINK)
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)
find_package(ZLIB)
endif()
############ Add projects
# Add main library
add_subdirectory (websocketpp)
# Add examples
if (BUILD_EXAMPLES)
include_subdirs ("examples")
endif ()
# Add tests
if (BUILD_TESTS)
include_subdirs ("test")
endif ()
print_used_build_config()
export (PACKAGE websocketpp)
include(CMakePackageConfigHelpers)
configure_package_config_file(websocketpp-config.cmake.in
"${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/websocketpp-config.cmake"
PATH_VARS INSTALL_INCLUDE_DIR
INSTALL_DESTINATION "${INSTALL_CMAKE_DIR}"
NO_CHECK_REQUIRED_COMPONENTS_MACRO
)
write_basic_package_version_file("${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/websocketpp-configVersion.cmake"
VERSION ${WEBSOCKETPP_VERSION}
COMPATIBILITY ExactVersion)
# 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)

145
module/Vendor/WebSocketPP/COPYING vendored Normal file
View File

@ -0,0 +1,145 @@
Main Library:
Copyright (c) 2014, 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.

2355
module/Vendor/WebSocketPP/Doxyfile vendored Normal file

File diff suppressed because it is too large Load Diff

285
module/Vendor/WebSocketPP/SConstruct vendored Normal file
View File

@ -0,0 +1,285 @@
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!"
## Custom OpenSSL
if os.environ.has_key('OPENSSL_PATH'):
env.Append(CPPPATH = os.path.join(os.environ['OPENSSL_PATH'], 'include'))
env.Append(LIBPATH = os.environ['OPENSSL_PATH'])
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 not os.environ.has_key('CXX'):
env['CXX'] = "clang++"
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.Append(LIBPATH = ['/usr/lib', '/usr/local/lib'])
# Compiler specific warning flags
if env['CXX'].startswith('g++'):
#env.Append(CCFLAGS = ['-Wconversion'])
env.Append(CCFLAGS = ['-Wcast-align'])
env.Append(CCFLAGS = ['-Wshadow'])
env.Append(CCFLAGS = ['-Wunused-parameter'])
elif env['CXX'].startswith('clang++'):
#env.Append(CCFLAGS = ['-Wcast-align'])
#env.Append(CCFLAGS = ['-Wglobal-constructors'])
#env.Append(CCFLAGS = ['-Wconversion'])
env.Append(CCFLAGS = ['-Wno-padded'])
env.Append(CCFLAGS = ['-Wshadow'])
env.Append(CCFLAGS = ['-Wunused-parameter'])
env.Append(CCFLAGS = ['-Wsometimes-uninitialized'])
env.Append(CCFLAGS = ['-Wuninitialized'])
#env.Append(CCFLAGS = ['-Weverything'])
#env.Append(CCFLAGS = ['-Wno-documentation'])
#env.Append(CCFLAGS = ['-Wno-weak-vtables'])
#env.Append(CCFLAGS = ['-Wno-global-constructors'])
#env.Append(CCFLAGS = ['-Wno-sign-conversion'])
#env.Append(CCFLAGS = ['-Wno-exit-time-destructors'])
# 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.Append(CXXFLANGS = ['-stdlib=libc++'],LINKFLAGS=['-stdlib=libc++'])
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_client
echo_client = SConscript('#/examples/echo_client/SConscript',variant_dir = builddir + 'echo_client',duplicate = 0)
# print_client
print_client = SConscript('#/examples/print_client/SConscript',variant_dir = builddir + 'print_client',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)
echo_server_both = SConscript('#/examples/echo_server_both/SConscript',variant_dir = builddir + 'echo_server_both',duplicate = 0)
print_client_tls = SConscript('#/examples/print_client_tls/SConscript',variant_dir = builddir + 'print_client_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)
# scratch_client
scratch_client = SConscript('#/examples/scratch_client/SConscript',variant_dir = builddir + 'scratch_client',duplicate = 0)
# scratch_server
scratch_server = SConscript('#/examples/scratch_server/SConscript',variant_dir = builddir + 'scratch_server',duplicate = 0)
# debug_client
debug_client = SConscript('#/examples/debug_client/SConscript',variant_dir = builddir + 'debug_client',duplicate = 0)
# debug_server
debug_server = SConscript('#/examples/debug_server/SConscript',variant_dir = builddir + 'debug_server',duplicate = 0)
# subprotocol_server
subprotocol_server = SConscript('#/examples/subprotocol_server/SConscript',variant_dir = builddir + 'subprotocol_server',duplicate = 0)
# telemetry_server
telemetry_server = SConscript('#/examples/telemetry_server/SConscript',variant_dir = builddir + 'telemetry_server',duplicate = 0)
# external_io_service
external_io_service = SConscript('#/examples/external_io_service/SConscript',variant_dir = builddir + 'external_io_service',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)

444
module/Vendor/WebSocketPP/changelog.md vendored Normal file
View File

@ -0,0 +1,444 @@
HEAD
0.8.2 - 2020-04-19
- Examples: Update print_client_tls example to remove use of deprecated
OpenSSL functions.
- Compatibility: Removes the use of make_shared in a number of cases where
it would be incompatible with newer versions of ASIO. Thank you Stefan
Floeren for the patch. #810 #814 #862 #843 #794 #808
- CMake: Update cmake installer to better handle dependencies when using
g++ on MacOS. Thank you Luca Palano for reporting and a patch. #831
- CMake: Update cmake installer to use a variable for the include directory
improving the ability of the install to be customized. THank you Schrijvers
Luc and Gianfranco Costamanga for reporting and a patch. #842
0.8.1 - 2018-07-16
Note: This release does not change library behavior. It only corrects issues
in the installer and test system.
- Test Suite: Adjust test suite to match behavior introduced in 0.8.0. Thank
you Gianfranco Costamagna for reporting and a patch. #731
- CMake: Update cmake installer to only install library files globally.
Thank you Gianfraco Costamanga for reporting and a patch. #732
0.8.0 - 2018-07-12
- Examples: Add `print_client` example. This demonstrates a minimal non-TLS
client that connects to a server and prints out the messages it receives.
- Examples: Add `print_client_tls` example. This demonstrates a minimal TLS
client, including basic support via Asio+OpenSSL for certificate chain
and hostname verification.
- Feature: Add getter for all headers to the HTTP parsers. This allows a
wrapping library to enumerate all headers to send upstream. Thank you Jupp
Müller for reporting and an initial pull request.
- Improvement: Move the `socket_init_handler` to execute as a part of `init_asio`
rather than connection `pre_init`. This allows setting of socket options prior
to the bind/listen/accept system calls. Thank you ChristianRobl3D for
reporting #530.
- Improvement: Timers in transport integration tests should only fail if their
own test times out, rather than any test. #643 Thank you Alex Korotkin for
reporting and a patch.
- Improvement: Preserve transport layer error codes in more cases, particularly
during calls to `endpoint::listen`. #652 Thank you vadz for reporting and
patches.
- Compatibility: Make sure the chrono library used by Boost/Asio is in sync
with what the websocketpp is using. Thank you Flow86 for reporting and a
patch.
- Compatibility: Update `telemetry_client` to use a slightly more cross platform
method of sleeping. Should work on windows now. Thank you Meir Yanovich for
reporting.
- Compatibility: Updated permessage-deflate support to reflect that the zlib
library does not actually support a sliding window size of 256 bits.
WebSocket++ will no longer negotiate 256 bit deflate windows. If the user
of the library tries to request a 256 bit window a 512 bit window will be
specified instead (This was the previous behavior). #596 #653 Thank you
Vinnie Falco and Gianfranco Costamagna for reporting.
- Compatibility: Better error handling and logging in cases where extension
requests parse correctly but negotiation fails.
- Compatibility: Removed custom handling of `SSL_R_SHORT_READ` error condition.
This error code no longer exists in modern versions of OpenSSL and causes
a build error. It wasn't being used for anything particularly important
(slightly improving error reporting) and there isn't a great replacement.
#599 Thank you Gianfranco Costamagna for reporting.
- Compatibility: Add missing `<stdint>` headers. Fixes issues with g++ 5.4.0.
#638 Thank you Alex Korotkin for reporting and a patch.
- Compatibility: Remove the use of `std::auto_ptr` and `std::binary_function`
from builds with C++11 or later. These features are deprecated and were
removed entirely in C++17. This change allows building WebSocket++ on
C++17 compilers. #592 Thank you Michal Fojtak for reporting and a patch
- Compatibility: Add 1014 close code and adds missing descriptions for codes
1012 and 1013. #589 Thank you jbwdevries and ronneke1996 for reporting and
patches.
- Compatibility: Add hooks to support `mingw-std-threads` C++11 thread and mutex
polyfill library as an alternative to Boost. #608 Thank you Peter Taylor for
reporting and an initial patch.
- Compatibility: Changed the handshake connection token to 'Upgrade' from
'upgrade'. Technically this header is supposed to be processed case
insensitively. In practice, there are browsers (such as Edge) that don't do
this and they tend to use the uppercase value used as an example in RFC6455.
Thank you Johann Bauer for reporting and a patch. #727
- Bug: Store loggers in shared pointers to avoid crashes related to connections
trying to write logs entries after their respective endpoint has been
deallocated. Thank you Thalhammer for reporting and Jupp Müller for the
patch. #539 #501
- Bug: Change default listen backlog from 0 to `socket_base::max_connections`.
#549. Thank you derwassi and zwelab for reporting and na1pir for providing
access to hardware to debug the issue.
- Bug: Fix a crash in the accept loop when `get_connection` fails. #551 Thank you
Walter Gray for a patch.
- Bug/Documentation: Fix incorrect example code that used
`websocketpp::lib::error_code` instead of `websocketpp::exception`. Thank you
heretic13 for reporting
- Bug: Fix uninitialized shared pointer in Asio transport test suite. #647
Thank you Alex Korotkin for reporting and a patch.
- Bug: Fix a thread safety issue in the permessage-deflate extension that
caused message corruption when sending compressed messages from a different
thread than the main I/O thread. #615 Thank you KyleNyenhuis and Pieter De
Gendt for reporting and a patch.
- Bug: Fix an undefined behavior issue performing a 64 bit wide shift on a 64
bit value. #636 Thank you Gregor Jasny for reporting and a patch
- Bug: Fix some compile issues with ASIO_STANDALONE. #662 #665 Thank you
chronoxor and Guillaume Egles for reporting and patches.
0.7.0 - 2016-02-22
- MINOR BREAKING SOCKET POLICY CHANGE: Asio transport socket policy method
`cancel_socket` will now return `lib::asio::error_code` instead of `void`.
Custom Asio transport socket policies will need to be updated accordingly.
This does not affect anyone using the bundled socket policies.
- Feature: Basic support for the permessage-deflate extension. #344
- Feature: Allow accessing the local endpoint when using the Asio transport.
This allows inspection of the address and port in cases where they are chosen
by the operating system rather than the user. Thank you Andreas Weis and
Muzahid Hussain for reporting and related code. #458
- Feature: Add support for subprotocols in Hybi00. Thank you Lukas Obermann
for reporting and a patch. #518
- Feature: Adds `tcp_pre_bind handler` to Asio transport. This allows setting
arbitrary socket options after the listen acceptor has been created but before
the socket bind has been performed. #634 #439 Thank you Gregor Jasny for
the patch.
- Improvement: Better automatic std::chrono feature detection for Visual Studio
- Improvement: Major refactoring to bundled CMake build system. CMake can now be
used to build all of the examples and the test suite. Thank you Thijs Wenker
for a significant portion of this code. #378, #435, #449
- Improvement: In build environments where `lib::error_code` and
`lib::asio::error_code` match (such as using `boost::asio` with
`boost::system_error` or standalone asio with `std::system_error`, transport
errors are passed through natively rather than being reported as a translated
`pass_through` error type.
- Improvement: Add a `get_transport_error` method to Asio transport connections
to allow retrieving a machine readable native transport error.
- Improvement: Add `connection::get_response`, `connection::get_response_code`,
and `connection::get_response_msg` methods to allow accessing additional
information about the HTTP responses that WebSocket++ sends. #465 Thank you
Flow86 for reporting.
- Improvement: Removes use of empty strings ("") in favor of `string::clear()`
and `string::empty()`. This avoids generating unnecessary temporary objects.
#468 Thank you Vladislav Yaroslavlev for reporting and a patch.
- Documentation: Adds an example demonstrating the use of external `io_service`
- Documentation: Adds a simple `echo_client` example.
- Documentation: Begins migration of the web based user manual into Doxygen.
- Bug: Fix memory leak when `init_asio` produces an error. #454 Thank you Mark
Grimes for reporting and fixing.
- Bug: Fix crash when processing a specially crafted HTTP header. Thank you Eli
Fidler for reporting, test cases, and a patch. #456
- Bug: Fix an issue where standalone Asio builds that use TLS would not compile
due to lingering boost code. #448 Thank you mjsp for reporting
- Bug: Fix an issue where canceling a socket could throw an exception on some
older Windows XP platforms. It now prints an appropriate set of log messages
instead. Thank you Thijs Wenker for reporting and researching solutions. #460
- Bug: Fix an issue where deferred HTTP connections that start sending a very
long response before their HTTP handler ends would result in a second set of
HTTP headers being injected into the output. Thank you Kevin Smith for
reporting and providing test case details. #443
- Bug: Fix an issue where the wrong type of strand was being created. Thank you
Bastien Brunnenstein for reporting and a patch. #462
- Bug: Fix an issue where TLS includes were broken for Asio Standalone builds.
Thank you giachi and Bastien Brunnenstein for reporting. #491
- Bug: Remove the use of cached read and write handlers in the Asio transport.
This feature caused memory leaks when the `io_service` the connection was
running on was abruptly stopped. There isn't a clean and safe way of using
this optimization without global state and the associated locks. The locks
perform worse. Thank you Xavier Gibert for reporting, test cases, and code.
Fixes #490.
- Bug: Fix a heap buffer overflow when checking very short URIs. Thank you
Xavier Gibert for reporting and a patch #524
- Compatibility: Fixes a number of build & config issues on Visual Studio 2015
- Compatibility: Removes non-standards compliant masking behavior. #395, #469
- Compatibility: Replace deprecated use of `auto_ptr` on systems where
`unique_ptr` is available.
0.6.0 - 2015-06-02
- MINOR BREAKING TRANSPORT POLICY CHANGE: Custom transport policies will now be
required to include a new method `void set_uri(uri_ptr u)`. An implementation
is not required. The stub transport policy includes an example stub method
that can be added to any existing custom transport policy to fulfill this
requirement. This does not affect anyone using the bundled transports or
configs.
- MINOR BREAKING SOCKET POLICY CHANGE: Custom asio transport socket policies
will now be required to include a new method `void set_uri(uri_ptr u)`. Like
with the transport layer, an implementation is not required. This does not
affect anyone using the bundled socket policies.
- MINOR BREAKING DEPENDENCY CHANGE: When using Boost versions greater than or
equal to 1.49 in C++03 mode, `libboost-chrono` is needed now instead of
`libboost-date_time`. Users with C++11 compilers or using Boost versions 1.48
and earlier are not affected. Note: This change affects the bundled unit test
suite.
- Feature: WebSocket++ Asio transport policy can now be used with the standalone
version of Asio (1.8.0+) when a C++11 compiler and standard library are
present. This means that it is possible now to use WebSocket++'s Asio
transport entirely without Boost. Thank you Robert Seiler for proof of concept
code that was used as a guide for this implementation. Fixes #324
- Feature: Adds a vectored/scatter-gather write handler to the iostream
transport.
- Feature: Adds the ability to defer sending an HTTP response until sometime
after the `http_handler` is run. This allows processing of long running http
handlers to defer their response until it is ready without blocking the
network thread. references #425
- Improvement: `echo_server_tls` has been update to demonstrate how to configure
it for Mozilla's recommended intermediate and modern TLS security profiles.
- Improvement: `endpoint::set_timer` now uses a steady clock provided by
`boost::chrono` or `std::chrono` where available instead of the non-monotonic
system clock. Thank you breyed for reporting. fixes #241
- Improvement: Outgoing TLS connections to servers using the SNI extension to
choose a certificate will now work. Thank you moozzyk for reporting.
Fixes #400
- Improvement: Removes an unnecessary mutex lock in `get_con_from_hdl`.
- Cleanup: Asio transport policy has been refactored to remove many Boost
dependencies. On C++03 compilers the `boost::noncopyable` dependency has been
removed and the `boost::date_time` dependency has been replaced with the newer
`boost::chrono` when possible. On C++11 compilers the `boost::aligned_storage`
and `boost::date_time` dependencies are gone, replaced with equivalent C++11
standard library features.
- Bug: Fixes a potential dangling pointer and inconsistent error message
handling in `websocketpp::exception`. #432 Thank you Tom Swirly for the fix.
0.5.1 - 2015-02-27
- Bug: Fixes an issue where some frame data was counted against the max header
size limit, resulting in connections that included a lot of frame data
immediately after the opening handshake to fail.
- Bug: Fix a typo in the name of the set method for `max_http_body_size`. #406
Thank you jplatte for reporting.
0.5.0 - 2015-01-22
- BREAKING UTILITY CHANGE: Deprecated methods `http::parser::parse_headers`,
`http::response::parse_complete`, and `http::request::parse_complete` have
been removed.
- Security: Disabled SSLv3 in example servers.
- Feature: Adds basic support for accessing HTTP request bodies in the http
handler. #181
- Feature: Adds the ability to register a shutdown handler when using the
iostream transport. This provides a clean interface for triggering the shut
down of external sockets and other cleanup without hooking in to higher level
WebSocket handlers.
- Feature: Adds the ability to register a write handler when using the iostream
transport. This handler can be used to handle transport output in place of
registering an ostream to write to.
- Feature: Adds a new logging policy that outputs to syslog. #386 Thank you Tom
Hughes for submitting the initial version of this policy.
- Improvement: Message payload logging now prints text for text messages rather
than binary.
- Improvement: Overhaul of handshake state machine. Should make it impossible
for exceptions to bubble out of transport methods like `io_service::run`.
- Improvement: Overhaul of handshake error reporting. Fail handler error codes
will be more detailed and precise. Adds new [fail] and [http] logging channels
that log failed websocket connections and successful HTTP connections
respectively. A new aggregate channel package, `alevel::access_core`, allows
enabling connect, disconnect, fail, and http together. Successful HTTP
connections will no longer trigger a fail handler.
- Improvement: Ability to terminate connection during an http handler to cleanly
suppress the default outgoing HTTP response.
- Documentation: Add Sending & Receiving Messages step to chapter one of the
`utility_client` tutorial. Update `utility_client` example to match.
- Cleanup: Removes unused files & STL includes. Adds required STL includes.
Normalizes include order.
- Bug: Fixes a fatal state error when a handshake response is completed
immediately after that handshake times out. #389
- Bug: MinGW fixes; C++11 feature detection, localtime use. #393 Thank you
Schebb for reporting, code, and testing.
- Bug: Fixes an issue where `websocketpp::exception::what()` could return an out
of scope pointer. #397 Thank you fabioang for reporting.
- Bug: Fixes an issue where endpoints were not reset properly after a call to
`endpoint::listen` failed. #390 Thank you wyyqyl for reporting.
0.4.0 - 2014-11-04
- BREAKING API CHANGE: All WebSocket++ methods now throw an exception of type
`websocketpp::exception` which derives from `std::exception`. This normalizes
all exception types under the standard exception hierarchy and allows
WebSocket++ exceptions to be caught in the same statement as others. The error
code that was previously thrown is wrapped in the exception object and can be
accessed via the `websocketpp::exception::code()` method.
- BREAKING API CHANGE: Custom logging policies have some new required
constructors that take generic config settings rather than pointers to
std::ostreams. This allows writing logging policies that do not involve the
use of std::ostream. This does not affect anyone using the built in logging
policies.
- BREAKING UTILITY CHANGE: `websocketpp::lib::net::htonll` and
`websocketpp::lib::net::ntohll` have been prefixed with an underscore to avoid
conflicts with similarly named macros in some operating systems. If you are
using the WebSocket++ provided 64 bit host/network byte order functions you
will need to switch to the prefixed versions.
- BREAKING UTILITY CHANGE: The signature of `base64_encode` has changed from
`websocketpp::base64_encode(unsigned char const *, unsigned int)` to
`websocketpp::base64_encode(unsigned char const *, size_t)`.
- BREAKING UTILITY CHANGE: The signature of `sha1::calc` has changed from
`websocketpp::sha1::calc(void const *, int, unsigned char *)` to
`websocketpp::sha1::calc(void const *, size_t, unsigned char *)`
- Feature: Adds incomplete `minimal_server` and `minimal_client` configs that
can be used to build custom configs without pulling in the dependencies of
`core` or `core_client`. These configs will offer a stable base config to
future-proof custom configs.
- Improvement: Core library no longer has std::iostream as a dependency.
std::iostream is still required for the optional iostream logging policy and
iostream transport.
- Bug: C++11 Chrono support was being incorrectly detected by the `boost_config`
header. Thank you Max Dmitrichenko for reporting and a patch.
- Bug: use of `std::put_time` is now guarded by a unique flag rather than a
chrono library flag. Thank you Max Dmitrichenko for reporting.
- Bug: Fixes non-thread safe use of std::localtime. #347 #383
- Compatibility: Adjust usage of std::min to be more compatible with systems
that define a min(...) macro.
- Compatibility: Removes unused parameters from all library, test, and example
code. This assists with those developing with -Werror and -Wunused-parameter
#376
- Compatibility: Renames ntohll and htonll methods to avoid conflicts with
platform specific macros. #358 #381, #382 Thank you logotype, unphased,
svendjo
- Cleanup: Removes unused functions, fixes variable shadow warnings, normalizes
all whitespace in library, examples, and tests to 4 spaces. #376
0.3.0 - 2014-08-10
- Feature: Adds `start_perpetual` and `stop_perpetual` methods to asio transport
These may be used to replace manually managed `asio::io_service::work` objects
- Feature: Allow setting pong and handshake timeouts at runtime.
- Feature: Allows changing the listen backlog queue length.
- Feature: Split tcp init into pre and post init.
- Feature: Adds URI method to extract query string from URI. Thank you Banaan
for code. #298
- Feature: Adds a compile time switch to asio transport config to disable
certain multithreading features (some locks, asio strands)
- Feature: Adds the ability to pause reading on a connection. Paused connections
will not read more data from their socket, allowing TCP flow control to work
without blocking the main thread.
- Feature: Adds the ability to specify whether or not to use the `SO_REUSEADDR`
TCP socket option. The default for this value has been changed from `true` to
`false`.
- Feature: Adds the ability to specify a maximum message size.
- Feature: Adds `close::status::get_string(...)` method to look up a human
readable string given a close code value.
- Feature: Adds `connection::read_all(...)` method to iostream transport as a
convenience method for reading all data into the connection buffer without the
end user needing to manually loop on `read_some`.
- Improvement: Open, close, and pong timeouts can be disabled entirely by
setting their duration to 0.
- Improvement: 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.
- Improvement: Cleaned up the handling of TLS related errors. TLS errors will
now be reported with more detail on the info channel rather than all being
`tls_short_read` or `pass_through`. In addition, many cases where a TLS short
read was in fact expected are no longer classified as errors. Expected TLS
short reads and quasi-expected socket shutdown related errors will no longer
be reported as unclean WebSocket shutdowns to the application. Information
about them will remain in the info error channel for debugging purposes.
- Improvement: `start_accept` and `listen` errors are now reported to the caller
either via an exception or an ec parameter.
- Improvement: Outgoing writes are now batched for improved message throughput
and reduced system call and TCP frame overhead.
- Bug: Fix some cases of calls to empty lib::function objects.
- Bug: Fix memory leak of connection objects due to cached handlers holding on to
reference counted pointers. #310 Thank you otaras for reporting.
- Bug: Fix issue with const endpoint accessors (such as `get_user_agent`) not
compiling due to non-const mutex use. #292 Thank you logofive for reporting.
- Bug: Fix handler allocation crash with multithreaded `io_service`.
- Bug: Fixes incorrect whitespace handling in header parsing. #301 Thank you
Wolfram Schroers for reporting
- Bug: Fix a crash when parsing empty HTTP headers. Thank you Thingol for
reporting.
- Bug: Fix a crash following use of the `stop_listening` function. Thank you
Thingol for reporting.
- Bug: Fix use of variable names that shadow function parameters. The library
should compile cleanly with -Wshadow now. Thank you giszo for reporting. #318
- Bug: Fix an issue where `set_open_handshake_timeout` was ignored by server
code. Thank you Robin Rowe for reporting.
- Bug: Fix an issue where custom timeout values weren't being propagated from
endpoints to new connections.
- Bug: Fix a number of memory leaks related to server connection failures. #323
#333 #334 #335 Thank you droppy and aydany for reporting and patches.
reporting.
- Compatibility: Fix compile time conflict with Visual Studio's MIN/MAX macros.
Thank you Robin Rowe for reporting.
- Documentation: Examples and test suite build system now defaults to clang on
OS X
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
implementation 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

49
module/Vendor/WebSocketPP/readme.md vendored Normal file
View File

@ -0,0 +1,49 @@
WebSocket++ (0.8.2)
==========================
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 raw char buffers, one based on C++ iostreams, and one based on Asio
(either via Boost or standalone). End users can write additional transport
policies to support other networking or event libraries as needed.
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 (raw, iostream, Asio, or custom)
* Portable/cross platform (Posix/Windows, 32/64bit, Intel/ARM/PPC)
* Thread-safe
Get Involved
============
[![Build Status](https://travis-ci.org/zaphoyd/websocketpp.png)](https://travis-ci.org/zaphoyd/websocketpp)
**Project Website**
http://www.zaphoyd.com/websocketpp/
**User Manual**
http://docs.websocketpp.org/
**GitHub Repository**
https://github.com/zaphoyd/websocketpp/
GitHub pull requests should be submitted to the `develop` branch.
**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

43
module/Vendor/WebSocketPP/roadmap.md vendored Normal file
View File

@ -0,0 +1,43 @@
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
- External io_service support
- TLS support
- exception/error handling
- Timeouts
- Subprotocol negotiation
- validate_handler
- Hybi 00/Hixie 76 legacy protocol support
- Outgoing Proxy Support
- socket_init_handler
- tls_init_handler
- tcp_init_handler
Ongoing work
- Performance tuning
- PowerPC support
- Visual Studio / Windows support
- CMake build/install support
- http_handler
Future feature roadmap
- Extension support
- permessage_compress extension
- Message buffer pool
- flow control
- tutorials & documentation

View File

@ -0,0 +1,14 @@
# - Config file for the websocketpp package
# It defines the following variables
# WEBSOCKETPP_FOUND - indicates that the module was found
# WEBSOCKETPP_INCLUDE_DIR - include directories
@PACKAGE_INIT@
set_and_check(WEBSOCKETPP_INCLUDE_DIR "@PACKAGE_INSTALL_INCLUDE_DIR@")
set(WEBSOCKETPP_FOUND TRUE)
#This is a bit of a hack, but it works well. It also allows continued support of CMake 2.8
if(${CMAKE_VERSION} VERSION_GREATER 3.0.0 OR ${CMAKE_VERSION} VERSION_EQUAL 3.0.0)
add_library(websocketpp::websocketpp INTERFACE IMPORTED)
set_target_properties(websocketpp::websocketpp PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${WEBSOCKETPP_INCLUDE_DIR}")
endif()

View File

@ -0,0 +1,2 @@
init_target("websocketpp")
final_target ()

View File

@ -0,0 +1,178 @@
/*
******
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
*/
#ifndef _BASE64_HPP_
#define _BASE64_HPP_
#include <string>
namespace websocketpp {
static std::string const base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
/// Test whether a character is a valid base64 character
/**
* @param c The character to test
* @return true if c is a valid base64 character
*/
static inline bool is_base64(unsigned char c) {
return (c == 43 || // +
(c >= 47 && c <= 57) || // /-9
(c >= 65 && c <= 90) || // A-Z
(c >= 97 && c <= 122)); // a-z
}
/// Encode a char buffer into a base64 string
/**
* @param input The input data
* @param len The length of input in bytes
* @return A base64 encoded string representing input
*/
inline std::string base64_encode(unsigned char const * input, size_t len) {
std::string ret;
int i = 0;
int j = 0;
unsigned char char_array_3[3];
unsigned char char_array_4[4];
while (len--) {
char_array_3[i++] = *(input++);
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;
}
/// Encode a string into a base64 string
/**
* @param input The input data
* @return A base64 encoded string representing input
*/
inline std::string base64_encode(std::string const & input) {
return base64_encode(
reinterpret_cast<const unsigned char *>(input.data()),
input.size()
);
}
/// Decode a base64 encoded string into a string of raw bytes
/**
* @param input The base64 encoded input data
* @return A string representing the decoded raw bytes
*/
inline std::string base64_decode(std::string const & input) {
size_t in_len = input.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-- && ( input[in_] != '=') && is_base64(input[in_])) {
char_array_4[i++] = input[in_]; in_++;
if (i ==4) {
for (i = 0; i <4; i++) {
char_array_4[i] = static_cast<unsigned char>(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] = static_cast<unsigned char>(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 += static_cast<std::string::value_type>(char_array_3[j]);
}
}
return ret;
}
} // namespace websocketpp
#endif // _BASE64_HPP_

View File

@ -0,0 +1,33 @@
/*
* Copyright (c) 2014, 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_CLIENT_HPP
#define WEBSOCKETPP_CLIENT_HPP
#include <websocketpp/roles/client_endpoint.hpp>
#endif //WEBSOCKETPP_CLIENT_HPP

View File

@ -0,0 +1,353 @@
/*
* Copyright (c) 2014, 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_CLOSE_HPP
#define WEBSOCKETPP_CLOSE_HPP
/** \file
* A package of types and methods for manipulating WebSocket close codes.
*/
#include <websocketpp/error.hpp>
#include <websocketpp/common/network.hpp>
#include <websocketpp/common/stdint.hpp>
#include <websocketpp/utf8_validator.hpp>
#include <string>
namespace websocketpp {
/// A package of types and methods for manipulating WebSocket close codes.
namespace close {
/// A package of types and methods for manipulating WebSocket close status'
namespace status {
/// The type of a close code value.
typedef uint16_t value;
/// A blank value for internal use.
static value const blank = 0;
/// Close the connection without a WebSocket close handshake.
/**
* This special value requests that the WebSocket connection be closed
* without performing the WebSocket closing handshake. This does not comply
* with RFC6455, but should be safe to do if necessary. This could be useful
* for clients that need to disconnect quickly and cannot afford the
* complete handshake.
*/
static value const omit_handshake = 1;
/// Close the connection with a forced TCP drop.
/**
* This special value requests that the WebSocket connection be closed by
* forcibly dropping the TCP connection. This will leave the other side of
* the connection with a broken connection and some expensive timeouts. this
* should not be done except in extreme cases or in cases of malicious
* remote endpoints.
*/
static value const force_tcp_drop = 2;
/// Normal closure, meaning that the purpose for which the connection was
/// established has been fulfilled.
static value const normal = 1000;
/// The endpoint was "going away", such as a server going down or a browser
/// navigating away from a page.
static value const going_away = 1001;
/// A protocol error occurred.
static value const protocol_error = 1002;
/// The connection was terminated because an endpoint received a type of
/// data it cannot accept.
/**
* (e.g., an endpoint that understands only text data MAY send this if it
* receives a binary message).
*/
static value const unsupported_data = 1003;
/// A dummy value to indicate that no status code was received.
/**
* This value is illegal on the wire.
*/
static value const no_status = 1005;
/// A dummy value to indicate that the connection was closed abnormally.
/**
* In such a case there was no close frame to extract a value from. This
* value is illegal on the wire.
*/
static value const abnormal_close = 1006;
/// An endpoint received message data inconsistent with its type.
/**
* For example: Invalid UTF8 bytes in a text message.
*/
static value const invalid_payload = 1007;
/// An endpoint received a message that violated its policy.
/**
* This is a generic status code that can be returned when there is no other
* more suitable status code (e.g., 1003 or 1009) or if there is a need to
* hide specific details about the policy.
*/
static value const policy_violation = 1008;
/// An endpoint received a message too large to process.
static value const message_too_big = 1009;
/// A client expected the server to accept a required extension request
/**
* The list of extensions that are needed SHOULD appear in the /reason/ part
* of the Close frame. Note that this status code is not used by the server,
* because it can fail the WebSocket handshake instead.
*/
static value const extension_required = 1010;
/// An endpoint encountered an unexpected condition that prevented it from
/// fulfilling the request.
static value const internal_endpoint_error = 1011;
/// Indicates that the service is restarted. A client may reconnect and if
/// if it chooses to do so, should reconnect using a randomized delay of
/// 5-30s
static value const service_restart = 1012;
/// Indicates that the service is experiencing overload. A client should
/// only connect to a different IP (when there are multiple for the target)
/// or reconnect to the same IP upon user action.
static value const try_again_later = 1013;
/// Indicates that the server was acting as a gateway or proxy and received
/// an invalid response from the upstream server. This is similar to 502
/// HTTP Status Code.
static value const bad_gateway = 1014;
/// An endpoint failed to perform a TLS handshake
/**
* Designated for use in applications expecting a status code to indicate
* that the connection was closed due to a failure to perform a TLS
* handshake (e.g., the server certificate can't be verified). This value is
* illegal on the wire.
*/
static value const tls_handshake = 1015;
/// A generic subprotocol error
/**
* Indicates that a subprotocol error occurred. Typically this involves
* receiving a message that is not formatted as a valid message for the
* subprotocol in use.
*/
static value const subprotocol_error = 3000;
/// A invalid subprotocol data
/**
* Indicates that data was received that violated the specification of the
* subprotocol in use.
*/
static value const invalid_subprotocol_data = 3001;
/// First value in range reserved for future protocol use
static value const rsv_start = 1016;
/// Last value in range reserved for future protocol use
static value const rsv_end = 2999;
/// Test whether a close code is in a reserved range
/**
* @param [in] code The code to test
* @return Whether or not code is reserved
*/
inline bool reserved(value code) {
return ((code >= rsv_start && code <= rsv_end) ||
code == 1004);
}
/// First value in range that is always invalid on the wire
static value const invalid_low = 999;
/// Last value in range that is always invalid on the wire
static value const invalid_high = 5000;
/// Test whether a close code is invalid on the wire
/**
* @param [in] code The code to test
* @return Whether or not code is invalid on the wire
*/
inline bool invalid(value code) {
return (code <= invalid_low || code >= invalid_high ||
code == no_status || code == abnormal_close ||
code == tls_handshake);
}
/// Determine if the code represents an unrecoverable error
/**
* There is a class of errors for which once they are discovered normal
* WebSocket functionality can no longer occur. This function determines
* if a given code is one of these values. This information is used to
* determine if the system has the capability of waiting for a close
* acknowledgement or if it should drop the TCP connection immediately
* after sending its close frame.
*
* @param [in] code The value to test.
* @return True if the code represents an unrecoverable error
*/
inline bool terminal(value code) {
return (code == protocol_error || code == invalid_payload ||
code == policy_violation || code == message_too_big ||
code == internal_endpoint_error);
}
/// Return a human readable interpretation of a WebSocket close code
/**
* See https://tools.ietf.org/html/rfc6455#section-7.4 for more details.
*
* @since 0.3.0
*
* @param [in] code The code to look up.
* @return A human readable interpretation of the code.
*/
inline std::string get_string(value code) {
switch (code) {
case normal:
return "Normal close";
case going_away:
return "Going away";
case protocol_error:
return "Protocol error";
case unsupported_data:
return "Unsupported data";
case no_status:
return "No status set";
case abnormal_close:
return "Abnormal close";
case invalid_payload:
return "Invalid payload";
case policy_violation:
return "Policy violoation";
case message_too_big:
return "Message too big";
case extension_required:
return "Extension required";
case internal_endpoint_error:
return "Internal endpoint error";
case service_restart:
return "Service restart";
case try_again_later:
return "Try again later";
case bad_gateway:
return "Bad gateway";
case tls_handshake:
return "TLS handshake failure";
case subprotocol_error:
return "Generic subprotocol error";
case invalid_subprotocol_data:
return "Invalid subprotocol data";
default:
return "Unknown";
}
}
} // namespace status
/// Type used to convert close statuses between integer and wire representations
union code_converter {
uint16_t i;
char c[2];
};
/// Extract a close code value from a close payload
/**
* If there is no close value (ie string is empty) status::no_status is
* returned. If a code couldn't be extracted (usually do to a short or
* otherwise mangled payload) status::protocol_error is returned and the ec
* value is flagged as an error. Note that this case is different than the case
* where protocol error is received over the wire.
*
* If the value is in an invalid or reserved range ec is set accordingly.
*
* @param [in] payload Close frame payload value received over the wire.
* @param [out] ec Set to indicate what error occurred, if any.
* @return The extracted value
*/
inline status::value extract_code(std::string const & payload, lib::error_code
& ec)
{
ec = lib::error_code();
if (payload.size() == 0) {
return status::no_status;
} else if (payload.size() == 1) {
ec = make_error_code(error::bad_close_code);
return status::protocol_error;
}
code_converter val;
val.c[0] = payload[0];
val.c[1] = payload[1];
status::value code(ntohs(val.i));
if (status::invalid(code)) {
ec = make_error_code(error::invalid_close_code);
}
if (status::reserved(code)) {
ec = make_error_code(error::reserved_close_code);
}
return code;
}
/// Extract the reason string from a close payload
/**
* The string should be a valid UTF8 message. error::invalid_utf8 will be set if
* the function extracts a reason that is not valid UTF8.
*
* @param [in] payload The payload string to extract a reason from.
* @param [out] ec Set to indicate what error occurred, if any.
* @return The reason string.
*/
inline std::string extract_reason(std::string const & payload, lib::error_code
& ec)
{
std::string reason;
ec = lib::error_code();
if (payload.size() > 2) {
reason.append(payload.begin()+2,payload.end());
}
if (!websocketpp::utf8_validator::validate(reason)) {
ec = make_error_code(error::invalid_utf8);
}
return reason;
}
} // namespace close
} // namespace websocketpp
#endif // WEBSOCKETPP_CLOSE_HPP

View File

@ -0,0 +1,141 @@
/*
* Copyright (c) 2015, Peter Thorson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef WEBSOCKETPP_COMMON_ASIO_HPP
#define WEBSOCKETPP_COMMON_ASIO_HPP
// This file goes to some length to preserve compatibility with versions of
// boost older than 1.49 (where the first modern steady_timer timer based on
// boost/std chrono was introduced.
//
// For the versions older than 1.49, the deadline_timer is used instead. this
// brings in dependencies on boost date_time and it has a different interface
// that is normalized by the `lib::asio::is_neg` and `lib::asio::milliseconds`
// wrappers provided by this file.
//
// The primary reason for this continued support is that boost 1.48 is the
// default and not easily changeable version of boost supplied by the package
// manager of popular Linux distributions like Ubuntu 12.04 LTS. Once the need
// for this has passed this should be cleaned up and simplified.
#ifdef ASIO_STANDALONE
#include <asio/version.hpp>
#if (ASIO_VERSION/100000) == 1 && ((ASIO_VERSION/100)%1000) < 8
static_assert(false, "The minimum version of standalone Asio is 1.8.0");
#endif
#include <asio.hpp>
#include <asio/steady_timer.hpp>
#include <websocketpp/common/chrono.hpp>
#else
#include <boost/version.hpp>
// See note above about boost <1.49 compatibility. If we are running on
// boost > 1.48 pull in the steady timer and chrono library
#if (BOOST_VERSION/100000) == 1 && ((BOOST_VERSION/100)%1000) > 48
#include <boost/asio/steady_timer.hpp>
#include <websocketpp/common/chrono.hpp>
#endif
#include <boost/asio.hpp>
#include <boost/system/error_code.hpp>
#endif
namespace websocketpp {
namespace lib {
#ifdef ASIO_STANDALONE
namespace asio {
using namespace ::asio;
// Here we assume that we will be using std::error_code with standalone
// Asio. This is probably a good assumption, but it is possible in rare
// cases that local Asio versions would be used.
using std::errc;
// See note above about boost <1.49 compatibility. Because we require
// a standalone Asio version of 1.8+ we are guaranteed to have
// steady_timer available. By convention we require the chrono library
// (either boost or std) for use with standalone Asio.
template <typename T>
bool is_neg(T duration) {
return duration.count() < 0;
}
inline lib::chrono::milliseconds milliseconds(long duration) {
return lib::chrono::milliseconds(duration);
}
} // namespace asio
#else
namespace asio {
using namespace boost::asio;
// See note above about boost <1.49 compatibility
#if (BOOST_VERSION/100000) == 1 && ((BOOST_VERSION/100)%1000) > 48
// Using boost::asio >=1.49 so we use chrono and steady_timer
template <typename T>
bool is_neg(T duration) {
return duration.count() < 0;
}
// If boost believes it has std::chrono available it will use it
// so we should also use it for things that relate to boost, even
// if the library would otherwise use boost::chrono.
#if defined(BOOST_ASIO_HAS_STD_CHRONO)
inline std::chrono::milliseconds milliseconds(long duration) {
return std::chrono::milliseconds(duration);
}
#else
inline lib::chrono::milliseconds milliseconds(long duration) {
return lib::chrono::milliseconds(duration);
}
#endif
#else
// Using boost::asio <1.49 we pretend a deadline timer is a steady
// timer and wrap the negative detection and duration conversion
// appropriately.
typedef boost::asio::deadline_timer steady_timer;
template <typename T>
bool is_neg(T duration) {
return duration.is_negative();
}
inline boost::posix_time::time_duration milliseconds(long duration) {
return boost::posix_time::milliseconds(duration);
}
#endif
using boost::system::error_code;
namespace errc = boost::system::errc;
} // namespace asio
#endif
} // namespace lib
} // namespace websocketpp
#endif // WEBSOCKETPP_COMMON_ASIO_HPP

View File

@ -0,0 +1,39 @@
/*
* Copyright (c) 2015, Peter Thorson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef WEBSOCKETPP_COMMON_ASIO_SSL_HPP
#define WEBSOCKETPP_COMMON_ASIO_SSL_HPP
// NOTE: This file must be included before common/asio.hpp
#ifdef ASIO_STANDALONE
#include <asio/ssl.hpp>
#else
#include <boost/asio/ssl.hpp>
#endif
#endif // WEBSOCKETPP_COMMON_ASIO_SSL_HPP

View File

@ -0,0 +1,68 @@
/*
* Copyright (c) 2015, Peter Thorson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef WEBSOCKETPP_COMMON_CHRONO_HPP
#define WEBSOCKETPP_COMMON_CHRONO_HPP
#include <websocketpp/common/cpp11.hpp>
// If we've determined that we're in full C++11 mode and the user hasn't
// explicitly disabled the use of C++11 functional header, then prefer it to
// boost.
#if defined _WEBSOCKETPP_CPP11_INTERNAL_ && !defined _WEBSOCKETPP_NO_CPP11_CHRONO_
#ifndef _WEBSOCKETPP_CPP11_CHRONO_
#define _WEBSOCKETPP_CPP11_CHRONO_
#endif
#endif
// If we're on Visual Studio 2012 or higher and haven't explicitly disabled
// the use of C++11 chrono header then prefer it to boost.
#if defined(_MSC_VER) && _MSC_VER >= 1700 && !defined _WEBSOCKETPP_NO_CPP11_CHRONO_
#ifndef _WEBSOCKETPP_CPP11_CHRONO_
#define _WEBSOCKETPP_CPP11_CHRONO_
#endif
#endif
#ifdef _WEBSOCKETPP_CPP11_CHRONO_
#include <chrono>
#else
#include <boost/chrono.hpp>
#endif
namespace websocketpp {
namespace lib {
#ifdef _WEBSOCKETPP_CPP11_CHRONO_
namespace chrono = std::chrono;
#else
namespace chrono = boost::chrono;
#endif
} // namespace lib
} // namespace websocketpp
#endif // WEBSOCKETPP_COMMON_CHRONO_HPP

View File

@ -0,0 +1,52 @@
/*
* Copyright (c) 2014, 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_COMMON_CONNECTION_HDL_HPP
#define WEBSOCKETPP_COMMON_CONNECTION_HDL_HPP
#include <websocketpp/common/memory.hpp>
namespace websocketpp {
/// A handle to uniquely identify a connection.
/**
* This type uniquely identifies a connection. It is implemented as a weak
* pointer to the connection in question. This provides uniqueness across
* multiple endpoints and ensures that IDs never conflict or run out.
*
* It is safe to make copies of this handle, store those copies in containers,
* and use them from other threads.
*
* This handle can be upgraded to a full shared_ptr using
* `endpoint::get_con_from_hdl()` from within a handler fired by the connection
* that owns the handler.
*/
typedef lib::weak_ptr<void> connection_hdl;
} // namespace websocketpp
#endif // WEBSOCKETPP_COMMON_CONNECTION_HDL_HPP

View File

@ -0,0 +1,162 @@
/*
* Copyright (c) 2014, 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_COMMON_CPP11_HPP
#define WEBSOCKETPP_COMMON_CPP11_HPP
/**
* This header sets up some constants based on the state of C++11 support
*/
// Hide clang feature detection from other compilers
#ifndef __has_feature // Optional of course.
#define __has_feature(x) 0 // Compatibility with non-clang compilers.
#endif
#ifndef __has_extension
#define __has_extension __has_feature // Compatibility with pre-3.0 compilers.
#endif
// The code below attempts to use information provided by the build system or
// user supplied defines to selectively enable C++11 language and library
// features. In most cases features that are targeted individually may also be
// selectively disabled via an associated _WEBSOCKETPP_NOXXX_ define.
#if defined(_WEBSOCKETPP_CPP11_STL_) || __cplusplus >= 201103L || defined(_WEBSOCKETPP_CPP11_STRICT_)
// This check tests for blanket c++11 coverage. It can be activated in one
// of three ways. Either the compiler itself reports that it is a full
// C++11 compiler via the __cplusplus macro or the user/build system
// supplies one of the two preprocessor defines below:
// This is defined to allow other WebSocket++ common headers to enable
// C++11 features when they are detected by this file rather than
// duplicating the above logic in every common header.
#define _WEBSOCKETPP_CPP11_INTERNAL_
// _WEBSOCKETPP_CPP11_STRICT_
//
// This define reports to WebSocket++ that 100% of the language and library
// features of C++11 are available. Using this define on a non-C++11
// compiler will result in problems.
// _WEBSOCKETPP_CPP11_STL_
//
// This define enables *most* C++11 options that were implemented early on
// by compilers. It is typically used for compilers that have many, but not
// all C++11 features. It should be safe to use on GCC 4.7-4.8 and perhaps
// earlier.
#ifndef _WEBSOCKETPP_NOEXCEPT_TOKEN_
#define _WEBSOCKETPP_NOEXCEPT_TOKEN_ noexcept
#endif
#ifndef _WEBSOCKETPP_CONSTEXPR_TOKEN_
#define _WEBSOCKETPP_CONSTEXPR_TOKEN_ constexpr
#endif
#ifndef _WEBSOCKETPP_INITIALIZER_LISTS_
#define _WEBSOCKETPP_INITIALIZER_LISTS_
#endif
#ifndef _WEBSOCKETPP_NULLPTR_TOKEN_
#define _WEBSOCKETPP_NULLPTR_TOKEN_ nullptr
#endif
#ifndef _WEBSOCKETPP_MOVE_SEMANTICS_
#define _WEBSOCKETPP_MOVE_SEMANTICS_
#endif
#ifndef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
#define _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
#endif
#ifndef __GNUC__
// GCC as of version 4.9 (latest) does not support std::put_time yet.
// so ignore it
#define _WEBSOCKETPP_PUTTIME_
#endif
#else
// In the absence of a blanket define, try to use compiler versions or
// feature testing macros to selectively enable what we can.
// Test for noexcept
#ifndef _WEBSOCKETPP_NOEXCEPT_TOKEN_
#ifdef _WEBSOCKETPP_NOEXCEPT_
// build system says we have noexcept
#define _WEBSOCKETPP_NOEXCEPT_TOKEN_ noexcept
#else
#if __has_feature(cxx_noexcept)
// clang feature detect says we have noexcept
#define _WEBSOCKETPP_NOEXCEPT_TOKEN_ noexcept
#elif defined(_MSC_VER) && _MSC_VER >= 1900
// Visual Studio 2015+ has noexcept
#define _WEBSOCKETPP_NOEXCEPT_TOKEN_ noexcept
#else
// assume we don't have noexcept
#define _WEBSOCKETPP_NOEXCEPT_TOKEN_
#endif
#endif
#endif
// Test for constexpr
#ifndef _WEBSOCKETPP_CONSTEXPR_TOKEN_
#ifdef _WEBSOCKETPP_CONSTEXPR_
// build system says we have constexpr
#define _WEBSOCKETPP_CONSTEXPR_TOKEN_ constexpr
#else
#if __has_feature(cxx_constexpr)
// clang feature detect says we have constexpr
#define _WEBSOCKETPP_CONSTEXPR_TOKEN_ constexpr
#elif defined(_MSC_VER) && _MSC_VER >= 1900
// Visual Studio 2015+ has constexpr
#define _WEBSOCKETPP_CONSTEXPR_TOKEN_ constexpr
#else
// assume we don't have constexpr
#define _WEBSOCKETPP_CONSTEXPR_TOKEN_
#endif
#endif
#endif
// Enable initializer lists on clang when available.
#if __has_feature(cxx_generalized_initializers) && !defined(_WEBSOCKETPP_INITIALIZER_LISTS_)
#define _WEBSOCKETPP_INITIALIZER_LISTS_
#endif
// Test for nullptr
#ifndef _WEBSOCKETPP_NULLPTR_TOKEN_
#ifdef _WEBSOCKETPP_NULLPTR_
// build system says we have nullptr
#define _WEBSOCKETPP_NULLPTR_TOKEN_ nullptr
#else
#if __has_feature(cxx_nullptr)
// clang feature detect says we have nullptr
#define _WEBSOCKETPP_NULLPTR_TOKEN_ nullptr
#elif defined(_MSC_VER) &&_MSC_VER >= 1600
// Visual Studio version that has nullptr
#define _WEBSOCKETPP_NULLPTR_TOKEN_ nullptr
#else
// assume we don't have nullptr
#define _WEBSOCKETPP_NULLPTR_TOKEN_ 0
#endif
#endif
#endif
#endif
#endif // WEBSOCKETPP_COMMON_CPP11_HPP

View File

@ -0,0 +1,105 @@
/*
* Copyright (c) 2014, 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_COMMON_FUNCTIONAL_HPP
#define WEBSOCKETPP_COMMON_FUNCTIONAL_HPP
#include <websocketpp/common/cpp11.hpp>
// If we've determined that we're in full C++11 mode and the user hasn't
// explicitly disabled the use of C++11 functional header, then prefer it to
// boost.
#if defined _WEBSOCKETPP_CPP11_INTERNAL_ && !defined _WEBSOCKETPP_NO_CPP11_FUNCTIONAL_
#ifndef _WEBSOCKETPP_CPP11_FUNCTIONAL_
#define _WEBSOCKETPP_CPP11_FUNCTIONAL_
#endif
#endif
// If we're on Visual Studio 2010 or higher and haven't explicitly disabled
// the use of C++11 functional header then prefer it to boost.
#if defined(_MSC_VER) && _MSC_VER >= 1600 && !defined _WEBSOCKETPP_NO_CPP11_FUNCTIONAL_
#ifndef _WEBSOCKETPP_CPP11_FUNCTIONAL_
#define _WEBSOCKETPP_CPP11_FUNCTIONAL_
#endif
#endif
#ifdef _WEBSOCKETPP_CPP11_FUNCTIONAL_
#include <functional>
#else
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/ref.hpp>
#endif
namespace websocketpp {
namespace lib {
#ifdef _WEBSOCKETPP_CPP11_FUNCTIONAL_
using std::function;
using std::bind;
using std::ref;
namespace placeholders = std::placeholders;
// There are some cases where a C++11 compiler balks at using std::ref
// but a C++03 compiler using boost function requires boost::ref. As such
// lib::ref is not useful in these cases. Instead this macro allows the use
// of boost::ref in the case of a boost compile or no reference wrapper at
// all in the case of a C++11 compile
#define _WEBSOCKETPP_REF(x) x
template <typename T>
void clear_function(T & x) {
x = nullptr;
}
#else
using boost::function;
using boost::bind;
using boost::ref;
namespace placeholders {
/// \todo this feels hacky, is there a better way?
using ::_1;
using ::_2;
using ::_3;
}
// See above definition for more details on what this is and why it exists
#define _WEBSOCKETPP_REF(x) boost::ref(x)
template <typename T>
void clear_function(T & x) {
x.clear();
}
#endif
} // namespace lib
} // namespace websocketpp
#endif // WEBSOCKETPP_COMMON_FUNCTIONAL_HPP

View File

@ -0,0 +1,448 @@
/*
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
*/
/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */
/*
Independent implementation of MD5 (RFC 1321).
This code implements the MD5 Algorithm defined in RFC 1321, whose
text is available at
http://www.ietf.org/rfc/rfc1321.txt
The code is derived from the text of the RFC, including the test suite
(section A.5) but excluding the rest of Appendix A. It does not include
any code or documentation that is identified in the RFC as being
copyrighted.
The original and principal author of md5.h is L. Peter Deutsch
<ghost@aladdin.com>. Other authors are noted in the change history
that follows (in reverse chronological order):
2002-04-13 lpd Removed support for non-ANSI compilers; removed
references to Ghostscript; clarified derivation from RFC 1321;
now handles byte order either statically or dynamically.
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
added conditionalization for C++ compilation from Martin
Purschke <purschke@bnl.gov>.
1999-05-03 lpd Original version.
*/
#ifndef WEBSOCKETPP_COMMON_MD5_HPP
#define WEBSOCKETPP_COMMON_MD5_HPP
/*
* This package supports both compile-time and run-time determination of CPU
* byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
* compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
* defined as non-zero, the code will be compiled to run only on big-endian
* CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
* run on either big- or little-endian CPUs, but will run slightly less
* efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
*/
#include <stddef.h>
#include <string>
#include <cstring>
namespace websocketpp {
/// Provides MD5 hashing functionality
namespace md5 {
typedef unsigned char md5_byte_t; /* 8-bit byte */
typedef unsigned int md5_word_t; /* 32-bit word */
/* Define the state of the MD5 Algorithm. */
typedef struct md5_state_s {
md5_word_t count[2]; /* message length in bits, lsw first */
md5_word_t abcd[4]; /* digest buffer */
md5_byte_t buf[64]; /* accumulate block */
} md5_state_t;
/* Initialize the algorithm. */
inline void md5_init(md5_state_t *pms);
/* Append a string to the message. */
inline void md5_append(md5_state_t *pms, md5_byte_t const * data, size_t nbytes);
/* Finish the message and return the digest. */
inline void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
#undef ZSW_MD5_BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
#ifdef ARCH_IS_BIG_ENDIAN
# define ZSW_MD5_BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
#else
# define ZSW_MD5_BYTE_ORDER 0
#endif
#define ZSW_MD5_T_MASK ((md5_word_t)~0)
#define ZSW_MD5_T1 /* 0xd76aa478 */ (ZSW_MD5_T_MASK ^ 0x28955b87)
#define ZSW_MD5_T2 /* 0xe8c7b756 */ (ZSW_MD5_T_MASK ^ 0x173848a9)
#define ZSW_MD5_T3 0x242070db
#define ZSW_MD5_T4 /* 0xc1bdceee */ (ZSW_MD5_T_MASK ^ 0x3e423111)
#define ZSW_MD5_T5 /* 0xf57c0faf */ (ZSW_MD5_T_MASK ^ 0x0a83f050)
#define ZSW_MD5_T6 0x4787c62a
#define ZSW_MD5_T7 /* 0xa8304613 */ (ZSW_MD5_T_MASK ^ 0x57cfb9ec)
#define ZSW_MD5_T8 /* 0xfd469501 */ (ZSW_MD5_T_MASK ^ 0x02b96afe)
#define ZSW_MD5_T9 0x698098d8
#define ZSW_MD5_T10 /* 0x8b44f7af */ (ZSW_MD5_T_MASK ^ 0x74bb0850)
#define ZSW_MD5_T11 /* 0xffff5bb1 */ (ZSW_MD5_T_MASK ^ 0x0000a44e)
#define ZSW_MD5_T12 /* 0x895cd7be */ (ZSW_MD5_T_MASK ^ 0x76a32841)
#define ZSW_MD5_T13 0x6b901122
#define ZSW_MD5_T14 /* 0xfd987193 */ (ZSW_MD5_T_MASK ^ 0x02678e6c)
#define ZSW_MD5_T15 /* 0xa679438e */ (ZSW_MD5_T_MASK ^ 0x5986bc71)
#define ZSW_MD5_T16 0x49b40821
#define ZSW_MD5_T17 /* 0xf61e2562 */ (ZSW_MD5_T_MASK ^ 0x09e1da9d)
#define ZSW_MD5_T18 /* 0xc040b340 */ (ZSW_MD5_T_MASK ^ 0x3fbf4cbf)
#define ZSW_MD5_T19 0x265e5a51
#define ZSW_MD5_T20 /* 0xe9b6c7aa */ (ZSW_MD5_T_MASK ^ 0x16493855)
#define ZSW_MD5_T21 /* 0xd62f105d */ (ZSW_MD5_T_MASK ^ 0x29d0efa2)
#define ZSW_MD5_T22 0x02441453
#define ZSW_MD5_T23 /* 0xd8a1e681 */ (ZSW_MD5_T_MASK ^ 0x275e197e)
#define ZSW_MD5_T24 /* 0xe7d3fbc8 */ (ZSW_MD5_T_MASK ^ 0x182c0437)
#define ZSW_MD5_T25 0x21e1cde6
#define ZSW_MD5_T26 /* 0xc33707d6 */ (ZSW_MD5_T_MASK ^ 0x3cc8f829)
#define ZSW_MD5_T27 /* 0xf4d50d87 */ (ZSW_MD5_T_MASK ^ 0x0b2af278)
#define ZSW_MD5_T28 0x455a14ed
#define ZSW_MD5_T29 /* 0xa9e3e905 */ (ZSW_MD5_T_MASK ^ 0x561c16fa)
#define ZSW_MD5_T30 /* 0xfcefa3f8 */ (ZSW_MD5_T_MASK ^ 0x03105c07)
#define ZSW_MD5_T31 0x676f02d9
#define ZSW_MD5_T32 /* 0x8d2a4c8a */ (ZSW_MD5_T_MASK ^ 0x72d5b375)
#define ZSW_MD5_T33 /* 0xfffa3942 */ (ZSW_MD5_T_MASK ^ 0x0005c6bd)
#define ZSW_MD5_T34 /* 0x8771f681 */ (ZSW_MD5_T_MASK ^ 0x788e097e)
#define ZSW_MD5_T35 0x6d9d6122
#define ZSW_MD5_T36 /* 0xfde5380c */ (ZSW_MD5_T_MASK ^ 0x021ac7f3)
#define ZSW_MD5_T37 /* 0xa4beea44 */ (ZSW_MD5_T_MASK ^ 0x5b4115bb)
#define ZSW_MD5_T38 0x4bdecfa9
#define ZSW_MD5_T39 /* 0xf6bb4b60 */ (ZSW_MD5_T_MASK ^ 0x0944b49f)
#define ZSW_MD5_T40 /* 0xbebfbc70 */ (ZSW_MD5_T_MASK ^ 0x4140438f)
#define ZSW_MD5_T41 0x289b7ec6
#define ZSW_MD5_T42 /* 0xeaa127fa */ (ZSW_MD5_T_MASK ^ 0x155ed805)
#define ZSW_MD5_T43 /* 0xd4ef3085 */ (ZSW_MD5_T_MASK ^ 0x2b10cf7a)
#define ZSW_MD5_T44 0x04881d05
#define ZSW_MD5_T45 /* 0xd9d4d039 */ (ZSW_MD5_T_MASK ^ 0x262b2fc6)
#define ZSW_MD5_T46 /* 0xe6db99e5 */ (ZSW_MD5_T_MASK ^ 0x1924661a)
#define ZSW_MD5_T47 0x1fa27cf8
#define ZSW_MD5_T48 /* 0xc4ac5665 */ (ZSW_MD5_T_MASK ^ 0x3b53a99a)
#define ZSW_MD5_T49 /* 0xf4292244 */ (ZSW_MD5_T_MASK ^ 0x0bd6ddbb)
#define ZSW_MD5_T50 0x432aff97
#define ZSW_MD5_T51 /* 0xab9423a7 */ (ZSW_MD5_T_MASK ^ 0x546bdc58)
#define ZSW_MD5_T52 /* 0xfc93a039 */ (ZSW_MD5_T_MASK ^ 0x036c5fc6)
#define ZSW_MD5_T53 0x655b59c3
#define ZSW_MD5_T54 /* 0x8f0ccc92 */ (ZSW_MD5_T_MASK ^ 0x70f3336d)
#define ZSW_MD5_T55 /* 0xffeff47d */ (ZSW_MD5_T_MASK ^ 0x00100b82)
#define ZSW_MD5_T56 /* 0x85845dd1 */ (ZSW_MD5_T_MASK ^ 0x7a7ba22e)
#define ZSW_MD5_T57 0x6fa87e4f
#define ZSW_MD5_T58 /* 0xfe2ce6e0 */ (ZSW_MD5_T_MASK ^ 0x01d3191f)
#define ZSW_MD5_T59 /* 0xa3014314 */ (ZSW_MD5_T_MASK ^ 0x5cfebceb)
#define ZSW_MD5_T60 0x4e0811a1
#define ZSW_MD5_T61 /* 0xf7537e82 */ (ZSW_MD5_T_MASK ^ 0x08ac817d)
#define ZSW_MD5_T62 /* 0xbd3af235 */ (ZSW_MD5_T_MASK ^ 0x42c50dca)
#define ZSW_MD5_T63 0x2ad7d2bb
#define ZSW_MD5_T64 /* 0xeb86d391 */ (ZSW_MD5_T_MASK ^ 0x14792c6e)
static void md5_process(md5_state_t *pms, md5_byte_t const * data /*[64]*/) {
md5_word_t
a = pms->abcd[0], b = pms->abcd[1],
c = pms->abcd[2], d = pms->abcd[3];
md5_word_t t;
#if ZSW_MD5_BYTE_ORDER > 0
/* Define storage only for big-endian CPUs. */
md5_word_t X[16];
#else
/* Define storage for little-endian or both types of CPUs. */
md5_word_t xbuf[16];
md5_word_t const * X;
#endif
{
#if ZSW_MD5_BYTE_ORDER == 0
/*
* Determine dynamically whether this is a big-endian or
* little-endian machine, since we can use a more efficient
* algorithm on the latter.
*/
static int const w = 1;
if (*((md5_byte_t const *)&w)) /* dynamic little-endian */
#endif
#if ZSW_MD5_BYTE_ORDER <= 0 /* little-endian */
{
/*
* On little-endian machines, we can process properly aligned
* data without copying it.
*/
if (!((data - (md5_byte_t const *)0) & 3)) {
/* data are properly aligned */
X = (md5_word_t const *)data;
} else {
/* not aligned */
std::memcpy(xbuf, data, 64);
X = xbuf;
}
}
#endif
#if ZSW_MD5_BYTE_ORDER == 0
else /* dynamic big-endian */
#endif
#if ZSW_MD5_BYTE_ORDER >= 0 /* big-endian */
{
/*
* On big-endian machines, we must arrange the bytes in the
* right order.
*/
const md5_byte_t *xp = data;
int i;
# if ZSW_MD5_BYTE_ORDER == 0
X = xbuf; /* (dynamic only) */
# else
# define xbuf X /* (static only) */
# endif
for (i = 0; i < 16; ++i, xp += 4)
xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
}
#endif
}
#define ZSW_MD5_ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
/* Round 1. */
/* Let [abcd k s i] denote the operation
a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
#define ZSW_MD5_F(x, y, z) (((x) & (y)) | (~(x) & (z)))
#define SET(a, b, c, d, k, s, Ti)\
t = a + ZSW_MD5_F(b,c,d) + X[k] + Ti;\
a = ZSW_MD5_ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 0, 7, ZSW_MD5_T1);
SET(d, a, b, c, 1, 12, ZSW_MD5_T2);
SET(c, d, a, b, 2, 17, ZSW_MD5_T3);
SET(b, c, d, a, 3, 22, ZSW_MD5_T4);
SET(a, b, c, d, 4, 7, ZSW_MD5_T5);
SET(d, a, b, c, 5, 12, ZSW_MD5_T6);
SET(c, d, a, b, 6, 17, ZSW_MD5_T7);
SET(b, c, d, a, 7, 22, ZSW_MD5_T8);
SET(a, b, c, d, 8, 7, ZSW_MD5_T9);
SET(d, a, b, c, 9, 12, ZSW_MD5_T10);
SET(c, d, a, b, 10, 17, ZSW_MD5_T11);
SET(b, c, d, a, 11, 22, ZSW_MD5_T12);
SET(a, b, c, d, 12, 7, ZSW_MD5_T13);
SET(d, a, b, c, 13, 12, ZSW_MD5_T14);
SET(c, d, a, b, 14, 17, ZSW_MD5_T15);
SET(b, c, d, a, 15, 22, ZSW_MD5_T16);
#undef SET
/* Round 2. */
/* Let [abcd k s i] denote the operation
a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
#define ZSW_MD5_G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
#define SET(a, b, c, d, k, s, Ti)\
t = a + ZSW_MD5_G(b,c,d) + X[k] + Ti;\
a = ZSW_MD5_ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 1, 5, ZSW_MD5_T17);
SET(d, a, b, c, 6, 9, ZSW_MD5_T18);
SET(c, d, a, b, 11, 14, ZSW_MD5_T19);
SET(b, c, d, a, 0, 20, ZSW_MD5_T20);
SET(a, b, c, d, 5, 5, ZSW_MD5_T21);
SET(d, a, b, c, 10, 9, ZSW_MD5_T22);
SET(c, d, a, b, 15, 14, ZSW_MD5_T23);
SET(b, c, d, a, 4, 20, ZSW_MD5_T24);
SET(a, b, c, d, 9, 5, ZSW_MD5_T25);
SET(d, a, b, c, 14, 9, ZSW_MD5_T26);
SET(c, d, a, b, 3, 14, ZSW_MD5_T27);
SET(b, c, d, a, 8, 20, ZSW_MD5_T28);
SET(a, b, c, d, 13, 5, ZSW_MD5_T29);
SET(d, a, b, c, 2, 9, ZSW_MD5_T30);
SET(c, d, a, b, 7, 14, ZSW_MD5_T31);
SET(b, c, d, a, 12, 20, ZSW_MD5_T32);
#undef SET
/* Round 3. */
/* Let [abcd k s t] denote the operation
a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
#define ZSW_MD5_H(x, y, z) ((x) ^ (y) ^ (z))
#define SET(a, b, c, d, k, s, Ti)\
t = a + ZSW_MD5_H(b,c,d) + X[k] + Ti;\
a = ZSW_MD5_ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 5, 4, ZSW_MD5_T33);
SET(d, a, b, c, 8, 11, ZSW_MD5_T34);
SET(c, d, a, b, 11, 16, ZSW_MD5_T35);
SET(b, c, d, a, 14, 23, ZSW_MD5_T36);
SET(a, b, c, d, 1, 4, ZSW_MD5_T37);
SET(d, a, b, c, 4, 11, ZSW_MD5_T38);
SET(c, d, a, b, 7, 16, ZSW_MD5_T39);
SET(b, c, d, a, 10, 23, ZSW_MD5_T40);
SET(a, b, c, d, 13, 4, ZSW_MD5_T41);
SET(d, a, b, c, 0, 11, ZSW_MD5_T42);
SET(c, d, a, b, 3, 16, ZSW_MD5_T43);
SET(b, c, d, a, 6, 23, ZSW_MD5_T44);
SET(a, b, c, d, 9, 4, ZSW_MD5_T45);
SET(d, a, b, c, 12, 11, ZSW_MD5_T46);
SET(c, d, a, b, 15, 16, ZSW_MD5_T47);
SET(b, c, d, a, 2, 23, ZSW_MD5_T48);
#undef SET
/* Round 4. */
/* Let [abcd k s t] denote the operation
a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
#define ZSW_MD5_I(x, y, z) ((y) ^ ((x) | ~(z)))
#define SET(a, b, c, d, k, s, Ti)\
t = a + ZSW_MD5_I(b,c,d) + X[k] + Ti;\
a = ZSW_MD5_ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 0, 6, ZSW_MD5_T49);
SET(d, a, b, c, 7, 10, ZSW_MD5_T50);
SET(c, d, a, b, 14, 15, ZSW_MD5_T51);
SET(b, c, d, a, 5, 21, ZSW_MD5_T52);
SET(a, b, c, d, 12, 6, ZSW_MD5_T53);
SET(d, a, b, c, 3, 10, ZSW_MD5_T54);
SET(c, d, a, b, 10, 15, ZSW_MD5_T55);
SET(b, c, d, a, 1, 21, ZSW_MD5_T56);
SET(a, b, c, d, 8, 6, ZSW_MD5_T57);
SET(d, a, b, c, 15, 10, ZSW_MD5_T58);
SET(c, d, a, b, 6, 15, ZSW_MD5_T59);
SET(b, c, d, a, 13, 21, ZSW_MD5_T60);
SET(a, b, c, d, 4, 6, ZSW_MD5_T61);
SET(d, a, b, c, 11, 10, ZSW_MD5_T62);
SET(c, d, a, b, 2, 15, ZSW_MD5_T63);
SET(b, c, d, a, 9, 21, ZSW_MD5_T64);
#undef SET
/* Then perform the following additions. (That is increment each
of the four registers by the value it had before this block
was started.) */
pms->abcd[0] += a;
pms->abcd[1] += b;
pms->abcd[2] += c;
pms->abcd[3] += d;
}
void md5_init(md5_state_t *pms) {
pms->count[0] = pms->count[1] = 0;
pms->abcd[0] = 0x67452301;
pms->abcd[1] = /*0xefcdab89*/ ZSW_MD5_T_MASK ^ 0x10325476;
pms->abcd[2] = /*0x98badcfe*/ ZSW_MD5_T_MASK ^ 0x67452301;
pms->abcd[3] = 0x10325476;
}
void md5_append(md5_state_t *pms, md5_byte_t const * data, size_t nbytes) {
md5_byte_t const * p = data;
size_t left = nbytes;
int offset = (pms->count[0] >> 3) & 63;
md5_word_t nbits = (md5_word_t)(nbytes << 3);
if (nbytes <= 0)
return;
/* Update the message length. */
pms->count[1] += nbytes >> 29;
pms->count[0] += nbits;
if (pms->count[0] < nbits)
pms->count[1]++;
/* Process an initial partial block. */
if (offset) {
int copy = (offset + nbytes > 64 ? 64 - offset : static_cast<int>(nbytes));
std::memcpy(pms->buf + offset, p, copy);
if (offset + copy < 64)
return;
p += copy;
left -= copy;
md5_process(pms, pms->buf);
}
/* Process full blocks. */
for (; left >= 64; p += 64, left -= 64)
md5_process(pms, p);
/* Process a final partial block. */
if (left)
std::memcpy(pms->buf, p, left);
}
void md5_finish(md5_state_t *pms, md5_byte_t digest[16]) {
static md5_byte_t const pad[64] = {
0x80, 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, 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
};
md5_byte_t data[8];
int i;
/* Save the length before padding. */
for (i = 0; i < 8; ++i)
data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
/* Pad to 56 bytes mod 64. */
md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
/* Append the length. */
md5_append(pms, data, 8);
for (i = 0; i < 16; ++i)
digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
}
// some convenience c++ functions
inline std::string md5_hash_string(std::string const & s) {
char digest[16];
md5_state_t state;
md5_init(&state);
md5_append(&state, (md5_byte_t const *)s.c_str(), s.size());
md5_finish(&state, (md5_byte_t *)digest);
std::string ret;
ret.resize(16);
std::copy(digest,digest+16,ret.begin());
return ret;
}
const char hexval[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
inline std::string md5_hash_hex(std::string const & input) {
std::string hash = md5_hash_string(input);
std::string hex;
for (size_t i = 0; i < hash.size(); i++) {
hex.push_back(hexval[((hash[i] >> 4) & 0xF)]);
hex.push_back(hexval[(hash[i]) & 0x0F]);
}
return hex;
}
} // md5
} // websocketpp
#endif // WEBSOCKETPP_COMMON_MD5_HPP

View File

@ -0,0 +1,88 @@
/*
* Copyright (c) 2014, 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_COMMON_MEMORY_HPP
#define WEBSOCKETPP_COMMON_MEMORY_HPP
#include <websocketpp/common/cpp11.hpp>
// If we've determined that we're in full C++11 mode and the user hasn't
// explicitly disabled the use of C++11 memory header, then prefer it to
// boost.
#if defined _WEBSOCKETPP_CPP11_INTERNAL_ && !defined _WEBSOCKETPP_NO_CPP11_MEMORY_
#ifndef _WEBSOCKETPP_CPP11_MEMORY_
#define _WEBSOCKETPP_CPP11_MEMORY_
#endif
#endif
// If we're on Visual Studio 2010 or higher and haven't explicitly disabled
// the use of C++11 functional header then prefer it to boost.
#if defined(_MSC_VER) && _MSC_VER >= 1600 && !defined _WEBSOCKETPP_NO_CPP11_MEMORY_
#ifndef _WEBSOCKETPP_CPP11_MEMORY_
#define _WEBSOCKETPP_CPP11_MEMORY_
#endif
#endif
#ifdef _WEBSOCKETPP_CPP11_MEMORY_
#include <memory>
#else
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/scoped_array.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/pointer_cast.hpp>
#endif
namespace websocketpp {
namespace lib {
#ifdef _WEBSOCKETPP_CPP11_MEMORY_
using std::shared_ptr;
using std::weak_ptr;
using std::enable_shared_from_this;
using std::static_pointer_cast;
using std::make_shared;
using std::unique_ptr;
typedef std::unique_ptr<unsigned char[]> unique_ptr_uchar_array;
#else
using boost::shared_ptr;
using boost::weak_ptr;
using std::auto_ptr;
using boost::enable_shared_from_this;
using boost::static_pointer_cast;
using boost::make_shared;
typedef boost::scoped_array<unsigned char> unique_ptr_uchar_array;
#endif
} // namespace lib
} // namespace websocketpp
#endif // WEBSOCKETPP_COMMON_MEMORY_HPP

View File

@ -0,0 +1,106 @@
/*
* Copyright (c) 2014, 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_COMMON_NETWORK_HPP
#define WEBSOCKETPP_COMMON_NETWORK_HPP
// For ntohs and htons
#if defined(_WIN32)
#include <winsock2.h>
#else
//#include <arpa/inet.h>
#include <netinet/in.h>
#endif
#include <websocketpp/common/stdint.hpp>
namespace websocketpp {
namespace lib {
namespace net {
inline bool is_little_endian() {
short int val = 0x1;
char *ptr = reinterpret_cast<char *>(&val);
return (ptr[0] == 1);
}
#define TYP_INIT 0
#define TYP_SMLE 1
#define TYP_BIGE 2
/// Convert 64 bit value to network byte order
/**
* This method is prefixed to avoid conflicts with operating system level
* macros for this functionality.
*
* TODO: figure out if it would be beneficial to use operating system level
* macros for this.
*
* @param src The integer in host byte order
* @return src converted to network byte order
*/
inline 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;
}
/// Convert 64 bit value to host byte order
/**
* This method is prefixed to avoid conflicts with operating system level
* macros for this functionality.
*
* TODO: figure out if it would be beneficial to use operating system level
* macros for this.
*
* @param src The integer in network byte order
* @return src converted to host byte order
*/
inline uint64_t _ntohll(uint64_t src) {
return _htonll(src);
}
} // net
} // lib
} // websocketpp
#endif // WEBSOCKETPP_COMMON_NETWORK_HPP

View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 2014, 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_COMMON_PLATFORMS_HPP
#define WEBSOCKETPP_COMMON_PLATFORMS_HPP
/**
* This header contains any platform specific preprocessor adjustments that
* don't fit somewhere else better.
*/
#if defined(_WIN32) && !defined(NOMINMAX)
// don't define min and max macros that conflict with std::min and std::max
#define NOMINMAX
#endif
// Bump up the variadic parameter max for Visual Studio 2012
#if defined(_MSC_VER) && _MSC_VER == 1700
#define _VARIADIC_MAX 8
#endif
#endif // WEBSOCKETPP_COMMON_PLATFORMS_HPP

View File

@ -0,0 +1,82 @@
/*
* Copyright (c) 2014, 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_COMMON_RANDOM_DEVICE_HPP
#define WEBSOCKETPP_COMMON_RANDOM_DEVICE_HPP
#include <websocketpp/common/cpp11.hpp>
// If we've determined that we're in full C++11 mode and the user hasn't
// explicitly disabled the use of C++11 random header, then prefer it to
// boost.
#if defined _WEBSOCKETPP_CPP11_INTERNAL_ && !defined _WEBSOCKETPP_NO_CPP11_RANDOM_DEVICE_
#ifndef _WEBSOCKETPP_CPP11_RANDOM_DEVICE_
#define _WEBSOCKETPP_CPP11_RANDOM_DEVICE_
#endif
#endif
// If we're on Visual Studio 2010 or higher and haven't explicitly disabled
// the use of C++11 random header then prefer it to boost.
#if defined(_MSC_VER) && _MSC_VER >= 1600 && !defined _WEBSOCKETPP_NO_CPP11_MEMORY_
#ifndef _WEBSOCKETPP_CPP11_MEMORY_
#define _WEBSOCKETPP_CPP11_MEMORY_
#endif
#endif
#ifdef _WEBSOCKETPP_CPP11_RANDOM_DEVICE_
#include <random>
#else
#include <boost/version.hpp>
#if (BOOST_VERSION/100000) == 1 && ((BOOST_VERSION/100)%1000) > 46
#include <boost/random/uniform_int_distribution.hpp>
#include <boost/random/random_device.hpp>
#elif (BOOST_VERSION/100000) == 1 && ((BOOST_VERSION/100)%1000) >= 43
#include <boost/nondet_random.hpp>
#else
// TODO: static_assert(false, "Could not find a suitable random_device")
#endif
#endif
namespace websocketpp {
namespace lib {
#ifdef _WEBSOCKETPP_CPP11_RANDOM_DEVICE_
using std::random_device;
using std::uniform_int_distribution;
#else
using boost::random::random_device;
using boost::random::uniform_int_distribution;
#endif
} // namespace lib
} // namespace websocketpp
#endif // WEBSOCKETPP_COMMON_RANDOM_DEVICE_HPP

View File

@ -0,0 +1,59 @@
/*
* Copyright (c) 2014, 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_COMMON_REGEX_HPP
#define WEBSOCKETPP_COMMON_REGEX_HPP
#if defined _WEBSOCKETPP_CPP11_STL_ && !defined _WEBSOCKETPP_NO_CPP11_REGEX_
#ifndef _WEBSOCKETPP_CPP11_REGEX_
#define _WEBSOCKETPP_CPP11_REGEX_
#endif
#endif
#ifdef _WEBSOCKETPP_CPP11_REGEX_
#include <regex>
#else
#include <boost/regex.hpp>
#endif
namespace websocketpp {
namespace lib {
#ifdef _WEBSOCKETPP_CPP11_REGEX_
using std::cmatch;
using std::regex;
using std::regex_match;
#else
using boost::cmatch;
using boost::regex;
using boost::regex_match;
#endif
} // namespace lib
} // namespace websocketpp
#endif // WEBSOCKETPP_COMMON_REGEX_HPP

View File

@ -0,0 +1,73 @@
/*
* Copyright (c) 2014, 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_COMMON_STDINT_HPP
#define WEBSOCKETPP_COMMON_STDINT_HPP
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS 1
#endif
#if defined (_WIN32) && defined (_MSC_VER) && (_MSC_VER < 1600)
#include <boost/cstdint.hpp>
using boost::int8_t;
using boost::int_least8_t;
using boost::int_fast8_t;
using boost::uint8_t;
using boost::uint_least8_t;
using boost::uint_fast8_t;
using boost::int16_t;
using boost::int_least16_t;
using boost::int_fast16_t;
using boost::uint16_t;
using boost::uint_least16_t;
using boost::uint_fast16_t;
using boost::int32_t;
using boost::int_least32_t;
using boost::int_fast32_t;
using boost::uint32_t;
using boost::uint_least32_t;
using boost::uint_fast32_t;
#ifndef BOOST_NO_INT64_T
using boost::int64_t;
using boost::int_least64_t;
using boost::int_fast64_t;
using boost::uint64_t;
using boost::uint_least64_t;
using boost::uint_fast64_t;
#endif
using boost::intmax_t;
using boost::uintmax_t;
#else
#include <stdint.h>
#endif
#endif // WEBSOCKETPP_COMMON_STDINT_HPP

View File

@ -0,0 +1,84 @@
/*
* Copyright (c) 2014, 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_COMMON_SYSTEM_ERROR_HPP
#define WEBSOCKETPP_COMMON_SYSTEM_ERROR_HPP
#include <websocketpp/common/cpp11.hpp>
// If we've determined that we're in full C++11 mode and the user hasn't
// explicitly disabled the use of C++11 system_error header, then prefer it to
// boost.
#if defined _WEBSOCKETPP_CPP11_INTERNAL_ && !defined _WEBSOCKETPP_NO_CPP11_SYSTEM_ERROR_
#ifndef _WEBSOCKETPP_CPP11_SYSTEM_ERROR_
#define _WEBSOCKETPP_CPP11_SYSTEM_ERROR_
#endif
#endif
// If we're on Visual Studio 2010 or higher and haven't explicitly disabled
// the use of C++11 system_error header then prefer it to boost.
#if defined(_MSC_VER) && _MSC_VER >= 1600 && !defined _WEBSOCKETPP_NO_CPP11_SYSTEM_ERROR_
#ifndef _WEBSOCKETPP_CPP11_SYSTEM_ERROR_
#define _WEBSOCKETPP_CPP11_SYSTEM_ERROR_
#endif
#endif
#ifdef _WEBSOCKETPP_CPP11_SYSTEM_ERROR_
#include <system_error>
#else
#include <boost/system/error_code.hpp>
#include <boost/system/system_error.hpp>
#endif
namespace websocketpp {
namespace lib {
#ifdef _WEBSOCKETPP_CPP11_SYSTEM_ERROR_
using std::errc;
using std::error_code;
using std::error_category;
using std::error_condition;
using std::system_error;
#define _WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_ namespace std {
#define _WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_ }
#else
namespace errc = boost::system::errc;
using boost::system::error_code;
using boost::system::error_category;
using boost::system::error_condition;
using boost::system::system_error;
#define _WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_ namespace boost { namespace system {
#define _WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_ }}
#endif
} // namespace lib
} // namespace websocketpp
#endif // WEBSOCKETPP_COMMON_SYSTEM_ERROR_HPP

View File

@ -0,0 +1,89 @@
/*
* Copyright (c) 2015, Peter Thorson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef WEBSOCKETPP_COMMON_THREAD_HPP
#define WEBSOCKETPP_COMMON_THREAD_HPP
#include <websocketpp/common/cpp11.hpp>
// If we autodetect C++11 and haven't been explicitly instructed to not use
// C++11 threads, then set the defines that instructs the rest of this header
// to use C++11 <thread> and <mutex>
#if defined _WEBSOCKETPP_CPP11_INTERNAL_ && !defined _WEBSOCKETPP_NO_CPP11_THREAD_
// MinGW by default does not support C++11 thread/mutex so even if the
// internal check for C++11 passes, ignore it if we are on MinGW
// Not true in our case. Force it ON.
//#if (!defined(__MINGW32__) && !defined(__MINGW64__))
#ifndef _WEBSOCKETPP_CPP11_THREAD_
#define _WEBSOCKETPP_CPP11_THREAD_
#endif
//#endif
#endif
// If we're on Visual Studio 2013 or higher and haven't explicitly disabled
// the use of C++11 thread header then prefer it to boost.
#if defined(_MSC_VER) && _MSC_VER >= 1800 && !defined _WEBSOCKETPP_NO_CPP11_THREAD_
#ifndef _WEBSOCKETPP_CPP11_THREAD_
#define _WEBSOCKETPP_CPP11_THREAD_
#endif
#endif
#if defined(_WEBSOCKETPP_MINGW_THREAD_)
#include <mingw-threads/mingw.thread.h>
#include <mingw-threads/mingw.mutex.h>
#include <mingw-threads/mingw.condition_variable.h>
#elif defined(_WEBSOCKETPP_CPP11_THREAD_)
#include <thread>
#include <mutex>
#include <condition_variable>
#else
#include <boost/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition_variable.hpp>
#endif
namespace websocketpp {
namespace lib {
#if defined(_WEBSOCKETPP_CPP11_THREAD_) || defined(_WEBSOCKETPP_MINGW_THREAD_)
using std::mutex;
using std::lock_guard;
using std::thread;
using std::unique_lock;
using std::condition_variable;
#else
using boost::mutex;
using boost::lock_guard;
using boost::thread;
using boost::unique_lock;
using boost::condition_variable;
#endif
} // namespace lib
} // namespace websocketpp
#endif // WEBSOCKETPP_COMMON_THREAD_HPP

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2014, 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_COMMON_TIME_HPP
#define WEBSOCKETPP_COMMON_TIME_HPP
#include <ctime>
namespace websocketpp {
namespace lib {
// Code in this header was inspired by the following article and includes some
// code from the related project g2log. The g2log code is public domain licensed
// http://kjellkod.wordpress.com/2013/01/22/exploring-c11-part-2-localtime-and-time-again/
/// Thread safe cross platform localtime
inline std::tm localtime(std::time_t const & time) {
std::tm tm_snapshot;
#if (defined(__MINGW32__) || defined(__MINGW64__))
memcpy(&tm_snapshot, ::localtime(&time), sizeof(std::tm));
#elif (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
localtime_s(&tm_snapshot, &time);
#else
localtime_r(&time, &tm_snapshot); // POSIX
#endif
return tm_snapshot;
}
} // lib
} // websocketpp
#endif // WEBSOCKETPP_COMMON_TIME_HPP

View File

@ -0,0 +1,65 @@
/*
* Copyright (c) 2015, Peter Thorson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef WEBSOCKETPP_COMMON_TYPE_TRAITS_HPP
#define WEBSOCKETPP_COMMON_TYPE_TRAITS_HPP
#include <websocketpp/common/cpp11.hpp>
// If we've determined that we're in full C++11 mode and the user hasn't
// explicitly disabled the use of C++11 functional header, then prefer it to
// boost.
#if defined _WEBSOCKETPP_CPP11_INTERNAL_ && !defined _WEBSOCKETPP_NO_CPP11_TYPE_TRAITS_
#ifndef _WEBSOCKETPP_CPP11_TYPE_TRAITS_
#define _WEBSOCKETPP_CPP11_TYPE_TRAITS_
#endif
#endif
#ifdef _WEBSOCKETPP_CPP11_TYPE_TRAITS_
#include <type_traits>
#else
#include <boost/aligned_storage.hpp>
#endif
namespace websocketpp {
namespace lib {
#ifdef _WEBSOCKETPP_CPP11_TYPE_TRAITS_
using std::aligned_storage;
using std::is_same;
#else
using boost::aligned_storage;
using boost::is_same;
#endif
} // namespace lib
} // namespace websocketpp
#endif // WEBSOCKETPP_COMMON_TYPE_TRAITS_HPP

View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 2014, 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_CONCURRENCY_BASIC_HPP
#define WEBSOCKETPP_CONCURRENCY_BASIC_HPP
#include <websocketpp/common/thread.hpp>
namespace websocketpp {
namespace concurrency {
/// Concurrency policy that uses std::mutex / boost::mutex
class basic {
public:
typedef lib::mutex mutex_type;
typedef lib::lock_guard<mutex_type> scoped_lock_type;
};
} // namespace concurrency
} // namespace websocketpp
#endif // WEBSOCKETPP_CONCURRENCY_BASIC_HPP

View File

@ -0,0 +1,80 @@
/*
* Copyright (c) 2014, 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_CONCURRENCY_NONE_HPP
#define WEBSOCKETPP_CONCURRENCY_NONE_HPP
namespace websocketpp {
/// Concurrency handling support
namespace concurrency {
/// Implementation for no-op locking primitives
namespace none_impl {
/// A fake mutex implementation that does nothing
class fake_mutex {
public:
fake_mutex() {}
~fake_mutex() {}
};
/// A fake lock guard implementation that does nothing
class fake_lock_guard {
public:
explicit fake_lock_guard(fake_mutex) {}
~fake_lock_guard() {}
};
} // namespace none_impl
/// Stub concurrency policy that implements the interface using no-ops.
/**
* This policy documents the concurrency policy interface using no-ops. It can
* be used as a reference or base for building a new concurrency policy. It can
* also be used as is to disable all locking for endpoints used in purely single
* threaded programs.
*/
class none {
public:
/// The type of a mutex primitive
/**
* std::mutex is an example.
*/
typedef none_impl::fake_mutex mutex_type;
/// The type of a scoped/RAII lock primitive.
/**
* The scoped lock constructor should take a mutex_type as a parameter,
* acquire that lock, and release it in its destructor. std::lock_guard is
* an example.
*/
typedef none_impl::fake_lock_guard scoped_lock_type;
};
} // namespace concurrency
} // namespace websocketpp
#endif // WEBSOCKETPP_CONCURRENCY_ASYNC_HPP

View File

@ -0,0 +1,77 @@
/*
* Copyright (c) 2014, 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_CONFIG_ASIO_TLS_HPP
#define WEBSOCKETPP_CONFIG_ASIO_TLS_HPP
#include <websocketpp/config/core.hpp>
#include <websocketpp/transport/asio/endpoint.hpp>
#include <websocketpp/transport/asio/security/tls.hpp>
// Pull in non-tls config
#include <websocketpp/config/asio_no_tls.hpp>
// Define TLS config
namespace websocketpp {
namespace config {
/// Server config with asio transport and TLS enabled
struct asio_tls : public core {
typedef asio_tls type;
typedef core base;
typedef base::concurrency_type concurrency_type;
typedef base::request_type request_type;
typedef base::response_type response_type;
typedef base::message_type message_type;
typedef base::con_msg_manager_type con_msg_manager_type;
typedef base::endpoint_msg_manager_type endpoint_msg_manager_type;
typedef base::alog_type alog_type;
typedef base::elog_type elog_type;
typedef base::rng_type rng_type;
struct transport_config : public base::transport_config {
typedef type::concurrency_type concurrency_type;
typedef type::alog_type alog_type;
typedef type::elog_type elog_type;
typedef type::request_type request_type;
typedef type::response_type response_type;
typedef websocketpp::transport::asio::tls_socket::endpoint socket_type;
};
typedef websocketpp::transport::asio::endpoint<transport_config>
transport_type;
};
} // namespace config
} // namespace websocketpp
#endif // WEBSOCKETPP_CONFIG_ASIO_TLS_HPP

View File

@ -0,0 +1,77 @@
/*
* Copyright (c) 2014, 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_CONFIG_ASIO_TLS_CLIENT_HPP
#define WEBSOCKETPP_CONFIG_ASIO_TLS_CLIENT_HPP
#include <websocketpp/config/core_client.hpp>
#include <websocketpp/transport/asio/endpoint.hpp>
#include <websocketpp/transport/asio/security/tls.hpp>
// Pull in non-tls config
#include <websocketpp/config/asio_no_tls_client.hpp>
// Define TLS config
namespace websocketpp {
namespace config {
/// Client config with asio transport and TLS enabled
struct asio_tls_client : public core_client {
typedef asio_tls_client type;
typedef core_client base;
typedef base::concurrency_type concurrency_type;
typedef base::request_type request_type;
typedef base::response_type response_type;
typedef base::message_type message_type;
typedef base::con_msg_manager_type con_msg_manager_type;
typedef base::endpoint_msg_manager_type endpoint_msg_manager_type;
typedef base::alog_type alog_type;
typedef base::elog_type elog_type;
typedef base::rng_type rng_type;
struct transport_config : public base::transport_config {
typedef type::concurrency_type concurrency_type;
typedef type::alog_type alog_type;
typedef type::elog_type elog_type;
typedef type::request_type request_type;
typedef type::response_type response_type;
typedef websocketpp::transport::asio::tls_socket::endpoint socket_type;
};
typedef websocketpp::transport::asio::endpoint<transport_config>
transport_type;
};
} // namespace config
} // namespace websocketpp
#endif // WEBSOCKETPP_CONFIG_ASIO_TLS_CLIENT_HPP

View File

@ -0,0 +1,73 @@
/*
* Copyright (c) 2014, 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_CONFIG_ASIO_HPP
#define WEBSOCKETPP_CONFIG_ASIO_HPP
#include <websocketpp/config/core.hpp>
#include <websocketpp/transport/asio/endpoint.hpp>
namespace websocketpp {
namespace config {
/// Server config with asio transport and TLS disabled
struct asio : public core {
typedef asio type;
typedef core base;
typedef base::concurrency_type concurrency_type;
typedef base::request_type request_type;
typedef base::response_type response_type;
typedef base::message_type message_type;
typedef base::con_msg_manager_type con_msg_manager_type;
typedef base::endpoint_msg_manager_type endpoint_msg_manager_type;
typedef base::alog_type alog_type;
typedef base::elog_type elog_type;
typedef base::rng_type rng_type;
struct transport_config : public base::transport_config {
typedef type::concurrency_type concurrency_type;
typedef type::alog_type alog_type;
typedef type::elog_type elog_type;
typedef type::request_type request_type;
typedef type::response_type response_type;
typedef websocketpp::transport::asio::basic_socket::endpoint
socket_type;
};
typedef websocketpp::transport::asio::endpoint<transport_config>
transport_type;
};
} // namespace config
} // namespace websocketpp
#endif // WEBSOCKETPP_CONFIG_ASIO_HPP

View File

@ -0,0 +1,73 @@
/*
* Copyright (c) 2014, 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_CONFIG_ASIO_CLIENT_HPP
#define WEBSOCKETPP_CONFIG_ASIO_CLIENT_HPP
#include <websocketpp/config/core_client.hpp>
#include <websocketpp/transport/asio/endpoint.hpp>
namespace websocketpp {
namespace config {
/// Client config with asio transport and TLS disabled
struct asio_client : public core_client {
typedef asio_client type;
typedef core_client base;
typedef base::concurrency_type concurrency_type;
typedef base::request_type request_type;
typedef base::response_type response_type;
typedef base::message_type message_type;
typedef base::con_msg_manager_type con_msg_manager_type;
typedef base::endpoint_msg_manager_type endpoint_msg_manager_type;
typedef base::alog_type alog_type;
typedef base::elog_type elog_type;
typedef base::rng_type rng_type;
struct transport_config : public base::transport_config {
typedef type::concurrency_type concurrency_type;
typedef type::alog_type alog_type;
typedef type::elog_type elog_type;
typedef type::request_type request_type;
typedef type::response_type response_type;
typedef websocketpp::transport::asio::basic_socket::endpoint
socket_type;
};
typedef websocketpp::transport::asio::endpoint<transport_config>
transport_type;
};
} // namespace config
} // namespace websocketpp
#endif // WEBSOCKETPP_CONFIG_ASIO_CLIENT_HPP

View File

@ -0,0 +1,72 @@
/*
* Copyright (c) 2014, 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 header defines WebSocket++ macros for C++11 compatibility based on the
// Boost.Config library. This will correctly configure most target platforms
// simply by including this header before any other WebSocket++ header.
#ifndef WEBSOCKETPP_CONFIG_BOOST_CONFIG_HPP
#define WEBSOCKETPP_CONFIG_BOOST_CONFIG_HPP
#include <boost/config.hpp>
// _WEBSOCKETPP_CPP11_MEMORY_ and _WEBSOCKETPP_CPP11_FUNCTIONAL_ presently
// only work if either both or neither is defined.
#if !defined BOOST_NO_CXX11_SMART_PTR && !defined BOOST_NO_CXX11_HDR_FUNCTIONAL
#define _WEBSOCKETPP_CPP11_MEMORY_
#define _WEBSOCKETPP_CPP11_FUNCTIONAL_
#endif
#ifdef BOOST_ASIO_HAS_STD_CHRONO
#define _WEBSOCKETPP_CPP11_CHRONO_
#endif
#ifndef BOOST_NO_CXX11_HDR_RANDOM
#define _WEBSOCKETPP_CPP11_RANDOM_DEVICE_
#endif
#ifndef BOOST_NO_CXX11_HDR_REGEX
#define _WEBSOCKETPP_CPP11_REGEX_
#endif
#ifndef BOOST_NO_CXX11_HDR_SYSTEM_ERROR
#define _WEBSOCKETPP_CPP11_SYSTEM_ERROR_
#endif
#ifndef BOOST_NO_CXX11_HDR_THREAD
#define _WEBSOCKETPP_CPP11_THREAD_
#endif
#ifndef BOOST_NO_CXX11_HDR_INITIALIZER_LIST
#define _WEBSOCKETPP_INITIALIZER_LISTS_
#endif
#define _WEBSOCKETPP_NOEXCEPT_TOKEN_ BOOST_NOEXCEPT
#define _WEBSOCKETPP_CONSTEXPR_TOKEN_ BOOST_CONSTEXPR
// TODO: nullptr support
#endif // WEBSOCKETPP_CONFIG_BOOST_CONFIG_HPP

View File

@ -0,0 +1,297 @@
/*
* Copyright (c) 2014, 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_CONFIG_CORE_HPP
#define WEBSOCKETPP_CONFIG_CORE_HPP
// Non-Policy common stuff
#include <websocketpp/common/platforms.hpp>
#include <websocketpp/common/cpp11.hpp>
#include <websocketpp/common/stdint.hpp>
// Concurrency
#include <websocketpp/concurrency/basic.hpp>
// Transport
#include <websocketpp/transport/iostream/endpoint.hpp>
// HTTP
#include <websocketpp/http/request.hpp>
#include <websocketpp/http/response.hpp>
// Messages
#include <websocketpp/message_buffer/message.hpp>
#include <websocketpp/message_buffer/alloc.hpp>
// Loggers
#include <websocketpp/logger/basic.hpp>
#include <websocketpp/logger/levels.hpp>
// RNG
#include <websocketpp/random/none.hpp>
// User stub base classes
#include <websocketpp/endpoint_base.hpp>
#include <websocketpp/connection_base.hpp>
// Extensions
#include <websocketpp/extensions/permessage_deflate/disabled.hpp>
namespace websocketpp {
namespace config {
/// Server config with iostream transport
struct core {
typedef core type;
// Concurrency policy
typedef websocketpp::concurrency::basic concurrency_type;
// HTTP Parser Policies
typedef http::parser::request request_type;
typedef http::parser::response response_type;
// Message Policies
typedef message_buffer::message<message_buffer::alloc::con_msg_manager>
message_type;
typedef message_buffer::alloc::con_msg_manager<message_type>
con_msg_manager_type;
typedef message_buffer::alloc::endpoint_msg_manager<con_msg_manager_type>
endpoint_msg_manager_type;
/// Logging policies
typedef websocketpp::log::basic<concurrency_type,
websocketpp::log::elevel> elog_type;
typedef websocketpp::log::basic<concurrency_type,
websocketpp::log::alevel> alog_type;
/// RNG policies
typedef websocketpp::random::none::int_generator<uint32_t> rng_type;
/// Controls compile time enabling/disabling of thread syncronization
/// code Disabling can provide a minor performance improvement to single
/// threaded applications
static bool const enable_multithreading = true;
struct transport_config {
typedef type::concurrency_type concurrency_type;
typedef type::elog_type elog_type;
typedef type::alog_type alog_type;
typedef type::request_type request_type;
typedef type::response_type response_type;
/// Controls compile time enabling/disabling of thread syncronization
/// code Disabling can provide a minor performance improvement to single
/// threaded applications
static bool const enable_multithreading = true;
/// Default timer values (in ms)
/// Length of time to wait for socket pre-initialization
/**
* Exactly what this includes depends on the socket policy in use
*/
static const long timeout_socket_pre_init = 5000;
/// Length of time to wait before a proxy handshake is aborted
static const long timeout_proxy = 5000;
/// Length of time to wait for socket post-initialization
/**
* Exactly what this includes depends on the socket policy in use.
* Often this means the TLS handshake
*/
static const long timeout_socket_post_init = 5000;
/// Length of time to wait for dns resolution
static const long timeout_dns_resolve = 5000;
/// Length of time to wait for TCP connect
static const long timeout_connect = 5000;
/// Length of time to wait for socket shutdown
static const long timeout_socket_shutdown = 5000;
};
/// Transport Endpoint Component
typedef websocketpp::transport::iostream::endpoint<transport_config>
transport_type;
/// User overridable Endpoint base class
typedef websocketpp::endpoint_base endpoint_base;
/// User overridable Connection base class
typedef websocketpp::connection_base connection_base;
/// Default timer values (in ms)
/// Length of time before an opening handshake is aborted
static const long timeout_open_handshake = 5000;
/// Length of time before a closing handshake is aborted
static const long timeout_close_handshake = 5000;
/// Length of time to wait for a pong after a ping
static const long timeout_pong = 5000;
/// WebSocket Protocol version to use as a client
/**
* What version of the WebSocket Protocol to use for outgoing client
* connections. Setting this to a value other than 13 (RFC6455) is not
* recommended.
*/
static const int client_version = 13; // RFC6455
/// Default static error logging channels
/**
* Which error logging channels to enable at compile time. Channels not
* enabled here will be unable to be selected by programs using the library.
* This option gives an optimizing compiler the ability to remove entirely
* code to test whether or not to print out log messages on a certain
* channel
*
* Default is all except for development/debug level errors
*/
static const websocketpp::log::level elog_level =
websocketpp::log::elevel::all ^ websocketpp::log::elevel::devel;
/// Default static access logging channels
/**
* Which access logging channels to enable at compile time. Channels not
* enabled here will be unable to be selected by programs using the library.
* This option gives an optimizing compiler the ability to remove entirely
* code to test whether or not to print out log messages on a certain
* channel
*
* Default is all except for development/debug level access messages
*/
static const websocketpp::log::level alog_level =
websocketpp::log::alevel::all ^ websocketpp::log::alevel::devel;
/// Size of the per-connection read buffer
/**
* Each connection has an internal buffer of this size. A larger value will
* result in fewer trips through the library and less CPU overhead at the
* expense of increased memory usage per connection.
*
* If your application primarily deals in very large messages you may want
* to try setting this value higher.
*
* If your application has a lot of connections or primarily deals in small
* messages you may want to try setting this smaller.
*/
static const size_t connection_read_buffer_size = 16384;
/// Drop connections immediately on protocol error.
/**
* Drop connections on protocol error rather than sending a close frame.
* Off by default. This may result in legit messages near the error being
* dropped as well. It may free up resources otherwise spent dealing with
* misbehaving clients.
*/
static const bool drop_on_protocol_error = false;
/// Suppresses the return of detailed connection close information
/**
* Silence close suppresses the return of detailed connection close
* information during the closing handshake. This information is useful
* for debugging and presenting useful errors to end users but may be
* undesirable for security reasons in some production environments.
* Close reasons could be used by an attacker to confirm that the endpoint
* is out of resources or be used to identify the WebSocket implementation
* in use.
*
* Note: this will suppress *all* close codes, including those explicitly
* sent by local applications.
*/
static const bool silent_close = false;
/// Default maximum message size
/**
* Default value for the processor's maximum message size. Maximum message size
* determines the point at which the library will fail a connection with the
* message_too_big protocol error.
*
* The default is 32MB
*
* @since 0.3.0
*/
static const size_t max_message_size = 32000000;
/// Default maximum http body size
/**
* Default value for the http parser's maximum body size. Maximum body size
* determines the point at which the library will abort reading an HTTP
* connection with the 413/request entity too large error.
*
* The default is 32MB
*
* @since 0.5.0
*/
static const size_t max_http_body_size = 32000000;
/// Global flag for enabling/disabling extensions
static const bool enable_extensions = true;
/// Extension specific settings:
/// permessage_compress extension
struct permessage_deflate_config {
typedef core::request_type request_type;
/// If the remote endpoint requests that we reset the compression
/// context after each message should we honor the request?
static const bool allow_disabling_context_takeover = true;
/// If the remote endpoint requests that we reduce the size of the
/// LZ77 sliding window size this is the lowest value that will be
/// allowed. Values range from 8 to 15. A value of 8 means we will
/// allow any possible window size. A value of 15 means do not allow
/// negotiation of the window size (ie require the default).
static const uint8_t minimum_outgoing_window_bits = 8;
};
typedef websocketpp::extensions::permessage_deflate::disabled
<permessage_deflate_config> permessage_deflate_type;
/// Autonegotiate permessage-deflate
/**
* Automatically enables the permessage-deflate extension.
*
* For clients this results in a permessage-deflate extension request being
* sent with every request rather than requiring it to be requested manually
*
* For servers this results in accepting the first set of extension settings
* requested by the client that we understand being used. The alternative is
* requiring the extension to be manually negotiated in `validate`. With
* auto-negotiate on, you may still override the auto-negotiate manually if
* needed.
*/
//static const bool autonegotiate_compression = false;
};
} // namespace config
} // namespace websocketpp
#endif // WEBSOCKETPP_CONFIG_CORE_HPP

View File

@ -0,0 +1,294 @@
/*
* Copyright (c) 2014, 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_CONFIG_CORE_CLIENT_HPP
#define WEBSOCKETPP_CONFIG_CORE_CLIENT_HPP
// Non-Policy common stuff
#include <websocketpp/common/platforms.hpp>
#include <websocketpp/common/cpp11.hpp>
#include <websocketpp/common/stdint.hpp>
// Concurrency
#ifndef _WEBSOCKETPP_NO_THREADING_
#include <websocketpp/concurrency/basic.hpp>
#else
#include <websocketpp/concurrency/none.hpp>
#endif
// Transport
#include <websocketpp/transport/iostream/endpoint.hpp>
// HTTP
#include <websocketpp/http/request.hpp>
#include <websocketpp/http/response.hpp>
// Messages
#include <websocketpp/message_buffer/message.hpp>
#include <websocketpp/message_buffer/alloc.hpp>
// Loggers
#include <websocketpp/logger/basic.hpp>
// RNG
#include <websocketpp/random/random_device.hpp>
// User stub base classes
#include <websocketpp/endpoint_base.hpp>
#include <websocketpp/connection_base.hpp>
// Extensions
#include <websocketpp/extensions/permessage_deflate/disabled.hpp>
namespace websocketpp {
namespace config {
/// Client config with iostream transport
struct core_client {
typedef core_client type;
// Concurrency policy
#ifndef _WEBSOCKETPP_NO_THREADING_
typedef websocketpp::concurrency::basic concurrency_type;
#else
typedef websocketpp::concurrency::none concurrency_type;
#endif
// HTTP Parser Policies
typedef http::parser::request request_type;
typedef http::parser::response response_type;
// Message Policies
typedef message_buffer::message<message_buffer::alloc::con_msg_manager>
message_type;
typedef message_buffer::alloc::con_msg_manager<message_type>
con_msg_manager_type;
typedef message_buffer::alloc::endpoint_msg_manager<con_msg_manager_type>
endpoint_msg_manager_type;
/// Logging policies
typedef websocketpp::log::basic<concurrency_type,
websocketpp::log::elevel> elog_type;
typedef websocketpp::log::basic<concurrency_type,
websocketpp::log::alevel> alog_type;
/// RNG policies
typedef websocketpp::random::random_device::int_generator<uint32_t,
concurrency_type> rng_type;
/// Controls compile time enabling/disabling of thread syncronization code
/// Disabling can provide a minor performance improvement to single threaded
/// applications
static bool const enable_multithreading = true;
struct transport_config {
typedef type::concurrency_type concurrency_type;
typedef type::elog_type elog_type;
typedef type::alog_type alog_type;
typedef type::request_type request_type;
typedef type::response_type response_type;
/// Controls compile time enabling/disabling of thread syncronization
/// code Disabling can provide a minor performance improvement to single
/// threaded applications
static bool const enable_multithreading = true;
/// Default timer values (in ms)
/// Length of time to wait for socket pre-initialization
/**
* Exactly what this includes depends on the socket policy in use
*/
static const long timeout_socket_pre_init = 5000;
/// Length of time to wait before a proxy handshake is aborted
static const long timeout_proxy = 5000;
/// Length of time to wait for socket post-initialization
/**
* Exactly what this includes depends on the socket policy in use.
* Often this means the TLS handshake
*/
static const long timeout_socket_post_init = 5000;
/// Length of time to wait for dns resolution
static const long timeout_dns_resolve = 5000;
/// Length of time to wait for TCP connect
static const long timeout_connect = 5000;
/// Length of time to wait for socket shutdown
static const long timeout_socket_shutdown = 5000;
};
/// Transport Endpoint Component
typedef websocketpp::transport::iostream::endpoint<transport_config>
transport_type;
/// User overridable Endpoint base class
typedef websocketpp::endpoint_base endpoint_base;
/// User overridable Connection base class
typedef websocketpp::connection_base connection_base;
/// Default timer values (in ms)
/// Length of time before an opening handshake is aborted
static const long timeout_open_handshake = 5000;
/// Length of time before a closing handshake is aborted
static const long timeout_close_handshake = 5000;
/// Length of time to wait for a pong after a ping
static const long timeout_pong = 5000;
/// WebSocket Protocol version to use as a client
/**
* What version of the WebSocket Protocol to use for outgoing client
* connections. Setting this to a value other than 13 (RFC6455) is not
* recommended.
*/
static const int client_version = 13; // RFC6455
/// Default static error logging channels
/**
* Which error logging channels to enable at compile time. Channels not
* enabled here will be unable to be selected by programs using the library.
* This option gives an optimizing compiler the ability to remove entirely
* code to test whether or not to print out log messages on a certain
* channel
*
* Default is all except for development/debug level errors
*/
static const websocketpp::log::level elog_level =
websocketpp::log::elevel::all ^ websocketpp::log::elevel::devel;
/// Default static access logging channels
/**
* Which access logging channels to enable at compile time. Channels not
* enabled here will be unable to be selected by programs using the library.
* This option gives an optimizing compiler the ability to remove entirely
* code to test whether or not to print out log messages on a certain
* channel
*
* Default is all except for development/debug level access messages
*/
static const websocketpp::log::level alog_level =
websocketpp::log::alevel::all ^ websocketpp::log::alevel::devel;
///
static const size_t connection_read_buffer_size = 16384;
/// Drop connections immediately on protocol error.
/**
* Drop connections on protocol error rather than sending a close frame.
* Off by default. This may result in legit messages near the error being
* dropped as well. It may free up resources otherwise spent dealing with
* misbehaving clients.
*/
static const bool drop_on_protocol_error = false;
/// Suppresses the return of detailed connection close information
/**
* Silence close suppresses the return of detailed connection close
* information during the closing handshake. This information is useful
* for debugging and presenting useful errors to end users but may be
* undesirable for security reasons in some production environments.
* Close reasons could be used by an attacker to confirm that the endpoint
* is out of resources or be used to identify the WebSocket implementation
* in use.
*
* Note: this will suppress *all* close codes, including those explicitly
* sent by local applications.
*/
static const bool silent_close = false;
/// Default maximum message size
/**
* Default value for the processor's maximum message size. Maximum message size
* determines the point at which the library will fail a connection with the
* message_too_big protocol error.
*
* The default is 32MB
*
* @since 0.3.0
*/
static const size_t max_message_size = 32000000;
/// Default maximum http body size
/**
* Default value for the http parser's maximum body size. Maximum body size
* determines the point at which the library will abort reading an HTTP
* connection with the 413/request entity too large error.
*
* The default is 32MB
*
* @since 0.5.0
*/
static const size_t max_http_body_size = 32000000;
/// Global flag for enabling/disabling extensions
static const bool enable_extensions = true;
/// Extension specific settings:
/// permessage_deflate extension
struct permessage_deflate_config {
typedef core_client::request_type request_type;
/// If the remote endpoint requests that we reset the compression
/// context after each message should we honor the request?
static const bool allow_disabling_context_takeover = true;
/// If the remote endpoint requests that we reduce the size of the
/// LZ77 sliding window size this is the lowest value that will be
/// allowed. Values range from 8 to 15. A value of 8 means we will
/// allow any possible window size. A value of 15 means do not allow
/// negotiation of the window size (ie require the default).
static const uint8_t minimum_outgoing_window_bits = 8;
};
typedef websocketpp::extensions::permessage_deflate::disabled
<permessage_deflate_config> permessage_deflate_type;
/// Autonegotiate permessage-compress
/**
* Automatically enables the permessage-compress extension.
*
* For clients this results in a permessage-compress extension request being
* sent with every request rather than requiring it to be requested manually
*
* For servers this results in accepting the first set of extension settings
* requested by the client that we understand being used. The alternative is
* requiring the extension to be manually negotiated in `validate`. With
* auto-negotiate on, you may still override the auto-negotiate manually if
* needed.
*/
//static const bool autonegotiate_compression = false;
};
} // namespace config
} // namespace websocketpp
#endif // WEBSOCKETPP_CONFIG_CORE_CLIENT_HPP

View File

@ -0,0 +1,286 @@
/*
* Copyright (c) 2014, 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_CONFIG_DEBUG_HPP
#define WEBSOCKETPP_CONFIG_DEBUG_HPP
// Non-Policy common stuff
#include <websocketpp/common/cpp11.hpp>
#include <websocketpp/common/stdint.hpp>
// Concurrency
#include <websocketpp/concurrency/basic.hpp>
// Transport
#include <websocketpp/transport/iostream/endpoint.hpp>
// HTTP
#include <websocketpp/http/request.hpp>
#include <websocketpp/http/response.hpp>
// Messages
#include <websocketpp/message_buffer/message.hpp>
#include <websocketpp/message_buffer/alloc.hpp>
// Loggers
#include <websocketpp/logger/basic.hpp>
// RNG
#include <websocketpp/random/none.hpp>
// User stub base classes
#include <websocketpp/endpoint_base.hpp>
#include <websocketpp/connection_base.hpp>
// Extensions
#include <websocketpp/extensions/permessage_deflate/disabled.hpp>
namespace websocketpp {
namespace config {
/// Client/Server debug config with iostream transport
struct debug_core {
typedef debug_core type;
// Concurrency policy
typedef websocketpp::concurrency::basic concurrency_type;
// HTTP Parser Policies
typedef http::parser::request request_type;
typedef http::parser::response response_type;
// Message Policies
typedef message_buffer::message<message_buffer::alloc::con_msg_manager>
message_type;
typedef message_buffer::alloc::con_msg_manager<message_type>
con_msg_manager_type;
typedef message_buffer::alloc::endpoint_msg_manager<con_msg_manager_type>
endpoint_msg_manager_type;
/// Logging policies
typedef websocketpp::log::basic<concurrency_type,
websocketpp::log::elevel> elog_type;
typedef websocketpp::log::basic<concurrency_type,
websocketpp::log::alevel> alog_type;
/// RNG policies
typedef websocketpp::random::none::int_generator<uint32_t> rng_type;
/// Controls compile time enabling/disabling of thread syncronization
/// code Disabling can provide a minor performance improvement to single
/// threaded applications
static bool const enable_multithreading = true;
struct transport_config {
typedef type::concurrency_type concurrency_type;
typedef type::elog_type elog_type;
typedef type::alog_type alog_type;
typedef type::request_type request_type;
typedef type::response_type response_type;
/// Controls compile time enabling/disabling of thread syncronization
/// code Disabling can provide a minor performance improvement to single
/// threaded applications
static bool const enable_multithreading = true;
/// Default timer values (in ms)
/// Length of time to wait for socket pre-initialization
/**
* Exactly what this includes depends on the socket policy in use
*/
static const long timeout_socket_pre_init = 5000;
/// Length of time to wait before a proxy handshake is aborted
static const long timeout_proxy = 5000;
/// Length of time to wait for socket post-initialization
/**
* Exactly what this includes depends on the socket policy in use.
* Often this means the TLS handshake
*/
static const long timeout_socket_post_init = 5000;
/// Length of time to wait for dns resolution
static const long timeout_dns_resolve = 5000;
/// Length of time to wait for TCP connect
static const long timeout_connect = 5000;
/// Length of time to wait for socket shutdown
static const long timeout_socket_shutdown = 5000;
};
/// Transport Endpoint Component
typedef websocketpp::transport::iostream::endpoint<transport_config>
transport_type;
/// User overridable Endpoint base class
typedef websocketpp::endpoint_base endpoint_base;
/// User overridable Connection base class
typedef websocketpp::connection_base connection_base;
/// Default timer values (in ms)
/// Length of time before an opening handshake is aborted
static const long timeout_open_handshake = 5000;
/// Length of time before a closing handshake is aborted
static const long timeout_close_handshake = 5000;
/// Length of time to wait for a pong after a ping
static const long timeout_pong = 5000;
/// WebSocket Protocol version to use as a client
/**
* What version of the WebSocket Protocol to use for outgoing client
* connections. Setting this to a value other than 13 (RFC6455) is not
* recommended.
*/
static const int client_version = 13; // RFC6455
/// Default static error logging channels
/**
* Which error logging channels to enable at compile time. Channels not
* enabled here will be unable to be selected by programs using the library.
* This option gives an optimizing compiler the ability to remove entirely
* code to test whether or not to print out log messages on a certain
* channel
*
* Default is all except for development/debug level errors
*/
static const websocketpp::log::level elog_level =
websocketpp::log::elevel::all;
/// Default static access logging channels
/**
* Which access logging channels to enable at compile time. Channels not
* enabled here will be unable to be selected by programs using the library.
* This option gives an optimizing compiler the ability to remove entirely
* code to test whether or not to print out log messages on a certain
* channel
*
* Default is all except for development/debug level access messages
*/
static const websocketpp::log::level alog_level =
websocketpp::log::alevel::all;
///
static const size_t connection_read_buffer_size = 16384;
/// Drop connections immediately on protocol error.
/**
* Drop connections on protocol error rather than sending a close frame.
* Off by default. This may result in legit messages near the error being
* dropped as well. It may free up resources otherwise spent dealing with
* misbehaving clients.
*/
static const bool drop_on_protocol_error = false;
/// Suppresses the return of detailed connection close information
/**
* Silence close suppresses the return of detailed connection close
* information during the closing handshake. This information is useful
* for debugging and presenting useful errors to end users but may be
* undesirable for security reasons in some production environments.
* Close reasons could be used by an attacker to confirm that the endpoint
* is out of resources or be used to identify the WebSocket implementation
* in use.
*
* Note: this will suppress *all* close codes, including those explicitly
* sent by local applications.
*/
static const bool silent_close = false;
/// Default maximum message size
/**
* Default value for the processor's maximum message size. Maximum message size
* determines the point at which the library will fail a connection with the
* message_too_big protocol error.
*
* The default is 32MB
*
* @since 0.3.0
*/
static const size_t max_message_size = 32000000;
/// Default maximum http body size
/**
* Default value for the http parser's maximum body size. Maximum body size
* determines the point at which the library will abort reading an HTTP
* connection with the 413/request entity too large error.
*
* The default is 32MB
*
* @since 0.5.0
*/
static const size_t max_http_body_size = 32000000;
/// Global flag for enabling/disabling extensions
static const bool enable_extensions = true;
/// Extension specific settings:
/// permessage_compress extension
struct permessage_deflate_config {
typedef type::request_type request_type;
/// If the remote endpoint requests that we reset the compression
/// context after each message should we honor the request?
static const bool allow_disabling_context_takeover = true;
/// If the remote endpoint requests that we reduce the size of the
/// LZ77 sliding window size this is the lowest value that will be
/// allowed. Values range from 8 to 15. A value of 8 means we will
/// allow any possible window size. A value of 15 means do not allow
/// negotiation of the window size (ie require the default).
static const uint8_t minimum_outgoing_window_bits = 8;
};
typedef websocketpp::extensions::permessage_deflate::disabled
<permessage_deflate_config> permessage_deflate_type;
/// Autonegotiate permessage-deflate
/**
* Automatically enables the permessage-deflate extension.
*
* For clients this results in a permessage-deflate extension request being
* sent with every request rather than requiring it to be requested manually
*
* For servers this results in accepting the first set of extension settings
* requested by the client that we understand being used. The alternative is
* requiring the extension to be manually negotiated in `validate`. With
* auto-negotiate on, you may still override the auto-negotiate manually if
* needed.
*/
//static const bool autonegotiate_compression = false;
};
} // namespace config
} // namespace websocketpp
#endif // WEBSOCKETPP_CONFIG_CORE_HPP

View File

@ -0,0 +1,77 @@
/*
* Copyright (c) 2014, 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_CONFIG_ASIO_TLS_DEBUG_HPP
#define WEBSOCKETPP_CONFIG_ASIO_TLS_DEBUG_HPP
#include <websocketpp/config/debug.hpp>
#include <websocketpp/transport/asio/endpoint.hpp>
#include <websocketpp/transport/asio/security/tls.hpp>
// Pull in non-tls config
#include <websocketpp/config/debug_asio_no_tls.hpp>
// Define TLS config
namespace websocketpp {
namespace config {
/// Client/Server debug config with asio transport and TLS enabled
struct debug_asio_tls : public debug_core {
typedef debug_asio_tls type;
typedef debug_core base;
typedef base::concurrency_type concurrency_type;
typedef base::request_type request_type;
typedef base::response_type response_type;
typedef base::message_type message_type;
typedef base::con_msg_manager_type con_msg_manager_type;
typedef base::endpoint_msg_manager_type endpoint_msg_manager_type;
typedef base::alog_type alog_type;
typedef base::elog_type elog_type;
typedef base::rng_type rng_type;
struct transport_config : public base::transport_config {
typedef type::concurrency_type concurrency_type;
typedef type::alog_type alog_type;
typedef type::elog_type elog_type;
typedef type::request_type request_type;
typedef type::response_type response_type;
typedef websocketpp::transport::asio::tls_socket::endpoint socket_type;
};
typedef websocketpp::transport::asio::endpoint<transport_config>
transport_type;
};
} // namespace config
} // namespace websocketpp
#endif // WEBSOCKETPP_CONFIG_ASIO_TLS_DEBUG_HPP

View File

@ -0,0 +1,73 @@
/*
* Copyright (c) 2014, 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_CONFIG_ASIO_DEBUG_HPP
#define WEBSOCKETPP_CONFIG_ASIO_DEBUG_HPP
#include <websocketpp/config/debug.hpp>
#include <websocketpp/transport/asio/endpoint.hpp>
namespace websocketpp {
namespace config {
/// Client/Server debug config with asio transport and TLS disabled
struct debug_asio : public debug_core {
typedef debug_asio type;
typedef debug_core base;
typedef base::concurrency_type concurrency_type;
typedef base::request_type request_type;
typedef base::response_type response_type;
typedef base::message_type message_type;
typedef base::con_msg_manager_type con_msg_manager_type;
typedef base::endpoint_msg_manager_type endpoint_msg_manager_type;
typedef base::alog_type alog_type;
typedef base::elog_type elog_type;
typedef base::rng_type rng_type;
struct transport_config : public base::transport_config {
typedef type::concurrency_type concurrency_type;
typedef type::alog_type alog_type;
typedef type::elog_type elog_type;
typedef type::request_type request_type;
typedef type::response_type response_type;
typedef websocketpp::transport::asio::basic_socket::endpoint
socket_type;
};
typedef websocketpp::transport::asio::endpoint<transport_config>
transport_type;
};
} // namespace config
} // namespace websocketpp
#endif // WEBSOCKETPP_CONFIG_ASIO_DEBUG_HPP

View File

@ -0,0 +1,72 @@
/*
* Copyright (c) 2014, 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_CONFIG_MINIMAL_CLIENT_HPP
#define WEBSOCKETPP_CONFIG_MINIMAL_CLIENT_HPP
#include <websocketpp/config/minimal_server.hpp>
namespace websocketpp {
namespace config {
/// Client config with minimal dependencies
/**
* This config strips out as many dependencies as possible. It is suitable for
* use as a base class for custom configs that want to implement or choose their
* own policies for components that even the core config includes.
*
* NOTE: this config stubs out enough that it cannot be used directly. You must
* supply at least a transport policy and a cryptographically secure random
* number generation policy for a config based on `minimal_client` to do
* anything useful.
*
* Present dependency list for minimal_server config:
*
* C++98 STL:
* <algorithm>
* <map>
* <sstream>
* <string>
* <vector>
*
* C++11 STL or Boost
* <memory>
* <functional>
* <system_error>
*
* Operating System:
* <stdint.h> or <boost/cstdint.hpp>
* <netinet/in.h> or <winsock2.h> (for ntohl.. could potentially bundle this)
*
* @since 0.4.0-dev
*/
typedef minimal_server minimal_client;
} // namespace config
} // namespace websocketpp
#endif // WEBSOCKETPP_CONFIG_MINIMAL_CLIENT_HPP

View File

@ -0,0 +1,312 @@
/*
* Copyright (c) 2014, 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_CONFIG_MINIMAL_HPP
#define WEBSOCKETPP_CONFIG_MINIMAL_HPP
// Non-Policy common stuff
#include <websocketpp/common/platforms.hpp>
#include <websocketpp/common/cpp11.hpp>
#include <websocketpp/common/stdint.hpp>
// Concurrency
#include <websocketpp/concurrency/none.hpp>
// Transport
#include <websocketpp/transport/stub/endpoint.hpp>
// HTTP
#include <websocketpp/http/request.hpp>
#include <websocketpp/http/response.hpp>
// Messages
#include <websocketpp/message_buffer/message.hpp>
#include <websocketpp/message_buffer/alloc.hpp>
// Loggers
#include <websocketpp/logger/stub.hpp>
// RNG
#include <websocketpp/random/none.hpp>
// User stub base classes
#include <websocketpp/endpoint_base.hpp>
#include <websocketpp/connection_base.hpp>
// Extensions
#include <websocketpp/extensions/permessage_deflate/disabled.hpp>
namespace websocketpp {
namespace config {
/// Server config with minimal dependencies
/**
* This config strips out as many dependencies as possible. It is suitable for
* use as a base class for custom configs that want to implement or choose their
* own policies for components that even the core config includes.
*
* NOTE: this config stubs out enough that it cannot be used directly. You must
* supply at least a transport policy for a config based on `minimal_server` to
* do anything useful.
*
* Present dependency list for minimal_server config:
*
* C++98 STL:
* <algorithm>
* <map>
* <sstream>
* <string>
* <vector>
*
* C++11 STL or Boost
* <memory>
* <functional>
* <system_error>
*
* Operating System:
* <stdint.h> or <boost/cstdint.hpp>
* <netinet/in.h> or <winsock2.h> (for ntohl.. could potentially bundle this)
*
* @since 0.4.0-dev
*/
struct minimal_server {
typedef minimal_server type;
// Concurrency policy
typedef websocketpp::concurrency::none concurrency_type;
// HTTP Parser Policies
typedef http::parser::request request_type;
typedef http::parser::response response_type;
// Message Policies
typedef message_buffer::message<message_buffer::alloc::con_msg_manager>
message_type;
typedef message_buffer::alloc::con_msg_manager<message_type>
con_msg_manager_type;
typedef message_buffer::alloc::endpoint_msg_manager<con_msg_manager_type>
endpoint_msg_manager_type;
/// Logging policies
typedef websocketpp::log::stub elog_type;
typedef websocketpp::log::stub alog_type;
/// RNG policies
typedef websocketpp::random::none::int_generator<uint32_t> rng_type;
/// Controls compile time enabling/disabling of thread syncronization
/// code Disabling can provide a minor performance improvement to single
/// threaded applications
static bool const enable_multithreading = true;
struct transport_config {
typedef type::concurrency_type concurrency_type;
typedef type::elog_type elog_type;
typedef type::alog_type alog_type;
typedef type::request_type request_type;
typedef type::response_type response_type;
/// Controls compile time enabling/disabling of thread syncronization
/// code Disabling can provide a minor performance improvement to single
/// threaded applications
static bool const enable_multithreading = true;
/// Default timer values (in ms)
/// Length of time to wait for socket pre-initialization
/**
* Exactly what this includes depends on the socket policy in use
*/
static const long timeout_socket_pre_init = 5000;
/// Length of time to wait before a proxy handshake is aborted
static const long timeout_proxy = 5000;
/// Length of time to wait for socket post-initialization
/**
* Exactly what this includes depends on the socket policy in use.
* Often this means the TLS handshake
*/
static const long timeout_socket_post_init = 5000;
/// Length of time to wait for dns resolution
static const long timeout_dns_resolve = 5000;
/// Length of time to wait for TCP connect
static const long timeout_connect = 5000;
/// Length of time to wait for socket shutdown
static const long timeout_socket_shutdown = 5000;
};
/// Transport Endpoint Component
typedef websocketpp::transport::stub::endpoint<transport_config>
transport_type;
/// User overridable Endpoint base class
typedef websocketpp::endpoint_base endpoint_base;
/// User overridable Connection base class
typedef websocketpp::connection_base connection_base;
/// Default timer values (in ms)
/// Length of time before an opening handshake is aborted
static const long timeout_open_handshake = 5000;
/// Length of time before a closing handshake is aborted
static const long timeout_close_handshake = 5000;
/// Length of time to wait for a pong after a ping
static const long timeout_pong = 5000;
/// WebSocket Protocol version to use as a client
/**
* What version of the WebSocket Protocol to use for outgoing client
* connections. Setting this to a value other than 13 (RFC6455) is not
* recommended.
*/
static const int client_version = 13; // RFC6455
/// Default static error logging channels
/**
* Which error logging channels to enable at compile time. Channels not
* enabled here will be unable to be selected by programs using the library.
* This option gives an optimizing compiler the ability to remove entirely
* code to test whether or not to print out log messages on a certain
* channel
*
* Default is all except for development/debug level errors
*/
static const websocketpp::log::level elog_level =
websocketpp::log::elevel::none;
/// Default static access logging channels
/**
* Which access logging channels to enable at compile time. Channels not
* enabled here will be unable to be selected by programs using the library.
* This option gives an optimizing compiler the ability to remove entirely
* code to test whether or not to print out log messages on a certain
* channel
*
* Default is all except for development/debug level access messages
*/
static const websocketpp::log::level alog_level =
websocketpp::log::alevel::none;
///
static const size_t connection_read_buffer_size = 16384;
/// Drop connections immediately on protocol error.
/**
* Drop connections on protocol error rather than sending a close frame.
* Off by default. This may result in legit messages near the error being
* dropped as well. It may free up resources otherwise spent dealing with
* misbehaving clients.
*/
static const bool drop_on_protocol_error = false;
/// Suppresses the return of detailed connection close information
/**
* Silence close suppresses the return of detailed connection close
* information during the closing handshake. This information is useful
* for debugging and presenting useful errors to end users but may be
* undesirable for security reasons in some production environments.
* Close reasons could be used by an attacker to confirm that the endpoint
* is out of resources or be used to identify the WebSocket implementation
* in use.
*
* Note: this will suppress *all* close codes, including those explicitly
* sent by local applications.
*/
static const bool silent_close = false;
/// Default maximum message size
/**
* Default value for the processor's maximum message size. Maximum message size
* determines the point at which the library will fail a connection with the
* message_too_big protocol error.
*
* The default is 32MB
*
* @since 0.4.0-alpha1
*/
static const size_t max_message_size = 32000000;
/// Default maximum http body size
/**
* Default value for the http parser's maximum body size. Maximum body size
* determines the point at which the library will abort reading an HTTP
* connection with the 413/request entity too large error.
*
* The default is 32MB
*
* @since 0.5.0
*/
static const size_t max_http_body_size = 32000000;
/// Global flag for enabling/disabling extensions
static const bool enable_extensions = true;
/// Extension specific settings:
/// permessage_compress extension
struct permessage_deflate_config {
typedef core::request_type request_type;
/// If the remote endpoint requests that we reset the compression
/// context after each message should we honor the request?
static const bool allow_disabling_context_takeover = true;
/// If the remote endpoint requests that we reduce the size of the
/// LZ77 sliding window size this is the lowest value that will be
/// allowed. Values range from 8 to 15. A value of 8 means we will
/// allow any possible window size. A value of 15 means do not allow
/// negotiation of the window size (ie require the default).
static const uint8_t minimum_outgoing_window_bits = 8;
};
typedef websocketpp::extensions::permessage_deflate::disabled
<permessage_deflate_config> permessage_deflate_type;
/// Autonegotiate permessage-deflate
/**
* Automatically enables the permessage-deflate extension.
*
* For clients this results in a permessage-deflate extension request being
* sent with every request rather than requiring it to be requested manually
*
* For servers this results in accepting the first set of extension settings
* requested by the client that we understand being used. The alternative is
* requiring the extension to be manually negotiated in `validate`. With
* auto-negotiate on, you may still override the auto-negotiate manually if
* needed.
*/
//static const bool autonegotiate_compression = false;
};
} // namespace config
} // namespace websocketpp
#endif // WEBSOCKETPP_CONFIG_MINIMAL_HPP

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,38 @@
/*
* Copyright (c) 2014, 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_CONNECTION_BASE_HPP
#define WEBSOCKETPP_CONNECTION_BASE_HPP
namespace websocketpp {
/// Stub for user supplied base class.
class connection_base {};
} // namespace websocketpp
#endif // WEBSOCKETPP_CONNECTION_BASE_HPP

View File

@ -0,0 +1,700 @@
/*
* Copyright (c) 2014, 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_ENDPOINT_HPP
#define WEBSOCKETPP_ENDPOINT_HPP
#include <websocketpp/connection.hpp>
#include <websocketpp/logger/levels.hpp>
#include <websocketpp/version.hpp>
#include <string>
namespace websocketpp {
/// Creates and manages connections associated with a WebSocket endpoint
template <typename connection, typename config>
class endpoint : public config::transport_type, public config::endpoint_base {
public:
// Import appropriate types from our helper class
// See endpoint_types for more details.
typedef endpoint<connection,config> type;
/// Type of the transport component of this endpoint
typedef typename config::transport_type transport_type;
/// Type of the concurrency component of this endpoint
typedef typename config::concurrency_type concurrency_type;
/// Type of the connections that this endpoint creates
typedef connection connection_type;
/// Shared pointer to connection_type
typedef typename connection_type::ptr connection_ptr;
/// Weak pointer to connection type
typedef typename connection_type::weak_ptr connection_weak_ptr;
/// Type of the transport component of the connections that this endpoint
/// creates
typedef typename transport_type::transport_con_type transport_con_type;
/// Type of a shared pointer to the transport component of the connections
/// that this endpoint creates.
typedef typename transport_con_type::ptr transport_con_ptr;
/// Type of message_handler
typedef typename connection_type::message_handler message_handler;
/// Type of message pointers that this endpoint uses
typedef typename connection_type::message_ptr message_ptr;
/// Type of error logger
typedef typename config::elog_type elog_type;
/// Type of access logger
typedef typename config::alog_type alog_type;
/// Type of our concurrency policy's scoped lock object
typedef typename concurrency_type::scoped_lock_type scoped_lock_type;
/// Type of our concurrency policy's mutex object
typedef typename concurrency_type::mutex_type mutex_type;
/// Type of RNG
typedef typename config::rng_type rng_type;
// TODO: organize these
typedef typename connection_type::termination_handler termination_handler;
// This would be ideal. Requires C++11 though
//friend connection;
explicit endpoint(bool p_is_server)
: m_alog(new alog_type(config::alog_level, log::channel_type_hint::access))
, m_elog(new elog_type(config::elog_level, log::channel_type_hint::error))
, m_user_agent(::websocketpp::user_agent)
, m_open_handshake_timeout_dur(config::timeout_open_handshake)
, m_close_handshake_timeout_dur(config::timeout_close_handshake)
, m_pong_timeout_dur(config::timeout_pong)
, m_max_message_size(config::max_message_size)
, m_max_http_body_size(config::max_http_body_size)
, m_is_server(p_is_server)
{
m_alog->set_channels(config::alog_level);
m_elog->set_channels(config::elog_level);
m_alog->write(log::alevel::devel, "endpoint constructor");
transport_type::init_logging(m_alog, m_elog);
}
/// Destructor
~endpoint<connection,config>() {}
#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
// no copy constructor because endpoints are not copyable
endpoint(endpoint &) = delete;
// no copy assignment operator because endpoints are not copyable
endpoint & operator=(endpoint const &) = delete;
#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
#ifdef _WEBSOCKETPP_MOVE_SEMANTICS_
/// Move constructor
endpoint(endpoint && o)
: config::transport_type(std::move(o))
, config::endpoint_base(std::move(o))
, m_alog(std::move(o.m_alog))
, m_elog(std::move(o.m_elog))
, m_user_agent(std::move(o.m_user_agent))
, m_open_handler(std::move(o.m_open_handler))
, m_close_handler(std::move(o.m_close_handler))
, m_fail_handler(std::move(o.m_fail_handler))
, m_ping_handler(std::move(o.m_ping_handler))
, m_pong_handler(std::move(o.m_pong_handler))
, m_pong_timeout_handler(std::move(o.m_pong_timeout_handler))
, m_interrupt_handler(std::move(o.m_interrupt_handler))
, m_http_handler(std::move(o.m_http_handler))
, m_validate_handler(std::move(o.m_validate_handler))
, m_message_handler(std::move(o.m_message_handler))
, m_open_handshake_timeout_dur(o.m_open_handshake_timeout_dur)
, m_close_handshake_timeout_dur(o.m_close_handshake_timeout_dur)
, m_pong_timeout_dur(o.m_pong_timeout_dur)
, m_max_message_size(o.m_max_message_size)
, m_max_http_body_size(o.m_max_http_body_size)
, m_rng(std::move(o.m_rng))
, m_is_server(o.m_is_server)
{}
#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
// no move assignment operator because of const member variables
endpoint & operator=(endpoint &&) = delete;
#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
#endif // _WEBSOCKETPP_MOVE_SEMANTICS_
/// Returns the user agent string that this endpoint will use
/**
* Returns the user agent string that this endpoint will use when creating
* new connections.
*
* The default value for this version is stored in websocketpp::user_agent
*
* @return The user agent string.
*/
std::string get_user_agent() const {
scoped_lock_type guard(m_mutex);
return m_user_agent;
}
/// Sets the user agent string that this endpoint will use
/**
* Sets the identifier that this endpoint will use when creating new
* connections. Changing this value will only affect future connections.
* For client endpoints this will be sent as the "User-Agent" header in
* outgoing requests. For server endpoints this will be sent in the "Server"
* response header.
*
* Setting this value to the empty string will suppress the use of the
* Server and User-Agent headers. This is typically done to hide
* implementation details for security purposes.
*
* For best results set this before accepting or opening connections.
*
* The default value for this version is stored in websocketpp::user_agent
*
* This can be overridden on an individual connection basis by setting a
* custom "Server" header during the validate handler or "User-Agent"
* header on a connection before calling connect().
*
* @param ua The string to set the user agent to.
*/
void set_user_agent(std::string const & ua) {
scoped_lock_type guard(m_mutex);
m_user_agent = ua;
}
/// Returns whether or not this endpoint is a server.
/**
* @return Whether or not this endpoint is a server
*/
bool is_server() const {
return m_is_server;
}
/********************************/
/* Pass-through logging adaptor */
/********************************/
/// Set Access logging channel
/**
* Set the access logger's channel value. The value is a number whose
* interpretation depends on the logging policy in use.
*
* @param channels The channel value(s) to set
*/
void set_access_channels(log::level channels) {
m_alog->set_channels(channels);
}
/// Clear Access logging channels
/**
* Clear the access logger's channel value. The value is a number whose
* interpretation depends on the logging policy in use.
*
* @param channels The channel value(s) to clear
*/
void clear_access_channels(log::level channels) {
m_alog->clear_channels(channels);
}
/// Set Error logging channel
/**
* Set the error logger's channel value. The value is a number whose
* interpretation depends on the logging policy in use.
*
* @param channels The channel value(s) to set
*/
void set_error_channels(log::level channels) {
m_elog->set_channels(channels);
}
/// Clear Error logging channels
/**
* Clear the error logger's channel value. The value is a number whose
* interpretation depends on the logging policy in use.
*
* @param channels The channel value(s) to clear
*/
void clear_error_channels(log::level channels) {
m_elog->clear_channels(channels);
}
/// Get reference to access logger
/**
* @return A reference to the access logger
*/
alog_type & get_alog() {
return *m_alog;
}
/// Get reference to error logger
/**
* @return A reference to the error logger
*/
elog_type & get_elog() {
return *m_elog;
}
/*************************/
/* Set Handler functions */
/*************************/
void set_open_handler(open_handler h) {
m_alog->write(log::alevel::devel,"set_open_handler");
scoped_lock_type guard(m_mutex);
m_open_handler = h;
}
void set_close_handler(close_handler h) {
m_alog->write(log::alevel::devel,"set_close_handler");
scoped_lock_type guard(m_mutex);
m_close_handler = h;
}
void set_fail_handler(fail_handler h) {
m_alog->write(log::alevel::devel,"set_fail_handler");
scoped_lock_type guard(m_mutex);
m_fail_handler = h;
}
void set_ping_handler(ping_handler h) {
m_alog->write(log::alevel::devel,"set_ping_handler");
scoped_lock_type guard(m_mutex);
m_ping_handler = h;
}
void set_pong_handler(pong_handler h) {
m_alog->write(log::alevel::devel,"set_pong_handler");
scoped_lock_type guard(m_mutex);
m_pong_handler = h;
}
void set_pong_timeout_handler(pong_timeout_handler h) {
m_alog->write(log::alevel::devel,"set_pong_timeout_handler");
scoped_lock_type guard(m_mutex);
m_pong_timeout_handler = h;
}
void set_interrupt_handler(interrupt_handler h) {
m_alog->write(log::alevel::devel,"set_interrupt_handler");
scoped_lock_type guard(m_mutex);
m_interrupt_handler = h;
}
void set_http_handler(http_handler h) {
m_alog->write(log::alevel::devel,"set_http_handler");
scoped_lock_type guard(m_mutex);
m_http_handler = h;
}
void set_validate_handler(validate_handler h) {
m_alog->write(log::alevel::devel,"set_validate_handler");
scoped_lock_type guard(m_mutex);
m_validate_handler = h;
}
void set_message_handler(message_handler h) {
m_alog->write(log::alevel::devel,"set_message_handler");
scoped_lock_type guard(m_mutex);
m_message_handler = h;
}
//////////////////////////////////////////
// Connection timeouts and other limits //
//////////////////////////////////////////
/// Set open handshake timeout
/**
* Sets the length of time the library will wait after an opening handshake
* has been initiated before cancelling it. This can be used to prevent
* excessive wait times for outgoing clients or excessive resource usage
* from broken clients or DoS attacks on servers.
*
* Connections that time out will have their fail handlers called with the
* open_handshake_timeout error code.
*
* The default value is specified via the compile time config value
* 'timeout_open_handshake'. The default value in the core config
* is 5000ms. A value of 0 will disable the timer entirely.
*
* To be effective, the transport you are using must support timers. See
* the documentation for your transport policy for details about its
* timer support.
*
* @param dur The length of the open handshake timeout in ms
*/
void set_open_handshake_timeout(long dur) {
scoped_lock_type guard(m_mutex);
m_open_handshake_timeout_dur = dur;
}
/// Set close handshake timeout
/**
* Sets the length of time the library will wait after a closing handshake
* has been initiated before cancelling it. This can be used to prevent
* excessive wait times for outgoing clients or excessive resource usage
* from broken clients or DoS attacks on servers.
*
* Connections that time out will have their close handlers called with the
* close_handshake_timeout error code.
*
* The default value is specified via the compile time config value
* 'timeout_close_handshake'. The default value in the core config
* is 5000ms. A value of 0 will disable the timer entirely.
*
* To be effective, the transport you are using must support timers. See
* the documentation for your transport policy for details about its
* timer support.
*
* @param dur The length of the close handshake timeout in ms
*/
void set_close_handshake_timeout(long dur) {
scoped_lock_type guard(m_mutex);
m_close_handshake_timeout_dur = dur;
}
/// Set pong timeout
/**
* Sets the length of time the library will wait for a pong response to a
* ping. This can be used as a keepalive or to detect broken connections.
*
* Pong responses that time out will have the pong timeout handler called.
*
* The default value is specified via the compile time config value
* 'timeout_pong'. The default value in the core config
* is 5000ms. A value of 0 will disable the timer entirely.
*
* To be effective, the transport you are using must support timers. See
* the documentation for your transport policy for details about its
* timer support.
*
* @param dur The length of the pong timeout in ms
*/
void set_pong_timeout(long dur) {
scoped_lock_type guard(m_mutex);
m_pong_timeout_dur = dur;
}
/// Get default maximum message size
/**
* Get the default maximum message size that will be used for new
* connections created by this endpoint. The maximum message size determines
* the point at which the connection will fail a connection with the
* message_too_big protocol error.
*
* The default is set by the max_message_size value from the template config
*
* @since 0.3.0
*/
size_t get_max_message_size() const {
return m_max_message_size;
}
/// Set default maximum message size
/**
* Set the default maximum message size that will be used for new
* connections created by this endpoint. Maximum message size determines the
* point at which the connection will fail a connection with the
* message_too_big protocol error.
*
* The default is set by the max_message_size value from the template config
*
* @since 0.3.0
*
* @param new_value The value to set as the maximum message size.
*/
void set_max_message_size(size_t new_value) {
m_max_message_size = new_value;
}
/// Get maximum HTTP message body size
/**
* Get maximum HTTP message body size. Maximum message body size determines
* the point at which the connection will stop reading an HTTP request whose
* body is too large.
*
* The default is set by the max_http_body_size value from the template
* config
*
* @since 0.5.0
*
* @return The maximum HTTP message body size
*/
size_t get_max_http_body_size() const {
return m_max_http_body_size;
}
/// Set maximum HTTP message body size
/**
* Set maximum HTTP message body size. Maximum message body size determines
* the point at which the connection will stop reading an HTTP request whose
* body is too large.
*
* The default is set by the max_http_body_size value from the template
* config
*
* @since 0.5.1
*
* @param new_value The value to set as the maximum message size.
*/
void set_max_http_body_size(size_t new_value) {
m_max_http_body_size = new_value;
}
/*************************************/
/* Connection pass through functions */
/*************************************/
/**
* These functions act as adaptors to their counterparts in connection. They
* can produce one additional type of error, the bad_connection error, that
* indicates that the conversion from connection_hdl to connection_ptr
* failed due to the connection not existing anymore. Each method has a
* default and an exception free varient.
*/
void interrupt(connection_hdl hdl, lib::error_code & ec);
void interrupt(connection_hdl hdl);
/// Pause reading of new data (exception free)
/**
* Signals to the connection to halt reading of new data. While reading is
* paused, the connection will stop reading from its associated socket. In
* turn this will result in TCP based flow control kicking in and slowing
* data flow from the remote endpoint.
*
* This is useful for applications that push new requests to a queue to be
* processed by another thread and need a way to signal when their request
* queue is full without blocking the network processing thread.
*
* Use `resume_reading()` to resume.
*
* If supported by the transport this is done asynchronously. As such
* reading may not stop until the current read operation completes.
* Typically you can expect to receive no more bytes after initiating a read
* pause than the size of the read buffer.
*
* If reading is paused for this connection already nothing is changed.
*/
void pause_reading(connection_hdl hdl, lib::error_code & ec);
/// Pause reading of new data
void pause_reading(connection_hdl hdl);
/// Resume reading of new data (exception free)
/**
* Signals to the connection to resume reading of new data after it was
* paused by `pause_reading()`.
*
* If reading is not paused for this connection already nothing is changed.
*/
void resume_reading(connection_hdl hdl, lib::error_code & ec);
/// Resume reading of new data
void resume_reading(connection_hdl hdl);
/// Send deferred HTTP Response
/**
* Sends an http response to an HTTP connection that was deferred. This will
* send a complete response including all headers, status line, and body
* text. The connection will be closed afterwards.
*
* Exception free variant
*
* @since 0.6.0
*
* @param hdl The connection to send the response on
* @param ec A status code, zero on success, non-zero otherwise
*/
void send_http_response(connection_hdl hdl, lib::error_code & ec);
/// Send deferred HTTP Response (exception free)
/**
* Sends an http response to an HTTP connection that was deferred. This will
* send a complete response including all headers, status line, and body
* text. The connection will be closed afterwards.
*
* Exception variant
*
* @since 0.6.0
*
* @param hdl The connection to send the response on
*/
void send_http_response(connection_hdl hdl);
/// Create a message and add it to the outgoing send queue (exception free)
/**
* Convenience method to send a message given a payload string and an opcode
*
* @param [in] hdl The handle identifying the connection to send via.
* @param [in] payload The payload string to generated the message with
* @param [in] op The opcode to generated the message with.
* @param [out] ec A code to fill in for errors
*/
void send(connection_hdl hdl, std::string const & payload,
frame::opcode::value op, lib::error_code & ec);
/// Create a message and add it to the outgoing send queue
/**
* Convenience method to send a message given a payload string and an opcode
*
* @param [in] hdl The handle identifying the connection to send via.
* @param [in] payload The payload string to generated the message with
* @param [in] op The opcode to generated the message with.
* @param [out] ec A code to fill in for errors
*/
void send(connection_hdl hdl, std::string const & payload,
frame::opcode::value op);
void send(connection_hdl hdl, void const * payload, size_t len,
frame::opcode::value op, lib::error_code & ec);
void send(connection_hdl hdl, void const * payload, size_t len,
frame::opcode::value op);
void send(connection_hdl hdl, message_ptr msg, lib::error_code & ec);
void send(connection_hdl hdl, message_ptr msg);
void close(connection_hdl hdl, close::status::value const code,
std::string const & reason, lib::error_code & ec);
void close(connection_hdl hdl, close::status::value const code,
std::string const & reason);
/// Send a ping to a specific connection
/**
* @since 0.3.0-alpha3
*
* @param [in] hdl The connection_hdl of the connection to send to.
* @param [in] payload The payload string to send.
* @param [out] ec A reference to an error code to fill in
*/
void ping(connection_hdl hdl, std::string const & payload,
lib::error_code & ec);
/// Send a ping to a specific connection
/**
* Exception variant of `ping`
*
* @since 0.3.0-alpha3
*
* @param [in] hdl The connection_hdl of the connection to send to.
* @param [in] payload The payload string to send.
*/
void ping(connection_hdl hdl, std::string const & payload);
/// Send a pong to a specific connection
/**
* @since 0.3.0-alpha3
*
* @param [in] hdl The connection_hdl of the connection to send to.
* @param [in] payload The payload string to send.
* @param [out] ec A reference to an error code to fill in
*/
void pong(connection_hdl hdl, std::string const & payload,
lib::error_code & ec);
/// Send a pong to a specific connection
/**
* Exception variant of `pong`
*
* @since 0.3.0-alpha3
*
* @param [in] hdl The connection_hdl of the connection to send to.
* @param [in] payload The payload string to send.
*/
void pong(connection_hdl hdl, std::string const & payload);
/// Retrieves a connection_ptr from a connection_hdl (exception free)
/**
* Converting a weak pointer to shared_ptr is not thread safe because the
* pointer could be deleted at any time.
*
* NOTE: This method may be called by handler to upgrade its handle to a
* full connection_ptr. That full connection may then be used safely for the
* remainder of the handler body. get_con_from_hdl and the resulting
* connection_ptr are NOT safe to use outside the handler loop.
*
* @param hdl The connection handle to translate
*
* @return the connection_ptr. May be NULL if the handle was invalid.
*/
connection_ptr get_con_from_hdl(connection_hdl hdl, lib::error_code & ec) {
connection_ptr con = lib::static_pointer_cast<connection_type>(
hdl.lock());
if (!con) {
ec = error::make_error_code(error::bad_connection);
}
return con;
}
/// Retrieves a connection_ptr from a connection_hdl (exception version)
connection_ptr get_con_from_hdl(connection_hdl hdl) {
lib::error_code ec;
connection_ptr con = this->get_con_from_hdl(hdl,ec);
if (ec) {
throw exception(ec);
}
return con;
}
protected:
connection_ptr create_connection();
lib::shared_ptr<alog_type> m_alog;
lib::shared_ptr<elog_type> m_elog;
private:
// dynamic settings
std::string m_user_agent;
open_handler m_open_handler;
close_handler m_close_handler;
fail_handler m_fail_handler;
ping_handler m_ping_handler;
pong_handler m_pong_handler;
pong_timeout_handler m_pong_timeout_handler;
interrupt_handler m_interrupt_handler;
http_handler m_http_handler;
validate_handler m_validate_handler;
message_handler m_message_handler;
long m_open_handshake_timeout_dur;
long m_close_handshake_timeout_dur;
long m_pong_timeout_dur;
size_t m_max_message_size;
size_t m_max_http_body_size;
rng_type m_rng;
// static settings
bool const m_is_server;
// endpoint state
mutable mutex_type m_mutex;
};
} // namespace websocketpp
#include <websocketpp/impl/endpoint_impl.hpp>
#endif // WEBSOCKETPP_ENDPOINT_HPP

View File

@ -0,0 +1,38 @@
/*
* Copyright (c) 2014, 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_ENDPOINT_BASE_HPP
#define WEBSOCKETPP_ENDPOINT_BASE_HPP
namespace websocketpp {
/// Stub for user supplied base class.
class endpoint_base {};
} // namespace websocketpp
#endif // WEBSOCKETPP_ENDPOINT_BASE_HPP

View File

@ -0,0 +1,277 @@
/*
* Copyright (c) 2014, 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_ERROR_HPP
#define WEBSOCKETPP_ERROR_HPP
#include <exception>
#include <string>
#include <utility>
#include <websocketpp/common/cpp11.hpp>
#include <websocketpp/common/system_error.hpp>
namespace websocketpp {
/// Combination error code / string type for returning two values
typedef std::pair<lib::error_code,std::string> err_str_pair;
/// Library level error codes
namespace error {
enum value {
/// Catch-all library error
general = 1,
/// send attempted when endpoint write queue was full
send_queue_full,
/// Attempted an operation using a payload that was improperly formatted
/// ex: invalid UTF8 encoding on a text message.
payload_violation,
/// Attempted to open a secure connection with an insecure endpoint
endpoint_not_secure,
/// Attempted an operation that required an endpoint that is no longer
/// available. This is usually because the endpoint went out of scope
/// before a connection that it created.
endpoint_unavailable,
/// An invalid uri was supplied
invalid_uri,
/// The endpoint is out of outgoing message buffers
no_outgoing_buffers,
/// The endpoint is out of incoming message buffers
no_incoming_buffers,
/// The connection was in the wrong state for this operation
invalid_state,
/// Unable to parse close code
bad_close_code,
/// Close code is in a reserved range
reserved_close_code,
/// Close code is invalid
invalid_close_code,
/// Invalid UTF-8
invalid_utf8,
/// Invalid subprotocol
invalid_subprotocol,
/// An operation was attempted on a connection that did not exist or was
/// already deleted.
bad_connection,
/// Unit testing utility error code
test,
/// Connection creation attempted failed
con_creation_failed,
/// Selected subprotocol was not requested by the client
unrequested_subprotocol,
/// Attempted to use a client specific feature on a server endpoint
client_only,
/// Attempted to use a server specific feature on a client endpoint
server_only,
/// HTTP connection ended
http_connection_ended,
/// WebSocket opening handshake timed out
open_handshake_timeout,
/// WebSocket close handshake timed out
close_handshake_timeout,
/// Invalid port in URI
invalid_port,
/// An async accept operation failed because the underlying transport has been
/// requested to not listen for new connections anymore.
async_accept_not_listening,
/// The requested operation was canceled
operation_canceled,
/// Connection rejected
rejected,
/// Upgrade Required. This happens if an HTTP request is made to a
/// WebSocket++ server that doesn't implement an http handler
upgrade_required,
/// Invalid WebSocket protocol version
invalid_version,
/// Unsupported WebSocket protocol version
unsupported_version,
/// HTTP parse error
http_parse_error,
/// Extension negotiation failed
extension_neg_failed
}; // enum value
class category : public lib::error_category {
public:
category() {}
char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ {
return "websocketpp";
}
std::string message(int value) const {
switch(value) {
case error::general:
return "Generic error";
case error::send_queue_full:
return "send queue full";
case error::payload_violation:
return "payload violation";
case error::endpoint_not_secure:
return "endpoint not secure";
case error::endpoint_unavailable:
return "endpoint not available";
case error::invalid_uri:
return "invalid uri";
case error::no_outgoing_buffers:
return "no outgoing message buffers";
case error::no_incoming_buffers:
return "no incoming message buffers";
case error::invalid_state:
return "invalid state";
case error::bad_close_code:
return "Unable to extract close code";
case error::invalid_close_code:
return "Extracted close code is in an invalid range";
case error::reserved_close_code:
return "Extracted close code is in a reserved range";
case error::invalid_utf8:
return "Invalid UTF-8";
case error::invalid_subprotocol:
return "Invalid subprotocol";
case error::bad_connection:
return "Bad Connection";
case error::test:
return "Test Error";
case error::con_creation_failed:
return "Connection creation attempt failed";
case error::unrequested_subprotocol:
return "Selected subprotocol was not requested by the client";
case error::client_only:
return "Feature not available on server endpoints";
case error::server_only:
return "Feature not available on client endpoints";
case error::http_connection_ended:
return "HTTP connection ended";
case error::open_handshake_timeout:
return "The opening handshake timed out";
case error::close_handshake_timeout:
return "The closing handshake timed out";
case error::invalid_port:
return "Invalid URI port";
case error::async_accept_not_listening:
return "Async Accept not listening";
case error::operation_canceled:
return "Operation canceled";
case error::rejected:
return "Connection rejected";
case error::upgrade_required:
return "Upgrade required";
case error::invalid_version:
return "Invalid version";
case error::unsupported_version:
return "Unsupported version";
case error::http_parse_error:
return "HTTP parse error";
case error::extension_neg_failed:
return "Extension negotiation failed";
default:
return "Unknown";
}
}
};
inline const lib::error_category& get_category() {
static category instance;
return instance;
}
inline lib::error_code make_error_code(error::value e) {
return lib::error_code(static_cast<int>(e), get_category());
}
} // namespace error
} // namespace websocketpp
_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_
template<> struct is_error_code_enum<websocketpp::error::value>
{
static bool const value = true;
};
_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_
namespace websocketpp {
class exception : public std::exception {
public:
exception(std::string const & msg, lib::error_code ec = make_error_code(error::general))
: m_msg(msg.empty() ? ec.message() : msg), m_code(ec)
{}
explicit exception(lib::error_code ec)
: m_msg(ec.message()), m_code(ec)
{}
~exception() throw() {}
virtual char const * what() const throw() {
return m_msg.c_str();
}
lib::error_code code() const throw() {
return m_code;
}
const std::string m_msg;
lib::error_code m_code;
};
} // namespace websocketpp
#endif // WEBSOCKETPP_ERROR_HPP

View File

@ -0,0 +1,102 @@
/*
* Copyright (c) 2014, 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_EXTENSION_HPP
#define WEBSOCKETPP_EXTENSION_HPP
#include <websocketpp/common/cpp11.hpp>
#include <websocketpp/common/system_error.hpp>
#include <string>
#include <vector>
namespace websocketpp {
/**
* Some generic information about extensions
*
* Each extension object has an implemented flag. It can be retrieved by calling
* is_implemented(). This compile time flag indicates whether or not the object
* in question actually implements the extension or if it is a placeholder stub
*
* Each extension object also has an enabled flag. It can be retrieved by
* calling is_enabled(). This runtime flag indicates whether or not the
* extension has been negotiated for this connection.
*/
namespace extensions {
namespace error {
enum value {
/// Catch all
general = 1,
/// Extension disabled
disabled
};
class category : public lib::error_category {
public:
category() {}
const char *name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ {
return "websocketpp.extension";
}
std::string message(int value) const {
switch(value) {
case general:
return "Generic extension error";
case disabled:
return "Use of methods from disabled extension";
default:
return "Unknown permessage-compress error";
}
}
};
inline lib::error_category const & get_category() {
static category instance;
return instance;
}
inline lib::error_code make_error_code(error::value e) {
return lib::error_code(static_cast<int>(e), get_category());
}
} // namespace error
} // namespace extensions
} // namespace websocketpp
_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_
template<> struct is_error_code_enum
<websocketpp::extensions::error::value>
{
static const bool value = true;
};
_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_
#endif // WEBSOCKETPP_EXTENSION_HPP

View File

@ -0,0 +1,129 @@
/*
* Copyright (c) 2014, 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_EXTENSION_PERMESSAGE_DEFLATE_DISABLED_HPP
#define WEBSOCKETPP_EXTENSION_PERMESSAGE_DEFLATE_DISABLED_HPP
#include <websocketpp/common/cpp11.hpp>
#include <websocketpp/common/stdint.hpp>
#include <websocketpp/common/system_error.hpp>
#include <websocketpp/http/constants.hpp>
#include <websocketpp/extensions/extension.hpp>
#include <map>
#include <string>
#include <utility>
namespace websocketpp {
namespace extensions {
namespace permessage_deflate {
/// Stub class for use when disabling permessage_deflate extension
/**
* This class is a stub that implements the permessage_deflate interface
* with minimal dependencies. It is used to disable permessage_deflate
* functionality at compile time without loading any unnecessary code.
*/
template <typename config>
class disabled {
typedef std::pair<lib::error_code,std::string> err_str_pair;
public:
/// Negotiate extension
/**
* The disabled extension always fails the negotiation with a disabled
* error.
*
* @param offer Attribute from client's offer
* @return Status code and value to return to remote endpoint
*/
err_str_pair negotiate(http::attribute_list const &) {
return make_pair(make_error_code(error::disabled),std::string());
}
/// Initialize state
/**
* For the disabled extension state initialization is a no-op.
*
* @param is_server True to initialize as a server, false for a client.
* @return A code representing the error that occurred, if any
*/
lib::error_code init(bool) {
return lib::error_code();
}
/// Returns true if the extension is capable of providing
/// permessage_deflate functionality
bool is_implemented() const {
return false;
}
/// Returns true if permessage_deflate functionality is active for this
/// connection
bool is_enabled() const {
return false;
}
/// Generate extension offer
/**
* Creates an offer string to include in the Sec-WebSocket-Extensions
* header of outgoing client requests.
*
* @return A WebSocket extension offer string for this extension
*/
std::string generate_offer() const {
return "";
}
/// Compress bytes
/**
* @param [in] in String to compress
* @param [out] out String to append compressed bytes to
* @return Error or status code
*/
lib::error_code compress(std::string const &, std::string &) {
return make_error_code(error::disabled);
}
/// Decompress bytes
/**
* @param buf Byte buffer to decompress
* @param len Length of buf
* @param out String to append decompressed bytes to
* @return Error or status code
*/
lib::error_code decompress(uint8_t const *, size_t, std::string &) {
return make_error_code(error::disabled);
}
};
} // namespace permessage_deflate
} // namespace extensions
} // namespace websocketpp
#endif // WEBSOCKETPP_EXTENSION_PERMESSAGE_DEFLATE_DISABLED_HPP

View File

@ -0,0 +1,817 @@
/*
* Copyright (c) 2015, Peter Thorson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef WEBSOCKETPP_PROCESSOR_EXTENSION_PERMESSAGEDEFLATE_HPP
#define WEBSOCKETPP_PROCESSOR_EXTENSION_PERMESSAGEDEFLATE_HPP
#include <websocketpp/common/cpp11.hpp>
#include <websocketpp/common/memory.hpp>
#include <websocketpp/common/platforms.hpp>
#include <websocketpp/common/stdint.hpp>
#include <websocketpp/common/system_error.hpp>
#include <websocketpp/error.hpp>
#include <websocketpp/extensions/extension.hpp>
#include "zlib.h"
#include <algorithm>
#include <string>
#include <vector>
namespace websocketpp {
namespace extensions {
/// Implementation of RFC 7692, the permessage-deflate WebSocket extension
/**
* ### permessage-deflate interface
*
* **init**\n
* `lib::error_code init(bool is_server)`\n
* Performs initialization
*
* **is_implimented**\n
* `bool is_implimented()`\n
* Returns whether or not the object impliments the extension or not
*
* **is_enabled**\n
* `bool is_enabled()`\n
* Returns whether or not the extension was negotiated for the current
* connection
*
* **generate_offer**\n
* `std::string generate_offer() const`\n
* Create an extension offer string based on local policy
*
* **validate_response**\n
* `lib::error_code validate_response(http::attribute_list const & response)`\n
* Negotiate the parameters of extension use
*
* **negotiate**\n
* `err_str_pair negotiate(http::attribute_list const & attributes)`\n
* Negotiate the parameters of extension use
*
* **compress**\n
* `lib::error_code compress(std::string const & in, std::string & out)`\n
* Compress the bytes in `in` and append them to `out`
*
* **decompress**\n
* `lib::error_code decompress(uint8_t const * buf, size_t len, std::string &
* out)`\n
* Decompress `len` bytes from `buf` and append them to string `out`
*/
namespace permessage_deflate {
/// Permessage deflate error values
namespace error {
enum value {
/// Catch all
general = 1,
/// Invalid extension attributes
invalid_attributes,
/// Invalid extension attribute value
invalid_attribute_value,
/// Invalid megotiation mode
invalid_mode,
/// Unsupported extension attributes
unsupported_attributes,
/// Invalid value for max_window_bits
invalid_max_window_bits,
/// ZLib Error
zlib_error,
/// Uninitialized
uninitialized,
};
/// Permessage-deflate error category
class category : public lib::error_category {
public:
category() {}
char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ {
return "websocketpp.extension.permessage-deflate";
}
std::string message(int value) const {
switch(value) {
case general:
return "Generic permessage-compress error";
case invalid_attributes:
return "Invalid extension attributes";
case invalid_attribute_value:
return "Invalid extension attribute value";
case invalid_mode:
return "Invalid permessage-deflate negotiation mode";
case unsupported_attributes:
return "Unsupported extension attributes";
case invalid_max_window_bits:
return "Invalid value for max_window_bits";
case zlib_error:
return "A zlib function returned an error";
case uninitialized:
return "Deflate extension must be initialized before use";
default:
return "Unknown permessage-compress error";
}
}
};
/// Get a reference to a static copy of the permessage-deflate error category
inline lib::error_category const & get_category() {
static category instance;
return instance;
}
/// Create an error code in the permessage-deflate category
inline lib::error_code make_error_code(error::value e) {
return lib::error_code(static_cast<int>(e), get_category());
}
} // namespace error
} // namespace permessage_deflate
} // namespace extensions
} // namespace websocketpp
_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_
template<> struct is_error_code_enum
<websocketpp::extensions::permessage_deflate::error::value>
{
static bool const value = true;
};
_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_
namespace websocketpp {
namespace extensions {
namespace permessage_deflate {
/// Default value for server_max_window_bits as defined by RFC 7692
static uint8_t const default_server_max_window_bits = 15;
/// Minimum value for server_max_window_bits as defined by RFC 7692
/**
* NOTE: A value of 8 is not actually supported by zlib, the deflate
* library that WebSocket++ uses. To preserve backwards compatibility
* with RFC 7692 and previous versions of the library a value of 8
* is accepted by the library but will always be negotiated as 9.
*/
static uint8_t const min_server_max_window_bits = 8;
/// Maximum value for server_max_window_bits as defined by RFC 7692
static uint8_t const max_server_max_window_bits = 15;
/// Default value for client_max_window_bits as defined by RFC 7692
static uint8_t const default_client_max_window_bits = 15;
/// Minimum value for client_max_window_bits as defined by RFC 7692
/**
* NOTE: A value of 8 is not actually supported by zlib, the deflate
* library that WebSocket++ uses. To preserve backwards compatibility
* with RFC 7692 and previous versions of the library a value of 8
* is accepted by the library but will always be negotiated as 9.
*/
static uint8_t const min_client_max_window_bits = 8;
/// Maximum value for client_max_window_bits as defined by RFC 7692
static uint8_t const max_client_max_window_bits = 15;
namespace mode {
enum value {
/// Accept any value the remote endpoint offers
accept = 1,
/// Decline any value the remote endpoint offers. Insist on defaults.
decline,
/// Use the largest value common to both offers
largest,
/// Use the smallest value common to both offers
smallest
};
} // namespace mode
template <typename config>
class enabled {
public:
enabled()
: m_enabled(false)
, m_server_no_context_takeover(false)
, m_client_no_context_takeover(false)
, m_server_max_window_bits(15)
, m_client_max_window_bits(15)
, m_server_max_window_bits_mode(mode::accept)
, m_client_max_window_bits_mode(mode::accept)
, m_initialized(false)
, m_compress_buffer_size(8192)
{
m_dstate.zalloc = Z_NULL;
m_dstate.zfree = Z_NULL;
m_dstate.opaque = Z_NULL;
m_istate.zalloc = Z_NULL;
m_istate.zfree = Z_NULL;
m_istate.opaque = Z_NULL;
m_istate.avail_in = 0;
m_istate.next_in = Z_NULL;
}
~enabled() {
if (!m_initialized) {
return;
}
int ret = deflateEnd(&m_dstate);
if (ret != Z_OK) {
//std::cout << "error cleaning up zlib compression state"
// << std::endl;
}
ret = inflateEnd(&m_istate);
if (ret != Z_OK) {
//std::cout << "error cleaning up zlib decompression state"
// << std::endl;
}
}
/// Initialize zlib state
/**
* Note: this should be called *after* the negotiation methods. It will use
* information from the negotiation to determine how to initialize the zlib
* data structures.
*
* @todo memory level, strategy, etc are hardcoded
*
* @param is_server True to initialize as a server, false for a client.
* @return A code representing the error that occurred, if any
*/
lib::error_code init(bool is_server) {
uint8_t deflate_bits;
uint8_t inflate_bits;
if (is_server) {
deflate_bits = m_server_max_window_bits;
inflate_bits = m_client_max_window_bits;
} else {
deflate_bits = m_client_max_window_bits;
inflate_bits = m_server_max_window_bits;
}
int ret = deflateInit2(
&m_dstate,
Z_DEFAULT_COMPRESSION,
Z_DEFLATED,
-1*deflate_bits,
4, // memory level 1-9
Z_DEFAULT_STRATEGY
);
if (ret != Z_OK) {
return make_error_code(error::zlib_error);
}
ret = inflateInit2(
&m_istate,
-1*inflate_bits
);
if (ret != Z_OK) {
return make_error_code(error::zlib_error);
}
m_compress_buffer.reset(new unsigned char[m_compress_buffer_size]);
m_decompress_buffer.reset(new unsigned char[m_compress_buffer_size]);
if ((m_server_no_context_takeover && is_server) ||
(m_client_no_context_takeover && !is_server))
{
m_flush = Z_FULL_FLUSH;
} else {
m_flush = Z_SYNC_FLUSH;
}
m_initialized = true;
return lib::error_code();
}
/// Test if this object implements the permessage-deflate specification
/**
* Because this object does implieent it, it will always return true.
*
* @return Whether or not this object implements permessage-deflate
*/
bool is_implemented() const {
return true;
}
/// Test if the extension was negotiated for this connection
/**
* Retrieves whether or not this extension is in use based on the initial
* handshake extension negotiations.
*
* @return Whether or not the extension is in use
*/
bool is_enabled() const {
return m_enabled;
}
/// Reset server's outgoing LZ77 sliding window for each new message
/**
* Enabling this setting will cause the server's compressor to reset the
* compression state (the LZ77 sliding window) for every message. This
* means that the compressor will not look back to patterns in previous
* messages to improve compression. This will reduce the compression
* efficiency for large messages somewhat and small messages drastically.
*
* This option may reduce server compressor memory usage and client
* decompressor memory usage.
* @todo Document to what extent memory usage will be reduced
*
* For clients, this option is dependent on server support. Enabling it
* via this method does not guarantee that it will be successfully
* negotiated, only that it will be requested.
*
* For servers, no client support is required. Enabling this option on a
* server will result in its use. The server will signal to clients that
* the option will be in use so they can optimize resource usage if they
* are able.
*/
void enable_server_no_context_takeover() {
m_server_no_context_takeover = true;
}
/// Reset client's outgoing LZ77 sliding window for each new message
/**
* Enabling this setting will cause the client's compressor to reset the
* compression state (the LZ77 sliding window) for every message. This
* means that the compressor will not look back to patterns in previous
* messages to improve compression. This will reduce the compression
* efficiency for large messages somewhat and small messages drastically.
*
* This option may reduce client compressor memory usage and server
* decompressor memory usage.
* @todo Document to what extent memory usage will be reduced
*
* This option is supported by all compliant clients and servers. Enabling
* it via either endpoint should be sufficient to ensure it is used.
*/
void enable_client_no_context_takeover() {
m_client_no_context_takeover = true;
}
/// Limit server LZ77 sliding window size
/**
* The bits setting is the base 2 logarithm of the maximum window size that
* the server must use to compress outgoing messages. The permitted range
* is 9 to 15 inclusive. 9 represents a 512 byte window and 15 a 32KiB
* window. The default setting is 15.
*
* Mode Options:
* - accept: Accept whatever the remote endpoint offers.
* - decline: Decline any offers to deviate from the defaults
* - largest: Accept largest window size acceptable to both endpoints
* - smallest: Accept smallest window size acceptiable to both endpoints
*
* This setting is dependent on server support. A client requesting this
* setting may be rejected by the server or have the exact value used
* adjusted by the server. A server may unilaterally set this value without
* client support.
*
* NOTE: The permessage-deflate spec specifies that a value of 8 is allowed.
* Prior to version 0.8.0 a value of 8 was also allowed by this library.
* zlib, the deflate compression library that WebSocket++ uses has always
* silently adjusted a value of 8 to 9. In recent versions of zlib (1.2.9
* and greater) a value of 8 is now explicitly rejected. WebSocket++ 0.8.0
* continues to perform the 8->9 conversion for backwards compatibility
* purposes but this should be considered deprecated functionality.
*
* @param bits The size to request for the outgoing window size
* @param mode The mode to use for negotiating this parameter
* @return A status code
*/
lib::error_code set_server_max_window_bits(uint8_t bits, mode::value mode) {
if (bits < min_server_max_window_bits || bits > max_server_max_window_bits) {
return error::make_error_code(error::invalid_max_window_bits);
}
// See note in doc comment above about what is happening here
if (bits == 8) {
bits = 9;
}
m_server_max_window_bits = bits;
m_server_max_window_bits_mode = mode;
return lib::error_code();
}
/// Limit client LZ77 sliding window size
/**
* The bits setting is the base 2 logarithm of the window size that the
* client must use to compress outgoing messages. The permitted range is 9
* to 15 inclusive. 9 represents a 512 byte window and 15 a 32KiB window.
* The default setting is 15.
*
* Mode Options:
* - accept: Accept whatever the remote endpoint offers.
* - decline: Decline any offers to deviate from the defaults
* - largest: Accept largest window size acceptable to both endpoints
* - smallest: Accept smallest window size acceptiable to both endpoints
*
* This setting is dependent on client support. A client may limit its own
* outgoing window size unilaterally. A server may only limit the client's
* window size if the remote client supports that feature.
*
* NOTE: The permessage-deflate spec specifies that a value of 8 is allowed.
* Prior to version 0.8.0 a value of 8 was also allowed by this library.
* zlib, the deflate compression library that WebSocket++ uses has always
* silently adjusted a value of 8 to 9. In recent versions of zlib (1.2.9
* and greater) a value of 8 is now explicitly rejected. WebSocket++ 0.8.0
* continues to perform the 8->9 conversion for backwards compatibility
* purposes but this should be considered deprecated functionality.
*
* @param bits The size to request for the outgoing window size
* @param mode The mode to use for negotiating this parameter
* @return A status code
*/
lib::error_code set_client_max_window_bits(uint8_t bits, mode::value mode) {
if (bits < min_client_max_window_bits || bits > max_client_max_window_bits) {
return error::make_error_code(error::invalid_max_window_bits);
}
// See note in doc comment above about what is happening here
if (bits == 8) {
bits = 9;
}
m_client_max_window_bits = bits;
m_client_max_window_bits_mode = mode;
return lib::error_code();
}
/// Generate extension offer
/**
* Creates an offer string to include in the Sec-WebSocket-Extensions
* header of outgoing client requests.
*
* @return A WebSocket extension offer string for this extension
*/
std::string generate_offer() const {
// TODO: this should be dynamically generated based on user settings
return "permessage-deflate; client_no_context_takeover; client_max_window_bits";
}
/// Validate extension response
/**
* Confirm that the server has negotiated settings compatible with our
* original offer and apply those settings to the extension state.
*
* @param response The server response attribute list to validate
* @return Validation error or 0 on success
*/
lib::error_code validate_offer(http::attribute_list const &) {
return lib::error_code();
}
/// Negotiate extension
/**
* Confirm that the client's extension negotiation offer has settings
* compatible with local policy. If so, generate a reply and apply those
* settings to the extension state.
*
* @param offer Attribute from client's offer
* @return Status code and value to return to remote endpoint
*/
err_str_pair negotiate(http::attribute_list const & offer) {
err_str_pair ret;
http::attribute_list::const_iterator it;
for (it = offer.begin(); it != offer.end(); ++it) {
if (it->first == "server_no_context_takeover") {
negotiate_server_no_context_takeover(it->second,ret.first);
} else if (it->first == "client_no_context_takeover") {
negotiate_client_no_context_takeover(it->second,ret.first);
} else if (it->first == "server_max_window_bits") {
negotiate_server_max_window_bits(it->second,ret.first);
} else if (it->first == "client_max_window_bits") {
negotiate_client_max_window_bits(it->second,ret.first);
} else {
ret.first = make_error_code(error::invalid_attributes);
}
if (ret.first) {
break;
}
}
if (ret.first == lib::error_code()) {
m_enabled = true;
ret.second = generate_response();
}
return ret;
}
/// Compress bytes
/**
* @todo: avail_in/out is 32 bit, need to fix for cases of >32 bit frames
* on 64 bit machines.
*
* @param [in] in String to compress
* @param [out] out String to append compressed bytes to
* @return Error or status code
*/
lib::error_code compress(std::string const & in, std::string & out) {
if (!m_initialized) {
return make_error_code(error::uninitialized);
}
size_t output;
if (in.empty()) {
uint8_t buf[6] = {0x02, 0x00, 0x00, 0x00, 0xff, 0xff};
out.append((char *)(buf),6);
return lib::error_code();
}
m_dstate.avail_in = in.size();
m_dstate.next_in = (unsigned char *)(const_cast<char *>(in.data()));
do {
// Output to local buffer
m_dstate.avail_out = m_compress_buffer_size;
m_dstate.next_out = m_compress_buffer.get();
deflate(&m_dstate, m_flush);
output = m_compress_buffer_size - m_dstate.avail_out;
out.append((char *)(m_compress_buffer.get()),output);
} while (m_dstate.avail_out == 0);
return lib::error_code();
}
/// Decompress bytes
/**
* @param buf Byte buffer to decompress
* @param len Length of buf
* @param out String to append decompressed bytes to
* @return Error or status code
*/
lib::error_code decompress(uint8_t const * buf, size_t len, std::string &
out)
{
if (!m_initialized) {
return make_error_code(error::uninitialized);
}
int ret;
m_istate.avail_in = len;
m_istate.next_in = const_cast<unsigned char *>(buf);
do {
m_istate.avail_out = m_compress_buffer_size;
m_istate.next_out = m_decompress_buffer.get();
ret = inflate(&m_istate, Z_SYNC_FLUSH);
if (ret == Z_NEED_DICT || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR) {
return make_error_code(error::zlib_error);
}
out.append(
reinterpret_cast<char *>(m_decompress_buffer.get()),
m_compress_buffer_size - m_istate.avail_out
);
} while (m_istate.avail_out == 0);
return lib::error_code();
}
private:
/// Generate negotiation response
/**
* @return Generate extension negotiation reponse string to send to client
*/
std::string generate_response() {
std::string ret = "permessage-deflate";
if (m_server_no_context_takeover) {
ret += "; server_no_context_takeover";
}
if (m_client_no_context_takeover) {
ret += "; client_no_context_takeover";
}
if (m_server_max_window_bits < default_server_max_window_bits) {
std::stringstream s;
s << int(m_server_max_window_bits);
ret += "; server_max_window_bits="+s.str();
}
if (m_client_max_window_bits < default_client_max_window_bits) {
std::stringstream s;
s << int(m_client_max_window_bits);
ret += "; client_max_window_bits="+s.str();
}
return ret;
}
/// Negotiate server_no_context_takeover attribute
/**
* @param [in] value The value of the attribute from the offer
* @param [out] ec A reference to the error code to return errors via
*/
void negotiate_server_no_context_takeover(std::string const & value,
lib::error_code & ec)
{
if (!value.empty()) {
ec = make_error_code(error::invalid_attribute_value);
return;
}
m_server_no_context_takeover = true;
}
/// Negotiate client_no_context_takeover attribute
/**
* @param [in] value The value of the attribute from the offer
* @param [out] ec A reference to the error code to return errors via
*/
void negotiate_client_no_context_takeover(std::string const & value,
lib::error_code & ec)
{
if (!value.empty()) {
ec = make_error_code(error::invalid_attribute_value);
return;
}
m_client_no_context_takeover = true;
}
/// Negotiate server_max_window_bits attribute
/**
* When this method starts, m_server_max_window_bits will contain the server's
* preferred value and m_server_max_window_bits_mode will contain the mode the
* server wants to use to for negotiation. `value` contains the value the
* client requested that we use.
*
* options:
* - decline (ignore value, offer our default instead)
* - accept (use the value requested by the client)
* - largest (use largest value acceptable to both)
* - smallest (use smallest possible value)
*
* NOTE: As a value of 8 is no longer explicitly supported by zlib but might
* be requested for negotiation by an older client/server, if the result of
* the negotiation would be to send a value of 8, a value of 9 is offered
* instead. This ensures that WebSocket++ will only ever negotiate connections
* with compression settings explicitly supported by zlib.
*
* @param [in] value The value of the attribute from the offer
* @param [out] ec A reference to the error code to return errors via
*/
void negotiate_server_max_window_bits(std::string const & value,
lib::error_code & ec)
{
uint8_t bits = uint8_t(atoi(value.c_str()));
if (bits < min_server_max_window_bits || bits > max_server_max_window_bits) {
ec = make_error_code(error::invalid_attribute_value);
m_server_max_window_bits = default_server_max_window_bits;
return;
}
switch (m_server_max_window_bits_mode) {
case mode::decline:
m_server_max_window_bits = default_server_max_window_bits;
break;
case mode::accept:
m_server_max_window_bits = bits;
break;
case mode::largest:
m_server_max_window_bits = std::min(bits,m_server_max_window_bits);
break;
case mode::smallest:
m_server_max_window_bits = min_server_max_window_bits;
break;
default:
ec = make_error_code(error::invalid_mode);
m_server_max_window_bits = default_server_max_window_bits;
}
// See note in doc comment
if (m_server_max_window_bits == 8) {
m_server_max_window_bits = 9;
}
}
/// Negotiate client_max_window_bits attribute
/**
* When this method starts, m_client_max_window_bits and m_c2s_max_window_mode
* will contain the server's preferred values for window size and
* negotiation mode.
*
* options:
* - decline (ignore value, offer our default instead)
* - accept (use the value requested by the client)
* - largest (use largest value acceptable to both)
* - smallest (use smallest possible value)
*
* NOTE: As a value of 8 is no longer explicitly supported by zlib but might
* be requested for negotiation by an older client/server, if the result of
* the negotiation would be to send a value of 8, a value of 9 is offered
* instead. This ensures that WebSocket++ will only ever negotiate connections
* with compression settings explicitly supported by zlib.
*
* @param [in] value The value of the attribute from the offer
* @param [out] ec A reference to the error code to return errors via
*/
void negotiate_client_max_window_bits(std::string const & value,
lib::error_code & ec)
{
uint8_t bits = uint8_t(atoi(value.c_str()));
if (value.empty()) {
bits = default_client_max_window_bits;
} else if (bits < min_client_max_window_bits ||
bits > max_client_max_window_bits)
{
ec = make_error_code(error::invalid_attribute_value);
m_client_max_window_bits = default_client_max_window_bits;
return;
}
switch (m_client_max_window_bits_mode) {
case mode::decline:
m_client_max_window_bits = default_client_max_window_bits;
break;
case mode::accept:
m_client_max_window_bits = bits;
break;
case mode::largest:
m_client_max_window_bits = std::min(bits,m_client_max_window_bits);
break;
case mode::smallest:
m_client_max_window_bits = min_client_max_window_bits;
break;
default:
ec = make_error_code(error::invalid_mode);
m_client_max_window_bits = default_client_max_window_bits;
}
// See note in doc comment
if (m_client_max_window_bits == 8) {
m_client_max_window_bits = 9;
}
}
bool m_enabled;
bool m_server_no_context_takeover;
bool m_client_no_context_takeover;
uint8_t m_server_max_window_bits;
uint8_t m_client_max_window_bits;
mode::value m_server_max_window_bits_mode;
mode::value m_client_max_window_bits_mode;
bool m_initialized;
int m_flush;
size_t m_compress_buffer_size;
lib::unique_ptr_uchar_array m_compress_buffer;
lib::unique_ptr_uchar_array m_decompress_buffer;
z_stream m_dstate;
z_stream m_istate;
};
} // namespace permessage_deflate
} // namespace extensions
} // namespace websocketpp
#endif // WEBSOCKETPP_PROCESSOR_EXTENSION_PERMESSAGEDEFLATE_HPP

View File

@ -0,0 +1,864 @@
/*
* Copyright (c) 2014, 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_FRAME_HPP
#define WEBSOCKETPP_FRAME_HPP
#include <algorithm>
#include <string>
#include <websocketpp/common/system_error.hpp>
#include <websocketpp/common/network.hpp>
#include <websocketpp/utilities.hpp>
namespace websocketpp {
/// Data structures and utility functions for manipulating WebSocket frames
/**
* namespace frame provides a number of data structures and utility functions
* for reading, writing, and manipulating binary encoded WebSocket frames.
*/
namespace frame {
/// Minimum length of a WebSocket frame header.
static unsigned int const BASIC_HEADER_LENGTH = 2;
/// Maximum length of a WebSocket header
static unsigned int const MAX_HEADER_LENGTH = 14;
/// Maximum length of the variable portion of the WebSocket header
static unsigned int const MAX_EXTENDED_HEADER_LENGTH = 12;
/// Two byte conversion union
union uint16_converter {
uint16_t i;
uint8_t c[2];
};
/// Four byte conversion union
union uint32_converter {
uint32_t i;
uint8_t c[4];
};
/// Eight byte conversion union
union uint64_converter {
uint64_t i;
uint8_t c[8];
};
/// Constants and utility functions related to WebSocket opcodes
/**
* WebSocket Opcodes are 4 bits. See RFC6455 section 5.2.
*/
namespace opcode {
enum value {
continuation = 0x0,
text = 0x1,
binary = 0x2,
rsv3 = 0x3,
rsv4 = 0x4,
rsv5 = 0x5,
rsv6 = 0x6,
rsv7 = 0x7,
close = 0x8,
ping = 0x9,
pong = 0xA,
control_rsvb = 0xB,
control_rsvc = 0xC,
control_rsvd = 0xD,
control_rsve = 0xE,
control_rsvf = 0xF,
CONTINUATION = 0x0,
TEXT = 0x1,
BINARY = 0x2,
RSV3 = 0x3,
RSV4 = 0x4,
RSV5 = 0x5,
RSV6 = 0x6,
RSV7 = 0x7,
CLOSE = 0x8,
PING = 0x9,
PONG = 0xA,
CONTROL_RSVB = 0xB,
CONTROL_RSVC = 0xC,
CONTROL_RSVD = 0xD,
CONTROL_RSVE = 0xE,
CONTROL_RSVF = 0xF
};
/// Check if an opcode is reserved
/**
* @param v The opcode to test.
* @return Whether or not the opcode is reserved.
*/
inline bool reserved(value v) {
return (v >= rsv3 && v <= rsv7) ||
(v >= control_rsvb && v <= control_rsvf);
}
/// Check if an opcode is invalid
/**
* Invalid opcodes are negative or require greater than 4 bits to store.
*
* @param v The opcode to test.
* @return Whether or not the opcode is invalid.
*/
inline bool invalid(value v) {
return (v > 0xF || v < 0);
}
/// Check if an opcode is for a control frame
/**
* @param v The opcode to test.
* @return Whether or not the opcode is a control opcode.
*/
inline bool is_control(value v) {
return v >= 0x8;
}
}
/// Constants related to frame and payload limits
namespace limits {
/// Minimum length of a WebSocket frame header.
static unsigned int const basic_header_length = 2;
/// Maximum length of a WebSocket header
static unsigned int const max_header_length = 14;
/// Maximum length of the variable portion of the WebSocket header
static unsigned int const max_extended_header_length = 12;
/// Maximum size of a basic WebSocket payload
static uint8_t const payload_size_basic = 125;
/// Maximum size of an extended WebSocket payload (basic payload = 126)
static uint16_t const payload_size_extended = 0xFFFF; // 2^16, 65535
/// Maximum size of a jumbo WebSocket payload (basic payload = 127)
static uint64_t const payload_size_jumbo = 0x7FFFFFFFFFFFFFFFLL;//2^63
/// Maximum size of close frame reason
/**
* This is payload_size_basic - 2 bytes (as first two bytes are used for
* the close code
*/
static uint8_t const close_reason_size = 123;
}
// masks for fields in the basic header
static uint8_t const BHB0_OPCODE = 0x0F;
static uint8_t const BHB0_RSV3 = 0x10;
static uint8_t const BHB0_RSV2 = 0x20;
static uint8_t const BHB0_RSV1 = 0x40;
static uint8_t const BHB0_FIN = 0x80;
static uint8_t const BHB1_PAYLOAD = 0x7F;
static uint8_t const BHB1_MASK = 0x80;
static uint8_t const payload_size_code_16bit = 0x7E; // 126
static uint8_t const payload_size_code_64bit = 0x7F; // 127
typedef uint32_converter masking_key_type;
/// The constant size component of a WebSocket frame header
struct basic_header {
basic_header() : b0(0x00),b1(0x00) {}
basic_header(uint8_t p0, uint8_t p1) : b0(p0), b1(p1) {}
basic_header(opcode::value op, uint64_t size, bool fin, bool mask,
bool rsv1 = false, bool rsv2 = false, bool rsv3 = false) : b0(0x00),
b1(0x00)
{
if (fin) {
b0 |= BHB0_FIN;
}
if (rsv1) {
b0 |= BHB0_RSV1;
}
if (rsv2) {
b0 |= BHB0_RSV2;
}
if (rsv3) {
b0 |= BHB0_RSV3;
}
b0 |= (op & BHB0_OPCODE);
if (mask) {
b1 |= BHB1_MASK;
}
uint8_t basic_value;
if (size <= limits::payload_size_basic) {
basic_value = static_cast<uint8_t>(size);
} else if (size <= limits::payload_size_extended) {
basic_value = payload_size_code_16bit;
} else {
basic_value = payload_size_code_64bit;
}
b1 |= basic_value;
}
uint8_t b0;
uint8_t b1;
};
/// The variable size component of a WebSocket frame header
struct extended_header {
extended_header() {
std::fill_n(this->bytes,MAX_EXTENDED_HEADER_LENGTH,0x00);
}
extended_header(uint64_t payload_size) {
std::fill_n(this->bytes,MAX_EXTENDED_HEADER_LENGTH,0x00);
copy_payload(payload_size);
}
extended_header(uint64_t payload_size, uint32_t masking_key) {
std::fill_n(this->bytes,MAX_EXTENDED_HEADER_LENGTH,0x00);
// Copy payload size
int offset = copy_payload(payload_size);
// Copy Masking Key
uint32_converter temp32;
temp32.i = masking_key;
std::copy(temp32.c,temp32.c+4,bytes+offset);
}
uint8_t bytes[MAX_EXTENDED_HEADER_LENGTH];
private:
int copy_payload(uint64_t payload_size) {
int payload_offset = 0;
if (payload_size <= limits::payload_size_basic) {
payload_offset = 8;
} else if (payload_size <= limits::payload_size_extended) {
payload_offset = 6;
}
uint64_converter temp64;
temp64.i = lib::net::_htonll(payload_size);
std::copy(temp64.c+payload_offset,temp64.c+8,bytes);
return 8-payload_offset;
}
};
bool get_fin(basic_header const &h);
void set_fin(basic_header &h, bool value);
bool get_rsv1(basic_header const &h);
void set_rsv1(basic_header &h, bool value);
bool get_rsv2(basic_header const &h);
void set_rsv2(basic_header &h, bool value);
bool get_rsv3(basic_header const &h);
void set_rsv3(basic_header &h, bool value);
opcode::value get_opcode(basic_header const &h);
bool get_masked(basic_header const &h);
void set_masked(basic_header &h, bool value);
uint8_t get_basic_size(basic_header const &);
size_t get_header_len(basic_header const &);
unsigned int get_masking_key_offset(basic_header const &);
std::string write_header(basic_header const &, extended_header const &);
masking_key_type get_masking_key(basic_header const &, extended_header const &);
uint16_t get_extended_size(extended_header const &);
uint64_t get_jumbo_size(extended_header const &);
uint64_t get_payload_size(basic_header const &, extended_header const &);
size_t prepare_masking_key(masking_key_type const & key);
size_t circshift_prepared_key(size_t prepared_key, size_t offset);
// Functions for performing xor based masking and unmasking
template <typename input_iter, typename output_iter>
void byte_mask(input_iter b, input_iter e, output_iter o, masking_key_type
const & key, size_t key_offset = 0);
template <typename iter_type>
void byte_mask(iter_type b, iter_type e, masking_key_type const & key,
size_t key_offset = 0);
void word_mask_exact(uint8_t * input, uint8_t * output, size_t length,
masking_key_type const & key);
void word_mask_exact(uint8_t * data, size_t length, masking_key_type const &
key);
size_t word_mask_circ(uint8_t * input, uint8_t * output, size_t length,
size_t prepared_key);
size_t word_mask_circ(uint8_t * data, size_t length, size_t prepared_key);
/// Check whether the frame's FIN bit is set.
/**
* @param [in] h The basic header to extract from.
* @return True if the header's fin bit is set.
*/
inline bool get_fin(basic_header const & h) {
return ((h.b0 & BHB0_FIN) == BHB0_FIN);
}
/// Set the frame's FIN bit
/**
* @param [out] h Header to set.
* @param [in] value Value to set it to.
*/
inline void set_fin(basic_header & h, bool value) {
h.b0 = (value ? h.b0 | BHB0_FIN : h.b0 & ~BHB0_FIN);
}
/// check whether the frame's RSV1 bit is set
/**
* @param [in] h The basic header to extract from.
* @return True if the header's RSV1 bit is set.
*/
inline bool get_rsv1(const basic_header &h) {
return ((h.b0 & BHB0_RSV1) == BHB0_RSV1);
}
/// Set the frame's RSV1 bit
/**
* @param [out] h Header to set.
* @param [in] value Value to set it to.
*/
inline void set_rsv1(basic_header &h, bool value) {
h.b0 = (value ? h.b0 | BHB0_RSV1 : h.b0 & ~BHB0_RSV1);
}
/// check whether the frame's RSV2 bit is set
/**
* @param [in] h The basic header to extract from.
* @return True if the header's RSV2 bit is set.
*/
inline bool get_rsv2(const basic_header &h) {
return ((h.b0 & BHB0_RSV2) == BHB0_RSV2);
}
/// Set the frame's RSV2 bit
/**
* @param [out] h Header to set.
* @param [in] value Value to set it to.
*/
inline void set_rsv2(basic_header &h, bool value) {
h.b0 = (value ? h.b0 | BHB0_RSV2 : h.b0 & ~BHB0_RSV2);
}
/// check whether the frame's RSV3 bit is set
/**
* @param [in] h The basic header to extract from.
* @return True if the header's RSV3 bit is set.
*/
inline bool get_rsv3(const basic_header &h) {
return ((h.b0 & BHB0_RSV3) == BHB0_RSV3);
}
/// Set the frame's RSV3 bit
/**
* @param [out] h Header to set.
* @param [in] value Value to set it to.
*/
inline void set_rsv3(basic_header &h, bool value) {
h.b0 = (value ? h.b0 | BHB0_RSV3 : h.b0 & ~BHB0_RSV3);
}
/// Extract opcode from basic header
/**
* @param [in] h The basic header to extract from.
* @return The opcode value of the header.
*/
inline opcode::value get_opcode(const basic_header &h) {
return opcode::value(h.b0 & BHB0_OPCODE);
}
/// check whether the frame is masked
/**
* @param [in] h The basic header to extract from.
* @return True if the header mask bit is set.
*/
inline bool get_masked(basic_header const & h) {
return ((h.b1 & BHB1_MASK) == BHB1_MASK);
}
/// Set the frame's MASK bit
/**
* @param [out] h Header to set.
* @param value Value to set it to.
*/
inline void set_masked(basic_header & h, bool value) {
h.b1 = (value ? h.b1 | BHB1_MASK : h.b1 & ~BHB1_MASK);
}
/// Extracts the raw payload length specified in the basic header
/**
* A basic WebSocket frame header contains a 7 bit value that represents the
* payload size. There are two reserved values that are used to indicate that
* the actual payload size will not fit in 7 bits and that the full payload
* size is included in a separate field. The values are as follows:
*
* PAYLOAD_SIZE_CODE_16BIT (0x7E) indicates that the actual payload is less
* than 16 bit
*
* PAYLOAD_SIZE_CODE_64BIT (0x7F) indicates that the actual payload is less
* than 63 bit
*
* @param [in] h Basic header to read value from.
* @return The exact size encoded in h.
*/
inline uint8_t get_basic_size(const basic_header &h) {
return h.b1 & BHB1_PAYLOAD;
}
/// Calculates the full length of the header based on the first bytes.
/**
* A WebSocket frame header always has at least two bytes. Encoded within the
* first two bytes is all the information necessary to calculate the full
* (variable) header length. get_header_len() calculates the full header
* length for the given two byte basic header.
*
* @param h Basic frame header to extract size from.
* @return Full length of the extended header.
*/
inline size_t get_header_len(basic_header const & h) {
// TODO: check extensions?
// masking key offset represents the space used for the extended length
// fields
size_t size = BASIC_HEADER_LENGTH + get_masking_key_offset(h);
// If the header is masked there is a 4 byte masking key
if (get_masked(h)) {
size += 4;
}
return size;
}
/// Calculate the offset location of the masking key within the extended header
/**
* Calculate the offset location of the masking key within the extended header
* using information from its corresponding basic header
*
* @param h Corresponding basic header to calculate from.
*
* @return byte offset of the first byte of the masking key
*/
inline unsigned int get_masking_key_offset(const basic_header &h) {
if (get_basic_size(h) == payload_size_code_16bit) {
return 2;
} else if (get_basic_size(h) == payload_size_code_64bit) {
return 8;
} else {
return 0;
}
}
/// Generate a properly sized contiguous string that encodes a full frame header
/**
* Copy the basic header h and extended header e into a properly sized
* contiguous frame header string for the purposes of writing out to the wire.
*
* @param h The basic header to include
* @param e The extended header to include
*
* @return A contiguous string containing h and e
*/
inline std::string prepare_header(const basic_header &h, const
extended_header &e)
{
std::string ret;
ret.push_back(char(h.b0));
ret.push_back(char(h.b1));
ret.append(
reinterpret_cast<const char*>(e.bytes),
get_header_len(h)-BASIC_HEADER_LENGTH
);
return ret;
}
/// Extract the masking key from a frame header
/**
* Note that while read and written as an integer at times, this value is not
* an integer and should never be interpreted as one. Big and little endian
* machines will generate and store masking keys differently without issue as
* long as the integer values remain irrelivant.
*
* @param h The basic header to extract from
* @param e The extended header to extract from
*
* @return The masking key as an integer.
*/
inline masking_key_type get_masking_key(const basic_header &h, const
extended_header &e)
{
masking_key_type temp32;
if (!get_masked(h)) {
temp32.i = 0;
} else {
unsigned int offset = get_masking_key_offset(h);
std::copy(e.bytes+offset,e.bytes+offset+4,temp32.c);
}
return temp32;
}
/// Extract the extended size field from an extended header
/**
* It is the responsibility of the caller to verify that e is a valid extended
* header. This function assumes that e contains an extended payload size.
*
* @param e The extended header to extract from
*
* @return The size encoded in the extended header in host byte order
*/
inline uint16_t get_extended_size(const extended_header &e) {
uint16_converter temp16;
std::copy(e.bytes,e.bytes+2,temp16.c);
return ntohs(temp16.i);
}
/// Extract the jumbo size field from an extended header
/**
* It is the responsibility of the caller to verify that e is a valid extended
* header. This function assumes that e contains a jumbo payload size.
*
* @param e The extended header to extract from
*
* @return The size encoded in the extended header in host byte order
*/
inline uint64_t get_jumbo_size(const extended_header &e) {
uint64_converter temp64;
std::copy(e.bytes,e.bytes+8,temp64.c);
return lib::net::_ntohll(temp64.i);
}
/// Extract the full payload size field from a WebSocket header
/**
* It is the responsibility of the caller to verify that h and e together
* represent a valid WebSocket frame header. This function assumes only that h
* and e are valid. It uses information in the basic header to determine where
* to look for the payload_size
*
* @param h The basic header to extract from
* @param e The extended header to extract from
*
* @return The size encoded in the combined header in host byte order.
*/
inline uint64_t get_payload_size(const basic_header &h, const
extended_header &e)
{
uint8_t val = get_basic_size(h);
if (val <= limits::payload_size_basic) {
return val;
} else if (val == payload_size_code_16bit) {
return get_extended_size(e);
} else {
return get_jumbo_size(e);
}
}
/// Extract a masking key into a value the size of a machine word.
/**
* Machine word size must be 4 or 8.
*
* @param key Masking key to extract from
*
* @return prepared key as a machine word
*/
inline size_t prepare_masking_key(const masking_key_type& key) {
size_t low_bits = static_cast<size_t>(key.i);
if (sizeof(size_t) == 8) {
uint64_t high_bits = static_cast<size_t>(key.i);
return static_cast<size_t>((high_bits << 32) | low_bits);
} else {
return low_bits;
}
}
/// circularly shifts the supplied prepared masking key by offset bytes
/**
* Prepared_key must be the output of prepare_masking_key with the associated
* restrictions on the machine word size. offset must be greater than or equal
* to zero and less than sizeof(size_t).
*/
inline size_t circshift_prepared_key(size_t prepared_key, size_t offset) {
if (offset == 0) {
return prepared_key;
}
if (lib::net::is_little_endian()) {
size_t temp = prepared_key << (sizeof(size_t)-offset)*8;
return (prepared_key >> offset*8) | temp;
} else {
size_t temp = prepared_key >> (sizeof(size_t)-offset)*8;
return (prepared_key << offset*8) | temp;
}
}
/// Byte by byte mask/unmask
/**
* Iterator based byte by byte masking and unmasking for WebSocket payloads.
* Performs masking in place using the supplied key offset by the supplied
* offset number of bytes.
*
* This function is simple and can be done in place on input with arbitrary
* lengths and does not vary based on machine word size. It is slow.
*
* @param b Beginning iterator to start masking
*
* @param e Ending iterator to end masking
*
* @param o Beginning iterator to store masked results
*
* @param key 32 bit key to mask with.
*
* @param key_offset offset value to start masking at.
*/
template <typename input_iter, typename output_iter>
void byte_mask(input_iter first, input_iter last, output_iter result,
masking_key_type const & key, size_t key_offset)
{
size_t key_index = key_offset%4;
while (first != last) {
*result = *first ^ key.c[key_index++];
key_index %= 4;
++result;
++first;
}
}
/// Byte by byte mask/unmask (in place)
/**
* Iterator based byte by byte masking and unmasking for WebSocket payloads.
* Performs masking in place using the supplied key offset by the supplied
* offset number of bytes.
*
* This function is simple and can be done in place on input with arbitrary
* lengths and does not vary based on machine word size. It is slow.
*
* @param b Beginning iterator to start masking
*
* @param e Ending iterator to end masking
*
* @param key 32 bit key to mask with.
*
* @param key_offset offset value to start masking at.
*/
template <typename iter_type>
void byte_mask(iter_type b, iter_type e, masking_key_type const & key,
size_t key_offset)
{
byte_mask(b,e,b,key,key_offset);
}
/// Exact word aligned mask/unmask
/**
* Balanced combination of byte by byte and circular word by word masking.
* Best used to mask complete messages at once. Has much higher setup costs than
* word_mask_circ but works with exact sized buffers.
*
* Buffer based word by word masking and unmasking for WebSocket payloads.
* Masking is done in word by word chunks with the remainder not divisible by
* the word size done byte by byte.
*
* input and output must both be at least length bytes. Exactly length bytes
* will be written.
*
* @param input buffer to mask or unmask
*
* @param output buffer to store the output. May be the same as input.
*
* @param length length of data buffer
*
* @param key Masking key to use
*/
inline void word_mask_exact(uint8_t* input, uint8_t* output, size_t length,
const masking_key_type& key)
{
size_t prepared_key = prepare_masking_key(key);
size_t n = length/sizeof(size_t);
size_t* input_word = reinterpret_cast<size_t*>(input);
size_t* output_word = reinterpret_cast<size_t*>(output);
for (size_t i = 0; i < n; i++) {
output_word[i] = input_word[i] ^ prepared_key;
}
for (size_t i = n*sizeof(size_t); i < length; i++) {
output[i] = input[i] ^ key.c[i%4];
}
}
/// Exact word aligned mask/unmask (in place)
/**
* In place version of word_mask_exact
*
* @see word_mask_exact
*
* @param data buffer to read and write from
*
* @param length length of data buffer
*
* @param key Masking key to use
*/
inline void word_mask_exact(uint8_t* data, size_t length, const
masking_key_type& key)
{
word_mask_exact(data,data,length,key);
}
/// Circular word aligned mask/unmask
/**
* Performs a circular mask/unmask in word sized chunks using pre-prepared keys
* that store state between calls. Best for providing streaming masking or
* unmasking of small chunks at a time of a larger message. Requires that the
* underlying allocated size of the data buffer be a multiple of the word size.
* Data in the buffer after `length` will be overwritten only with the same
* values that were originally present.
*
* Buffer based word by word masking and unmasking for WebSocket payloads.
* Performs masking in place using the supplied key. Casts the data buffer to
* an array of size_t's and performs masking word by word. The underlying
* buffer size must be a muliple of the word size.
*
* word_mask returns a copy of prepared_key circularly shifted based on the
* length value. The returned value may be fed back into word_mask when more
* data is available.
*
* input and output must both have length at least:
* ceil(length/sizeof(size_t))*sizeof(size_t)
* Exactly that many bytes will be written, although only exactly length bytes
* will be changed (trailing bytes will be replaced without masking)
*
* @param data Character buffer to mask
*
* @param length Length of data
*
* @param prepared_key Prepared key to use.
*
* @return the prepared_key shifted to account for the input length
*/
inline size_t word_mask_circ(uint8_t * input, uint8_t * output, size_t length,
size_t prepared_key)
{
size_t n = length / sizeof(size_t); // whole words
size_t l = length - (n * sizeof(size_t)); // remaining bytes
size_t * input_word = reinterpret_cast<size_t *>(input);
size_t * output_word = reinterpret_cast<size_t *>(output);
// mask word by word
for (size_t i = 0; i < n; i++) {
output_word[i] = input_word[i] ^ prepared_key;
}
// mask partial word at the end
size_t start = length - l;
uint8_t * byte_key = reinterpret_cast<uint8_t *>(&prepared_key);
for (size_t i = 0; i < l; ++i) {
output[start+i] = input[start+i] ^ byte_key[i];
}
return circshift_prepared_key(prepared_key,l);
}
/// Circular word aligned mask/unmask (in place)
/**
* In place version of word_mask_circ
*
* @see word_mask_circ
*
* @param data Character buffer to read from and write to
*
* @param length Length of data
*
* @param prepared_key Prepared key to use.
*
* @return the prepared_key shifted to account for the input length
*/
inline size_t word_mask_circ(uint8_t* data, size_t length, size_t prepared_key){
return word_mask_circ(data,data,length,prepared_key);
}
/// Circular byte aligned mask/unmask
/**
* Performs a circular mask/unmask in byte sized chunks using pre-prepared keys
* that store state between calls. Best for providing streaming masking or
* unmasking of small chunks at a time of a larger message. Requires that the
* underlying allocated size of the data buffer be a multiple of the word size.
* Data in the buffer after `length` will be overwritten only with the same
* values that were originally present.
*
* word_mask returns a copy of prepared_key circularly shifted based on the
* length value. The returned value may be fed back into byte_mask when more
* data is available.
*
* @param data Character buffer to mask
*
* @param length Length of data
*
* @param prepared_key Prepared key to use.
*
* @return the prepared_key shifted to account for the input length
*/
inline size_t byte_mask_circ(uint8_t * input, uint8_t * output, size_t length,
size_t prepared_key)
{
uint32_converter key;
key.i = prepared_key;
for (size_t i = 0; i < length; ++i) {
output[i] = input[i] ^ key.c[i % 4];
}
return circshift_prepared_key(prepared_key,length % 4);
}
/// Circular byte aligned mask/unmask (in place)
/**
* In place version of byte_mask_circ
*
* @see byte_mask_circ
*
* @param data Character buffer to read from and write to
*
* @param length Length of data
*
* @param prepared_key Prepared key to use.
*
* @return the prepared_key shifted to account for the input length
*/
inline size_t byte_mask_circ(uint8_t* data, size_t length, size_t prepared_key){
return byte_mask_circ(data,data,length,prepared_key);
}
} // namespace frame
} // namespace websocketpp
#endif //WEBSOCKETPP_FRAME_HPP

View File

@ -0,0 +1,308 @@
/*
* Copyright (c) 2014, 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 HTTP_CONSTANTS_HPP
#define HTTP_CONSTANTS_HPP
#include <exception>
#include <map>
#include <string>
#include <vector>
#include <utility>
namespace websocketpp {
/// HTTP handling support
namespace http {
/// The type of an HTTP attribute list
/**
* The attribute list is an unordered key/value map. Encoded attribute
* values are delimited by semicolons.
*/
typedef std::map<std::string,std::string> attribute_list;
/// The type of an HTTP parameter list
/**
* The parameter list is an ordered pairing of a parameter and its
* associated attribute list. Encoded parameter values are delimited by
* commas.
*/
typedef std::vector< std::pair<std::string,attribute_list> > parameter_list;
/// Literal value of the HTTP header delimiter
static char const header_delimiter[] = "\r\n";
/// Literal value of the HTTP header separator
static char const header_separator[] = ":";
/// Literal value of an empty header
static std::string const empty_header;
/// Maximum size in bytes before rejecting an HTTP header as too big.
size_t const max_header_size = 16000;
/// Default Maximum size in bytes for HTTP message bodies.
size_t const max_body_size = 32000000;
/// Number of bytes to use for temporary istream read buffers
size_t const istream_buffer = 512;
/// invalid HTTP token characters
/**
* 0x00 - 0x32, 0x7f-0xff
* ( ) < > @ , ; : \ " / [ ] ? = { }
*/
static char const header_token[] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..0f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 10..1f
0,1,0,1,1,1,1,1,0,0,1,1,0,1,1,0, // 20..2f
1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, // 30..3f
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 40..4f
1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1, // 50..5f
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 60..6f
1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,0, // 70..7f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 80..8f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 90..9f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // a0..af
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // b0..bf
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // c0..cf
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // d0..df
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // e0..ef
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // f0..ff
};
/// Is the character a token
inline bool is_token_char(unsigned char c) {
return (header_token[c] == 1);
}
/// Is the character a non-token
inline bool is_not_token_char(unsigned char c) {
return !header_token[c];
}
/// Is the character whitespace
/**
* whitespace is space (32) or horizontal tab (9)
*/
inline bool is_whitespace_char(unsigned char c) {
return (c == 9 || c == 32);
}
/// Is the character non-whitespace
inline bool is_not_whitespace_char(unsigned char c) {
return (c != 9 && c != 32);
}
/// HTTP Status codes
namespace status_code {
enum value {
uninitialized = 0,
continue_code = 100,
switching_protocols = 101,
ok = 200,
created = 201,
accepted = 202,
non_authoritative_information = 203,
no_content = 204,
reset_content = 205,
partial_content = 206,
multiple_choices = 300,
moved_permanently = 301,
found = 302,
see_other = 303,
not_modified = 304,
use_proxy = 305,
temporary_redirect = 307,
bad_request = 400,
unauthorized = 401,
payment_required = 402,
forbidden = 403,
not_found = 404,
method_not_allowed = 405,
not_acceptable = 406,
proxy_authentication_required = 407,
request_timeout = 408,
conflict = 409,
gone = 410,
length_required = 411,
precondition_failed = 412,
request_entity_too_large = 413,
request_uri_too_long = 414,
unsupported_media_type = 415,
request_range_not_satisfiable = 416,
expectation_failed = 417,
im_a_teapot = 418,
upgrade_required = 426,
precondition_required = 428,
too_many_requests = 429,
request_header_fields_too_large = 431,
internal_server_error = 500,
not_implemented = 501,
bad_gateway = 502,
service_unavailable = 503,
gateway_timeout = 504,
http_version_not_supported = 505,
not_extended = 510,
network_authentication_required = 511
};
// TODO: should this be inline?
inline std::string get_string(value c) {
switch (c) {
case uninitialized:
return "Uninitialized";
case continue_code:
return "Continue";
case switching_protocols:
return "Switching Protocols";
case ok:
return "OK";
case created:
return "Created";
case accepted:
return "Accepted";
case non_authoritative_information:
return "Non Authoritative Information";
case no_content:
return "No Content";
case reset_content:
return "Reset Content";
case partial_content:
return "Partial Content";
case multiple_choices:
return "Multiple Choices";
case moved_permanently:
return "Moved Permanently";
case found:
return "Found";
case see_other:
return "See Other";
case not_modified:
return "Not Modified";
case use_proxy:
return "Use Proxy";
case temporary_redirect:
return "Temporary Redirect";
case bad_request:
return "Bad Request";
case unauthorized:
return "Unauthorized";
case payment_required:
return "Payment Required";
case forbidden:
return "Forbidden";
case not_found:
return "Not Found";
case method_not_allowed:
return "Method Not Allowed";
case not_acceptable:
return "Not Acceptable";
case proxy_authentication_required:
return "Proxy Authentication Required";
case request_timeout:
return "Request Timeout";
case conflict:
return "Conflict";
case gone:
return "Gone";
case length_required:
return "Length Required";
case precondition_failed:
return "Precondition Failed";
case request_entity_too_large:
return "Request Entity Too Large";
case request_uri_too_long:
return "Request-URI Too Long";
case unsupported_media_type:
return "Unsupported Media Type";
case request_range_not_satisfiable:
return "Requested Range Not Satisfiable";
case expectation_failed:
return "Expectation Failed";
case im_a_teapot:
return "I'm a teapot";
case upgrade_required:
return "Upgrade Required";
case precondition_required:
return "Precondition Required";
case too_many_requests:
return "Too Many Requests";
case request_header_fields_too_large:
return "Request Header Fields Too Large";
case internal_server_error:
return "Internal Server Error";
case not_implemented:
return "Not Implemented";
case bad_gateway:
return "Bad Gateway";
case service_unavailable:
return "Service Unavailable";
case gateway_timeout:
return "Gateway Timeout";
case http_version_not_supported:
return "HTTP Version Not Supported";
case not_extended:
return "Not Extended";
case network_authentication_required:
return "Network Authentication Required";
default:
return "Unknown";
}
}
}
class exception : public std::exception {
public:
exception(const std::string& log_msg,
status_code::value error_code,
const std::string& error_msg = std::string(),
const std::string& body = std::string())
: m_msg(log_msg)
, m_error_msg(error_msg)
, m_body(body)
, m_error_code(error_code) {}
~exception() throw() {}
virtual const char* what() const throw() {
return m_msg.c_str();
}
std::string m_msg;
std::string m_error_msg;
std::string m_body;
status_code::value m_error_code;
};
}
}
#endif // HTTP_CONSTANTS_HPP

View File

@ -0,0 +1,200 @@
/*
* Copyright (c) 2014, 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 HTTP_PARSER_IMPL_HPP
#define HTTP_PARSER_IMPL_HPP
#include <algorithm>
#include <cstdlib>
#include <istream>
#include <sstream>
#include <string>
namespace websocketpp {
namespace http {
namespace parser {
inline void parser::set_version(std::string const & version) {
m_version = version;
}
inline std::string const & parser::get_header(std::string const & key) const {
header_list::const_iterator h = m_headers.find(key);
if (h == m_headers.end()) {
return empty_header;
} else {
return h->second;
}
}
inline bool parser::get_header_as_plist(std::string const & key,
parameter_list & out) const
{
header_list::const_iterator it = m_headers.find(key);
if (it == m_headers.end() || it->second.size() == 0) {
return false;
}
return this->parse_parameter_list(it->second,out);
}
inline void parser::append_header(std::string const & key, std::string const &
val)
{
if (std::find_if(key.begin(),key.end(),is_not_token_char) != key.end()) {
throw exception("Invalid header name",status_code::bad_request);
}
if (this->get_header(key).empty()) {
m_headers[key] = val;
} else {
m_headers[key] += ", " + val;
}
}
inline void parser::replace_header(std::string const & key, std::string const &
val)
{
m_headers[key] = val;
}
inline void parser::remove_header(std::string const & key) {
m_headers.erase(key);
}
inline void parser::set_body(std::string const & value) {
if (value.size() == 0) {
remove_header("Content-Length");
m_body.clear();
return;
}
// TODO: should this method respect the max size? If so how should errors
// be indicated?
std::stringstream len;
len << value.size();
replace_header("Content-Length", len.str());
m_body = value;
}
inline bool parser::parse_parameter_list(std::string const & in,
parameter_list & out) const
{
if (in.size() == 0) {
return false;
}
std::string::const_iterator it;
it = extract_parameters(in.begin(),in.end(),out);
return (it == in.begin());
}
inline bool parser::prepare_body() {
if (!get_header("Content-Length").empty()) {
std::string const & cl_header = get_header("Content-Length");
char * end;
// TODO: not 100% sure what the compatibility of this method is. Also,
// I believe this will only work up to 32bit sizes. Is there a need for
// > 4GiB HTTP payloads?
m_body_bytes_needed = std::strtoul(cl_header.c_str(),&end,10);
if (m_body_bytes_needed > m_body_bytes_max) {
throw exception("HTTP message body too large",
status_code::request_entity_too_large);
}
m_body_encoding = body_encoding::plain;
return true;
} else if (get_header("Transfer-Encoding") == "chunked") {
// TODO
//m_body_encoding = body_encoding::chunked;
return false;
} else {
return false;
}
}
inline size_t parser::process_body(char const * buf, size_t len) {
if (m_body_encoding == body_encoding::plain) {
size_t processed = (std::min)(m_body_bytes_needed,len);
m_body.append(buf,processed);
m_body_bytes_needed -= processed;
return processed;
} else if (m_body_encoding == body_encoding::chunked) {
// TODO:
throw exception("Unexpected body encoding",
status_code::internal_server_error);
} else {
throw exception("Unexpected body encoding",
status_code::internal_server_error);
}
}
inline void parser::process_header(std::string::iterator begin,
std::string::iterator end)
{
std::string::iterator cursor = std::search(
begin,
end,
header_separator,
header_separator + sizeof(header_separator) - 1
);
if (cursor == end) {
throw exception("Invalid header line",status_code::bad_request);
}
append_header(strip_lws(std::string(begin,cursor)),
strip_lws(std::string(cursor+sizeof(header_separator)-1,end)));
}
inline header_list const & parser::get_headers() const {
return m_headers;
}
inline std::string parser::raw_headers() const {
std::stringstream raw;
header_list::const_iterator it;
for (it = m_headers.begin(); it != m_headers.end(); it++) {
raw << it->first << ": " << it->second << "\r\n";
}
return raw.str();
}
} // namespace parser
} // namespace http
} // namespace websocketpp
#endif // HTTP_PARSER_IMPL_HPP

View File

@ -0,0 +1,191 @@
/*
* Copyright (c) 2014, 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 HTTP_PARSER_REQUEST_IMPL_HPP
#define HTTP_PARSER_REQUEST_IMPL_HPP
#include <algorithm>
#include <sstream>
#include <string>
#include <websocketpp/http/parser.hpp>
namespace websocketpp {
namespace http {
namespace parser {
inline size_t request::consume(char const * buf, size_t len) {
size_t bytes_processed;
if (m_ready) {return 0;}
if (m_body_bytes_needed > 0) {
bytes_processed = process_body(buf,len);
if (body_ready()) {
m_ready = true;
}
return bytes_processed;
}
// copy new header bytes into buffer
m_buf->append(buf,len);
// Search for delimiter in buf. If found read until then. If not read all
std::string::iterator begin = m_buf->begin();
std::string::iterator end;
for (;;) {
// search for line delimiter
end = std::search(
begin,
m_buf->end(),
header_delimiter,
header_delimiter+sizeof(header_delimiter)-1
);
m_header_bytes += (end-begin+sizeof(header_delimiter));
if (m_header_bytes > max_header_size) {
// exceeded max header size
throw exception("Maximum header size exceeded.",
status_code::request_header_fields_too_large);
}
if (end == m_buf->end()) {
// we are out of bytes. Discard the processed bytes and copy the
// remaining unprecessed bytes to the beginning of the buffer
std::copy(begin,end,m_buf->begin());
m_buf->resize(static_cast<std::string::size_type>(end-begin));
m_header_bytes -= m_buf->size();
return len;
}
//the range [begin,end) now represents a line to be processed.
if (end-begin == 0) {
// we got a blank line
if (m_method.empty() || get_header("Host").empty()) {
throw exception("Incomplete Request",status_code::bad_request);
}
bytes_processed = (
len - static_cast<std::string::size_type>(m_buf->end()-end)
+ sizeof(header_delimiter) - 1
);
// frees memory used temporarily during request parsing
m_buf.reset();
// if this was not an upgrade request and has a content length
// continue capturing content-length bytes and expose them as a
// request body.
if (prepare_body()) {
bytes_processed += process_body(buf+bytes_processed,len-bytes_processed);
if (body_ready()) {
m_ready = true;
}
return bytes_processed;
} else {
m_ready = true;
// return number of bytes processed (starting bytes - bytes left)
return bytes_processed;
}
} else {
if (m_method.empty()) {
this->process(begin,end);
} else {
this->process_header(begin,end);
}
}
begin = end+(sizeof(header_delimiter)-1);
}
}
inline std::string request::raw() const {
// TODO: validation. Make sure all required fields have been set?
std::stringstream ret;
ret << m_method << " " << m_uri << " " << get_version() << "\r\n";
ret << raw_headers() << "\r\n" << m_body;
return ret.str();
}
inline std::string request::raw_head() const {
// TODO: validation. Make sure all required fields have been set?
std::stringstream ret;
ret << m_method << " " << m_uri << " " << get_version() << "\r\n";
ret << raw_headers() << "\r\n";
return ret.str();
}
inline void request::set_method(std::string const & method) {
if (std::find_if(method.begin(),method.end(),is_not_token_char) != method.end()) {
throw exception("Invalid method token.",status_code::bad_request);
}
m_method = method;
}
inline void request::set_uri(std::string const & uri) {
// TODO: validation?
m_uri = uri;
}
inline void request::process(std::string::iterator begin, std::string::iterator
end)
{
std::string::iterator cursor_start = begin;
std::string::iterator cursor_end = std::find(begin,end,' ');
if (cursor_end == end) {
throw exception("Invalid request line1",status_code::bad_request);
}
set_method(std::string(cursor_start,cursor_end));
cursor_start = cursor_end+1;
cursor_end = std::find(cursor_start,end,' ');
if (cursor_end == end) {
throw exception("Invalid request line2",status_code::bad_request);
}
set_uri(std::string(cursor_start,cursor_end));
set_version(std::string(cursor_end+1,end));
}
} // namespace parser
} // namespace http
} // namespace websocketpp
#endif // HTTP_PARSER_REQUEST_IMPL_HPP

View File

@ -0,0 +1,266 @@
/*
* Copyright (c) 2014, 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 HTTP_PARSER_RESPONSE_IMPL_HPP
#define HTTP_PARSER_RESPONSE_IMPL_HPP
#include <algorithm>
#include <istream>
#include <sstream>
#include <string>
#include <websocketpp/http/parser.hpp>
namespace websocketpp {
namespace http {
namespace parser {
inline size_t response::consume(char const * buf, size_t len) {
if (m_state == DONE) {return 0;}
if (m_state == BODY) {
return this->process_body(buf,len);
}
// copy new header bytes into buffer
m_buf->append(buf,len);
// Search for delimiter in buf. If found read until then. If not read all
std::string::iterator begin = m_buf->begin();
std::string::iterator end = begin;
for (;;) {
// search for delimiter
end = std::search(
begin,
m_buf->end(),
header_delimiter,
header_delimiter + sizeof(header_delimiter) - 1
);
m_header_bytes += (end-begin+sizeof(header_delimiter));
if (m_header_bytes > max_header_size) {
// exceeded max header size
throw exception("Maximum header size exceeded.",
status_code::request_header_fields_too_large);
}
if (end == m_buf->end()) {
// we are out of bytes. Discard the processed bytes and copy the
// remaining unprecessed bytes to the beginning of the buffer
std::copy(begin,end,m_buf->begin());
m_buf->resize(static_cast<std::string::size_type>(end-begin));
m_read += len;
m_header_bytes -= m_buf->size();
return len;
}
//the range [begin,end) now represents a line to be processed.
if (end-begin == 0) {
// we got a blank line
if (m_state == RESPONSE_LINE) {
throw exception("Incomplete Request",status_code::bad_request);
}
// TODO: grab content-length
std::string length = get_header("Content-Length");
if (length.empty()) {
// no content length found, read indefinitely
m_read = 0;
} else {
std::istringstream ss(length);
if ((ss >> m_read).fail()) {
throw exception("Unable to parse Content-Length header",
status_code::bad_request);
}
}
m_state = BODY;
// calc header bytes processed (starting bytes - bytes left)
size_t read = (
len - static_cast<std::string::size_type>(m_buf->end() - end)
+ sizeof(header_delimiter) - 1
);
// if there were bytes left process them as body bytes
if (read < len) {
read += this->process_body(buf+read,(len-read));
}
// frees memory used temporarily during header parsing
m_buf.reset();
return read;
} else {
if (m_state == RESPONSE_LINE) {
this->process(begin,end);
m_state = HEADERS;
} else {
this->process_header(begin,end);
}
}
begin = end+(sizeof(header_delimiter) - 1);
}
}
inline size_t response::consume(std::istream & s) {
char buf[istream_buffer];
size_t bytes_read;
size_t bytes_processed;
size_t total = 0;
while (s.good()) {
s.getline(buf,istream_buffer);
bytes_read = static_cast<size_t>(s.gcount());
if (s.fail() || s.eof()) {
bytes_processed = this->consume(buf,bytes_read);
total += bytes_processed;
if (bytes_processed != bytes_read) {
// problem
break;
}
} else if (s.bad()) {
// problem
break;
} else {
// the delimiting newline was found. Replace the trailing null with
// the newline that was discarded, since our raw consume function
// expects the newline to be be there.
buf[bytes_read-1] = '\n';
bytes_processed = this->consume(buf,bytes_read);
total += bytes_processed;
if (bytes_processed != bytes_read) {
// problem
break;
}
}
}
return total;
}
inline std::string response::raw() const {
// TODO: validation. Make sure all required fields have been set?
std::stringstream ret;
ret << get_version() << " " << m_status_code << " " << m_status_msg;
ret << "\r\n" << raw_headers() << "\r\n";
ret << m_body;
return ret.str();
}
inline void response::set_status(status_code::value code) {
// TODO: validation?
m_status_code = code;
m_status_msg = get_string(code);
}
inline void response::set_status(status_code::value code, std::string const &
msg)
{
// TODO: validation?
m_status_code = code;
m_status_msg = msg;
}
inline void response::process(std::string::iterator begin,
std::string::iterator end)
{
std::string::iterator cursor_start = begin;
std::string::iterator cursor_end = std::find(begin,end,' ');
if (cursor_end == end) {
throw exception("Invalid response line",status_code::bad_request);
}
set_version(std::string(cursor_start,cursor_end));
cursor_start = cursor_end+1;
cursor_end = std::find(cursor_start,end,' ');
if (cursor_end == end) {
throw exception("Invalid request line",status_code::bad_request);
}
int code;
std::istringstream ss(std::string(cursor_start,cursor_end));
if ((ss >> code).fail()) {
throw exception("Unable to parse response code",status_code::bad_request);
}
set_status(status_code::value(code),std::string(cursor_end+1,end));
}
inline size_t response::process_body(char const * buf, size_t len) {
// If no content length was set then we read forever and never set m_ready
if (m_read == 0) {
//m_body.append(buf,len);
//return len;
m_state = DONE;
return 0;
}
// Otherwise m_read is the number of bytes left.
size_t to_read;
if (len >= m_read) {
// if we have more bytes than we need read, read only the amount needed
// then set done state
to_read = m_read;
m_state = DONE;
} else {
// we need more bytes than are available, read them all
to_read = len;
}
m_body.append(buf,to_read);
m_read -= to_read;
return to_read;
}
} // namespace parser
} // namespace http
} // namespace websocketpp
#endif // HTTP_PARSER_RESPONSE_IMPL_HPP

View File

@ -0,0 +1,629 @@
/*
* Copyright (c) 2014, 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 HTTP_PARSER_HPP
#define HTTP_PARSER_HPP
#include <algorithm>
#include <map>
#include <string>
#include <utility>
#include <websocketpp/utilities.hpp>
#include <websocketpp/http/constants.hpp>
namespace websocketpp {
namespace http {
namespace parser {
namespace state {
enum value {
method,
resource,
version,
headers
};
}
namespace body_encoding {
enum value {
unknown,
plain,
chunked
};
}
typedef std::map<std::string, std::string, utility::ci_less > header_list;
/// Read and return the next token in the stream
/**
* Read until a non-token character is found and then return the token and
* iterator to the next character to read
*
* @param begin An iterator to the beginning of the sequence
* @param end An iterator to the end of the sequence
* @return A pair containing the token and an iterator to the next character in
* the stream
*/
template <typename InputIterator>
std::pair<std::string,InputIterator> extract_token(InputIterator begin,
InputIterator end)
{
InputIterator it = std::find_if(begin,end,&is_not_token_char);
return std::make_pair(std::string(begin,it),it);
}
/// Read and return the next quoted string in the stream
/**
* Read a double quoted string starting at `begin`. The quotes themselves are
* stripped. The quoted value is returned along with an iterator to the next
* character to read
*
* @param begin An iterator to the beginning of the sequence
* @param end An iterator to the end of the sequence
* @return A pair containing the string read and an iterator to the next
* character in the stream
*/
template <typename InputIterator>
std::pair<std::string,InputIterator> extract_quoted_string(InputIterator begin,
InputIterator end)
{
std::string s;
if (end == begin) {
return std::make_pair(s,begin);
}
if (*begin != '"') {
return std::make_pair(s,begin);
}
InputIterator cursor = begin+1;
InputIterator marker = cursor;
cursor = std::find(cursor,end,'"');
while (cursor != end) {
// either this is the end or a quoted string
if (*(cursor-1) == '\\') {
s.append(marker,cursor-1);
s.append(1,'"');
++cursor;
marker = cursor;
} else {
s.append(marker,cursor);
++cursor;
return std::make_pair(s,cursor);
}
cursor = std::find(cursor,end,'"');
}
return std::make_pair("",begin);
}
/// Read and discard one unit of linear whitespace
/**
* Read one unit of linear white space and return the iterator to the character
* afterwards. If `begin` is returned, no whitespace was extracted.
*
* @param begin An iterator to the beginning of the sequence
* @param end An iterator to the end of the sequence
* @return An iterator to the character after the linear whitespace read
*/
template <typename InputIterator>
InputIterator extract_lws(InputIterator begin, InputIterator end) {
InputIterator it = begin;
// strip leading CRLF
if (end-begin > 2 && *begin == '\r' && *(begin+1) == '\n' &&
is_whitespace_char(static_cast<unsigned char>(*(begin+2))))
{
it+=3;
}
it = std::find_if(it,end,&is_not_whitespace_char);
return it;
}
/// Read and discard linear whitespace
/**
* Read linear white space until a non-lws character is read and return an
* iterator to that character. If `begin` is returned, no whitespace was
* extracted.
*
* @param begin An iterator to the beginning of the sequence
* @param end An iterator to the end of the sequence
* @return An iterator to the character after the linear whitespace read
*/
template <typename InputIterator>
InputIterator extract_all_lws(InputIterator begin, InputIterator end) {
InputIterator old_it;
InputIterator new_it = begin;
do {
// Pull value from previous iteration
old_it = new_it;
// look ahead another pass
new_it = extract_lws(old_it,end);
} while (new_it != end && old_it != new_it);
return new_it;
}
/// Extract HTTP attributes
/**
* An http attributes list is a semicolon delimited list of key value pairs in
* the format: *( ";" attribute "=" value ) where attribute is a token and value
* is a token or quoted string.
*
* Attributes extracted are appended to the supplied attributes list
* `attributes`.
*
* @param [in] begin An iterator to the beginning of the sequence
* @param [in] end An iterator to the end of the sequence
* @param [out] attributes A reference to the attributes list to append
* attribute/value pairs extracted to
* @return An iterator to the character after the last atribute read
*/
template <typename InputIterator>
InputIterator extract_attributes(InputIterator begin, InputIterator end,
attribute_list & attributes)
{
InputIterator cursor;
bool first = true;
if (begin == end) {
return begin;
}
cursor = begin;
std::pair<std::string,InputIterator> ret;
while (cursor != end) {
std::string name;
cursor = http::parser::extract_all_lws(cursor,end);
if (cursor == end) {
break;
}
if (first) {
// ignore this check for the very first pass
first = false;
} else {
if (*cursor == ';') {
// advance past the ';'
++cursor;
} else {
// non-semicolon in this position indicates end end of the
// attribute list, break and return.
break;
}
}
cursor = http::parser::extract_all_lws(cursor,end);
ret = http::parser::extract_token(cursor,end);
if (ret.first.empty()) {
// error: expected a token
return begin;
} else {
name = ret.first;
cursor = ret.second;
}
cursor = http::parser::extract_all_lws(cursor,end);
if (cursor == end || *cursor != '=') {
// if there is an equals sign, read the attribute value. Otherwise
// record a blank value and continue
attributes[name].clear();
continue;
}
// advance past the '='
++cursor;
cursor = http::parser::extract_all_lws(cursor,end);
if (cursor == end) {
// error: expected a token or quoted string
return begin;
}
ret = http::parser::extract_quoted_string(cursor,end);
if (ret.second != cursor) {
attributes[name] = ret.first;
cursor = ret.second;
continue;
}
ret = http::parser::extract_token(cursor,end);
if (ret.first.empty()) {
// error : expected token or quoted string
return begin;
} else {
attributes[name] = ret.first;
cursor = ret.second;
}
}
return cursor;
}
/// Extract HTTP parameters
/**
* An http parameters list is a comma delimited list of tokens followed by
* optional semicolon delimited attributes lists.
*
* Parameters extracted are appended to the supplied parameters list
* `parameters`.
*
* @param [in] begin An iterator to the beginning of the sequence
* @param [in] end An iterator to the end of the sequence
* @param [out] parameters A reference to the parameters list to append
* paramter values extracted to
* @return An iterator to the character after the last parameter read
*/
template <typename InputIterator>
InputIterator extract_parameters(InputIterator begin, InputIterator end,
parameter_list &parameters)
{
InputIterator cursor;
if (begin == end) {
// error: expected non-zero length range
return begin;
}
cursor = begin;
std::pair<std::string,InputIterator> ret;
/**
* LWS
* token
* LWS
* *(";" method-param)
* LWS
* ,=loop again
*/
while (cursor != end) {
std::string parameter_name;
attribute_list attributes;
// extract any stray whitespace
cursor = http::parser::extract_all_lws(cursor,end);
if (cursor == end) {break;}
ret = http::parser::extract_token(cursor,end);
if (ret.first.empty()) {
// error: expected a token
return begin;
} else {
parameter_name = ret.first;
cursor = ret.second;
}
// Safe break point, insert parameter with blank attributes and exit
cursor = http::parser::extract_all_lws(cursor,end);
if (cursor == end) {
//parameters[parameter_name] = attributes;
parameters.push_back(std::make_pair(parameter_name,attributes));
break;
}
// If there is an attribute list, read it in
if (*cursor == ';') {
InputIterator acursor;
++cursor;
acursor = http::parser::extract_attributes(cursor,end,attributes);
if (acursor == cursor) {
// attribute extraction ended in syntax error
return begin;
}
cursor = acursor;
}
// insert parameter into output list
//parameters[parameter_name] = attributes;
parameters.push_back(std::make_pair(parameter_name,attributes));
cursor = http::parser::extract_all_lws(cursor,end);
if (cursor == end) {break;}
// if next char is ',' then read another parameter, else stop
if (*cursor != ',') {
break;
}
// advance past comma
++cursor;
if (cursor == end) {
// expected more bytes after a comma
return begin;
}
}
return cursor;
}
inline std::string strip_lws(std::string const & input) {
std::string::const_iterator begin = extract_all_lws(input.begin(),input.end());
if (begin == input.end()) {
return std::string();
}
std::string::const_reverse_iterator rbegin = extract_all_lws(input.rbegin(),input.rend());
if (rbegin == input.rend()) {
return std::string();
}
return std::string(begin,rbegin.base());
}
/// Base HTTP parser
/**
* Includes methods and data elements common to all types of HTTP messages such
* as headers, versions, bodies, etc.
*/
class parser {
public:
parser()
: m_header_bytes(0)
, m_body_bytes_needed(0)
, m_body_bytes_max(max_body_size)
, m_body_encoding(body_encoding::unknown) {}
/// Get the HTTP version string
/**
* @return The version string for this parser
*/
std::string const & get_version() const {
return m_version;
}
/// Set HTTP parser Version
/**
* Input should be in format: HTTP/x.y where x and y are positive integers.
* @todo Does this method need any validation?
*
* @param [in] version The value to set the HTTP version to.
*/
void set_version(std::string const & version);
/// Get the value of an HTTP header
/**
* @todo Make this method case insensitive.
*
* @param [in] key The name/key of the header to get.
* @return The value associated with the given HTTP header key.
*/
std::string const & get_header(std::string const & key) const;
/// Extract an HTTP parameter list from a parser header.
/**
* If the header requested doesn't exist or exists and is empty the
* parameter list is valid (but empty).
*
* @param [in] key The name/key of the HTTP header to use as input.
* @param [out] out The parameter list to store extracted parameters in.
* @return Whether or not the input was a valid parameter list.
*/
bool get_header_as_plist(std::string const & key, parameter_list & out)
const;
/// Return a list of all HTTP headers
/**
* Return a list of all HTTP headers
*
* @since 0.8.0
*
* @return A list of all HTTP headers
*/
header_list const & get_headers() const;
/// Append a value to an existing HTTP header
/**
* This method will set the value of the HTTP header `key` with the
* indicated value. If a header with the name `key` already exists, `val`
* will be appended to the existing value.
*
* @todo Make this method case insensitive.
* @todo Should there be any restrictions on which keys are allowed?
* @todo Exception free varient
*
* @see replace_header
*
* @param [in] key The name/key of the header to append to.
* @param [in] val The value to append.
*/
void append_header(std::string const & key, std::string const & val);
/// Set a value for an HTTP header, replacing an existing value
/**
* This method will set the value of the HTTP header `key` with the
* indicated value. If a header with the name `key` already exists, `val`
* will replace the existing value.
*
* @todo Make this method case insensitive.
* @todo Should there be any restrictions on which keys are allowed?
* @todo Exception free varient
*
* @see append_header
*
* @param [in] key The name/key of the header to append to.
* @param [in] val The value to append.
*/
void replace_header(std::string const & key, std::string const & val);
/// Remove a header from the parser
/**
* Removes the header entirely from the parser. This is different than
* setting the value of the header to blank.
*
* @todo Make this method case insensitive.
*
* @param [in] key The name/key of the header to remove.
*/
void remove_header(std::string const & key);
/// Get HTTP body
/**
* Gets the body of the HTTP object
*
* @return The body of the HTTP message.
*/
std::string const & get_body() const {
return m_body;
}
/// Set body content
/**
* Set the body content of the HTTP response to the parameter string. Note
* set_body will also set the Content-Length HTTP header to the appropriate
* value. If you want the Content-Length header to be something else, do so
* via replace_header("Content-Length") after calling set_body()
*
* @param value String data to include as the body content.
*/
void set_body(std::string const & value);
/// Get body size limit
/**
* Retrieves the maximum number of bytes to parse & buffer before canceling
* a request.
*
* @since 0.5.0
*
* @return The maximum length of a message body.
*/
size_t get_max_body_size() const {
return m_body_bytes_max;
}
/// Set body size limit
/**
* Set the maximum number of bytes to parse and buffer before canceling a
* request.
*
* @since 0.5.0
*
* @param value The size to set the max body length to.
*/
void set_max_body_size(size_t value) {
m_body_bytes_max = value;
}
/// Extract an HTTP parameter list from a string.
/**
* @param [in] in The input string.
* @param [out] out The parameter list to store extracted parameters in.
* @return Whether or not the input was a valid parameter list.
*/
bool parse_parameter_list(std::string const & in, parameter_list & out)
const;
protected:
/// Process a header line
/**
* @todo Update this method to be exception free.
*
* @param [in] begin An iterator to the beginning of the sequence.
* @param [in] end An iterator to the end of the sequence.
*/
void process_header(std::string::iterator begin, std::string::iterator end);
/// Prepare the parser to begin parsing body data
/**
* Inspects headers to determine if the message has a body that needs to be
* read. If so, sets up the necessary state, otherwise returns false. If
* this method returns true and loading the message body is desired call
* `process_body` until it returns zero bytes or an error.
*
* Must not be called until after all headers have been processed.
*
* @since 0.5.0
*
* @return True if more bytes are needed to load the body, false otherwise.
*/
bool prepare_body();
/// Process body data
/**
* Parses body data.
*
* @since 0.5.0
*
* @param [in] begin An iterator to the beginning of the sequence.
* @param [in] end An iterator to the end of the sequence.
* @return The number of bytes processed
*/
size_t process_body(char const * buf, size_t len);
/// Check if the parser is done parsing the body
/**
* Behavior before a call to `prepare_body` is undefined.
*
* @since 0.5.0
*
* @return True if the message body has been completed loaded.
*/
bool body_ready() const {
return (m_body_bytes_needed == 0);
}
/// Generate and return the HTTP headers as a string
/**
* Each headers will be followed by the \r\n sequence including the last one.
* A second \r\n sequence (blank header) is not appended by this method
*
* @return The HTTP headers as a string.
*/
std::string raw_headers() const;
std::string m_version;
header_list m_headers;
size_t m_header_bytes;
std::string m_body;
size_t m_body_bytes_needed;
size_t m_body_bytes_max;
body_encoding::value m_body_encoding;
};
} // namespace parser
} // namespace http
} // namespace websocketpp
#include <websocketpp/http/impl/parser.hpp>
#endif // HTTP_PARSER_HPP

View File

@ -0,0 +1,124 @@
/*
* Copyright (c) 2014, 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 HTTP_PARSER_REQUEST_HPP
#define HTTP_PARSER_REQUEST_HPP
#include <string>
#include <websocketpp/common/memory.hpp>
#include <websocketpp/http/parser.hpp>
namespace websocketpp {
namespace http {
namespace parser {
/// Stores, parses, and manipulates HTTP requests
/**
* http::request provides the following functionality for working with HTTP
* requests.
*
* - Initialize request via manually setting each element
* - Initialize request via reading raw bytes and parsing
* - Once initialized, access individual parsed elements
* - Once initialized, read entire request as raw bytes
*/
class request : public parser {
public:
typedef request type;
typedef lib::shared_ptr<type> ptr;
request()
: m_buf(lib::make_shared<std::string>())
, m_ready(false) {}
/// Process bytes in the input buffer
/**
* Process up to len bytes from input buffer buf. Returns the number of
* bytes processed. Bytes left unprocessed means bytes left over after the
* final header delimiters.
*
* Consume is a streaming processor. It may be called multiple times on one
* request and the full headers need not be available before processing can
* begin. If the end of the request was reached during this call to consume
* the ready flag will be set. Further calls to consume once ready will be
* ignored.
*
* Consume will throw an http::exception in the case of an error. Typical
* error reasons include malformed requests, incomplete requests, and max
* header size being reached.
*
* @param buf Pointer to byte buffer
* @param len Size of byte buffer
* @return Number of bytes processed.
*/
size_t consume(char const * buf, size_t len);
/// Returns whether or not the request is ready for reading.
bool ready() const {
return m_ready;
}
/// Returns the full raw request (including the body)
std::string raw() const;
/// Returns the raw request headers only (similar to an HTTP HEAD request)
std::string raw_head() const;
/// Set the HTTP method. Must be a valid HTTP token
void set_method(std::string const & method);
/// Return the request method
std::string const & get_method() const {
return m_method;
}
/// Set the HTTP uri. Must be a valid HTTP uri
void set_uri(std::string const & uri);
/// Return the requested URI
std::string const & get_uri() const {
return m_uri;
}
private:
/// Helper function for message::consume. Process request line
void process(std::string::iterator begin, std::string::iterator end);
lib::shared_ptr<std::string> m_buf;
std::string m_method;
std::string m_uri;
bool m_ready;
};
} // namespace parser
} // namespace http
} // namespace websocketpp
#include <websocketpp/http/impl/request.hpp>
#endif // HTTP_PARSER_REQUEST_HPP

View File

@ -0,0 +1,188 @@
/*
* Copyright (c) 2014, 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 HTTP_PARSER_RESPONSE_HPP
#define HTTP_PARSER_RESPONSE_HPP
#include <iostream>
#include <string>
#include <websocketpp/http/parser.hpp>
namespace websocketpp {
namespace http {
namespace parser {
/// Stores, parses, and manipulates HTTP responses
/**
* http::response provides the following functionality for working with HTTP
* responses.
*
* - Initialize response via manually setting each element
* - Initialize response via reading raw bytes and parsing
* - Once initialized, access individual parsed elements
* - Once initialized, read entire response as raw bytes
*
* http::response checks for header completeness separately from the full
* response. Once the header is complete, the Content-Length header is read to
* determine when to stop reading body bytes. If no Content-Length is present
* ready() will never return true. It is the responsibility of the caller to
* consume to determine when the response is complete (ie when the connection
* terminates, or some other metric).
*/
class response : public parser {
public:
typedef response type;
typedef lib::shared_ptr<type> ptr;
response()
: m_read(0)
, m_buf(lib::make_shared<std::string>())
, m_status_code(status_code::uninitialized)
, m_state(RESPONSE_LINE) {}
/// Process bytes in the input buffer
/**
* Process up to len bytes from input buffer buf. Returns the number of
* bytes processed. Bytes left unprocessed means bytes left over after the
* final header delimiters.
*
* Consume is a streaming processor. It may be called multiple times on one
* response and the full headers need not be available before processing can
* begin. If the end of the response was reached during this call to consume
* the ready flag will be set. Further calls to consume once ready will be
* ignored.
*
* Consume will throw an http::exception in the case of an error. Typical
* error reasons include malformed responses, incomplete responses, and max
* header size being reached.
*
* @param buf Pointer to byte buffer
* @param len Size of byte buffer
* @return Number of bytes processed.
*/
size_t consume(char const * buf, size_t len);
/// Process bytes in the input buffer (istream version)
/**
* Process bytes from istream s. Returns the number of bytes processed.
* Bytes left unprocessed means bytes left over after the final header
* delimiters.
*
* Consume is a streaming processor. It may be called multiple times on one
* response and the full headers need not be available before processing can
* begin. If the end of the response was reached during this call to consume
* the ready flag will be set. Further calls to consume once ready will be
* ignored.
*
* Consume will throw an http::exception in the case of an error. Typical
* error reasons include malformed responses, incomplete responses, and max
* header size being reached.
*
* @param buf Pointer to byte buffer
* @param len Size of byte buffer
* @return Number of bytes processed.
*/
size_t consume(std::istream & s);
/// Returns true if the response is ready.
/**
* @note will never return true if the content length header is not present
*/
bool ready() const {
return m_state == DONE;
}
/// Returns true if the response headers are fully parsed.
bool headers_ready() const {
return (m_state == BODY || m_state == DONE);
}
/// Returns the full raw response
std::string raw() const;
/// Set response status code and message
/**
* Sets the response status code to `code` and looks up the corresponding
* message for standard codes. Non-standard codes will be entered as Unknown
* use set_status(status_code::value,std::string) overload to set both
* values explicitly.
*
* @param code Code to set
* @param msg Message to set
*/
void set_status(status_code::value code);
/// Set response status code and message
/**
* Sets the response status code and message to independent custom values.
* use set_status(status_code::value) to set the code and have the standard
* message be automatically set.
*
* @param code Code to set
* @param msg Message to set
*/
void set_status(status_code::value code, std::string const & msg);
/// Return the response status code
status_code::value get_status_code() const {
return m_status_code;
}
/// Return the response status message
const std::string& get_status_msg() const {
return m_status_msg;
}
private:
/// Helper function for consume. Process response line
void process(std::string::iterator begin, std::string::iterator end);
/// Helper function for processing body bytes
size_t process_body(char const * buf, size_t len);
enum state {
RESPONSE_LINE = 0,
HEADERS = 1,
BODY = 2,
DONE = 3
};
std::string m_status_msg;
size_t m_read;
lib::shared_ptr<std::string> m_buf;
status_code::value m_status_code;
state m_state;
};
} // namespace parser
} // namespace http
} // namespace websocketpp
#include <websocketpp/http/impl/response.hpp>
#endif // HTTP_PARSER_RESPONSE_HPP

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,269 @@
/*
* Copyright (c) 2014, 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_ENDPOINT_IMPL_HPP
#define WEBSOCKETPP_ENDPOINT_IMPL_HPP
#include <string>
namespace websocketpp {
template <typename connection, typename config>
typename endpoint<connection,config>::connection_ptr
endpoint<connection,config>::create_connection() {
m_alog->write(log::alevel::devel,"create_connection");
//scoped_lock_type lock(m_state_lock);
/*if (m_state == STOPPING || m_state == STOPPED) {
return connection_ptr();
}*/
//scoped_lock_type guard(m_mutex);
// Create a connection on the heap and manage it using a shared pointer
connection_ptr con = lib::make_shared<connection_type>(m_is_server,
m_user_agent, m_alog, m_elog, lib::ref(m_rng));
connection_weak_ptr w(con);
// Create a weak pointer on the heap using that shared_ptr.
// Cast that weak pointer to void* and manage it using another shared_ptr
// connection_hdl hdl(reinterpret_cast<void*>(new connection_weak_ptr(con)));
con->set_handle(w);
// Copy default handlers from the endpoint
con->set_open_handler(m_open_handler);
con->set_close_handler(m_close_handler);
con->set_fail_handler(m_fail_handler);
con->set_ping_handler(m_ping_handler);
con->set_pong_handler(m_pong_handler);
con->set_pong_timeout_handler(m_pong_timeout_handler);
con->set_interrupt_handler(m_interrupt_handler);
con->set_http_handler(m_http_handler);
con->set_validate_handler(m_validate_handler);
con->set_message_handler(m_message_handler);
if (m_open_handshake_timeout_dur != config::timeout_open_handshake) {
con->set_open_handshake_timeout(m_open_handshake_timeout_dur);
}
if (m_close_handshake_timeout_dur != config::timeout_close_handshake) {
con->set_close_handshake_timeout(m_close_handshake_timeout_dur);
}
if (m_pong_timeout_dur != config::timeout_pong) {
con->set_pong_timeout(m_pong_timeout_dur);
}
if (m_max_message_size != config::max_message_size) {
con->set_max_message_size(m_max_message_size);
}
con->set_max_http_body_size(m_max_http_body_size);
lib::error_code ec;
ec = transport_type::init(con);
if (ec) {
m_elog->write(log::elevel::fatal,ec.message());
return connection_ptr();
}
return con;
}
template <typename connection, typename config>
void endpoint<connection,config>::interrupt(connection_hdl hdl, lib::error_code & ec)
{
connection_ptr con = get_con_from_hdl(hdl,ec);
if (ec) {return;}
m_alog->write(log::alevel::devel,"Interrupting connection");
ec = con->interrupt();
}
template <typename connection, typename config>
void endpoint<connection,config>::interrupt(connection_hdl hdl) {
lib::error_code ec;
interrupt(hdl,ec);
if (ec) { throw exception(ec); }
}
template <typename connection, typename config>
void endpoint<connection,config>::pause_reading(connection_hdl hdl, lib::error_code & ec)
{
connection_ptr con = get_con_from_hdl(hdl,ec);
if (ec) {return;}
ec = con->pause_reading();
}
template <typename connection, typename config>
void endpoint<connection,config>::pause_reading(connection_hdl hdl) {
lib::error_code ec;
pause_reading(hdl,ec);
if (ec) { throw exception(ec); }
}
template <typename connection, typename config>
void endpoint<connection,config>::resume_reading(connection_hdl hdl, lib::error_code & ec)
{
connection_ptr con = get_con_from_hdl(hdl,ec);
if (ec) {return;}
ec = con->resume_reading();
}
template <typename connection, typename config>
void endpoint<connection,config>::resume_reading(connection_hdl hdl) {
lib::error_code ec;
resume_reading(hdl,ec);
if (ec) { throw exception(ec); }
}
template <typename connection, typename config>
void endpoint<connection,config>::send_http_response(connection_hdl hdl,
lib::error_code & ec)
{
connection_ptr con = get_con_from_hdl(hdl,ec);
if (ec) {return;}
con->send_http_response(ec);
}
template <typename connection, typename config>
void endpoint<connection,config>::send_http_response(connection_hdl hdl) {
lib::error_code ec;
send_http_response(hdl,ec);
if (ec) { throw exception(ec); }
}
template <typename connection, typename config>
void endpoint<connection,config>::send(connection_hdl hdl, std::string const & payload,
frame::opcode::value op, lib::error_code & ec)
{
connection_ptr con = get_con_from_hdl(hdl,ec);
if (ec) {return;}
ec = con->send(payload,op);
}
template <typename connection, typename config>
void endpoint<connection,config>::send(connection_hdl hdl, std::string const & payload,
frame::opcode::value op)
{
lib::error_code ec;
send(hdl,payload,op,ec);
if (ec) { throw exception(ec); }
}
template <typename connection, typename config>
void endpoint<connection,config>::send(connection_hdl hdl, void const * payload,
size_t len, frame::opcode::value op, lib::error_code & ec)
{
connection_ptr con = get_con_from_hdl(hdl,ec);
if (ec) {return;}
ec = con->send(payload,len,op);
}
template <typename connection, typename config>
void endpoint<connection,config>::send(connection_hdl hdl, void const * payload,
size_t len, frame::opcode::value op)
{
lib::error_code ec;
send(hdl,payload,len,op,ec);
if (ec) { throw exception(ec); }
}
template <typename connection, typename config>
void endpoint<connection,config>::send(connection_hdl hdl, message_ptr msg,
lib::error_code & ec)
{
connection_ptr con = get_con_from_hdl(hdl,ec);
if (ec) {return;}
ec = con->send(msg);
}
template <typename connection, typename config>
void endpoint<connection,config>::send(connection_hdl hdl, message_ptr msg) {
lib::error_code ec;
send(hdl,msg,ec);
if (ec) { throw exception(ec); }
}
template <typename connection, typename config>
void endpoint<connection,config>::close(connection_hdl hdl, close::status::value
const code, std::string const & reason,
lib::error_code & ec)
{
connection_ptr con = get_con_from_hdl(hdl,ec);
if (ec) {return;}
con->close(code,reason,ec);
}
template <typename connection, typename config>
void endpoint<connection,config>::close(connection_hdl hdl, close::status::value
const code, std::string const & reason)
{
lib::error_code ec;
close(hdl,code,reason,ec);
if (ec) { throw exception(ec); }
}
template <typename connection, typename config>
void endpoint<connection,config>::ping(connection_hdl hdl, std::string const &
payload, lib::error_code & ec)
{
connection_ptr con = get_con_from_hdl(hdl,ec);
if (ec) {return;}
con->ping(payload,ec);
}
template <typename connection, typename config>
void endpoint<connection,config>::ping(connection_hdl hdl, std::string const & payload)
{
lib::error_code ec;
ping(hdl,payload,ec);
if (ec) { throw exception(ec); }
}
template <typename connection, typename config>
void endpoint<connection,config>::pong(connection_hdl hdl, std::string const & payload,
lib::error_code & ec)
{
connection_ptr con = get_con_from_hdl(hdl,ec);
if (ec) {return;}
con->pong(payload,ec);
}
template <typename connection, typename config>
void endpoint<connection,config>::pong(connection_hdl hdl, std::string const & payload)
{
lib::error_code ec;
pong(hdl,payload,ec);
if (ec) { throw exception(ec); }
}
} // namespace websocketpp
#endif // WEBSOCKETPP_ENDPOINT_IMPL_HPP

View File

@ -0,0 +1,87 @@
/*
* Copyright (c) 2014, 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_UTILITIES_IMPL_HPP
#define WEBSOCKETPP_UTILITIES_IMPL_HPP
#include <algorithm>
#include <string>
namespace websocketpp {
namespace utility {
inline std::string to_lower(std::string const & in) {
std::string out = in;
std::transform(out.begin(),out.end(),out.begin(),::tolower);
return out;
}
inline std::string to_hex(std::string const & input) {
std::string output;
std::string hex = "0123456789ABCDEF";
for (size_t i = 0; i < input.size(); i++) {
output += hex[(input[i] & 0xF0) >> 4];
output += hex[input[i] & 0x0F];
output += " ";
}
return output;
}
inline std::string to_hex(uint8_t const * input, size_t length) {
std::string output;
std::string hex = "0123456789ABCDEF";
for (size_t i = 0; i < length; i++) {
output += hex[(input[i] & 0xF0) >> 4];
output += hex[input[i] & 0x0F];
output += " ";
}
return output;
}
inline std::string to_hex(const char* input,size_t length) {
return to_hex(reinterpret_cast<const uint8_t*>(input),length);
}
inline std::string string_replace_all(std::string subject, std::string const &
search, std::string const & replace)
{
size_t pos = 0;
while((pos = subject.find(search, pos)) != std::string::npos) {
subject.replace(pos, search.length(), replace);
pos += replace.length();
}
return subject;
}
} // namespace utility
} // namespace websocketpp
#endif // WEBSOCKETPP_UTILITIES_IMPL_HPP

View File

@ -0,0 +1,199 @@
/*
* Copyright (c) 2014, 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_LOGGER_BASIC_HPP
#define WEBSOCKETPP_LOGGER_BASIC_HPP
/* Need a way to print a message to the log
*
* - timestamps
* - channels
* - thread safe
* - output to stdout or file
* - selective output channels, both compile time and runtime
* - named channels
* - ability to test whether a log message will be printed at compile time
*
*/
#include <websocketpp/logger/levels.hpp>
#include <websocketpp/common/cpp11.hpp>
#include <websocketpp/common/stdint.hpp>
#include <websocketpp/common/time.hpp>
#include <ctime>
#include <iostream>
#include <iomanip>
#include <string>
namespace websocketpp {
namespace log {
/// Basic logger that outputs to an ostream
template <typename concurrency, typename names>
class basic {
public:
basic<concurrency,names>(channel_type_hint::value h =
channel_type_hint::access)
: m_static_channels(0xffffffff)
, m_dynamic_channels(0)
, m_out(h == channel_type_hint::error ? &std::cerr : &std::cout) {}
basic<concurrency,names>(std::ostream * out)
: m_static_channels(0xffffffff)
, m_dynamic_channels(0)
, m_out(out) {}
basic<concurrency,names>(level c, channel_type_hint::value h =
channel_type_hint::access)
: m_static_channels(c)
, m_dynamic_channels(0)
, m_out(h == channel_type_hint::error ? &std::cerr : &std::cout) {}
basic<concurrency,names>(level c, std::ostream * out)
: m_static_channels(c)
, m_dynamic_channels(0)
, m_out(out) {}
/// Destructor
~basic<concurrency,names>() {}
/// Copy constructor
basic<concurrency,names>(basic<concurrency,names> const & other)
: m_static_channels(other.m_static_channels)
, m_dynamic_channels(other.m_dynamic_channels)
, m_out(other.m_out)
{}
#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
// no copy assignment operator because of const member variables
basic<concurrency,names> & operator=(basic<concurrency,names> const &) = delete;
#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
#ifdef _WEBSOCKETPP_MOVE_SEMANTICS_
/// Move constructor
basic<concurrency,names>(basic<concurrency,names> && other)
: m_static_channels(other.m_static_channels)
, m_dynamic_channels(other.m_dynamic_channels)
, m_out(other.m_out)
{}
#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
// no move assignment operator because of const member variables
basic<concurrency,names> & operator=(basic<concurrency,names> &&) = delete;
#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
#endif // _WEBSOCKETPP_MOVE_SEMANTICS_
void set_ostream(std::ostream * out = &std::cout) {
m_out = out;
}
void set_channels(level channels) {
if (channels == names::none) {
clear_channels(names::all);
return;
}
scoped_lock_type lock(m_lock);
m_dynamic_channels |= (channels & m_static_channels);
}
void clear_channels(level channels) {
scoped_lock_type lock(m_lock);
m_dynamic_channels &= ~channels;
}
/// Write a string message to the given channel
/**
* @param channel The channel to write to
* @param msg The message to write
*/
void write(level channel, std::string const & msg) {
scoped_lock_type lock(m_lock);
if (!this->dynamic_test(channel)) { return; }
*m_out << "[" << timestamp << "] "
<< "[" << names::channel_name(channel) << "] "
<< msg << "\n";
m_out->flush();
}
/// Write a cstring message to the given channel
/**
* @param channel The channel to write to
* @param msg The message to write
*/
void write(level channel, char const * msg) {
scoped_lock_type lock(m_lock);
if (!this->dynamic_test(channel)) { return; }
*m_out << "[" << timestamp << "] "
<< "[" << names::channel_name(channel) << "] "
<< msg << "\n";
m_out->flush();
}
_WEBSOCKETPP_CONSTEXPR_TOKEN_ bool static_test(level channel) const {
return ((channel & m_static_channels) != 0);
}
bool dynamic_test(level channel) {
return ((channel & m_dynamic_channels) != 0);
}
protected:
typedef typename concurrency::scoped_lock_type scoped_lock_type;
typedef typename concurrency::mutex_type mutex_type;
mutex_type m_lock;
private:
// The timestamp does not include the time zone, because on Windows with the
// default registry settings, the time zone would be written out in full,
// which would be obnoxiously verbose.
//
// TODO: find a workaround for this or make this format user settable
static std::ostream & timestamp(std::ostream & os) {
std::time_t t = std::time(NULL);
std::tm lt = lib::localtime(t);
#ifdef _WEBSOCKETPP_PUTTIME_
return os << std::put_time(&lt,"%Y-%m-%d %H:%M:%S");
#else // Falls back to strftime, which requires a temporary copy of the string.
char buffer[20];
size_t result = std::strftime(buffer,sizeof(buffer),"%Y-%m-%d %H:%M:%S",&lt);
return os << (result == 0 ? "Unknown" : buffer);
#endif
}
level const m_static_channels;
level m_dynamic_channels;
std::ostream * m_out;
};
} // log
} // websocketpp
#endif // WEBSOCKETPP_LOGGER_BASIC_HPP

View File

@ -0,0 +1,203 @@
/*
* Copyright (c) 2014, 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_LOGGER_LEVELS_HPP
#define WEBSOCKETPP_LOGGER_LEVELS_HPP
#include <websocketpp/common/stdint.hpp>
namespace websocketpp {
namespace log {
/// Type of a channel package
typedef uint32_t level;
/// Package of values for hinting at the nature of a given logger.
/**
* Used by the library to signal to the logging class a hint that it can use to
* set itself up. For example, the `access` hint indicates that it is an access
* log that might be suitable for being printed to an access log file or to cout
* whereas `error` might be suitable for an error log file or cerr.
*/
struct channel_type_hint {
/// Type of a channel type hint value
typedef uint32_t value;
/// No information
static value const none = 0;
/// Access log
static value const access = 1;
/// Error log
static value const error = 2;
};
/// Package of log levels for logging errors
struct elevel {
/// Special aggregate value representing "no levels"
static level const none = 0x0;
/// Low level debugging information (warning: very chatty)
static level const devel = 0x1;
/// Information about unusual system states or other minor internal library
/// problems, less chatty than devel.
static level const library = 0x2;
/// Information about minor configuration problems or additional information
/// about other warnings.
static level const info = 0x4;
/// Information about important problems not severe enough to terminate
/// connections.
static level const warn = 0x8;
/// Recoverable error. Recovery may mean cleanly closing the connection with
/// an appropriate error code to the remote endpoint.
static level const rerror = 0x10;
/// Unrecoverable error. This error will trigger immediate unclean
/// termination of the connection or endpoint.
static level const fatal = 0x20;
/// Special aggregate value representing "all levels"
static level const all = 0xffffffff;
/// Get the textual name of a channel given a channel id
/**
* The id must be that of a single channel. Passing an aggregate channel
* package results in undefined behavior.
*
* @param channel The channel id to look up.
*
* @return The name of the specified channel.
*/
static char const * channel_name(level channel) {
switch(channel) {
case devel:
return "devel";
case library:
return "library";
case info:
return "info";
case warn:
return "warning";
case rerror:
return "error";
case fatal:
return "fatal";
default:
return "unknown";
}
}
};
/// Package of log levels for logging access events
struct alevel {
/// Special aggregate value representing "no levels"
static level const none = 0x0;
/// Information about new connections
/**
* One line for each new connection that includes a host of information
* including: the remote address, websocket version, requested resource,
* http code, remote user agent
*/
static level const connect = 0x1;
/// One line for each closed connection. Includes closing codes and reasons.
static level const disconnect = 0x2;
/// One line per control frame
static level const control = 0x4;
/// One line per frame, includes the full frame header
static level const frame_header = 0x8;
/// One line per frame, includes the full message payload (warning: chatty)
static level const frame_payload = 0x10;
/// Reserved
static level const message_header = 0x20;
/// Reserved
static level const message_payload = 0x40;
/// Reserved
static level const endpoint = 0x80;
/// Extra information about opening handshakes
static level const debug_handshake = 0x100;
/// Extra information about closing handshakes
static level const debug_close = 0x200;
/// Development messages (warning: very chatty)
static level const devel = 0x400;
/// Special channel for application specific logs. Not used by the library.
static level const app = 0x800;
/// Access related to HTTP requests
static level const http = 0x1000;
/// One line for each failed WebSocket connection with details
static level const fail = 0x2000;
/// Aggregate package representing the commonly used core access channels
/// Connect, Disconnect, Fail, and HTTP
static level const access_core = 0x00003003;
/// Special aggregate value representing "all levels"
static level const all = 0xffffffff;
/// Get the textual name of a channel given a channel id
/**
* Get the textual name of a channel given a channel id. The id must be that
* of a single channel. Passing an aggregate channel package results in
* undefined behavior.
*
* @param channel The channelid to look up.
*
* @return The name of the specified channel.
*/
static char const * channel_name(level channel) {
switch(channel) {
case connect:
return "connect";
case disconnect:
return "disconnect";
case control:
return "control";
case frame_header:
return "frame_header";
case frame_payload:
return "frame_payload";
case message_header:
return "message_header";
case message_payload:
return "message_payload";
case endpoint:
return "endpoint";
case debug_handshake:
return "debug_handshake";
case debug_close:
return "debug_close";
case devel:
return "devel";
case app:
return "application";
case http:
return "http";
case fail:
return "fail";
default:
return "unknown";
}
}
};
} // logger
} // websocketpp
#endif //WEBSOCKETPP_LOGGER_LEVELS_HPP

View File

@ -0,0 +1,119 @@
/*
* Copyright (c) 2014, 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_LOGGER_STUB_HPP
#define WEBSOCKETPP_LOGGER_STUB_HPP
#include <websocketpp/logger/levels.hpp>
#include <websocketpp/common/cpp11.hpp>
#include <string>
namespace websocketpp {
namespace log {
/// Stub logger that ignores all input
class stub {
public:
/// Construct the logger
/**
* @param hint A channel type specific hint for how to construct the logger
*/
explicit stub(channel_type_hint::value) {}
/// Construct the logger
/**
* @param default_channels A set of channels to statically enable
* @param hint A channel type specific hint for how to construct the logger
*/
stub(level, channel_type_hint::value) {}
_WEBSOCKETPP_CONSTEXPR_TOKEN_ stub() {}
/// Dynamically enable the given list of channels
/**
* All operations on the stub logger are no-ops and all arguments are
* ignored
*
* @param channels The package of channels to enable
*/
void set_channels(level) {}
/// Dynamically disable the given list of channels
/**
* All operations on the stub logger are no-ops and all arguments are
* ignored
*
* @param channels The package of channels to disable
*/
void clear_channels(level) {}
/// Write a string message to the given channel
/**
* Writing on the stub logger is a no-op and all arguments are ignored
*
* @param channel The channel to write to
* @param msg The message to write
*/
void write(level, std::string const &) {}
/// Write a cstring message to the given channel
/**
* Writing on the stub logger is a no-op and all arguments are ignored
*
* @param channel The channel to write to
* @param msg The message to write
*/
void write(level, char const *) {}
/// Test whether a channel is statically enabled
/**
* The stub logger has no channels so all arguments are ignored and
* `static_test` always returns false.
*
* @param channel The package of channels to test
*/
_WEBSOCKETPP_CONSTEXPR_TOKEN_ bool static_test(level) const {
return false;
}
/// Test whether a channel is dynamically enabled
/**
* The stub logger has no channels so all arguments are ignored and
* `dynamic_test` always returns false.
*
* @param channel The package of channels to test
*/
bool dynamic_test(level) {
return false;
}
};
} // log
} // websocketpp
#endif // WEBSOCKETPP_LOGGER_STUB_HPP

View File

@ -0,0 +1,146 @@
/*
* Copyright (c) 2014, 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.
*
*
* The initial version of this logging policy was contributed to the WebSocket++
* project by Tom Hughes.
*/
#ifndef WEBSOCKETPP_LOGGER_SYSLOG_HPP
#define WEBSOCKETPP_LOGGER_SYSLOG_HPP
#include <syslog.h>
#include <websocketpp/logger/basic.hpp>
#include <websocketpp/common/cpp11.hpp>
#include <websocketpp/logger/levels.hpp>
namespace websocketpp {
namespace log {
/// Basic logger that outputs to syslog
template <typename concurrency, typename names>
class syslog : public basic<concurrency, names> {
public:
typedef basic<concurrency, names> base;
/// Construct the logger
/**
* @param hint A channel type specific hint for how to construct the logger
*/
syslog<concurrency,names>(channel_type_hint::value hint =
channel_type_hint::access)
: basic<concurrency,names>(hint), m_channel_type_hint(hint) {}
/// Construct the logger
/**
* @param channels A set of channels to statically enable
* @param hint A channel type specific hint for how to construct the logger
*/
syslog<concurrency,names>(level channels, channel_type_hint::value hint =
channel_type_hint::access)
: basic<concurrency,names>(channels, hint), m_channel_type_hint(hint) {}
/// Write a string message to the given channel
/**
* @param channel The channel to write to
* @param msg The message to write
*/
void write(level channel, std::string const & msg) {
write(channel, msg.c_str());
}
/// Write a cstring message to the given channel
/**
* @param channel The channel to write to
* @param msg The message to write
*/
void write(level channel, char const * msg) {
scoped_lock_type lock(base::m_lock);
if (!this->dynamic_test(channel)) { return; }
::syslog(syslog_priority(channel), "[%s] %s",
names::channel_name(channel), msg);
}
private:
typedef typename base::scoped_lock_type scoped_lock_type;
/// The default level is used for all access logs and any error logs that
/// don't trivially map to one of the standard syslog levels.
static int const default_level = LOG_INFO;
/// retrieve the syslog priority code given a WebSocket++ channel
/**
* @param channel The level to look up
* @return The syslog level associated with `channel`
*/
int syslog_priority(level channel) const {
if (m_channel_type_hint == channel_type_hint::access) {
return syslog_priority_access(channel);
} else {
return syslog_priority_error(channel);
}
}
/// retrieve the syslog priority code given a WebSocket++ error channel
/**
* @param channel The level to look up
* @return The syslog level associated with `channel`
*/
int syslog_priority_error(level channel) const {
switch (channel) {
case elevel::devel:
return LOG_DEBUG;
case elevel::library:
return LOG_DEBUG;
case elevel::info:
return LOG_INFO;
case elevel::warn:
return LOG_WARNING;
case elevel::rerror:
return LOG_ERR;
case elevel::fatal:
return LOG_CRIT;
default:
return default_level;
}
}
/// retrieve the syslog priority code given a WebSocket++ access channel
/**
* @param channel The level to look up
* @return The syslog level associated with `channel`
*/
_WEBSOCKETPP_CONSTEXPR_TOKEN_ int syslog_priority_access(level) const {
return default_level;
}
channel_type_hint::value m_channel_type_hint;
};
} // log
} // websocketpp
#endif // WEBSOCKETPP_LOGGER_SYSLOG_HPP

View File

@ -0,0 +1,105 @@
/*
* Copyright (c) 2014, 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_MESSAGE_BUFFER_ALLOC_HPP
#define WEBSOCKETPP_MESSAGE_BUFFER_ALLOC_HPP
#include <websocketpp/common/memory.hpp>
#include <websocketpp/frame.hpp>
namespace websocketpp {
namespace message_buffer {
namespace alloc {
/// A connection message manager that allocates a new message for each
/// request.
template <typename message>
class con_msg_manager
: public lib::enable_shared_from_this<con_msg_manager<message> >
{
public:
typedef con_msg_manager<message> type;
typedef lib::shared_ptr<con_msg_manager> ptr;
typedef lib::weak_ptr<con_msg_manager> weak_ptr;
typedef typename message::ptr message_ptr;
/// Get an empty message buffer
/**
* @return A shared pointer to an empty new message
*/
message_ptr get_message() {
return message_ptr(lib::make_shared<message>(type::shared_from_this()));
}
/// Get a message buffer with specified size and opcode
/**
* @param op The opcode to use
* @param size Minimum size in bytes to request for the message payload.
*
* @return A shared pointer to a new message with specified size.
*/
message_ptr get_message(frame::opcode::value op,size_t size) {
return message_ptr(lib::make_shared<message>(type::shared_from_this(),op,size));
}
/// Recycle a message
/**
* This method shouldn't be called. If it is, return false to indicate an
* error. The rest of the method recycle chain should notice this and free
* the memory.
*
* @param msg The message to be recycled.
*
* @return true if the message was successfully recycled, false otherwse.
*/
bool recycle(message *) {
return false;
}
};
/// An endpoint message manager that allocates a new manager for each
/// connection.
template <typename con_msg_manager>
class endpoint_msg_manager {
public:
typedef typename con_msg_manager::ptr con_msg_man_ptr;
/// Get a pointer to a connection message manager
/**
* @return A pointer to the requested connection message manager.
*/
con_msg_man_ptr get_manager() const {
return con_msg_man_ptr(lib::make_shared<con_msg_manager>());
}
};
} // namespace alloc
} // namespace message_buffer
} // namespace websocketpp
#endif // WEBSOCKETPP_MESSAGE_BUFFER_ALLOC_HPP

View File

@ -0,0 +1,340 @@
/*
* Copyright (c) 2014, 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_MESSAGE_BUFFER_MESSAGE_HPP
#define WEBSOCKETPP_MESSAGE_BUFFER_MESSAGE_HPP
#include <websocketpp/common/memory.hpp>
#include <websocketpp/frame.hpp>
#include <string>
namespace websocketpp {
namespace message_buffer {
/* # message:
* object that stores a message while it is being sent or received. Contains
* the message payload itself, the message header, the extension data, and the
* opcode.
*
* # connection_message_manager:
* An object that manages all of the message_buffers associated with a given
* connection. Implements the get_message_buffer(size) method that returns
* a message buffer at least size bytes long.
*
* Message buffers are reference counted with shared ownership semantics. Once
* requested from the manager the requester and it's associated downstream code
* may keep a pointer to the message indefinitely at a cost of extra resource
* usage. Once the reference count drops to the point where the manager is the
* only reference the messages is recycled using whatever method is implemented
* in the manager.
*
* # endpoint_message_manager:
* An object that manages connection_message_managers. Implements the
* get_message_manager() method. This is used once by each connection to
* request the message manager that they are supposed to use to manage message
* buffers for their own use.
*
* TYPES OF CONNECTION_MESSAGE_MANAGERS
* - allocate a message with the exact size every time one is requested
* - maintain a pool of pre-allocated messages and return one when needed.
* Recycle previously used messages back into the pool
*
* TYPES OF ENDPOINT_MESSAGE_MANAGERS
* - allocate a new connection manager for each connection. Message pools
* become connection specific. This increases memory usage but improves
* concurrency.
* - allocate a single connection manager and share a pointer to it with all
* connections created by this endpoint. The message pool will be shared
* among all connections, improving memory usage and performance at the cost
* of reduced concurrency
*/
/// Represents a buffer for a single WebSocket message.
/**
*
*
*/
template <template<class> class con_msg_manager>
class message {
public:
typedef lib::shared_ptr<message> ptr;
typedef con_msg_manager<message> con_msg_man_type;
typedef typename con_msg_man_type::ptr con_msg_man_ptr;
typedef typename con_msg_man_type::weak_ptr con_msg_man_weak_ptr;
/// Construct an empty message
/**
* Construct an empty message
*/
message(const con_msg_man_ptr manager)
: m_manager(manager)
, m_prepared(false)
, m_fin(true)
, m_terminal(false)
, m_compressed(false) {}
/// Construct a message and fill in some values
/**
*
*/
message(const con_msg_man_ptr manager, frame::opcode::value op, size_t size = 128)
: m_manager(manager)
, m_opcode(op)
, m_prepared(false)
, m_fin(true)
, m_terminal(false)
, m_compressed(false)
{
m_payload.reserve(size);
}
/// Return whether or not the message has been prepared for sending
/**
* The prepared flag indicates that the message has been prepared by a
* websocket protocol processor and is ready to be written to the wire.
*
* @return whether or not the message has been prepared for sending
*/
bool get_prepared() const {
return m_prepared;
}
/// Set or clear the flag that indicates that the message has been prepared
/**
* This flag should not be set by end user code without a very good reason.
*
* @param value The value to set the prepared flag to
*/
void set_prepared(bool value) {
m_prepared = value;
}
/// Return whether or not the message is flagged as compressed
/**
* @return whether or not the message is/should be compressed
*/
bool get_compressed() const {
return m_compressed;
}
/// Set or clear the compression flag
/**
* Setting the compression flag indicates that the data in this message
* would benefit from compression. If both endpoints negotiate a compression
* extension WebSocket++ will attempt to compress messages with this flag.
* Setting this flag does not guarantee that the message will be compressed.
*
* @param value The value to set the compressed flag to
*/
void set_compressed(bool value) {
m_compressed = value;
}
/// Get whether or not the message is terminal
/**
* Messages can be flagged as terminal, which results in the connection
* being close after they are written rather than the implementation going
* on to the next message in the queue. This is typically used internally
* for close messages only.
*
* @return Whether or not this message is marked terminal
*/
bool get_terminal() const {
return m_terminal;
}
/// Set the terminal flag
/**
* This flag should not be set by end user code without a very good reason.
*
* @see get_terminal()
*
* @param value The value to set the terminal flag to.
*/
void set_terminal(bool value) {
m_terminal = value;
}
/// Read the fin bit
/**
* A message with the fin bit set will be sent as the last message of its
* sequence. A message with the fin bit cleared will require subsequent
* frames of opcode continuation until one of them has the fin bit set.
*
* The remote end likely will not deliver any bytes until the frame with the fin
* bit set has been received.
*
* @return Whether or not the fin bit is set
*/
bool get_fin() const {
return m_fin;
}
/// Set the fin bit
/**
* @see get_fin for a more detailed explaination of the fin bit
*
* @param value The value to set the fin bit to.
*/
void set_fin(bool value) {
m_fin = value;
}
/// Return the message opcode
frame::opcode::value get_opcode() const {
return m_opcode;
}
/// Set the opcode
void set_opcode(frame::opcode::value op) {
m_opcode = op;
}
/// Return the prepared frame header
/**
* This value is typically set by a websocket protocol processor
* and shouldn't be tampered with.
*/
std::string const & get_header() const {
return m_header;
}
/// Set prepared frame header
/**
* Under normal circumstances this should not be called by end users
*
* @param header A string to set the header to.
*/
void set_header(std::string const & header) {
m_header = header;
}
std::string const & get_extension_data() const {
return m_extension_data;
}
/// Get a reference to the payload string
/**
* @return A const reference to the message's payload string
*/
std::string const & get_payload() const {
return m_payload;
}
/// Get a non-const reference to the payload string
/**
* @return A reference to the message's payload string
*/
std::string & get_raw_payload() {
return m_payload;
}
/// Set payload data
/**
* Set the message buffer's payload to the given value.
*
* @param payload A string to set the payload to.
*/
void set_payload(std::string const & payload) {
m_payload = payload;
}
/// Set payload data
/**
* Set the message buffer's payload to the given value.
*
* @param payload A pointer to a data array to set to.
* @param len The length of new payload in bytes.
*/
void set_payload(void const * payload, size_t len) {
m_payload.reserve(len);
char const * pl = static_cast<char const *>(payload);
m_payload.assign(pl, pl + len);
}
/// Append payload data
/**
* Append data to the message buffer's payload.
*
* @param payload A string containing the data array to append.
*/
void append_payload(std::string const & payload) {
m_payload.append(payload);
}
/// Append payload data
/**
* Append data to the message buffer's payload.
*
* @param payload A pointer to a data array to append
* @param len The length of payload in bytes
*/
void append_payload(void const * payload, size_t len) {
m_payload.reserve(m_payload.size()+len);
m_payload.append(static_cast<char const *>(payload),len);
}
/// Recycle the message
/**
* A request to recycle this message was received. Forward that request to
* the connection message manager for processing. Errors and exceptions
* from the manager's recycle member function should be passed back up the
* call chain. The caller to message::recycle will deal with them.
*
* Recycle must *only* be called by the message shared_ptr's destructor.
* Once recycled successfully, ownership of the memory has been passed to
* another system and must not be accessed again.
*
* @return true if the message was successfully recycled, false otherwise.
*/
bool recycle() {
con_msg_man_ptr shared = m_manager.lock();
if (shared) {
return shared->recycle(this);
} else {
return false;
}
}
private:
con_msg_man_weak_ptr m_manager;
std::string m_header;
std::string m_extension_data;
std::string m_payload;
frame::opcode::value m_opcode;
bool m_prepared;
bool m_fin;
bool m_terminal;
bool m_compressed;
};
} // namespace message_buffer
} // namespace websocketpp
#endif // WEBSOCKETPP_MESSAGE_BUFFER_MESSAGE_HPP

View File

@ -0,0 +1,229 @@
/*
* Copyright (c) 2014, 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_MESSAGE_BUFFER_ALLOC_HPP
#define WEBSOCKETPP_MESSAGE_BUFFER_ALLOC_HPP
#include <websocketpp/common/memory.hpp>
#include <string>
namespace websocketpp {
namespace message_buffer {
/* # message:
* object that stores a message while it is being sent or received. Contains
* the message payload itself, the message header, the extension data, and the
* opcode.
*
* # connection_message_manager:
* An object that manages all of the message_buffers associated with a given
* connection. Implements the get_message_buffer(size) method that returns
* a message buffer at least size bytes long.
*
* Message buffers are reference counted with shared ownership semantics. Once
* requested from the manager the requester and it's associated downstream code
* may keep a pointer to the message indefinitely at a cost of extra resource
* usage. Once the reference count drops to the point where the manager is the
* only reference the messages is recycled using whatever method is implemented
* in the manager.
*
* # endpoint_message_manager:
* An object that manages connection_message_managers. Implements the
* get_message_manager() method. This is used once by each connection to
* request the message manager that they are supposed to use to manage message
* buffers for their own use.
*
* TYPES OF CONNECTION_MESSAGE_MANAGERS
* - allocate a message with the exact size every time one is requested
* - maintain a pool of pre-allocated messages and return one when needed.
* Recycle previously used messages back into the pool
*
* TYPES OF ENDPOINT_MESSAGE_MANAGERS
* - allocate a new connection manager for each connection. Message pools
* become connection specific. This increases memory usage but improves
* concurrency.
* - allocate a single connection manager and share a pointer to it with all
* connections created by this endpoint. The message pool will be shared
* among all connections, improving memory usage and performance at the cost
* of reduced concurrency
*/
/// Custom deleter for use in shared_ptrs to message.
/**
* This is used to catch messages about to be deleted and offer the manager the
* ability to recycle them instead. Message::recycle will return true if it was
* successfully recycled and false otherwise. In the case of exceptions or error
* this deleter frees the memory.
*/
template <typename T>
void message_deleter(T* msg) {
try {
if (!msg->recycle()) {
delete msg;
}
} catch (...) {
// TODO: is there a better way to ensure this function doesn't throw?
delete msg;
}
}
/// Represents a buffer for a single WebSocket message.
/**
*
*
*/
template <typename con_msg_manager>
class message {
public:
typedef lib::shared_ptr<message> ptr;
typedef typename con_msg_manager::weak_ptr con_msg_man_ptr;
message(con_msg_man_ptr manager, size_t size = 128)
: m_manager(manager)
, m_payload(size) {}
frame::opcode::value get_opcode() const {
return m_opcode;
}
const std::string& get_header() const {
return m_header;
}
const std::string& get_extension_data() const {
return m_extension_data;
}
const std::string& get_payload() const {
return m_payload;
}
/// Recycle the message
/**
* A request to recycle this message was received. Forward that request to
* the connection message manager for processing. Errors and exceptions
* from the manager's recycle member function should be passed back up the
* call chain. The caller to message::recycle will deal with them.
*
* Recycle must *only* be called by the message shared_ptr's destructor.
* Once recycled successfully, ownership of the memory has been passed to
* another system and must not be accessed again.
*
* @return true if the message was successfully recycled, false otherwise.
*/
bool recycle() {
typename con_msg_manager::ptr shared = m_manager.lock();
if (shared) {
return shared->(recycle(this));
} else {
return false;
}
}
private:
con_msg_man_ptr m_manager;
frame::opcode::value m_opcode;
std::string m_header;
std::string m_extension_data;
std::string m_payload;
};
namespace alloc {
/// A connection message manager that allocates a new message for each
/// request.
template <typename message>
class con_msg_manager {
public:
typedef lib::shared_ptr<con_msg_manager> ptr;
typedef lib::weak_ptr<con_msg_manager> weak_ptr;
typedef typename message::ptr message_ptr;
/// Get a message buffer with specified size
/**
* @param size Minimum size in bytes to request for the message payload.
*
* @return A shared pointer to a new message with specified size.
*/
message_ptr get_message(size_t size) const {
return lib::make_shared<message>(size);
}
/// Recycle a message
/**
* This method shouldn't be called. If it is, return false to indicate an
* error. The rest of the method recycle chain should notice this and free
* the memory.
*
* @param msg The message to be recycled.
*
* @return true if the message was successfully recycled, false otherwse.
*/
bool recycle(message * msg) {
return false;
}
};
/// An endpoint message manager that allocates a new manager for each
/// connection.
template <typename con_msg_manager>
class endpoint_msg_manager {
public:
typedef typename con_msg_manager::ptr con_msg_man_ptr;
/// Get a pointer to a connection message manager
/**
* @return A pointer to the requested connection message manager.
*/
con_msg_man_ptr get_manager() const {
return lib::make_shared<con_msg_manager>();
}
};
} // namespace alloc
namespace pool {
/// A connection messages manager that maintains a pool of messages that is
/// used to fulfill get_message requests.
class con_msg_manager {
};
/// An endpoint manager that maintains a shared pool of connection managers
/// and returns an appropriate one for the requesting connection.
class endpoint_msg_manager {
};
} // namespace pool
} // namespace message_buffer
} // namespace websocketpp
#endif // WEBSOCKETPP_MESSAGE_BUFFER_ALLOC_HPP

View File

@ -0,0 +1,299 @@
/*
* Copyright (c) 2014, 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_PROCESSOR_BASE_HPP
#define WEBSOCKETPP_PROCESSOR_BASE_HPP
#include <websocketpp/close.hpp>
#include <websocketpp/utilities.hpp>
#include <websocketpp/uri.hpp>
#include <websocketpp/common/cpp11.hpp>
#include <websocketpp/common/system_error.hpp>
#include <string>
namespace websocketpp {
namespace processor {
/// Constants related to processing WebSocket connections
namespace constants {
static char const upgrade_token[] = "websocket";
static char const connection_token[] = "Upgrade";
static char const handshake_guid[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
} // namespace constants
/// Processor class related error codes
namespace error_cat {
enum value {
BAD_REQUEST = 0, // Error was the result of improperly formatted user input
INTERNAL_ERROR = 1, // Error was a logic error internal to WebSocket++
PROTOCOL_VIOLATION = 2,
MESSAGE_TOO_BIG = 3,
PAYLOAD_VIOLATION = 4 // Error was due to receiving invalid payload data
};
} // namespace error_cat
/// Error code category and codes used by all processor types
namespace error {
enum processor_errors {
/// Catch-all error for processor policy errors that don't fit in other
/// categories
general = 1,
/// Error was the result of improperly formatted user input
bad_request,
/// Processor encountered a protocol violation in an incoming message
protocol_violation,
/// Processor encountered a message that was too large
message_too_big,
/// Processor encountered invalid payload data.
invalid_payload,
/// The processor method was called with invalid arguments
invalid_arguments,
/// Opcode was invalid for requested operation
invalid_opcode,
/// Control frame too large
control_too_big,
/// Illegal use of reserved bit
invalid_rsv_bit,
/// Fragmented control message
fragmented_control,
/// Continuation without message
invalid_continuation,
/// Clients may not send unmasked frames
masking_required,
/// Servers may not send masked frames
masking_forbidden,
/// Payload length not minimally encoded
non_minimal_encoding,
/// Not supported on 32 bit systems
requires_64bit,
/// Invalid UTF-8 encoding
invalid_utf8,
/// Operation required not implemented functionality
not_implemented,
/// Invalid HTTP method
invalid_http_method,
/// Invalid HTTP version
invalid_http_version,
/// Invalid HTTP status
invalid_http_status,
/// Missing Required Header
missing_required_header,
/// Embedded SHA-1 library error
sha1_library,
/// No support for this feature in this protocol version.
no_protocol_support,
/// Reserved close code used
reserved_close_code,
/// Invalid close code used
invalid_close_code,
/// Using a reason requires a close code
reason_requires_code,
/// Error parsing subprotocols
subprotocol_parse_error,
/// Error parsing extensions
extension_parse_error,
/// Extension related operation was ignored because extensions are disabled
extensions_disabled,
/// Short Ke3 read. Hybi00 requires a third key to be read from the 8 bytes
/// after the handshake. Less than 8 bytes were read.
short_key3
};
/// Category for processor errors
class processor_category : public lib::error_category {
public:
processor_category() {}
char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ {
return "websocketpp.processor";
}
std::string message(int value) const {
switch(value) {
case error::general:
return "Generic processor error";
case error::bad_request:
return "invalid user input";
case error::protocol_violation:
return "Generic protocol violation";
case error::message_too_big:
return "A message was too large";
case error::invalid_payload:
return "A payload contained invalid data";
case error::invalid_arguments:
return "invalid function arguments";
case error::invalid_opcode:
return "invalid opcode";
case error::control_too_big:
return "Control messages are limited to fewer than 125 characters";
case error::invalid_rsv_bit:
return "Invalid use of reserved bits";
case error::fragmented_control:
return "Control messages cannot be fragmented";
case error::invalid_continuation:
return "Invalid message continuation";
case error::masking_required:
return "Clients may not send unmasked frames";
case error::masking_forbidden:
return "Servers may not send masked frames";
case error::non_minimal_encoding:
return "Payload length was not minimally encoded";
case error::requires_64bit:
return "64 bit frames are not supported on 32 bit systems";
case error::invalid_utf8:
return "Invalid UTF8 encoding";
case error::not_implemented:
return "Operation required not implemented functionality";
case error::invalid_http_method:
return "Invalid HTTP method.";
case error::invalid_http_version:
return "Invalid HTTP version.";
case error::invalid_http_status:
return "Invalid HTTP status.";
case error::missing_required_header:
return "A required HTTP header is missing";
case error::sha1_library:
return "SHA-1 library error";
case error::no_protocol_support:
return "The WebSocket protocol version in use does not support this feature";
case error::reserved_close_code:
return "Reserved close code used";
case error::invalid_close_code:
return "Invalid close code used";
case error::reason_requires_code:
return "Using a close reason requires a valid close code";
case error::subprotocol_parse_error:
return "Error parsing subprotocol header";
case error::extension_parse_error:
return "Error parsing extension header";
case error::extensions_disabled:
return "Extensions are disabled";
case error::short_key3:
return "Short Hybi00 Key 3 read";
default:
return "Unknown";
}
}
};
/// Get a reference to a static copy of the processor error category
inline lib::error_category const & get_processor_category() {
static processor_category instance;
return instance;
}
/// Create an error code with the given value and the processor category
inline lib::error_code make_error_code(error::processor_errors e) {
return lib::error_code(static_cast<int>(e), get_processor_category());
}
/// Converts a processor error_code into a websocket close code
/**
* Looks up the appropriate WebSocket close code that should be sent after an
* error of this sort occurred.
*
* If the error is not in the processor category close::status::blank is
* returned.
*
* If the error isn't normally associated with reasons to close a connection
* (such as errors intended to be used internally or delivered to client
* applications, ex: invalid arguments) then
* close::status::internal_endpoint_error is returned.
*/
inline close::status::value to_ws(lib::error_code ec) {
if (ec.category() != get_processor_category()) {
return close::status::blank;
}
switch (ec.value()) {
case error::protocol_violation:
case error::control_too_big:
case error::invalid_opcode:
case error::invalid_rsv_bit:
case error::fragmented_control:
case error::invalid_continuation:
case error::masking_required:
case error::masking_forbidden:
case error::reserved_close_code:
case error::invalid_close_code:
return close::status::protocol_error;
case error::invalid_payload:
case error::invalid_utf8:
return close::status::invalid_payload;
case error::message_too_big:
return close::status::message_too_big;
default:
return close::status::internal_endpoint_error;
}
}
} // namespace error
} // namespace processor
} // namespace websocketpp
_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_
template<> struct is_error_code_enum<websocketpp::processor::error::processor_errors>
{
static bool const value = true;
};
_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_
#endif //WEBSOCKETPP_PROCESSOR_BASE_HPP

View File

@ -0,0 +1,462 @@
/*
* Copyright (c) 2014, 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_PROCESSOR_HYBI00_HPP
#define WEBSOCKETPP_PROCESSOR_HYBI00_HPP
#include <websocketpp/frame.hpp>
#include <websocketpp/http/constants.hpp>
#include <websocketpp/utf8_validator.hpp>
#include <websocketpp/common/network.hpp>
#include <websocketpp/common/md5.hpp>
#include <websocketpp/common/platforms.hpp>
#include <websocketpp/processors/processor.hpp>
#include <algorithm>
#include <cstdlib>
#include <string>
#include <vector>
namespace websocketpp {
namespace processor {
/// Processor for Hybi Draft version 00
/**
* There are many differences between Hybi 00 and Hybi 13
*/
template <typename config>
class hybi00 : public processor<config> {
public:
typedef processor<config> base;
typedef typename config::request_type request_type;
typedef typename config::response_type response_type;
typedef typename config::message_type message_type;
typedef typename message_type::ptr message_ptr;
typedef typename config::con_msg_manager_type::ptr msg_manager_ptr;
explicit hybi00(bool secure, bool p_is_server, msg_manager_ptr manager)
: processor<config>(secure, p_is_server)
, msg_hdr(0x00)
, msg_ftr(0xff)
, m_state(HEADER)
, m_msg_manager(manager) {}
int get_version() const {
return 0;
}
lib::error_code validate_handshake(request_type const & r) const {
if (r.get_method() != "GET") {
return make_error_code(error::invalid_http_method);
}
if (r.get_version() != "HTTP/1.1") {
return make_error_code(error::invalid_http_version);
}
// required headers
// Host is required by HTTP/1.1
// Connection is required by is_websocket_handshake
// Upgrade is required by is_websocket_handshake
if (r.get_header("Sec-WebSocket-Key1").empty() ||
r.get_header("Sec-WebSocket-Key2").empty() ||
r.get_header("Sec-WebSocket-Key3").empty())
{
return make_error_code(error::missing_required_header);
}
return lib::error_code();
}
lib::error_code process_handshake(request_type const & req,
std::string const & subprotocol, response_type & res) const
{
char key_final[16];
// copy key1 into final key
decode_client_key(req.get_header("Sec-WebSocket-Key1"), &key_final[0]);
// copy key2 into final key
decode_client_key(req.get_header("Sec-WebSocket-Key2"), &key_final[4]);
// copy key3 into final key
// key3 should be exactly 8 bytes. If it is more it will be truncated
// if it is less the final key will almost certainly be wrong.
// TODO: decide if it is best to silently fail here or produce some sort
// of warning or exception.
std::string const & key3 = req.get_header("Sec-WebSocket-Key3");
std::copy(key3.c_str(),
key3.c_str()+(std::min)(static_cast<size_t>(8), key3.size()),
&key_final[8]);
res.append_header(
"Sec-WebSocket-Key3",
md5::md5_hash_string(std::string(key_final,16))
);
res.append_header("Upgrade","WebSocket");
res.append_header("Connection","Upgrade");
// Echo back client's origin unless our local application set a
// more restrictive one.
if (res.get_header("Sec-WebSocket-Origin").empty()) {
res.append_header("Sec-WebSocket-Origin",req.get_header("Origin"));
}
// Echo back the client's request host unless our local application
// set a different one.
if (res.get_header("Sec-WebSocket-Location").empty()) {
uri_ptr uri = get_uri(req);
res.append_header("Sec-WebSocket-Location",uri->str());
}
if (!subprotocol.empty()) {
res.replace_header("Sec-WebSocket-Protocol",subprotocol);
}
return lib::error_code();
}
/// Fill in a set of request headers for a client connection request
/**
* The Hybi 00 processor only implements incoming connections so this will
* always return an error.
*
* @param [out] req Set of headers to fill in
* @param [in] uri The uri being connected to
* @param [in] subprotocols The list of subprotocols to request
*/
lib::error_code client_handshake_request(request_type &, uri_ptr,
std::vector<std::string> const &) const
{
return error::make_error_code(error::no_protocol_support);
}
/// Validate the server's response to an outgoing handshake request
/**
* The Hybi 00 processor only implements incoming connections so this will
* always return an error.
*
* @param req The original request sent
* @param res The reponse to generate
* @return An error code, 0 on success, non-zero for other errors
*/
lib::error_code validate_server_handshake_response(request_type const &,
response_type &) const
{
return error::make_error_code(error::no_protocol_support);
}
std::string get_raw(response_type const & res) const {
response_type temp = res;
temp.remove_header("Sec-WebSocket-Key3");
return temp.raw() + res.get_header("Sec-WebSocket-Key3");
}
std::string const & get_origin(request_type const & r) const {
return r.get_header("Origin");
}
/// Extracts requested subprotocols from a handshake request
/**
* hybi00 does support subprotocols
* https://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-00#section-1.9
*
* @param [in] req The request to extract from
* @param [out] subprotocol_list A reference to a vector of strings to store
* the results in.
*/
lib::error_code extract_subprotocols(request_type const & req,
std::vector<std::string> & subprotocol_list)
{
if (!req.get_header("Sec-WebSocket-Protocol").empty()) {
http::parameter_list p;
if (!req.get_header_as_plist("Sec-WebSocket-Protocol",p)) {
http::parameter_list::const_iterator it;
for (it = p.begin(); it != p.end(); ++it) {
subprotocol_list.push_back(it->first);
}
} else {
return error::make_error_code(error::subprotocol_parse_error);
}
}
return lib::error_code();
}
uri_ptr get_uri(request_type const & request) const {
std::string h = request.get_header("Host");
size_t last_colon = h.rfind(":");
size_t last_sbrace = h.rfind("]");
// no : = hostname with no port
// last : before ] = ipv6 literal with no port
// : with no ] = hostname with port
// : after ] = ipv6 literal with port
if (last_colon == std::string::npos ||
(last_sbrace != std::string::npos && last_sbrace > last_colon))
{
return lib::make_shared<uri>(base::m_secure, h, request.get_uri());
} else {
return lib::make_shared<uri>(base::m_secure,
h.substr(0,last_colon),
h.substr(last_colon+1),
request.get_uri());
}
// TODO: check if get_uri is a full uri
}
/// Get hybi00 handshake key3
/**
* @todo This doesn't appear to be used anymore. It might be able to be
* removed
*/
std::string get_key3() const {
return "";
}
/// Process new websocket connection bytes
size_t consume(uint8_t * buf, size_t len, lib::error_code & ec) {
// if in state header we are expecting a 0x00 byte, if we don't get one
// it is a fatal error
size_t p = 0; // bytes processed
size_t l = 0;
ec = lib::error_code();
while (p < len) {
if (m_state == HEADER) {
if (buf[p] == msg_hdr) {
p++;
m_msg_ptr = m_msg_manager->get_message(frame::opcode::text,1);
if (!m_msg_ptr) {
ec = make_error_code(websocketpp::error::no_incoming_buffers);
m_state = FATAL_ERROR;
} else {
m_state = PAYLOAD;
}
} else {
ec = make_error_code(error::protocol_violation);
m_state = FATAL_ERROR;
}
} else if (m_state == PAYLOAD) {
uint8_t *it = std::find(buf+p,buf+len,msg_ftr);
// 0 1 2 3 4 5
// 0x00 0x23 0x23 0x23 0xff 0xXX
// Copy payload bytes into message
l = static_cast<size_t>(it-(buf+p));
m_msg_ptr->append_payload(buf+p,l);
p += l;
if (it != buf+len) {
// message is done, copy it and the trailing
p++;
// TODO: validation
m_state = READY;
}
} else {
// TODO
break;
}
}
// If we get one, we create a new message and move to application state
// if in state application we are copying bytes into the output message
// and validating them for UTF8 until we hit a 0xff byte. Once we hit
// 0x00, the message is complete and is dispatched. Then we go back to
// header state.
//ec = make_error_code(error::not_implemented);
return p;
}
bool ready() const {
return (m_state == READY);
}
bool get_error() const {
return false;
}
message_ptr get_message() {
message_ptr ret = m_msg_ptr;
m_msg_ptr = message_ptr();
m_state = HEADER;
return ret;
}
/// Prepare a message for writing
/**
* Performs validation, masking, compression, etc. will return an error if
* there was an error, otherwise msg will be ready to be written
*/
virtual lib::error_code prepare_data_frame(message_ptr in, message_ptr out)
{
if (!in || !out) {
return make_error_code(error::invalid_arguments);
}
// TODO: check if the message is prepared already
// validate opcode
if (in->get_opcode() != frame::opcode::text) {
return make_error_code(error::invalid_opcode);
}
std::string& i = in->get_raw_payload();
//std::string& o = out->get_raw_payload();
// validate payload utf8
if (!utf8_validator::validate(i)) {
return make_error_code(error::invalid_payload);
}
// generate header
out->set_header(std::string(reinterpret_cast<char const *>(&msg_hdr),1));
// process payload
out->set_payload(i);
out->append_payload(std::string(reinterpret_cast<char const *>(&msg_ftr),1));
// hybi00 doesn't support compression
// hybi00 doesn't have masking
out->set_prepared(true);
return lib::error_code();
}
/// Prepare a ping frame
/**
* Hybi 00 doesn't support pings so this will always return an error
*
* @param in The string to use for the ping payload
* @param out The message buffer to prepare the ping in.
* @return Status code, zero on success, non-zero on failure
*/
lib::error_code prepare_ping(std::string const &, message_ptr) const
{
return lib::error_code(error::no_protocol_support);
}
/// Prepare a pong frame
/**
* Hybi 00 doesn't support pongs so this will always return an error
*
* @param in The string to use for the pong payload
* @param out The message buffer to prepare the pong in.
* @return Status code, zero on success, non-zero on failure
*/
lib::error_code prepare_pong(std::string const &, message_ptr) const
{
return lib::error_code(error::no_protocol_support);
}
/// Prepare a close frame
/**
* Hybi 00 doesn't support the close code or reason so these parameters are
* ignored.
*
* @param code The close code to send
* @param reason The reason string to send
* @param out The message buffer to prepare the fame in
* @return Status code, zero on success, non-zero on failure
*/
lib::error_code prepare_close(close::status::value, std::string const &,
message_ptr out) const
{
if (!out) {
return lib::error_code(error::invalid_arguments);
}
std::string val;
val.append(1,'\xff');
val.append(1,'\x00');
out->set_payload(val);
out->set_prepared(true);
return lib::error_code();
}
private:
void decode_client_key(std::string const & key, char * result) const {
unsigned int spaces = 0;
std::string digits;
uint32_t num;
// key2
for (size_t i = 0; i < key.size(); i++) {
if (key[i] == ' ') {
spaces++;
} else if (key[i] >= '0' && key[i] <= '9') {
digits += key[i];
}
}
num = static_cast<uint32_t>(strtoul(digits.c_str(), NULL, 10));
if (spaces > 0 && num > 0) {
num = htonl(num/spaces);
std::copy(reinterpret_cast<char*>(&num),
reinterpret_cast<char*>(&num)+4,
result);
} else {
std::fill(result,result+4,0);
}
}
enum state {
HEADER = 0,
PAYLOAD = 1,
READY = 2,
FATAL_ERROR = 3
};
uint8_t const msg_hdr;
uint8_t const msg_ftr;
state m_state;
msg_manager_ptr m_msg_manager;
message_ptr m_msg_ptr;
utf8_validator::validator m_validator;
};
} // namespace processor
} // namespace websocketpp
#endif //WEBSOCKETPP_PROCESSOR_HYBI00_HPP

View File

@ -0,0 +1,78 @@
/*
* Copyright (c) 2014, 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_PROCESSOR_HYBI07_HPP
#define WEBSOCKETPP_PROCESSOR_HYBI07_HPP
#include <websocketpp/processors/hybi08.hpp>
#include <string>
#include <vector>
namespace websocketpp {
namespace processor {
/// Processor for Hybi Draft version 07
/**
* The primary difference between 07 and 08 is a version number.
*/
template <typename config>
class hybi07 : public hybi08<config> {
public:
typedef typename config::request_type request_type;
typedef typename config::con_msg_manager_type::ptr msg_manager_ptr;
typedef typename config::rng_type rng_type;
explicit hybi07(bool secure, bool p_is_server, msg_manager_ptr manager, rng_type& rng)
: hybi08<config>(secure, p_is_server, manager, rng) {}
/// Fill in a set of request headers for a client connection request
/**
* The Hybi 07 processor only implements incoming connections so this will
* always return an error.
*
* @param [out] req Set of headers to fill in
* @param [in] uri The uri being connected to
* @param [in] subprotocols The list of subprotocols to request
*/
lib::error_code client_handshake_request(request_type &, uri_ptr,
std::vector<std::string> const &) const
{
return error::make_error_code(error::no_protocol_support);
}
int get_version() const {
return 7;
}
private:
};
} // namespace processor
} // namespace websocketpp
#endif //WEBSOCKETPP_PROCESSOR_HYBI07_HPP

View File

@ -0,0 +1,83 @@
/*
* Copyright (c) 2014, 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_PROCESSOR_HYBI08_HPP
#define WEBSOCKETPP_PROCESSOR_HYBI08_HPP
#include <websocketpp/processors/hybi13.hpp>
#include <string>
#include <vector>
namespace websocketpp {
namespace processor {
/// Processor for Hybi Draft version 08
/**
* The primary difference between 08 and 13 is a different origin header name
*/
template <typename config>
class hybi08 : public hybi13<config> {
public:
typedef hybi08<config> type;
typedef typename config::request_type request_type;
typedef typename config::con_msg_manager_type::ptr msg_manager_ptr;
typedef typename config::rng_type rng_type;
explicit hybi08(bool secure, bool p_is_server, msg_manager_ptr manager, rng_type& rng)
: hybi13<config>(secure, p_is_server, manager, rng) {}
/// Fill in a set of request headers for a client connection request
/**
* The Hybi 08 processor only implements incoming connections so this will
* always return an error.
*
* @param [out] req Set of headers to fill in
* @param [in] uri The uri being connected to
* @param [in] subprotocols The list of subprotocols to request
*/
lib::error_code client_handshake_request(request_type &, uri_ptr,
std::vector<std::string> const &) const
{
return error::make_error_code(error::no_protocol_support);
}
int get_version() const {
return 8;
}
std::string const & get_origin(request_type const & r) const {
return r.get_header("Sec-WebSocket-Origin");
}
private:
};
} // namespace processor
} // namespace websocketpp
#endif //WEBSOCKETPP_PROCESSOR_HYBI08_HPP

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,407 @@
/*
* Copyright (c) 2015, Peter Thorson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef WEBSOCKETPP_PROCESSOR_HPP
#define WEBSOCKETPP_PROCESSOR_HPP
#include <websocketpp/processors/base.hpp>
#include <websocketpp/common/system_error.hpp>
#include <websocketpp/close.hpp>
#include <websocketpp/utilities.hpp>
#include <websocketpp/uri.hpp>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
namespace websocketpp {
/// Processors encapsulate the protocol rules specific to each WebSocket version
/**
* The processors namespace includes a number of free functions that operate on
* various WebSocket related data structures and perform processing that is not
* related to specific versions of the protocol.
*
* It also includes the abstract interface for the protocol specific processing
* engines. These engines wrap all of the logic necessary for parsing and
* validating WebSocket handshakes and messages of specific protocol version
* and set of allowed extensions.
*
* An instance of a processor represents the state of a single WebSocket
* connection of the associated version. One processor instance is needed per
* logical WebSocket connection.
*/
namespace processor {
/// Determine whether or not a generic HTTP request is a WebSocket handshake
/**
* @param r The HTTP request to read.
*
* @return True if the request is a WebSocket handshake, false otherwise
*/
template <typename request_type>
bool is_websocket_handshake(request_type& r) {
using utility::ci_find_substr;
std::string const & upgrade_header = r.get_header("Upgrade");
if (ci_find_substr(upgrade_header, constants::upgrade_token,
sizeof(constants::upgrade_token)-1) == upgrade_header.end())
{
return false;
}
std::string const & con_header = r.get_header("Connection");
if (ci_find_substr(con_header, constants::connection_token,
sizeof(constants::connection_token)-1) == con_header.end())
{
return false;
}
return true;
}
/// Extract the version from a WebSocket handshake request
/**
* A blank version header indicates a spec before versions were introduced.
* The only such versions in shipping products are Hixie Draft 75 and Hixie
* Draft 76. Draft 75 is present in Chrome 4-5 and Safari 5.0.0, Draft 76 (also
* known as hybi 00 is present in Chrome 6-13 and Safari 5.0.1+. As
* differentiating between these two sets of browsers is very difficult and
* Safari 5.0.1+ accounts for the vast majority of cases in the wild this
* function assumes that all handshakes without a valid version header are
* Hybi 00.
*
* @param r The WebSocket handshake request to read.
*
* @return The WebSocket handshake version or -1 if there was an extraction
* error.
*/
template <typename request_type>
int get_websocket_version(request_type& r) {
if (!r.ready()) {
return -2;
}
if (r.get_header("Sec-WebSocket-Version").empty()) {
return 0;
}
int version;
std::istringstream ss(r.get_header("Sec-WebSocket-Version"));
if ((ss >> version).fail()) {
return -1;
}
return version;
}
/// Extract a URI ptr from the host header of the request
/**
* @param request The request to extract the Host header from.
*
* @param scheme The scheme under which this request was received (ws, wss,
* http, https, etc)
*
* @return A uri_pointer that encodes the value of the host header.
*/
template <typename request_type>
uri_ptr get_uri_from_host(request_type & request, std::string scheme) {
std::string h = request.get_header("Host");
size_t last_colon = h.rfind(":");
size_t last_sbrace = h.rfind("]");
// no : = hostname with no port
// last : before ] = ipv6 literal with no port
// : with no ] = hostname with port
// : after ] = ipv6 literal with port
if (last_colon == std::string::npos ||
(last_sbrace != std::string::npos && last_sbrace > last_colon))
{
return lib::make_shared<uri>(scheme, h, request.get_uri());
} else {
return lib::make_shared<uri>(scheme,
h.substr(0,last_colon),
h.substr(last_colon+1),
request.get_uri());
}
}
/// WebSocket protocol processor abstract base class
template <typename config>
class processor {
public:
typedef processor<config> type;
typedef typename config::request_type request_type;
typedef typename config::response_type response_type;
typedef typename config::message_type::ptr message_ptr;
typedef std::pair<lib::error_code,std::string> err_str_pair;
explicit processor(bool secure, bool p_is_server)
: m_secure(secure)
, m_server(p_is_server)
, m_max_message_size(config::max_message_size)
{}
virtual ~processor() {}
/// Get the protocol version of this processor
virtual int get_version() const = 0;
/// Get maximum message size
/**
* Get maximum message size. Maximum message size determines the point at which the
* processor will fail a connection with the message_too_big protocol error.
*
* The default is retrieved from the max_message_size value from the template config
*
* @since 0.3.0
*/
size_t get_max_message_size() const {
return m_max_message_size;
}
/// Set maximum message size
/**
* Set maximum message size. Maximum message size determines the point at which the
* processor will fail a connection with the message_too_big protocol error.
*
* The default is retrieved from the max_message_size value from the template config
*
* @since 0.3.0
*
* @param new_value The value to set as the maximum message size.
*/
void set_max_message_size(size_t new_value) {
m_max_message_size = new_value;
}
/// Returns whether or not the permessage_compress extension is implemented
/**
* Compile time flag that indicates whether this processor has implemented
* the permessage_compress extension. By default this is false.
*/
virtual bool has_permessage_compress() const {
return false;
}
/// Initializes extensions based on the Sec-WebSocket-Extensions header
/**
* Reads the Sec-WebSocket-Extensions header and determines if any of the
* requested extensions are supported by this processor. If they are their
* settings data is initialized and an extension string to send to the
* is returned.
*
* @param request The request or response headers to look at.
*/
virtual err_str_pair negotiate_extensions(request_type const &) {
return err_str_pair();
}
/// Initializes extensions based on the Sec-WebSocket-Extensions header
/**
* Reads the Sec-WebSocket-Extensions header and determines if any of the
* requested extensions were accepted by the server. If they are their
* settings data is initialized. If they are not a list of required
* extensions (if any) is returned. This list may be sent back to the server
* as a part of the 1010/Extension required close code.
*
* @param response The request or response headers to look at.
*/
virtual err_str_pair negotiate_extensions(response_type const &) {
return err_str_pair();
}
/// validate a WebSocket handshake request for this version
/**
* @param request The WebSocket handshake request to validate.
* is_websocket_handshake(request) must be true and
* get_websocket_version(request) must equal this->get_version().
*
* @return A status code, 0 on success, non-zero for specific sorts of
* failure
*/
virtual lib::error_code validate_handshake(request_type const & request) const = 0;
/// Calculate the appropriate response for this websocket request
/**
* @param req The request to process
*
* @param subprotocol The subprotocol in use
*
* @param res The response to store the processed response in
*
* @return An error code, 0 on success, non-zero for other errors
*/
virtual lib::error_code process_handshake(request_type const & req,
std::string const & subprotocol, response_type& res) const = 0;
/// Fill in an HTTP request for an outgoing connection handshake
/**
* @param req The request to process.
*
* @return An error code, 0 on success, non-zero for other errors
*/
virtual lib::error_code client_handshake_request(request_type & req,
uri_ptr uri, std::vector<std::string> const & subprotocols) const = 0;
/// Validate the server's response to an outgoing handshake request
/**
* @param req The original request sent
* @param res The reponse to generate
* @return An error code, 0 on success, non-zero for other errors
*/
virtual lib::error_code validate_server_handshake_response(request_type
const & req, response_type & res) const = 0;
/// Given a completed response, get the raw bytes to put on the wire
virtual std::string get_raw(response_type const & request) const = 0;
/// Return the value of the header containing the CORS origin.
virtual std::string const & get_origin(request_type const & request) const = 0;
/// Extracts requested subprotocols from a handshake request
/**
* Extracts a list of all subprotocols that the client has requested in the
* given opening handshake request.
*
* @param [in] req The request to extract from
* @param [out] subprotocol_list A reference to a vector of strings to store
* the results in.
*/
virtual lib::error_code extract_subprotocols(const request_type & req,
std::vector<std::string> & subprotocol_list) = 0;
/// Extracts client uri from a handshake request
virtual uri_ptr get_uri(request_type const & request) const = 0;
/// process new websocket connection bytes
/**
* WebSocket connections are a continous stream of bytes that must be
* interpreted by a protocol processor into discrete frames.
*
* @param buf Buffer from which bytes should be read.
* @param len Length of buffer
* @param ec Reference to an error code to return any errors in
* @return Number of bytes processed
*/
virtual size_t consume(uint8_t *buf, size_t len, lib::error_code & ec) = 0;
/// Checks if there is a message ready
/**
* Checks if the most recent consume operation processed enough bytes to
* complete a new WebSocket message. The message can be retrieved by calling
* get_message() which will reset the internal state to not-ready and allow
* consume to read more bytes.
*
* @return Whether or not a message is ready.
*/
virtual bool ready() const = 0;
/// Retrieves the most recently processed message
/**
* Retrieves a shared pointer to the recently completed message if there is
* one. If ready() returns true then there is a message available.
* Retrieving the message with get_message will reset the state of ready.
* As such, each new message may be retrieved only once. Calling get_message
* when there is no message available will result in a null pointer being
* returned.
*
* @return A pointer to the most recently processed message or a null shared
* pointer.
*/
virtual message_ptr get_message() = 0;
/// Tests whether the processor is in a fatal error state
virtual bool get_error() const = 0;
/// Retrieves the number of bytes presently needed by the processor
/// This value may be used as a hint to the transport layer as to how many
/// bytes to wait for before running consume again.
virtual size_t get_bytes_needed() const {
return 1;
}
/// Prepare a data message for writing
/**
* Performs validation, masking, compression, etc. will return an error if
* there was an error, otherwise msg will be ready to be written
*/
virtual lib::error_code prepare_data_frame(message_ptr in, message_ptr out) = 0;
/// Prepare a ping frame
/**
* Ping preparation is entirely state free. There is no payload validation
* other than length. Payload need not be UTF-8.
*
* @param in The string to use for the ping payload
* @param out The message buffer to prepare the ping in.
* @return Status code, zero on success, non-zero on failure
*/
virtual lib::error_code prepare_ping(std::string const & in, message_ptr out) const
= 0;
/// Prepare a pong frame
/**
* Pong preparation is entirely state free. There is no payload validation
* other than length. Payload need not be UTF-8.
*
* @param in The string to use for the pong payload
* @param out The message buffer to prepare the pong in.
* @return Status code, zero on success, non-zero on failure
*/
virtual lib::error_code prepare_pong(std::string const & in, message_ptr out) const
= 0;
/// Prepare a close frame
/**
* Close preparation is entirely state free. The code and reason are both
* subject to validation. Reason must be valid UTF-8. Code must be a valid
* un-reserved WebSocket close code. Use close::status::no_status to
* indicate no code. If no code is supplied a reason may not be specified.
*
* @param code The close code to send
* @param reason The reason string to send
* @param out The message buffer to prepare the fame in
* @return Status code, zero on success, non-zero on failure
*/
virtual lib::error_code prepare_close(close::status::value code,
std::string const & reason, message_ptr out) const = 0;
protected:
bool const m_secure;
bool const m_server;
size_t m_max_message_size;
};
} // namespace processor
} // namespace websocketpp
#endif //WEBSOCKETPP_PROCESSOR_HPP

View File

@ -0,0 +1,60 @@
/*
* Copyright (c) 2014, 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_RANDOM_NONE_HPP
#define WEBSOCKETPP_RANDOM_NONE_HPP
namespace websocketpp {
/// Random number generation policies
namespace random {
/// Stub RNG policy that always returns 0
namespace none {
/// Thread safe stub "random" integer generator.
/**
* This template class provides a random integer stub. The interface mimics the
* WebSocket++ RNG generator classes but the generater function always returns
* zero. This can be used to stub out the RNG for unit and performance testing.
*
* Call operator() to generate the next number
*/
template <typename int_type>
class int_generator {
public:
int_generator() {}
/// advances the engine's state and returns the generated value
int_type operator()() {
return 0;
}
};
} // namespace none
} // namespace random
} // namespace websocketpp
#endif //WEBSOCKETPP_RANDOM_NONE_HPP

View File

@ -0,0 +1,80 @@
/*
* Copyright (c) 2014, 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_RANDOM_RANDOM_DEVICE_HPP
#define WEBSOCKETPP_RANDOM_RANDOM_DEVICE_HPP
#include <websocketpp/common/random.hpp>
namespace websocketpp {
namespace random {
/// RNG policy based on std::random_device or boost::random_device
namespace random_device {
/// Thread safe non-deterministic random integer generator.
/**
* This template class provides thread safe non-deterministic random integer
* generation. Numbers are produced in a uniformly distributed range from the
* smallest to largest value that int_type can store.
*
* Thread-safety is provided via locking based on the concurrency template
* parameter.
*
* Non-deterministic RNG is provided via websocketpp::lib which uses either
* C++11 or Boost 1.47+'s random_device class.
*
* Call operator() to generate the next number
*/
template <typename int_type, typename concurrency>
class int_generator {
public:
typedef typename concurrency::scoped_lock_type scoped_lock_type;
typedef typename concurrency::mutex_type mutex_type;
/// constructor
//mac TODO: figure out if signed types present a range problem
int_generator() {}
/// advances the engine's state and returns the generated value
int_type operator()() {
scoped_lock_type guard(m_lock);
return m_dis(m_rng);
}
private:
lib::random_device m_rng;
lib::uniform_int_distribution<int_type> m_dis;
mutex_type m_lock;
};
} // namespace random_device
} // namespace random
} // namespace websocketpp
#endif //WEBSOCKETPP_RANDOM_RANDOM_DEVICE_HPP

View File

@ -0,0 +1,173 @@
/*
* Copyright (c) 2014, 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_CLIENT_ENDPOINT_HPP
#define WEBSOCKETPP_CLIENT_ENDPOINT_HPP
#include <websocketpp/endpoint.hpp>
#include <websocketpp/uri.hpp>
#include <websocketpp/logger/levels.hpp>
#include <websocketpp/common/system_error.hpp>
#include <string>
namespace websocketpp {
/// Client endpoint role based on the given config
/**
*
*/
template <typename config>
class client : public endpoint<connection<config>,config> {
public:
/// Type of this endpoint
typedef client<config> type;
/// Type of the endpoint concurrency component
typedef typename config::concurrency_type concurrency_type;
/// Type of the endpoint transport component
typedef typename config::transport_type transport_type;
/// Type of the connections this server will create
typedef connection<config> connection_type;
/// Type of a shared pointer to the connections this server will create
typedef typename connection_type::ptr connection_ptr;
/// Type of the connection transport component
typedef typename transport_type::transport_con_type transport_con_type;
/// Type of a shared pointer to the connection transport component
typedef typename transport_con_type::ptr transport_con_ptr;
/// Type of the endpoint component of this server
typedef endpoint<connection_type,config> endpoint_type;
friend class connection<config>;
explicit client() : endpoint_type(false)
{
endpoint_type::m_alog->write(log::alevel::devel, "client constructor");
}
/// Get a new connection
/**
* Creates and returns a pointer to a new connection to the given URI
* suitable for passing to connect(connection_ptr). This method allows
* applying connection specific settings before performing the opening
* handshake.
*
* @param [in] location URI to open the connection to as a uri_ptr
* @param [out] ec An status code indicating failure reasons, if any
*
* @return A connection_ptr to the new connection
*/
connection_ptr get_connection(uri_ptr location, lib::error_code & ec) {
if (location->get_secure() && !transport_type::is_secure()) {
ec = error::make_error_code(error::endpoint_not_secure);
return connection_ptr();
}
connection_ptr con = endpoint_type::create_connection();
if (!con) {
ec = error::make_error_code(error::con_creation_failed);
return con;
}
con->set_uri(location);
ec = lib::error_code();
return con;
}
/// Get a new connection (string version)
/**
* Creates and returns a pointer to a new connection to the given URI
* suitable for passing to connect(connection_ptr). This overload allows
* default construction of the uri_ptr from a standard string.
*
* @param [in] u URI to open the connection to as a string
* @param [out] ec An status code indicating failure reasons, if any
*
* @return A connection_ptr to the new connection
*/
connection_ptr get_connection(std::string const & u, lib::error_code & ec) {
uri_ptr location = lib::make_shared<uri>(u);
if (!location->get_valid()) {
ec = error::make_error_code(error::invalid_uri);
return connection_ptr();
}
return get_connection(location, ec);
}
/// Begin the connection process for the given connection
/**
* Initiates the opening connection handshake for connection con. Exact
* behavior depends on the underlying transport policy.
*
* @param con The connection to connect
*
* @return The pointer to the connection originally passed in.
*/
connection_ptr connect(connection_ptr con) {
// Ask transport to perform a connection
transport_type::async_connect(
lib::static_pointer_cast<transport_con_type>(con),
con->get_uri(),
lib::bind(
&type::handle_connect,
this,
con,
lib::placeholders::_1
)
);
return con;
}
private:
// handle_connect
void handle_connect(connection_ptr con, lib::error_code const & ec) {
if (ec) {
con->terminate(ec);
endpoint_type::m_elog->write(log::elevel::rerror,
"handle_connect error: "+ec.message());
} else {
endpoint_type::m_alog->write(log::alevel::connect,
"Successful connection");
con->start();
}
}
};
} // namespace websocketpp
#endif //WEBSOCKETPP_CLIENT_ENDPOINT_HPP

View File

@ -0,0 +1,195 @@
/*
* Copyright (c) 2014, 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_SERVER_ENDPOINT_HPP
#define WEBSOCKETPP_SERVER_ENDPOINT_HPP
#include <websocketpp/endpoint.hpp>
#include <websocketpp/logger/levels.hpp>
#include <websocketpp/common/system_error.hpp>
namespace websocketpp {
/// Server endpoint role based on the given config
/**
*
*/
template <typename config>
class server : public endpoint<connection<config>,config> {
public:
/// Type of this endpoint
typedef server<config> type;
/// Type of the endpoint concurrency component
typedef typename config::concurrency_type concurrency_type;
/// Type of the endpoint transport component
typedef typename config::transport_type transport_type;
/// Type of the connections this server will create
typedef connection<config> connection_type;
/// Type of a shared pointer to the connections this server will create
typedef typename connection_type::ptr connection_ptr;
/// Type of the connection transport component
typedef typename transport_type::transport_con_type transport_con_type;
/// Type of a shared pointer to the connection transport component
typedef typename transport_con_type::ptr transport_con_ptr;
/// Type of the endpoint component of this server
typedef endpoint<connection_type,config> endpoint_type;
friend class connection<config>;
explicit server() : endpoint_type(true)
{
endpoint_type::m_alog->write(log::alevel::devel, "server constructor");
}
/// Destructor
~server<config>() {}
#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
// no copy constructor because endpoints are not copyable
server<config>(server<config> &) = delete;
// no copy assignment operator because endpoints are not copyable
server<config> & operator=(server<config> const &) = delete;
#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
#ifdef _WEBSOCKETPP_MOVE_SEMANTICS_
/// Move constructor
server<config>(server<config> && o) : endpoint<connection<config>,config>(std::move(o)) {}
#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
// no move assignment operator because of const member variables
server<config> & operator=(server<config> &&) = delete;
#endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
#endif // _WEBSOCKETPP_MOVE_SEMANTICS_
/// Create and initialize a new connection
/**
* The connection will be initialized and ready to begin. Call its start()
* method to begin the processing loop.
*
* Note: The connection must either be started or terminated using
* connection::terminate in order to avoid memory leaks.
*
* @return A pointer to the new connection.
*/
connection_ptr get_connection() {
return endpoint_type::create_connection();
}
/// Starts the server's async connection acceptance loop (exception free)
/**
* Initiates the server connection acceptance loop. Must be called after
* listen. This method will have no effect until the underlying io_service
* starts running. It may be called after the io_service is already running.
*
* Refer to documentation for the transport policy you are using for
* instructions on how to stop this acceptance loop.
*
* @param [out] ec A status code indicating an error, if any.
*/
void start_accept(lib::error_code & ec) {
if (!transport_type::is_listening()) {
ec = error::make_error_code(error::async_accept_not_listening);
return;
}
ec = lib::error_code();
connection_ptr con = get_connection();
if (!con) {
ec = error::make_error_code(error::con_creation_failed);
return;
}
transport_type::async_accept(
lib::static_pointer_cast<transport_con_type>(con),
lib::bind(&type::handle_accept,this,con,lib::placeholders::_1),
ec
);
if (ec && con) {
// If the connection was constructed but the accept failed,
// terminate the connection to prevent memory leaks
con->terminate(lib::error_code());
}
}
/// Starts the server's async connection acceptance loop
/**
* Initiates the server connection acceptance loop. Must be called after
* listen. This method will have no effect until the underlying io_service
* starts running. It may be called after the io_service is already running.
*
* Refer to documentation for the transport policy you are using for
* instructions on how to stop this acceptance loop.
*/
void start_accept() {
lib::error_code ec;
start_accept(ec);
if (ec) {
throw exception(ec);
}
}
/// Handler callback for start_accept
void handle_accept(connection_ptr con, lib::error_code const & ec) {
if (ec) {
con->terminate(ec);
if (ec == error::operation_canceled) {
endpoint_type::m_elog->write(log::elevel::info,
"handle_accept error: "+ec.message());
} else {
endpoint_type::m_elog->write(log::elevel::rerror,
"handle_accept error: "+ec.message());
}
} else {
con->start();
}
lib::error_code start_ec;
start_accept(start_ec);
if (start_ec == error::async_accept_not_listening) {
endpoint_type::m_elog->write(log::elevel::info,
"Stopping acceptance of new connections because the underlying transport is no longer listening.");
} else if (start_ec) {
endpoint_type::m_elog->write(log::elevel::rerror,
"Restarting async_accept loop failed: "+ec.message());
}
}
};
} // namespace websocketpp
#endif //WEBSOCKETPP_SERVER_ENDPOINT_HPP

View File

@ -0,0 +1,33 @@
/*
* Copyright (c) 2014, 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_SERVER_HPP
#define WEBSOCKETPP_SERVER_HPP
#include <websocketpp/roles/server_endpoint.hpp>
#endif //WEBSOCKETPP_SERVER_HPP

View File

@ -0,0 +1,189 @@
/*
*****
sha1.hpp is a repackaging of the sha1.cpp and sha1.h files from the smallsha1
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.
*/
#ifndef SHA1_DEFINED
#define SHA1_DEFINED
namespace websocketpp {
namespace sha1 {
namespace { // local
// Rotate an integer value to left.
inline unsigned int rol(unsigned int value, unsigned int steps) {
return ((value << steps) | (value >> (32 - steps)));
}
// Sets the first 16 integers in the buffert to zero.
// Used for clearing the W buffert.
inline void clearWBuffert(unsigned int * buffert)
{
for (int pos = 16; --pos >= 0;)
{
buffert[pos] = 0;
}
}
inline void innerHash(unsigned int * result, unsigned int * w)
{
unsigned int a = result[0];
unsigned int b = result[1];
unsigned int c = result[2];
unsigned int d = result[3];
unsigned int e = result[4];
int round = 0;
#define sha1macro(func,val) \
{ \
const unsigned int t = rol(a, 5) + (func) + e + val + w[round]; \
e = d; \
d = c; \
c = rol(b, 30); \
b = a; \
a = t; \
}
while (round < 16)
{
sha1macro((b & c) | (~b & d), 0x5a827999)
++round;
}
while (round < 20)
{
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
sha1macro((b & c) | (~b & d), 0x5a827999)
++round;
}
while (round < 40)
{
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
sha1macro(b ^ c ^ d, 0x6ed9eba1)
++round;
}
while (round < 60)
{
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
sha1macro((b & c) | (b & d) | (c & d), 0x8f1bbcdc)
++round;
}
while (round < 80)
{
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
sha1macro(b ^ c ^ d, 0xca62c1d6)
++round;
}
#undef sha1macro
result[0] += a;
result[1] += b;
result[2] += c;
result[3] += d;
result[4] += e;
}
} // namespace
/// Calculate a SHA1 hash
/**
* @param src points to any kind of data to be hashed.
* @param bytelength the number of bytes to hash from the src pointer.
* @param hash should point to a buffer of at least 20 bytes of size for storing
* the sha1 result in.
*/
inline void calc(void const * src, size_t bytelength, unsigned char * hash) {
// Init the result array.
unsigned int result[5] = { 0x67452301, 0xefcdab89, 0x98badcfe,
0x10325476, 0xc3d2e1f0 };
// Cast the void src pointer to be the byte array we can work with.
unsigned char const * sarray = (unsigned char const *) src;
// The reusable round buffer
unsigned int w[80];
// Loop through all complete 64byte blocks.
size_t endCurrentBlock;
size_t currentBlock = 0;
if (bytelength >= 64) {
size_t const endOfFullBlocks = bytelength - 64;
while (currentBlock <= endOfFullBlocks) {
endCurrentBlock = currentBlock + 64;
// Init the round buffer with the 64 byte block data.
for (int roundPos = 0; currentBlock < endCurrentBlock; currentBlock += 4)
{
// This line will swap endian on big endian and keep endian on
// little endian.
w[roundPos++] = (unsigned int) sarray[currentBlock + 3]
| (((unsigned int) sarray[currentBlock + 2]) << 8)
| (((unsigned int) sarray[currentBlock + 1]) << 16)
| (((unsigned int) sarray[currentBlock]) << 24);
}
innerHash(result, w);
}
}
// Handle the last and not full 64 byte block if existing.
endCurrentBlock = bytelength - currentBlock;
clearWBuffert(w);
size_t lastBlockBytes = 0;
for (;lastBlockBytes < endCurrentBlock; ++lastBlockBytes) {
w[lastBlockBytes >> 2] |= (unsigned int) sarray[lastBlockBytes + currentBlock] << ((3 - (lastBlockBytes & 3)) << 3);
}
w[lastBlockBytes >> 2] |= 0x80 << ((3 - (lastBlockBytes & 3)) << 3);
if (endCurrentBlock >= 56) {
innerHash(result, w);
clearWBuffert(w);
}
w[15] = bytelength << 3;
innerHash(result, w);
// Store hash in result pointer, and make sure we get in in the correct
// order on both endian models.
for (int hashByte = 20; --hashByte >= 0;) {
hash[hashByte] = (result[hashByte >> 2] >> (((3 - hashByte) & 0x3) << 3)) & 0xff;
}
}
} // namespace sha1
} // namespace websocketpp
#endif // SHA1_DEFINED

View File

@ -0,0 +1,232 @@
/*
* Copyright (c) 2015, Peter Thorson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef WEBSOCKETPP_TRANSPORT_ASIO_BASE_HPP
#define WEBSOCKETPP_TRANSPORT_ASIO_BASE_HPP
#include <websocketpp/common/asio.hpp>
#include <websocketpp/common/cpp11.hpp>
#include <websocketpp/common/functional.hpp>
#include <websocketpp/common/system_error.hpp>
#include <websocketpp/common/type_traits.hpp>
#include <string>
namespace websocketpp {
namespace transport {
/// Transport policy that uses asio
/**
* This policy uses a single asio io_service to provide transport
* services to a WebSocket++ endpoint.
*/
namespace asio {
// Class to manage the memory to be used for handler-based custom allocation.
// It contains a single block of memory which may be returned for allocation
// requests. If the memory is in use when an allocation request is made, the
// allocator delegates allocation to the global heap.
class handler_allocator {
public:
static const size_t size = 1024;
handler_allocator() : m_in_use(false) {}
#ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
handler_allocator(handler_allocator const & cpy) = delete;
handler_allocator & operator =(handler_allocator const &) = delete;
#endif
void * allocate(std::size_t memsize) {
if (!m_in_use && memsize < size) {
m_in_use = true;
return static_cast<void*>(&m_storage);
} else {
return ::operator new(memsize);
}
}
void deallocate(void * pointer) {
if (pointer == &m_storage) {
m_in_use = false;
} else {
::operator delete(pointer);
}
}
private:
// Storage space used for handler-based custom memory allocation.
lib::aligned_storage<size>::type m_storage;
// Whether the handler-based custom allocation storage has been used.
bool m_in_use;
};
// Wrapper class template for handler objects to allow handler memory
// allocation to be customised. Calls to operator() are forwarded to the
// encapsulated handler.
template <typename Handler>
class custom_alloc_handler {
public:
custom_alloc_handler(handler_allocator& a, Handler h)
: allocator_(a),
handler_(h)
{}
template <typename Arg1>
void operator()(Arg1 arg1) {
handler_(arg1);
}
template <typename Arg1, typename Arg2>
void operator()(Arg1 arg1, Arg2 arg2) {
handler_(arg1, arg2);
}
friend void* asio_handler_allocate(std::size_t size,
custom_alloc_handler<Handler> * this_handler)
{
return this_handler->allocator_.allocate(size);
}
friend void asio_handler_deallocate(void* pointer, std::size_t /*size*/,
custom_alloc_handler<Handler> * this_handler)
{
this_handler->allocator_.deallocate(pointer);
}
private:
handler_allocator & allocator_;
Handler handler_;
};
// Helper function to wrap a handler object to add custom allocation.
template <typename Handler>
inline custom_alloc_handler<Handler> make_custom_alloc_handler(
handler_allocator & a, Handler h)
{
return custom_alloc_handler<Handler>(a, h);
}
// Forward declaration of class endpoint so that it can be friended/referenced
// before being included.
template <typename config>
class endpoint;
typedef lib::function<void (lib::asio::error_code const & ec,
size_t bytes_transferred)> async_read_handler;
typedef lib::function<void (lib::asio::error_code const & ec,
size_t bytes_transferred)> async_write_handler;
typedef lib::function<void (lib::error_code const & ec)> pre_init_handler;
// handle_timer: dynamic parameters, multiple copies
// handle_proxy_write
// handle_proxy_read
// handle_async_write
// handle_pre_init
/// Asio transport errors
namespace error {
enum value {
/// Catch-all error for transport policy errors that don't fit in other
/// categories
general = 1,
/// async_read_at_least call requested more bytes than buffer can store
invalid_num_bytes,
/// there was an error in the underlying transport library
pass_through,
/// The connection to the requested proxy server failed
proxy_failed,
/// Invalid Proxy URI
proxy_invalid,
/// Invalid host or service
invalid_host_service
};
/// Asio transport error category
class category : public lib::error_category {
public:
char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ {
return "websocketpp.transport.asio";
}
std::string message(int value) const {
switch(value) {
case error::general:
return "Generic asio transport policy error";
case error::invalid_num_bytes:
return "async_read_at_least call requested more bytes than buffer can store";
case error::pass_through:
return "Underlying Transport Error";
case error::proxy_failed:
return "Proxy connection failed";
case error::proxy_invalid:
return "Invalid proxy URI";
case error::invalid_host_service:
return "Invalid host or service";
default:
return "Unknown";
}
}
};
/// Get a reference to a static copy of the asio transport error category
inline lib::error_category const & get_category() {
static category instance;
return instance;
}
/// Create an error code with the given value and the asio transport category
inline lib::error_code make_error_code(error::value e) {
return lib::error_code(static_cast<int>(e), get_category());
}
} // namespace error
} // namespace asio
} // namespace transport
} // namespace websocketpp
_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_
template<> struct is_error_code_enum<websocketpp::transport::asio::error::value>
{
static bool const value = true;
};
_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_
#endif // WEBSOCKETPP_TRANSPORT_ASIO_HPP

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,159 @@
/*
* Copyright (c) 2015, Peter Thorson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef WEBSOCKETPP_TRANSPORT_ASIO_SOCKET_BASE_HPP
#define WEBSOCKETPP_TRANSPORT_ASIO_SOCKET_BASE_HPP
#include <websocketpp/common/asio.hpp>
#include <websocketpp/common/memory.hpp>
#include <websocketpp/common/functional.hpp>
#include <websocketpp/common/system_error.hpp>
#include <websocketpp/common/cpp11.hpp>
#include <websocketpp/common/connection_hdl.hpp>
#include <string>
// Interface that sockets/security policies must implement
/*
* Endpoint Interface
*
* bool is_secure() const;
* @return Whether or not the endpoint creates secure connections
*
* lib::error_code init(socket_con_ptr scon);
* Called by the transport after a new connection is created to initialize
* the socket component of the connection.
* @param scon Pointer to the socket component of the connection
* @return Error code (empty on success)
*/
// Connection
// TODO
// set_hostname(std::string hostname)
// pre_init(init_handler);
// post_init(init_handler);
namespace websocketpp {
namespace transport {
namespace asio {
namespace socket {
typedef lib::function<void(lib::asio::error_code const &)> shutdown_handler;
/**
* The transport::asio::socket::* classes are a set of security/socket related
* policies and support code for the ASIO transport types.
*/
/// Errors related to asio transport sockets
namespace error {
enum value {
/// Catch-all error for security policy errors that don't fit in other
/// categories
security = 1,
/// Catch-all error for socket component errors that don't fit in other
/// categories
socket,
/// A function was called in a state that it was illegal to do so.
invalid_state,
/// The application was prompted to provide a TLS context and it was
/// empty or otherwise invalid
invalid_tls_context,
/// TLS Handshake Timeout
tls_handshake_timeout,
/// pass_through from underlying library
pass_through,
/// Required tls_init handler not present
missing_tls_init_handler,
/// TLS Handshake Failed
tls_handshake_failed,
/// Failed to set TLS SNI hostname
tls_failed_sni_hostname
};
} // namespace error
/// Error category related to asio transport socket policies
class socket_category : public lib::error_category {
public:
char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ {
return "websocketpp.transport.asio.socket";
}
std::string message(int value) const {
switch(value) {
case error::security:
return "Security policy error";
case error::socket:
return "Socket component error";
case error::invalid_state:
return "Invalid state";
case error::invalid_tls_context:
return "Invalid or empty TLS context supplied";
case error::tls_handshake_timeout:
return "TLS handshake timed out";
case error::pass_through:
return "Pass through from socket policy";
case error::missing_tls_init_handler:
return "Required tls_init handler not present.";
case error::tls_handshake_failed:
return "TLS handshake failed";
case error::tls_failed_sni_hostname:
return "Failed to set TLS SNI hostname";
default:
return "Unknown";
}
}
};
inline lib::error_category const & get_socket_category() {
static socket_category instance;
return instance;
}
inline lib::error_code make_error_code(error::value e) {
return lib::error_code(static_cast<int>(e), get_socket_category());
}
/// Type of asio transport socket policy initialization handlers
typedef lib::function<void(const lib::error_code&)> init_handler;
} // namespace socket
} // namespace asio
} // namespace transport
} // namespace websocketpp
#endif // WEBSOCKETPP_TRANSPORT_ASIO_SOCKET_BASE_HPP

View File

@ -0,0 +1,372 @@
/*
* Copyright (c) 2015, Peter Thorson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef WEBSOCKETPP_TRANSPORT_SECURITY_NONE_HPP
#define WEBSOCKETPP_TRANSPORT_SECURITY_NONE_HPP
#include <websocketpp/uri.hpp>
#include <websocketpp/transport/base/connection.hpp>
#include <websocketpp/transport/asio/security/base.hpp>
#include <websocketpp/common/asio.hpp>
#include <websocketpp/common/memory.hpp>
#include <sstream>
#include <string>
namespace websocketpp {
namespace transport {
namespace asio {
/// A socket policy for the asio transport that implements a plain, unencrypted
/// socket
namespace basic_socket {
/// The signature of the socket init handler for this socket policy
typedef lib::function<void(connection_hdl,lib::asio::ip::tcp::socket&)>
socket_init_handler;
/// Basic Asio connection socket component
/**
* transport::asio::basic_socket::connection implements a connection socket
* component using Asio ip::tcp::socket.
*/
class connection : public lib::enable_shared_from_this<connection> {
public:
/// Type of this connection socket component
typedef connection type;
/// Type of a shared pointer to this connection socket component
typedef lib::shared_ptr<type> ptr;
/// Type of a pointer to the Asio io_service being used
typedef lib::asio::io_service* io_service_ptr;
/// Type of a pointer to the Asio io_service strand being used
typedef lib::shared_ptr<lib::asio::io_service::strand> strand_ptr;
/// Type of the ASIO socket being used
typedef lib::asio::ip::tcp::socket socket_type;
/// Type of a shared pointer to the socket being used.
typedef lib::shared_ptr<socket_type> socket_ptr;
explicit connection() : m_state(UNINITIALIZED) {
//std::cout << "transport::asio::basic_socket::connection constructor"
// << std::endl;
}
/// Get a shared pointer to this component
ptr get_shared() {
return shared_from_this();
}
/// Check whether or not this connection is secure
/**
* @return Whether or not this connection is secure
*/
bool is_secure() const {
return false;
}
/// Set the socket initialization handler
/**
* The socket initialization handler is called after the socket object is
* created but before it is used. This gives the application a chance to
* set any Asio socket options it needs.
*
* @param h The new socket_init_handler
*/
void set_socket_init_handler(socket_init_handler h) {
m_socket_init_handler = h;
}
/// Retrieve a pointer to the underlying socket
/**
* This is used internally. It can also be used to set socket options, etc
*/
lib::asio::ip::tcp::socket & get_socket() {
return *m_socket;
}
/// Retrieve a pointer to the underlying socket
/**
* This is used internally.
*/
lib::asio::ip::tcp::socket & get_next_layer() {
return *m_socket;
}
/// Retrieve a pointer to the underlying socket
/**
* This is used internally. It can also be used to set socket options, etc
*/
lib::asio::ip::tcp::socket & get_raw_socket() {
return *m_socket;
}
/// Get the remote endpoint address
/**
* The iostream transport has no information about the ultimate remote
* endpoint. It will return the string "iostream transport". To indicate
* this.
*
* TODO: allow user settable remote endpoint addresses if this seems useful
*
* @return A string identifying the address of the remote endpoint
*/
std::string get_remote_endpoint(lib::error_code & ec) const {
std::stringstream s;
lib::asio::error_code aec;
lib::asio::ip::tcp::endpoint ep = m_socket->remote_endpoint(aec);
if (aec) {
ec = error::make_error_code(error::pass_through);
s << "Error getting remote endpoint: " << aec
<< " (" << aec.message() << ")";
return s.str();
} else {
ec = lib::error_code();
s << ep;
return s.str();
}
}
protected:
/// Perform one time initializations
/**
* init_asio is called once immediately after construction to initialize
* Asio components to the io_service
*
* @param service A pointer to the endpoint's io_service
* @param strand A shared pointer to the connection's asio strand
* @param is_server Whether or not the endpoint is a server or not.
*/
lib::error_code init_asio (io_service_ptr service, strand_ptr, bool)
{
if (m_state != UNINITIALIZED) {
return socket::make_error_code(socket::error::invalid_state);
}
m_socket.reset(new lib::asio::ip::tcp::socket(*service));
if (m_socket_init_handler) {
m_socket_init_handler(m_hdl, *m_socket);
}
m_state = READY;
return lib::error_code();
}
/// Set uri hook
/**
* Called by the transport as a connection is being established to provide
* the uri being connected to to the security/socket layer.
*
* This socket policy doesn't use the uri so it is ignored.
*
* @since 0.6.0
*
* @param u The uri to set
*/
void set_uri(uri_ptr) {}
/// Pre-initialize security policy
/**
* Called by the transport after a new connection is created to initialize
* the socket component of the connection. This method is not allowed to
* write any bytes to the wire. This initialization happens before any
* proxies or other intermediate wrappers are negotiated.
*
* @param callback Handler to call back with completion information
*/
void pre_init(init_handler callback) {
if (m_state != READY) {
callback(socket::make_error_code(socket::error::invalid_state));
return;
}
m_state = READING;
callback(lib::error_code());
}
/// Post-initialize security policy
/**
* Called by the transport after all intermediate proxies have been
* negotiated. This gives the security policy the chance to talk with the
* real remote endpoint for a bit before the websocket handshake.
*
* @param callback Handler to call back with completion information
*/
void post_init(init_handler callback) {
callback(lib::error_code());
}
/// Sets the connection handle
/**
* The connection handle is passed to any handlers to identify the
* connection
*
* @param hdl The new handle
*/
void set_handle(connection_hdl hdl) {
m_hdl = hdl;
}
/// Cancel all async operations on this socket
/**
* Attempts to cancel all async operations on this socket and reports any
* failures.
*
* NOTE: Windows XP and earlier do not support socket cancellation.
*
* @return The error that occurred, if any.
*/
lib::asio::error_code cancel_socket() {
lib::asio::error_code ec;
m_socket->cancel(ec);
return ec;
}
void async_shutdown(socket::shutdown_handler h) {
lib::asio::error_code ec;
m_socket->shutdown(lib::asio::ip::tcp::socket::shutdown_both, ec);
h(ec);
}
lib::error_code get_ec() const {
return lib::error_code();
}
public:
/// Translate any security policy specific information about an error code
/**
* Translate_ec takes an Asio error code and attempts to convert its value
* to an appropriate websocketpp error code. In the case that the Asio and
* Websocketpp error types are the same (such as using boost::asio and
* boost::system_error or using standalone asio and std::system_error the
* code will be passed through natively.
*
* In the case of a mismatch (boost::asio with std::system_error) a
* translated code will be returned. The plain socket policy does not have
* any additional information so all such errors will be reported as the
* generic transport pass_through error.
*
* @since 0.3.0
*
* @param ec The error code to translate_ec
* @return The translated error code
*/
template <typename ErrorCodeType>
static
lib::error_code translate_ec(ErrorCodeType) {
// We don't know any more information about this error so pass through
return make_error_code(transport::error::pass_through);
}
static
/// Overload of translate_ec to catch cases where lib::error_code is the
/// same type as lib::asio::error_code
lib::error_code translate_ec(lib::error_code ec) {
// We don't know any more information about this error, but the error is
// the same type as the one we are translating to, so pass through
// untranslated.
return ec;
}
private:
enum state {
UNINITIALIZED = 0,
READY = 1,
READING = 2
};
socket_ptr m_socket;
state m_state;
connection_hdl m_hdl;
socket_init_handler m_socket_init_handler;
};
/// Basic ASIO endpoint socket component
/**
* transport::asio::basic_socket::endpoint implements an endpoint socket
* component that uses Boost ASIO's ip::tcp::socket.
*/
class endpoint {
public:
/// The type of this endpoint socket component
typedef endpoint type;
/// The type of the corresponding connection socket component
typedef connection socket_con_type;
/// The type of a shared pointer to the corresponding connection socket
/// component.
typedef socket_con_type::ptr socket_con_ptr;
explicit endpoint() {}
/// Checks whether the endpoint creates secure connections
/**
* @return Whether or not the endpoint creates secure connections
*/
bool is_secure() const {
return false;
}
/// Set socket init handler
/**
* The socket init handler is called after a connection's socket is created
* but before it is used. This gives the end application an opportunity to
* set asio socket specific parameters.
*
* @param h The new socket_init_handler
*/
void set_socket_init_handler(socket_init_handler h) {
m_socket_init_handler = h;
}
protected:
/// Initialize a connection
/**
* Called by the transport after a new connection is created to initialize
* the socket component of the connection.
*
* @param scon Pointer to the socket component of the connection
*
* @return Error code (empty on success)
*/
lib::error_code init(socket_con_ptr scon) {
scon->set_socket_init_handler(m_socket_init_handler);
return lib::error_code();
}
private:
socket_init_handler m_socket_init_handler;
};
} // namespace basic_socket
} // namespace asio
} // namespace transport
} // namespace websocketpp
#endif // WEBSOCKETPP_TRANSPORT_SECURITY_NONE_HPP

View File

@ -0,0 +1,474 @@
/*
* Copyright (c) 2015, Peter Thorson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef WEBSOCKETPP_TRANSPORT_SECURITY_TLS_HPP
#define WEBSOCKETPP_TRANSPORT_SECURITY_TLS_HPP
#include <websocketpp/transport/asio/security/base.hpp>
#include <websocketpp/uri.hpp>
#include <websocketpp/common/asio_ssl.hpp>
#include <websocketpp/common/asio.hpp>
#include <websocketpp/common/connection_hdl.hpp>
#include <websocketpp/common/functional.hpp>
#include <websocketpp/common/memory.hpp>
#include <sstream>
#include <string>
namespace websocketpp {
namespace transport {
namespace asio {
/// A socket policy for the asio transport that implements a TLS encrypted
/// socket by wrapping with an asio::ssl::stream
namespace tls_socket {
/// The signature of the socket_init_handler for this socket policy
typedef lib::function<void(connection_hdl,lib::asio::ssl::stream<
lib::asio::ip::tcp::socket>&)> socket_init_handler;
/// The signature of the tls_init_handler for this socket policy
typedef lib::function<lib::shared_ptr<lib::asio::ssl::context>(connection_hdl)>
tls_init_handler;
/// TLS enabled Asio connection socket component
/**
* transport::asio::tls_socket::connection implements a secure connection socket
* component that uses Asio's ssl::stream to wrap an ip::tcp::socket.
*/
class connection : public lib::enable_shared_from_this<connection> {
public:
/// Type of this connection socket component
typedef connection type;
/// Type of a shared pointer to this connection socket component
typedef lib::shared_ptr<type> ptr;
/// Type of the ASIO socket being used
typedef lib::asio::ssl::stream<lib::asio::ip::tcp::socket> socket_type;
/// Type of a shared pointer to the ASIO socket being used
typedef lib::shared_ptr<socket_type> socket_ptr;
/// Type of a pointer to the ASIO io_service being used
typedef lib::asio::io_service * io_service_ptr;
/// Type of a pointer to the ASIO io_service strand being used
typedef lib::shared_ptr<lib::asio::io_service::strand> strand_ptr;
/// Type of a shared pointer to the ASIO TLS context being used
typedef lib::shared_ptr<lib::asio::ssl::context> context_ptr;
explicit connection() {
//std::cout << "transport::asio::tls_socket::connection constructor"
// << std::endl;
}
/// Get a shared pointer to this component
ptr get_shared() {
return shared_from_this();
}
/// Check whether or not this connection is secure
/**
* @return Whether or not this connection is secure
*/
bool is_secure() const {
return true;
}
/// Retrieve a pointer to the underlying socket
/**
* This is used internally. It can also be used to set socket options, etc
*/
socket_type::lowest_layer_type & get_raw_socket() {
return m_socket->lowest_layer();
}
/// Retrieve a pointer to the layer below the ssl stream
/**
* This is used internally.
*/
socket_type::next_layer_type & get_next_layer() {
return m_socket->next_layer();
}
/// Retrieve a pointer to the wrapped socket
/**
* This is used internally.
*/
socket_type & get_socket() {
return *m_socket;
}
/// Set the socket initialization handler
/**
* The socket initialization handler is called after the socket object is
* created but before it is used. This gives the application a chance to
* set any ASIO socket options it needs.
*
* @param h The new socket_init_handler
*/
void set_socket_init_handler(socket_init_handler h) {
m_socket_init_handler = h;
}
/// Set TLS init handler
/**
* The tls init handler is called when needed to request a TLS context for
* the library to use. A TLS init handler must be set and it must return a
* valid TLS context in order for this endpoint to be able to initialize
* TLS connections
*
* @param h The new tls_init_handler
*/
void set_tls_init_handler(tls_init_handler h) {
m_tls_init_handler = h;
}
/// Get the remote endpoint address
/**
* The iostream transport has no information about the ultimate remote
* endpoint. It will return the string "iostream transport". To indicate
* this.
*
* TODO: allow user settable remote endpoint addresses if this seems useful
*
* @return A string identifying the address of the remote endpoint
*/
std::string get_remote_endpoint(lib::error_code & ec) const {
std::stringstream s;
lib::asio::error_code aec;
lib::asio::ip::tcp::endpoint ep = m_socket->lowest_layer().remote_endpoint(aec);
if (aec) {
ec = error::make_error_code(error::pass_through);
s << "Error getting remote endpoint: " << aec
<< " (" << aec.message() << ")";
return s.str();
} else {
ec = lib::error_code();
s << ep;
return s.str();
}
}
protected:
/// Perform one time initializations
/**
* init_asio is called once immediately after construction to initialize
* Asio components to the io_service
*
* @param service A pointer to the endpoint's io_service
* @param strand A pointer to the connection's strand
* @param is_server Whether or not the endpoint is a server or not.
*/
lib::error_code init_asio (io_service_ptr service, strand_ptr strand,
bool is_server)
{
if (!m_tls_init_handler) {
return socket::make_error_code(socket::error::missing_tls_init_handler);
}
m_context = m_tls_init_handler(m_hdl);
if (!m_context) {
return socket::make_error_code(socket::error::invalid_tls_context);
}
m_socket.reset(new socket_type(*service, *m_context));
if (m_socket_init_handler) {
m_socket_init_handler(m_hdl, get_socket());
}
m_io_service = service;
m_strand = strand;
m_is_server = is_server;
return lib::error_code();
}
/// Set hostname hook
/**
* Called by the transport as a connection is being established to provide
* the hostname being connected to to the security/socket layer.
*
* This socket policy uses the hostname to set the appropriate TLS SNI
* header.
*
* @since 0.6.0
*
* @param u The uri to set
*/
void set_uri(uri_ptr u) {
m_uri = u;
}
/// Pre-initialize security policy
/**
* Called by the transport after a new connection is created to initialize
* the socket component of the connection. This method is not allowed to
* write any bytes to the wire. This initialization happens before any
* proxies or other intermediate wrappers are negotiated.
*
* @param callback Handler to call back with completion information
*/
void pre_init(init_handler callback) {
// TODO: is this the best way to check whether this function is
// available in the version of OpenSSL being used?
// TODO: consider case where host is an IP address
#if OPENSSL_VERSION_NUMBER >= 0x90812f
if (!m_is_server) {
// For clients on systems with a suitable OpenSSL version, set the
// TLS SNI hostname header so connecting to TLS servers using SNI
// will work.
long res = SSL_set_tlsext_host_name(
get_socket().native_handle(), m_uri->get_host().c_str());
if (!(1 == res)) {
callback(socket::make_error_code(socket::error::tls_failed_sni_hostname));
}
}
#endif
callback(lib::error_code());
}
/// Post-initialize security policy
/**
* Called by the transport after all intermediate proxies have been
* negotiated. This gives the security policy the chance to talk with the
* real remote endpoint for a bit before the websocket handshake.
*
* @param callback Handler to call back with completion information
*/
void post_init(init_handler callback) {
m_ec = socket::make_error_code(socket::error::tls_handshake_timeout);
// TLS handshake
if (m_strand) {
m_socket->async_handshake(
get_handshake_type(),
m_strand->wrap(lib::bind(
&type::handle_init, get_shared(),
callback,
lib::placeholders::_1
))
);
} else {
m_socket->async_handshake(
get_handshake_type(),
lib::bind(
&type::handle_init, get_shared(),
callback,
lib::placeholders::_1
)
);
}
}
/// Sets the connection handle
/**
* The connection handle is passed to any handlers to identify the
* connection
*
* @param hdl The new handle
*/
void set_handle(connection_hdl hdl) {
m_hdl = hdl;
}
void handle_init(init_handler callback,lib::asio::error_code const & ec) {
if (ec) {
m_ec = socket::make_error_code(socket::error::tls_handshake_failed);
} else {
m_ec = lib::error_code();
}
callback(m_ec);
}
lib::error_code get_ec() const {
return m_ec;
}
/// Cancel all async operations on this socket
/**
* Attempts to cancel all async operations on this socket and reports any
* failures.
*
* NOTE: Windows XP and earlier do not support socket cancellation.
*
* @return The error that occurred, if any.
*/
lib::asio::error_code cancel_socket() {
lib::asio::error_code ec;
get_raw_socket().cancel(ec);
return ec;
}
void async_shutdown(socket::shutdown_handler callback) {
if (m_strand) {
m_socket->async_shutdown(m_strand->wrap(callback));
} else {
m_socket->async_shutdown(callback);
}
}
public:
/// Translate any security policy specific information about an error code
/**
* Translate_ec takes an Asio error code and attempts to convert its value
* to an appropriate websocketpp error code. In the case that the Asio and
* Websocketpp error types are the same (such as using boost::asio and
* boost::system_error or using standalone asio and std::system_error the
* code will be passed through natively.
*
* In the case of a mismatch (boost::asio with std::system_error) a
* translated code will be returned. Any error that is determined to be
* related to TLS but does not have a more specific websocketpp error code
* is returned under the catch all error `tls_error`. Non-TLS related errors
* are returned as the transport generic error `pass_through`
*
* @since 0.3.0
*
* @param ec The error code to translate_ec
* @return The translated error code
*/
template <typename ErrorCodeType>
static
lib::error_code translate_ec(ErrorCodeType ec) {
if (ec.category() == lib::asio::error::get_ssl_category()) {
// We know it is a TLS related error, but otherwise don't know more.
// Pass through as TLS generic.
return make_error_code(transport::error::tls_error);
} else {
// We don't know any more information about this error so pass
// through
return make_error_code(transport::error::pass_through);
}
}
static
/// Overload of translate_ec to catch cases where lib::error_code is the
/// same type as lib::asio::error_code
lib::error_code translate_ec(lib::error_code ec) {
return ec;
}
private:
socket_type::handshake_type get_handshake_type() {
if (m_is_server) {
return lib::asio::ssl::stream_base::server;
} else {
return lib::asio::ssl::stream_base::client;
}
}
io_service_ptr m_io_service;
strand_ptr m_strand;
context_ptr m_context;
socket_ptr m_socket;
uri_ptr m_uri;
bool m_is_server;
lib::error_code m_ec;
connection_hdl m_hdl;
socket_init_handler m_socket_init_handler;
tls_init_handler m_tls_init_handler;
};
/// TLS enabled Asio endpoint socket component
/**
* transport::asio::tls_socket::endpoint implements a secure endpoint socket
* component that uses Asio's ssl::stream to wrap an ip::tcp::socket.
*/
class endpoint {
public:
/// The type of this endpoint socket component
typedef endpoint type;
/// The type of the corresponding connection socket component
typedef connection socket_con_type;
/// The type of a shared pointer to the corresponding connection socket
/// component.
typedef socket_con_type::ptr socket_con_ptr;
explicit endpoint() {}
/// Checks whether the endpoint creates secure connections
/**
* @return Whether or not the endpoint creates secure connections
*/
bool is_secure() const {
return true;
}
/// Set socket init handler
/**
* The socket init handler is called after a connection's socket is created
* but before it is used. This gives the end application an opportunity to
* set asio socket specific parameters.
*
* @param h The new socket_init_handler
*/
void set_socket_init_handler(socket_init_handler h) {
m_socket_init_handler = h;
}
/// Set TLS init handler
/**
* The tls init handler is called when needed to request a TLS context for
* the library to use. A TLS init handler must be set and it must return a
* valid TLS context in order for this endpoint to be able to initialize
* TLS connections
*
* @param h The new tls_init_handler
*/
void set_tls_init_handler(tls_init_handler h) {
m_tls_init_handler = h;
}
protected:
/// Initialize a connection
/**
* Called by the transport after a new connection is created to initialize
* the socket component of the connection.
*
* @param scon Pointer to the socket component of the connection
*
* @return Error code (empty on success)
*/
lib::error_code init(socket_con_ptr scon) {
scon->set_socket_init_handler(m_socket_init_handler);
scon->set_tls_init_handler(m_tls_init_handler);
return lib::error_code();
}
private:
socket_init_handler m_socket_init_handler;
tls_init_handler m_tls_init_handler;
};
} // namespace tls_socket
} // namespace asio
} // namespace transport
} // namespace websocketpp
#endif // WEBSOCKETPP_TRANSPORT_SECURITY_TLS_HPP

View File

@ -0,0 +1,238 @@
/*
* Copyright (c) 2014, 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_TRANSPORT_BASE_CON_HPP
#define WEBSOCKETPP_TRANSPORT_BASE_CON_HPP
#include <websocketpp/common/cpp11.hpp>
#include <websocketpp/common/connection_hdl.hpp>
#include <websocketpp/common/functional.hpp>
#include <websocketpp/common/system_error.hpp>
#include <string>
namespace websocketpp {
/// Transport policies provide network connectivity and timers
/**
* ### Connection Interface
*
* Transport connection components needs to provide:
*
* **init**\n
* `void init(init_handler handler)`\n
* Called once shortly after construction to give the policy the chance to
* perform one time initialization. When complete, the policy must call the
* supplied `init_handler` to continue setup. The handler takes one argument
* with the error code if any. If an error is returned here setup will fail and
* the connection will be aborted or terminated.
*
* WebSocket++ will call init only once. The transport must call `handler`
* exactly once.
*
* **async_read_at_least**\n
* `void async_read_at_least(size_t num_bytes, char *buf, size_t len,
* read_handler handler)`\n
* start an async read for at least num_bytes and at most len
* bytes into buf. Call handler when done with number of bytes read.
*
* WebSocket++ promises to have only one async_read_at_least in flight at a
* time. The transport must promise to only call read_handler once per async
* read.
*
* **async_write**\n
* `void async_write(const char* buf, size_t len, write_handler handler)`\n
* `void async_write(std::vector<buffer> & bufs, write_handler handler)`\n
* Start a write of all of the data in buf or bufs. In second case data is
* written sequentially and in place without copying anything to a temporary
* location.
*
* Websocket++ promises to have only one async_write in flight at a time.
* The transport must promise to only call the write_handler once per async
* write
*
* **set_handle**\n
* `void set_handle(connection_hdl hdl)`\n
* Called by WebSocket++ to let this policy know the hdl to the connection. It
* may be stored for later use or ignored/discarded. This handle should be used
* if the policy adds any connection handlers. Connection handlers must be
* called with the handle as the first argument so that the handler code knows
* which connection generated the callback.
*
* **set_timer**\n
* `timer_ptr set_timer(long duration, timer_handler handler)`\n
* WebSocket++ uses the timers provided by the transport policy as the
* implementation of timers is often highly coupled with the implementation of
* the networking event loops.
*
* Transport timer support is an optional feature. A transport method may elect
* to implement a dummy timer object and have this method return an empty
* pointer. If so, all timer related features of WebSocket++ core will be
* disabled. This includes many security features designed to prevent denial of
* service attacks. Use timer-free transport policies with caution.
*
* **get_remote_endpoint**\n
* `std::string get_remote_endpoint()`\n
* retrieve address of remote endpoint
*
* **is_secure**\n
* `void is_secure()`\n
* whether or not the connection to the remote endpoint is secure
*
* **dispatch**\n
* `lib::error_code dispatch(dispatch_handler handler)`: invoke handler within
* the transport's event system if it uses one. Otherwise, this method should
* simply call `handler` immediately.
*
* **async_shutdown**\n
* `void async_shutdown(shutdown_handler handler)`\n
* Perform any cleanup necessary (if any). Call `handler` when complete.
*/
namespace transport {
/// The type and signature of the callback passed to the init hook
typedef lib::function<void(lib::error_code const &)> init_handler;
/// The type and signature of the callback passed to the read method
typedef lib::function<void(lib::error_code const &,size_t)> read_handler;
/// The type and signature of the callback passed to the write method
typedef lib::function<void(lib::error_code const &)> write_handler;
/// The type and signature of the callback passed to the read method
typedef lib::function<void(lib::error_code const &)> timer_handler;
/// The type and signature of the callback passed to the shutdown method
typedef lib::function<void(lib::error_code const &)> shutdown_handler;
/// The type and signature of the callback passed to the interrupt method
typedef lib::function<void()> interrupt_handler;
/// The type and signature of the callback passed to the dispatch method
typedef lib::function<void()> dispatch_handler;
/// A simple utility buffer class
struct buffer {
buffer(char const * b, size_t l) : buf(b),len(l) {}
char const * buf;
size_t len;
};
/// Generic transport related errors
namespace error {
enum value {
/// Catch-all error for transport policy errors that don't fit in other
/// categories
general = 1,
/// underlying transport pass through
pass_through,
/// async_read_at_least call requested more bytes than buffer can store
invalid_num_bytes,
/// async_read called while another async_read was in progress
double_read,
/// Operation aborted
operation_aborted,
/// Operation not supported
operation_not_supported,
/// End of file
eof,
/// TLS short read
tls_short_read,
/// Timer expired
timeout,
/// read or write after shutdown
action_after_shutdown,
/// Other TLS error
tls_error
};
class category : public lib::error_category {
public:
category() {}
char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ {
return "websocketpp.transport";
}
std::string message(int value) const {
switch(value) {
case general:
return "Generic transport policy error";
case pass_through:
return "Underlying Transport Error";
case invalid_num_bytes:
return "async_read_at_least call requested more bytes than buffer can store";
case operation_aborted:
return "The operation was aborted";
case operation_not_supported:
return "The operation is not supported by this transport";
case eof:
return "End of File";
case tls_short_read:
return "TLS Short Read";
case timeout:
return "Timer Expired";
case action_after_shutdown:
return "A transport action was requested after shutdown";
case tls_error:
return "Generic TLS related error";
default:
return "Unknown";
}
}
};
inline lib::error_category const & get_category() {
static category instance;
return instance;
}
inline lib::error_code make_error_code(error::value e) {
return lib::error_code(static_cast<int>(e), get_category());
}
} // namespace error
} // namespace transport
} // namespace websocketpp
_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_
template<> struct is_error_code_enum<websocketpp::transport::error::value>
{
static bool const value = true;
};
_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_
#endif // WEBSOCKETPP_TRANSPORT_BASE_CON_HPP

View File

@ -0,0 +1,77 @@
/*
* Copyright (c) 2014, 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_TRANSPORT_BASE_HPP
#define WEBSOCKETPP_TRANSPORT_BASE_HPP
#include <websocketpp/common/functional.hpp>
#include <websocketpp/common/system_error.hpp>
namespace websocketpp {
/// Transport policies provide network connectivity and timers
/**
* ### Endpoint Interface
*
* Transport endpoint components needs to provide:
*
* **init**\n
* `lib::error_code init(transport_con_ptr tcon)`\n
* init is called by an endpoint once for each newly created connection.
* It's purpose is to give the transport policy the chance to perform any
* transport specific initialization that couldn't be done via the default
* constructor.
*
* **is_secure**\n
* `bool is_secure() const`\n
* Test whether the transport component of this endpoint is capable of secure
* connections.
*
* **async_connect**\n
* `void async_connect(transport_con_ptr tcon, uri_ptr location,
* connect_handler handler)`\n
* Initiate a connection to `location` using the given connection `tcon`. `tcon`
* is a pointer to the transport connection component of the connection. When
* complete, `handler` should be called with the the connection's
* `connection_hdl` and any error that occurred.
*
* **init_logging**
* `void init_logging(const lib::shared_ptr<alog_type>& a, const lib::shared_ptr<elog_type>& e)`\n
* Called once after construction to provide pointers to the endpoint's access
* and error loggers. These may be stored and used to log messages or ignored.
*/
namespace transport {
/// The type and signature of the callback passed to the accept method
typedef lib::function<void(lib::error_code const &)> accept_handler;
/// The type and signature of the callback passed to the connect method
typedef lib::function<void(lib::error_code const &)> connect_handler;
} // namespace transport
} // namespace websocketpp
#endif // WEBSOCKETPP_TRANSPORT_BASE_HPP

View File

@ -0,0 +1,104 @@
/*
* Copyright (c) 2014, 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_TRANSPORT_DEBUG_BASE_HPP
#define WEBSOCKETPP_TRANSPORT_DEBUG_BASE_HPP
#include <websocketpp/common/system_error.hpp>
#include <websocketpp/common/cpp11.hpp>
#include <string>
namespace websocketpp {
namespace transport {
/// Debug transport policy that is used for various mocking and stubbing duties
/// in unit tests.
namespace debug {
/// debug transport errors
namespace error {
enum value {
/// Catch-all error for transport policy errors that don't fit in other
/// categories
general = 1,
/// not implemented
not_implemented,
invalid_num_bytes,
double_read
};
/// debug transport error category
class category : public lib::error_category {
public:
category() {}
char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ {
return "websocketpp.transport.debug";
}
std::string message(int value) const {
switch(value) {
case general:
return "Generic stub transport policy error";
case not_implemented:
return "feature not implemented";
case invalid_num_bytes:
return "Invalid number of bytes";
case double_read:
return "Read while another read was outstanding";
default:
return "Unknown";
}
}
};
/// Get a reference to a static copy of the debug transport error category
inline lib::error_category const & get_category() {
static category instance;
return instance;
}
/// Get an error code with the given value and the debug transport category
inline lib::error_code make_error_code(error::value e) {
return lib::error_code(static_cast<int>(e), get_category());
}
} // namespace error
} // namespace debug
} // namespace transport
} // namespace websocketpp
_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_
template<> struct is_error_code_enum<websocketpp::transport::debug::error::value>
{
static bool const value = true;
};
_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_
#endif // WEBSOCKETPP_TRANSPORT_DEBUG_BASE_HPP

View File

@ -0,0 +1,412 @@
/*
* Copyright (c) 2014, 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_TRANSPORT_DEBUG_CON_HPP
#define WEBSOCKETPP_TRANSPORT_DEBUG_CON_HPP
#include <websocketpp/transport/debug/base.hpp>
#include <websocketpp/transport/base/connection.hpp>
#include <websocketpp/uri.hpp>
#include <websocketpp/logger/levels.hpp>
#include <websocketpp/common/connection_hdl.hpp>
#include <websocketpp/common/memory.hpp>
#include <websocketpp/common/platforms.hpp>
#include <string>
#include <vector>
namespace websocketpp {
namespace transport {
namespace debug {
/// Empty timer class to stub out for timer functionality that stub
/// transport doesn't support
struct timer {
void cancel() {}
};
template <typename config>
class connection : public lib::enable_shared_from_this< connection<config> > {
public:
/// Type of this connection transport component
typedef connection<config> type;
/// Type of a shared pointer to this connection transport component
typedef lib::shared_ptr<type> ptr;
/// transport concurrency policy
typedef typename config::concurrency_type concurrency_type;
/// Type of this transport's access logging policy
typedef typename config::alog_type alog_type;
/// Type of this transport's error logging policy
typedef typename config::elog_type elog_type;
// Concurrency policy types
typedef typename concurrency_type::scoped_lock_type scoped_lock_type;
typedef typename concurrency_type::mutex_type mutex_type;
typedef lib::shared_ptr<timer> timer_ptr;
explicit connection(bool is_server, const lib::shared_ptr<alog_type> & alog, const lib::shared_ptr<elog_type> & elog)
: m_reading(false), m_is_server(is_server), m_alog(alog), m_elog(elog)
{
m_alog->write(log::alevel::devel,"debug con transport constructor");
}
/// Get a shared pointer to this component
ptr get_shared() {
return type::shared_from_this();
}
/// Set whether or not this connection is secure
/**
* Todo: docs
*
* @since 0.3.0-alpha4
*
* @param value Whether or not this connection is secure.
*/
void set_secure(bool) {}
/// Tests whether or not the underlying transport is secure
/**
* TODO: docs
*
* @return Whether or not the underlying transport is secure
*/
bool is_secure() const {
return false;
}
/// Set uri hook
/**
* Called by the endpoint as a connection is being established to provide
* the uri being connected to to the transport layer.
*
* Implementation is optional and can be ignored if the transport has no
* need for this information.
*
* @since 0.6.0
*
* @param u The uri to set
*/
void set_uri(uri_ptr) {}
/// Set human readable remote endpoint address
/**
* Sets the remote endpoint address returned by `get_remote_endpoint`. This
* value should be a human readable string that describes the remote
* endpoint. Typically an IP address or hostname, perhaps with a port. But
* may be something else depending on the nature of the underlying
* transport.
*
* If none is set a default is returned.
*
* @since 0.3.0-alpha4
*
* @param value The remote endpoint address to set.
*/
void set_remote_endpoint(std::string) {}
/// Get human readable remote endpoint address
/**
* TODO: docs
*
* This value is used in access and error logs and is available to the end
* application for including in user facing interfaces and messages.
*
* @return A string identifying the address of the remote endpoint
*/
std::string get_remote_endpoint() const {
return "unknown (debug transport)";
}
/// Get the connection handle
/**
* @return The handle for this connection.
*/
connection_hdl get_handle() const {
return connection_hdl();
}
/// Call back a function after a period of time.
/**
* Timers are not implemented in this transport. The timer pointer will
* always be empty. The handler will never be called.
*
* @param duration Length of time to wait in milliseconds
* @param callback The function to call back when the timer has expired
* @return A handle that can be used to cancel the timer if it is no longer
* needed.
*/
timer_ptr set_timer(long, timer_handler handler) {
m_alog->write(log::alevel::devel,"debug connection set timer");
m_timer_handler = handler;
return timer_ptr();
}
/// Manual input supply (read all)
/**
* Similar to read_some, but continues to read until all bytes in the
* supplied buffer have been read or the connection runs out of read
* requests.
*
* This method still may not read all of the bytes in the input buffer. if
* it doesn't it indicates that the connection was most likely closed or
* is in an error state where it is no longer accepting new input.
*
* @since 0.3.0
*
* @param buf Char buffer to read into the websocket
* @param len Length of buf
* @return The number of characters from buf actually read.
*/
size_t read_all(char const * buf, size_t len) {
size_t total_read = 0;
size_t temp_read = 0;
do {
temp_read = this->read_some_impl(buf+total_read,len-total_read);
total_read += temp_read;
} while (temp_read != 0 && total_read < len);
return total_read;
}
// debug stuff to invoke the async handlers
void expire_timer(lib::error_code const & ec) {
m_timer_handler(ec);
}
void fullfil_write() {
m_write_handler(lib::error_code());
}
protected:
/// Initialize the connection transport
/**
* Initialize the connection's transport component.
*
* @param handler The `init_handler` to call when initialization is done
*/
void init(init_handler handler) {
m_alog->write(log::alevel::devel,"debug connection init");
handler(lib::error_code());
}
/// Initiate an async_read for at least num_bytes bytes into buf
/**
* Initiates an async_read request for at least num_bytes bytes. The input
* will be read into buf. A maximum of len bytes will be input. When the
* operation is complete, handler will be called with the status and number
* of bytes read.
*
* This method may or may not call handler from within the initial call. The
* application should be prepared to accept either.
*
* The application should never call this method a second time before it has
* been called back for the first read. If this is done, the second read
* will be called back immediately with a double_read error.
*
* If num_bytes or len are zero handler will be called back immediately
* indicating success.
*
* @param num_bytes Don't call handler until at least this many bytes have
* been read.
* @param buf The buffer to read bytes into
* @param len The size of buf. At maximum, this many bytes will be read.
* @param handler The callback to invoke when the operation is complete or
* ends in an error
*/
void async_read_at_least(size_t num_bytes, char * buf, size_t len,
read_handler handler)
{
std::stringstream s;
s << "debug_con async_read_at_least: " << num_bytes;
m_alog->write(log::alevel::devel,s.str());
if (num_bytes > len) {
handler(make_error_code(error::invalid_num_bytes),size_t(0));
return;
}
if (m_reading == true) {
handler(make_error_code(error::double_read),size_t(0));
return;
}
if (num_bytes == 0 || len == 0) {
handler(lib::error_code(),size_t(0));
return;
}
m_buf = buf;
m_len = len;
m_bytes_needed = num_bytes;
m_read_handler = handler;
m_cursor = 0;
m_reading = true;
}
/// Asyncronous Transport Write
/**
* Write len bytes in buf to the output stream. Call handler to report
* success or failure. handler may or may not be called during async_write,
* but it must be safe for this to happen.
*
* Will return 0 on success.
*
* @param buf buffer to read bytes from
* @param len number of bytes to write
* @param handler Callback to invoke with operation status.
*/
void async_write(char const *, size_t, write_handler handler) {
m_alog->write(log::alevel::devel,"debug_con async_write");
m_write_handler = handler;
}
/// Asyncronous Transport Write (scatter-gather)
/**
* Write a sequence of buffers to the output stream. Call handler to report
* success or failure. handler may or may not be called during async_write,
* but it must be safe for this to happen.
*
* Will return 0 on success.
*
* @param bufs vector of buffers to write
* @param handler Callback to invoke with operation status.
*/
void async_write(std::vector<buffer> const &, write_handler handler) {
m_alog->write(log::alevel::devel,"debug_con async_write buffer list");
m_write_handler = handler;
}
/// Set Connection Handle
/**
* @param hdl The new handle
*/
void set_handle(connection_hdl) {}
/// Call given handler back within the transport's event system (if present)
/**
* Invoke a callback within the transport's event system if it has one. If
* it doesn't, the handler will be invoked immediately before this function
* returns.
*
* @param handler The callback to invoke
*
* @return Whether or not the transport was able to register the handler for
* callback.
*/
lib::error_code dispatch(dispatch_handler handler) {
handler();
return lib::error_code();
}
/// Perform cleanup on socket shutdown_handler
/**
* @param h The `shutdown_handler` to call back when complete
*/
void async_shutdown(shutdown_handler handler) {
handler(lib::error_code());
}
size_t read_some_impl(char const * buf, size_t len) {
m_alog->write(log::alevel::devel,"debug_con read_some");
if (!m_reading) {
m_elog->write(log::elevel::devel,"write while not reading");
return 0;
}
size_t bytes_to_copy = (std::min)(len,m_len-m_cursor);
std::copy(buf,buf+bytes_to_copy,m_buf+m_cursor);
m_cursor += bytes_to_copy;
if (m_cursor >= m_bytes_needed) {
complete_read(lib::error_code());
}
return bytes_to_copy;
}
/// Signal that a requested read is complete
/**
* Sets the reading flag to false and returns the handler that should be
* called back with the result of the read. The cursor position that is sent
* is whatever the value of m_cursor is.
*
* It MUST NOT be called when m_reading is false.
* it MUST be called while holding the read lock
*
* It is important to use this method rather than directly setting/calling
* m_read_handler back because this function makes sure to delete the
* locally stored handler which contains shared pointers that will otherwise
* cause circular reference based memory leaks.
*
* @param ec The error code to forward to the read handler
*/
void complete_read(lib::error_code const & ec) {
m_reading = false;
read_handler handler = m_read_handler;
m_read_handler = read_handler();
handler(ec,m_cursor);
}
private:
timer_handler m_timer_handler;
// Read space (Protected by m_read_mutex)
char * m_buf;
size_t m_len;
size_t m_bytes_needed;
read_handler m_read_handler;
size_t m_cursor;
// transport resources
connection_hdl m_connection_hdl;
write_handler m_write_handler;
shutdown_handler m_shutdown_handler;
bool m_reading;
bool const m_is_server;
bool m_is_secure;
lib::shared_ptr<alog_type> m_alog;
lib::shared_ptr<elog_type> m_elog;
std::string m_remote_endpoint;
};
} // namespace debug
} // namespace transport
} // namespace websocketpp
#endif // WEBSOCKETPP_TRANSPORT_DEBUG_CON_HPP

View File

@ -0,0 +1,140 @@
/*
* Copyright (c) 2014, 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_TRANSPORT_DEBUG_HPP
#define WEBSOCKETPP_TRANSPORT_DEBUG_HPP
#include <websocketpp/common/memory.hpp>
#include <websocketpp/logger/levels.hpp>
#include <websocketpp/transport/base/endpoint.hpp>
#include <websocketpp/transport/debug/connection.hpp>
namespace websocketpp {
namespace transport {
namespace debug {
template <typename config>
class endpoint {
public:
/// Type of this endpoint transport component
typedef endpoint type;
/// Type of a pointer to this endpoint transport component
typedef lib::shared_ptr<type> ptr;
/// Type of this endpoint's concurrency policy
typedef typename config::concurrency_type concurrency_type;
/// Type of this endpoint's error logging policy
typedef typename config::elog_type elog_type;
/// Type of this endpoint's access logging policy
typedef typename config::alog_type alog_type;
/// Type of this endpoint transport component's associated connection
/// transport component.
typedef debug::connection<config> transport_con_type;
/// Type of a shared pointer to this endpoint transport component's
/// associated connection transport component
typedef typename transport_con_type::ptr transport_con_ptr;
// generate and manage our own io_service
explicit endpoint()
{
//std::cout << "transport::iostream::endpoint constructor" << std::endl;
}
/// Set whether or not endpoint can create secure connections
/**
* TODO: docs
*
* Setting this value only indicates whether or not the endpoint is capable
* of producing and managing secure connections. Connections produced by
* this endpoint must also be individually flagged as secure if they are.
*
* @since 0.3.0-alpha4
*
* @param value Whether or not the endpoint can create secure connections.
*/
void set_secure(bool) {}
/// Tests whether or not the underlying transport is secure
/**
* TODO: docs
*
* @return Whether or not the underlying transport is secure
*/
bool is_secure() const {
return false;
}
protected:
/// Initialize logging
/**
* The loggers are located in the main endpoint class. As such, the
* transport doesn't have direct access to them. This method is called
* by the endpoint constructor to allow shared logging from the transport
* component. These are raw pointers to member variables of the endpoint.
* In particular, they cannot be used in the transport constructor as they
* haven't been constructed yet, and cannot be used in the transport
* destructor as they will have been destroyed by then.
*
* @param a A pointer to the access logger to use.
* @param e A pointer to the error logger to use.
*/
void init_logging(lib::shared_ptr<alog_type>, lib::shared_ptr<elog_type>) {}
/// Initiate a new connection
/**
* @param tcon A pointer to the transport connection component of the
* connection to connect.
* @param u A URI pointer to the URI to connect to.
* @param cb The function to call back with the results when complete.
*/
void async_connect(transport_con_ptr, uri_ptr, connect_handler cb) {
cb(lib::error_code());
}
/// Initialize a connection
/**
* Init is called by an endpoint once for each newly created connection.
* It's purpose is to give the transport policy the chance to perform any
* transport specific initialization that couldn't be done via the default
* constructor.
*
* @param tcon A pointer to the transport portion of the connection.
* @return A status code indicating the success or failure of the operation
*/
lib::error_code init(transport_con_ptr) {
return lib::error_code();
}
private:
};
} // namespace debug
} // namespace transport
} // namespace websocketpp
#endif // WEBSOCKETPP_TRANSPORT_DEBUG_HPP

View File

@ -0,0 +1,133 @@
/*
* Copyright (c) 2014, 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_TRANSPORT_IOSTREAM_BASE_HPP
#define WEBSOCKETPP_TRANSPORT_IOSTREAM_BASE_HPP
#include <websocketpp/common/system_error.hpp>
#include <websocketpp/common/cpp11.hpp>
#include <websocketpp/common/functional.hpp>
#include <websocketpp/common/connection_hdl.hpp>
#include <websocketpp/transport/base/connection.hpp>
#include <string>
#include <vector>
namespace websocketpp {
namespace transport {
/// Transport policy that uses STL iostream for I/O and does not support timers
namespace iostream {
/// The type and signature of the callback used by iostream transport to write
typedef lib::function<lib::error_code(connection_hdl, char const *, size_t)>
write_handler;
/// The type and signature of the callback used by iostream transport to perform
/// vectored writes.
/**
* If a vectored write handler is not set the standard write handler will be
* called multiple times.
*/
typedef lib::function<lib::error_code(connection_hdl, std::vector<transport::buffer> const
& bufs)> vector_write_handler;
/// The type and signature of the callback used by iostream transport to signal
/// a transport shutdown.
typedef lib::function<lib::error_code(connection_hdl)> shutdown_handler;
/// iostream transport errors
namespace error {
enum value {
/// Catch-all error for transport policy errors that don't fit in other
/// categories
general = 1,
/// async_read_at_least call requested more bytes than buffer can store
invalid_num_bytes,
/// async_read called while another async_read was in progress
double_read,
/// An operation that requires an output stream was attempted before
/// setting one.
output_stream_required,
/// stream error
bad_stream
};
/// iostream transport error category
class category : public lib::error_category {
public:
category() {}
char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ {
return "websocketpp.transport.iostream";
}
std::string message(int value) const {
switch(value) {
case general:
return "Generic iostream transport policy error";
case invalid_num_bytes:
return "async_read_at_least call requested more bytes than buffer can store";
case double_read:
return "Async read already in progress";
case output_stream_required:
return "An output stream to be set before async_write can be used";
case bad_stream:
return "A stream operation returned ios::bad";
default:
return "Unknown";
}
}
};
/// Get a reference to a static copy of the iostream transport error category
inline lib::error_category const & get_category() {
static category instance;
return instance;
}
/// Get an error code with the given value and the iostream transport category
inline lib::error_code make_error_code(error::value e) {
return lib::error_code(static_cast<int>(e), get_category());
}
} // namespace error
} // namespace iostream
} // namespace transport
} // namespace websocketpp
_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_
template<> struct is_error_code_enum<websocketpp::transport::iostream::error::value>
{
static bool const value = true;
};
_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_
#endif // WEBSOCKETPP_TRANSPORT_IOSTREAM_BASE_HPP

View File

@ -0,0 +1,714 @@
/*
* Copyright (c) 2014, 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_TRANSPORT_IOSTREAM_CON_HPP
#define WEBSOCKETPP_TRANSPORT_IOSTREAM_CON_HPP
#include <websocketpp/transport/iostream/base.hpp>
#include <websocketpp/transport/base/connection.hpp>
#include <websocketpp/uri.hpp>
#include <websocketpp/logger/levels.hpp>
#include <websocketpp/common/connection_hdl.hpp>
#include <websocketpp/common/memory.hpp>
#include <websocketpp/common/platforms.hpp>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
namespace websocketpp {
namespace transport {
namespace iostream {
/// Empty timer class to stub out for timer functionality that iostream
/// transport doesn't support
struct timer {
void cancel() {}
};
template <typename config>
class connection : public lib::enable_shared_from_this< connection<config> > {
public:
/// Type of this connection transport component
typedef connection<config> type;
/// Type of a shared pointer to this connection transport component
typedef lib::shared_ptr<type> ptr;
/// transport concurrency policy
typedef typename config::concurrency_type concurrency_type;
/// Type of this transport's access logging policy
typedef typename config::alog_type alog_type;
/// Type of this transport's error logging policy
typedef typename config::elog_type elog_type;
// Concurrency policy types
typedef typename concurrency_type::scoped_lock_type scoped_lock_type;
typedef typename concurrency_type::mutex_type mutex_type;
typedef lib::shared_ptr<timer> timer_ptr;
explicit connection(bool is_server, const lib::shared_ptr<alog_type> & alog, const lib::shared_ptr<elog_type> & elog)
: m_output_stream(NULL)
, m_reading(false)
, m_is_server(is_server)
, m_is_secure(false)
, m_alog(alog)
, m_elog(elog)
, m_remote_endpoint("iostream transport")
{
m_alog->write(log::alevel::devel,"iostream con transport constructor");
}
/// Get a shared pointer to this component
ptr get_shared() {
return type::shared_from_this();
}
/// Register a std::ostream with the transport for writing output
/**
* Register a std::ostream with the transport. All future writes will be
* done to this output stream.
*
* @param o A pointer to the ostream to use for output.
*/
void register_ostream(std::ostream * o) {
// TODO: lock transport state?
scoped_lock_type lock(m_read_mutex);
m_output_stream = o;
}
/// Set uri hook
/**
* Called by the endpoint as a connection is being established to provide
* the uri being connected to to the transport layer.
*
* This transport policy doesn't use the uri so it is ignored.
*
* @since 0.6.0
*
* @param u The uri to set
*/
void set_uri(uri_ptr) {}
/// Overloaded stream input operator
/**
* Attempts to read input from the given stream into the transport. Bytes
* will be extracted from the input stream to fulfill any pending reads.
* Input in this manner will only read until the current read buffer has
* been filled. Then it will signal the library to process the input. If the
* library's input handler adds a new async_read, additional bytes will be
* read, otherwise the input operation will end.
*
* When this function returns one of the following conditions is true:
* - There is no outstanding read operation
* - There are no more bytes available in the input stream
*
* You can use tellg() on the input stream to determine if all of the input
* bytes were read or not.
*
* If there is no pending read operation when the input method is called, it
* will return immediately and tellg() will not have changed.
*/
friend std::istream & operator>> (std::istream & in, type & t) {
// this serializes calls to external read.
scoped_lock_type lock(t.m_read_mutex);
t.read(in);
return in;
}
/// Manual input supply (read some)
/**
* Copies bytes from buf into WebSocket++'s input buffers. Bytes will be
* copied from the supplied buffer to fulfill any pending library reads. It
* will return the number of bytes successfully processed. If there are no
* pending reads read_some will return immediately. Not all of the bytes may
* be able to be read in one call.
*
* @since 0.3.0-alpha4
*
* @param buf Char buffer to read into the websocket
* @param len Length of buf
* @return The number of characters from buf actually read.
*/
size_t read_some(char const * buf, size_t len) {
// this serializes calls to external read.
scoped_lock_type lock(m_read_mutex);
return this->read_some_impl(buf,len);
}
/// Manual input supply (read all)
/**
* Similar to read_some, but continues to read until all bytes in the
* supplied buffer have been read or the connection runs out of read
* requests.
*
* This method still may not read all of the bytes in the input buffer. if
* it doesn't it indicates that the connection was most likely closed or
* is in an error state where it is no longer accepting new input.
*
* @since 0.3.0
*
* @param buf Char buffer to read into the websocket
* @param len Length of buf
* @return The number of characters from buf actually read.
*/
size_t read_all(char const * buf, size_t len) {
// this serializes calls to external read.
scoped_lock_type lock(m_read_mutex);
size_t total_read = 0;
size_t temp_read = 0;
do {
temp_read = this->read_some_impl(buf+total_read,len-total_read);
total_read += temp_read;
} while (temp_read != 0 && total_read < len);
return total_read;
}
/// Manual input supply (DEPRECATED)
/**
* @deprecated DEPRECATED in favor of read_some()
* @see read_some()
*/
size_t readsome(char const * buf, size_t len) {
return this->read_some(buf,len);
}
/// Signal EOF
/**
* Signals to the transport that data stream being read has reached EOF and
* that no more bytes may be read or written to/from the transport.
*
* @since 0.3.0-alpha4
*/
void eof() {
// this serializes calls to external read.
scoped_lock_type lock(m_read_mutex);
if (m_reading) {
complete_read(make_error_code(transport::error::eof));
}
}
/// Signal transport error
/**
* Signals to the transport that a fatal data stream error has occurred and
* that no more bytes may be read or written to/from the transport.
*
* @since 0.3.0-alpha4
*/
void fatal_error() {
// this serializes calls to external read.
scoped_lock_type lock(m_read_mutex);
if (m_reading) {
complete_read(make_error_code(transport::error::pass_through));
}
}
/// Set whether or not this connection is secure
/**
* The iostream transport does not provide any security features. As such
* it defaults to returning false when `is_secure` is called. However, the
* iostream transport may be used to wrap an external socket API that may
* provide secure transport. This method allows that external API to flag
* whether or not this connection is secure so that users of the WebSocket++
* API will get more accurate information.
*
* @since 0.3.0-alpha4
*
* @param value Whether or not this connection is secure.
*/
void set_secure(bool value) {
m_is_secure = value;
}
/// Tests whether or not the underlying transport is secure
/**
* iostream transport will return false always because it has no information
* about the ultimate remote endpoint. This may or may not be accurate
* depending on the real source of bytes being input. The `set_secure`
* method may be used to flag connections that are secured by an external
* API
*
* @return Whether or not the underlying transport is secure
*/
bool is_secure() const {
return m_is_secure;
}
/// Set human readable remote endpoint address
/**
* Sets the remote endpoint address returned by `get_remote_endpoint`. This
* value should be a human readable string that describes the remote
* endpoint. Typically an IP address or hostname, perhaps with a port. But
* may be something else depending on the nature of the underlying
* transport.
*
* If none is set the default is "iostream transport".
*
* @since 0.3.0-alpha4
*
* @param value The remote endpoint address to set.
*/
void set_remote_endpoint(std::string value) {
m_remote_endpoint = value;
}
/// Get human readable remote endpoint address
/**
* The iostream transport has no information about the ultimate remote
* endpoint. It will return the string "iostream transport". The
* `set_remote_endpoint` method may be used by external network code to set
* a more accurate value.
*
* This value is used in access and error logs and is available to the end
* application for including in user facing interfaces and messages.
*
* @return A string identifying the address of the remote endpoint
*/
std::string get_remote_endpoint() const {
return m_remote_endpoint;
}
/// Get the connection handle
/**
* @return The handle for this connection.
*/
connection_hdl get_handle() const {
return m_connection_hdl;
}
/// Call back a function after a period of time.
/**
* Timers are not implemented in this transport. The timer pointer will
* always be empty. The handler will never be called.
*
* @param duration Length of time to wait in milliseconds
* @param callback The function to call back when the timer has expired
* @return A handle that can be used to cancel the timer if it is no longer
* needed.
*/
timer_ptr set_timer(long, timer_handler) {
return timer_ptr();
}
/// Sets the write handler
/**
* The write handler is called when the iostream transport receives data
* that needs to be written to the appropriate output location. This handler
* can be used in place of registering an ostream for output.
*
* The signature of the handler is
* `lib::error_code (connection_hdl, char const *, size_t)` The
* code returned will be reported and logged by the core library.
*
* See also, set_vector_write_handler, for an optional write handler that
* allows more efficient handling of multiple writes at once.
*
* @see set_vector_write_handler
*
* @since 0.5.0
*
* @param h The handler to call when data is to be written.
*/
void set_write_handler(write_handler h) {
m_write_handler = h;
}
/// Sets the vectored write handler
/**
* The vectored write handler is called when the iostream transport receives
* multiple chunks of data that need to be written to the appropriate output
* location. This handler can be used in conjunction with the write_handler
* in place of registering an ostream for output.
*
* The sequence of buffers represents bytes that should be written
* consecutively and it is suggested to group the buffers into as few next
* layer packets as possible. Vector write is used to allow implementations
* that support it to coalesce writes into a single TCP packet or TLS
* segment for improved efficiency.
*
* This is an optional handler. If it is not defined then multiple calls
* will be made to the standard write handler.
*
* The signature of the handler is
* `lib::error_code (connection_hdl, std::vector<websocketpp::transport::buffer>
* const & bufs)`. The code returned will be reported and logged by the core
* library. The `websocketpp::transport::buffer` type is a struct with two
* data members. buf (char const *) and len (size_t).
*
* @since 0.6.0
*
* @param h The handler to call when vectored data is to be written.
*/
void set_vector_write_handler(vector_write_handler h) {
m_vector_write_handler = h;
}
/// Sets the shutdown handler
/**
* The shutdown handler is called when the iostream transport receives a
* notification from the core library that it is finished with all read and
* write operations and that the underlying transport can be cleaned up.
*
* If you are using iostream transport with another socket library, this is
* a good time to close/shutdown the socket for this connection.
*
* The signature of the handler is `lib::error_code (connection_hdl)`. The
* code returned will be reported and logged by the core library.
*
* @since 0.5.0
*
* @param h The handler to call on connection shutdown.
*/
void set_shutdown_handler(shutdown_handler h) {
m_shutdown_handler = h;
}
protected:
/// Initialize the connection transport
/**
* Initialize the connection's transport component.
*
* @param handler The `init_handler` to call when initialization is done
*/
void init(init_handler handler) {
m_alog->write(log::alevel::devel,"iostream connection init");
handler(lib::error_code());
}
/// Initiate an async_read for at least num_bytes bytes into buf
/**
* Initiates an async_read request for at least num_bytes bytes. The input
* will be read into buf. A maximum of len bytes will be input. When the
* operation is complete, handler will be called with the status and number
* of bytes read.
*
* This method may or may not call handler from within the initial call. The
* application should be prepared to accept either.
*
* The application should never call this method a second time before it has
* been called back for the first read. If this is done, the second read
* will be called back immediately with a double_read error.
*
* If num_bytes or len are zero handler will be called back immediately
* indicating success.
*
* @param num_bytes Don't call handler until at least this many bytes have
* been read.
* @param buf The buffer to read bytes into
* @param len The size of buf. At maximum, this many bytes will be read.
* @param handler The callback to invoke when the operation is complete or
* ends in an error
*/
void async_read_at_least(size_t num_bytes, char *buf, size_t len,
read_handler handler)
{
std::stringstream s;
s << "iostream_con async_read_at_least: " << num_bytes;
m_alog->write(log::alevel::devel,s.str());
if (num_bytes > len) {
handler(make_error_code(error::invalid_num_bytes),size_t(0));
return;
}
if (m_reading == true) {
handler(make_error_code(error::double_read),size_t(0));
return;
}
if (num_bytes == 0 || len == 0) {
handler(lib::error_code(),size_t(0));
return;
}
m_buf = buf;
m_len = len;
m_bytes_needed = num_bytes;
m_read_handler = handler;
m_cursor = 0;
m_reading = true;
}
/// Asyncronous Transport Write
/**
* Write len bytes in buf to the output method. Call handler to report
* success or failure. handler may or may not be called during async_write,
* but it must be safe for this to happen.
*
* Will return 0 on success. Other possible errors (not exhaustive)
* output_stream_required: No output stream was registered to write to
* bad_stream: a ostream pass through error
*
* This method will attempt to write to the registered ostream first. If an
* ostream is not registered it will use the write handler. If neither are
* registered then an error is passed up to the connection.
*
* @param buf buffer to read bytes from
* @param len number of bytes to write
* @param handler Callback to invoke with operation status.
*/
void async_write(char const * buf, size_t len, transport::write_handler
handler)
{
m_alog->write(log::alevel::devel,"iostream_con async_write");
// TODO: lock transport state?
lib::error_code ec;
if (m_output_stream) {
m_output_stream->write(buf,len);
if (m_output_stream->bad()) {
ec = make_error_code(error::bad_stream);
}
} else if (m_write_handler) {
ec = m_write_handler(m_connection_hdl, buf, len);
} else {
ec = make_error_code(error::output_stream_required);
}
handler(ec);
}
/// Asyncronous Transport Write (scatter-gather)
/**
* Write a sequence of buffers to the output method. Call handler to report
* success or failure. handler may or may not be called during async_write,
* but it must be safe for this to happen.
*
* Will return 0 on success. Other possible errors (not exhaustive)
* output_stream_required: No output stream was registered to write to
* bad_stream: a ostream pass through error
*
* This method will attempt to write to the registered ostream first. If an
* ostream is not registered it will use the write handler. If neither are
* registered then an error is passed up to the connection.
*
* @param bufs vector of buffers to write
* @param handler Callback to invoke with operation status.
*/
void async_write(std::vector<buffer> const & bufs, transport::write_handler
handler)
{
m_alog->write(log::alevel::devel,"iostream_con async_write buffer list");
// TODO: lock transport state?
lib::error_code ec;
if (m_output_stream) {
std::vector<buffer>::const_iterator it;
for (it = bufs.begin(); it != bufs.end(); it++) {
m_output_stream->write((*it).buf,(*it).len);
if (m_output_stream->bad()) {
ec = make_error_code(error::bad_stream);
break;
}
}
} else if (m_vector_write_handler) {
ec = m_vector_write_handler(m_connection_hdl, bufs);
} else if (m_write_handler) {
std::vector<buffer>::const_iterator it;
for (it = bufs.begin(); it != bufs.end(); it++) {
ec = m_write_handler(m_connection_hdl, (*it).buf, (*it).len);
if (ec) {break;}
}
} else {
ec = make_error_code(error::output_stream_required);
}
handler(ec);
}
/// Set Connection Handle
/**
* @param hdl The new handle
*/
void set_handle(connection_hdl hdl) {
m_connection_hdl = hdl;
}
/// Call given handler back within the transport's event system (if present)
/**
* Invoke a callback within the transport's event system if it has one. If
* it doesn't, the handler will be invoked immediately before this function
* returns.
*
* @param handler The callback to invoke
*
* @return Whether or not the transport was able to register the handler for
* callback.
*/
lib::error_code dispatch(dispatch_handler handler) {
handler();
return lib::error_code();
}
/// Perform cleanup on socket shutdown_handler
/**
* If a shutdown handler is set, call it and pass through its return error
* code. Otherwise assume there is nothing to do and pass through a success
* code.
*
* @param handler The `shutdown_handler` to call back when complete
*/
void async_shutdown(transport::shutdown_handler handler) {
lib::error_code ec;
if (m_shutdown_handler) {
ec = m_shutdown_handler(m_connection_hdl);
}
handler(ec);
}
private:
void read(std::istream &in) {
m_alog->write(log::alevel::devel,"iostream_con read");
while (in.good()) {
if (!m_reading) {
m_elog->write(log::elevel::devel,"write while not reading");
break;
}
in.read(m_buf+m_cursor,static_cast<std::streamsize>(m_len-m_cursor));
if (in.gcount() == 0) {
m_elog->write(log::elevel::devel,"read zero bytes");
break;
}
m_cursor += static_cast<size_t>(in.gcount());
// TODO: error handling
if (in.bad()) {
m_reading = false;
complete_read(make_error_code(error::bad_stream));
}
if (m_cursor >= m_bytes_needed) {
m_reading = false;
complete_read(lib::error_code());
}
}
}
size_t read_some_impl(char const * buf, size_t len) {
m_alog->write(log::alevel::devel,"iostream_con read_some");
if (!m_reading) {
m_elog->write(log::elevel::devel,"write while not reading");
return 0;
}
size_t bytes_to_copy = (std::min)(len,m_len-m_cursor);
std::copy(buf,buf+bytes_to_copy,m_buf+m_cursor);
m_cursor += bytes_to_copy;
if (m_cursor >= m_bytes_needed) {
complete_read(lib::error_code());
}
return bytes_to_copy;
}
/// Signal that a requested read is complete
/**
* Sets the reading flag to false and returns the handler that should be
* called back with the result of the read. The cursor position that is sent
* is whatever the value of m_cursor is.
*
* It MUST NOT be called when m_reading is false.
* it MUST be called while holding the read lock
*
* It is important to use this method rather than directly setting/calling
* m_read_handler back because this function makes sure to delete the
* locally stored handler which contains shared pointers that will otherwise
* cause circular reference based memory leaks.
*
* @param ec The error code to forward to the read handler
*/
void complete_read(lib::error_code const & ec) {
m_reading = false;
read_handler handler = m_read_handler;
m_read_handler = read_handler();
handler(ec,m_cursor);
}
// Read space (Protected by m_read_mutex)
char * m_buf;
size_t m_len;
size_t m_bytes_needed;
read_handler m_read_handler;
size_t m_cursor;
// transport resources
std::ostream * m_output_stream;
connection_hdl m_connection_hdl;
write_handler m_write_handler;
vector_write_handler m_vector_write_handler;
shutdown_handler m_shutdown_handler;
bool m_reading;
bool const m_is_server;
bool m_is_secure;
lib::shared_ptr<alog_type> m_alog;
lib::shared_ptr<elog_type> m_elog;
std::string m_remote_endpoint;
// This lock ensures that only one thread can edit read data for this
// connection. This is a very coarse lock that is basically locked all the
// time. The nature of the connection is such that it cannot be
// parallelized, the locking is here to prevent intra-connection concurrency
// in order to allow inter-connection concurrency.
mutex_type m_read_mutex;
};
} // namespace iostream
} // namespace transport
} // namespace websocketpp
#endif // WEBSOCKETPP_TRANSPORT_IOSTREAM_CON_HPP

View File

@ -0,0 +1,222 @@
/*
* Copyright (c) 2014, 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_TRANSPORT_IOSTREAM_HPP
#define WEBSOCKETPP_TRANSPORT_IOSTREAM_HPP
#include <websocketpp/transport/base/endpoint.hpp>
#include <websocketpp/transport/iostream/connection.hpp>
#include <websocketpp/uri.hpp>
#include <websocketpp/logger/levels.hpp>
#include <websocketpp/common/memory.hpp>
#include <ostream>
namespace websocketpp {
namespace transport {
namespace iostream {
template <typename config>
class endpoint {
public:
/// Type of this endpoint transport component
typedef endpoint type;
/// Type of a pointer to this endpoint transport component
typedef lib::shared_ptr<type> ptr;
/// Type of this endpoint's concurrency policy
typedef typename config::concurrency_type concurrency_type;
/// Type of this endpoint's error logging policy
typedef typename config::elog_type elog_type;
/// Type of this endpoint's access logging policy
typedef typename config::alog_type alog_type;
/// Type of this endpoint transport component's associated connection
/// transport component.
typedef iostream::connection<config> transport_con_type;
/// Type of a shared pointer to this endpoint transport component's
/// associated connection transport component
typedef typename transport_con_type::ptr transport_con_ptr;
// generate and manage our own io_service
explicit endpoint() : m_output_stream(NULL), m_is_secure(false)
{
//std::cout << "transport::iostream::endpoint constructor" << std::endl;
}
/// Register a default output stream
/**
* The specified output stream will be assigned to future connections as the
* default output stream.
*
* @param o The ostream to use as the default output stream.
*/
void register_ostream(std::ostream * o) {
m_alog->write(log::alevel::devel,"register_ostream");
m_output_stream = o;
}
/// Set whether or not endpoint can create secure connections
/**
* The iostream transport does not provide any security features. As such
* it defaults to returning false when `is_secure` is called. However, the
* iostream transport may be used to wrap an external socket API that may
* provide secure transport. This method allows that external API to flag
* whether or not it can create secure connections so that users of the
* WebSocket++ API will get more accurate information.
*
* Setting this value only indicates whether or not the endpoint is capable
* of producing and managing secure connections. Connections produced by
* this endpoint must also be individually flagged as secure if they are.
*
* @since 0.3.0-alpha4
*
* @param value Whether or not the endpoint can create secure connections.
*/
void set_secure(bool value) {
m_is_secure = value;
}
/// Tests whether or not the underlying transport is secure
/**
* iostream transport will return false by default because it has no
* information about the ultimate remote endpoint. This may or may not be
* accurate depending on the real source of bytes being input. `set_secure`
* may be used by a wrapper API to correct the return value in the case that
* secure connections are in fact possible.
*
* @return Whether or not the underlying transport is secure
*/
bool is_secure() const {
return m_is_secure;
}
/// Sets the write handler
/**
* The write handler is called when the iostream transport receives data
* that needs to be written to the appropriate output location. This handler
* can be used in place of registering an ostream for output.
*
* The signature of the handler is
* `lib::error_code (connection_hdl, char const *, size_t)` The
* code returned will be reported and logged by the core library.
*
* @since 0.5.0
*
* @param h The handler to call on connection shutdown.
*/
void set_write_handler(write_handler h) {
m_write_handler = h;
}
/// Sets the shutdown handler
/**
* The shutdown handler is called when the iostream transport receives a
* notification from the core library that it is finished with all read and
* write operations and that the underlying transport can be cleaned up.
*
* If you are using iostream transport with another socket library, this is
* a good time to close/shutdown the socket for this connection.
*
* The signature of the handler is lib::error_code (connection_hdl). The
* code returned will be reported and logged by the core library.
*
* @since 0.5.0
*
* @param h The handler to call on connection shutdown.
*/
void set_shutdown_handler(shutdown_handler h) {
m_shutdown_handler = h;
}
protected:
/// Initialize logging
/**
* The loggers are located in the main endpoint class. As such, the
* transport doesn't have direct access to them. This method is called
* by the endpoint constructor to allow shared logging from the transport
* component. These are raw pointers to member variables of the endpoint.
* In particular, they cannot be used in the transport constructor as they
* haven't been constructed yet, and cannot be used in the transport
* destructor as they will have been destroyed by then.
*
* @param a A pointer to the access logger to use.
* @param e A pointer to the error logger to use.
*/
void init_logging(lib::shared_ptr<alog_type> a, lib::shared_ptr<elog_type> e) {
m_elog = e;
m_alog = a;
}
/// Initiate a new connection
/**
* @param tcon A pointer to the transport connection component of the
* connection to connect.
* @param u A URI pointer to the URI to connect to.
* @param cb The function to call back with the results when complete.
*/
void async_connect(transport_con_ptr, uri_ptr, connect_handler cb) {
cb(lib::error_code());
}
/// Initialize a connection
/**
* Init is called by an endpoint once for each newly created connection.
* It's purpose is to give the transport policy the chance to perform any
* transport specific initialization that couldn't be done via the default
* constructor.
*
* @param tcon A pointer to the transport portion of the connection.
* @return A status code indicating the success or failure of the operation
*/
lib::error_code init(transport_con_ptr tcon) {
tcon->register_ostream(m_output_stream);
if (m_shutdown_handler) {
tcon->set_shutdown_handler(m_shutdown_handler);
}
if (m_write_handler) {
tcon->set_write_handler(m_write_handler);
}
return lib::error_code();
}
private:
std::ostream * m_output_stream;
shutdown_handler m_shutdown_handler;
write_handler m_write_handler;
lib::shared_ptr<elog_type> m_elog;
lib::shared_ptr<alog_type> m_alog;
bool m_is_secure;
};
} // namespace iostream
} // namespace transport
} // namespace websocketpp
#endif // WEBSOCKETPP_TRANSPORT_IOSTREAM_HPP

View File

@ -0,0 +1,95 @@
/*
* Copyright (c) 2014, 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_TRANSPORT_STUB_BASE_HPP
#define WEBSOCKETPP_TRANSPORT_STUB_BASE_HPP
#include <websocketpp/common/system_error.hpp>
#include <websocketpp/common/cpp11.hpp>
#include <string>
namespace websocketpp {
namespace transport {
/// Stub transport policy that has no input or output.
namespace stub {
/// stub transport errors
namespace error {
enum value {
/// Catch-all error for transport policy errors that don't fit in other
/// categories
general = 1,
/// not implemented
not_implemented
};
/// stub transport error category
class category : public lib::error_category {
public:
category() {}
char const * name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ {
return "websocketpp.transport.stub";
}
std::string message(int value) const {
switch(value) {
case general:
return "Generic stub transport policy error";
case not_implemented:
return "feature not implemented";
default:
return "Unknown";
}
}
};
/// Get a reference to a static copy of the stub transport error category
inline lib::error_category const & get_category() {
static category instance;
return instance;
}
/// Get an error code with the given value and the stub transport category
inline lib::error_code make_error_code(error::value e) {
return lib::error_code(static_cast<int>(e), get_category());
}
} // namespace error
} // namespace stub
} // namespace transport
} // namespace websocketpp
_WEBSOCKETPP_ERROR_CODE_ENUM_NS_START_
template<> struct is_error_code_enum<websocketpp::transport::stub::error::value>
{
static bool const value = true;
};
_WEBSOCKETPP_ERROR_CODE_ENUM_NS_END_
#endif // WEBSOCKETPP_TRANSPORT_STUB_BASE_HPP

View File

@ -0,0 +1,286 @@
/*
* Copyright (c) 2014, 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_TRANSPORT_STUB_CON_HPP
#define WEBSOCKETPP_TRANSPORT_STUB_CON_HPP
#include <websocketpp/transport/stub/base.hpp>
#include <websocketpp/transport/base/connection.hpp>
#include <websocketpp/logger/levels.hpp>
#include <websocketpp/common/connection_hdl.hpp>
#include <websocketpp/common/memory.hpp>
#include <websocketpp/common/platforms.hpp>
#include <string>
#include <vector>
namespace websocketpp {
namespace transport {
namespace stub {
/// Empty timer class to stub out for timer functionality that stub
/// transport doesn't support
struct timer {
void cancel() {}
};
template <typename config>
class connection : public lib::enable_shared_from_this< connection<config> > {
public:
/// Type of this connection transport component
typedef connection<config> type;
/// Type of a shared pointer to this connection transport component
typedef lib::shared_ptr<type> ptr;
/// transport concurrency policy
typedef typename config::concurrency_type concurrency_type;
/// Type of this transport's access logging policy
typedef typename config::alog_type alog_type;
/// Type of this transport's error logging policy
typedef typename config::elog_type elog_type;
// Concurrency policy types
typedef typename concurrency_type::scoped_lock_type scoped_lock_type;
typedef typename concurrency_type::mutex_type mutex_type;
typedef lib::shared_ptr<timer> timer_ptr;
explicit connection(bool is_server, const lib::shared_ptr<alog_type> & alog, const lib::shared_ptr<elog_type> & elog)
: m_alog(alog), m_elog(elog)
{
m_alog->write(log::alevel::devel,"stub con transport constructor");
}
/// Get a shared pointer to this component
ptr get_shared() {
return type::shared_from_this();
}
/// Set whether or not this connection is secure
/**
* Todo: docs
*
* @since 0.3.0-alpha4
*
* @param value Whether or not this connection is secure.
*/
void set_secure(bool value) {}
/// Tests whether or not the underlying transport is secure
/**
* TODO: docs
*
* @return Whether or not the underlying transport is secure
*/
bool is_secure() const {
return false;
}
/// Set uri hook
/**
* Called by the endpoint as a connection is being established to provide
* the uri being connected to to the transport layer.
*
* Implementation is optional and can be ignored if the transport has no
* need for this information.
*
* @since 0.6.0
*
* @param u The uri to set
*/
void set_uri(uri_ptr) {}
/// Set human readable remote endpoint address
/**
* Sets the remote endpoint address returned by `get_remote_endpoint`. This
* value should be a human readable string that describes the remote
* endpoint. Typically an IP address or hostname, perhaps with a port. But
* may be something else depending on the nature of the underlying
* transport.
*
* If none is set a default is returned.
*
* @since 0.3.0-alpha4
*
* @param value The remote endpoint address to set.
*/
void set_remote_endpoint(std::string value) {}
/// Get human readable remote endpoint address
/**
* TODO: docs
*
* This value is used in access and error logs and is available to the end
* application for including in user facing interfaces and messages.
*
* @return A string identifying the address of the remote endpoint
*/
std::string get_remote_endpoint() const {
return "unknown (stub transport)";
}
/// Get the connection handle
/**
* @return The handle for this connection.
*/
connection_hdl get_handle() const {
return connection_hdl();
}
/// Call back a function after a period of time.
/**
* Timers are not implemented in this transport. The timer pointer will
* always be empty. The handler will never be called.
*
* @param duration Length of time to wait in milliseconds
* @param callback The function to call back when the timer has expired
* @return A handle that can be used to cancel the timer if it is no longer
* needed.
*/
timer_ptr set_timer(long duration, timer_handler handler) {
return timer_ptr();
}
protected:
/// Initialize the connection transport
/**
* Initialize the connection's transport component.
*
* @param handler The `init_handler` to call when initialization is done
*/
void init(init_handler handler) {
m_alog->write(log::alevel::devel,"stub connection init");
handler(make_error_code(error::not_implemented));
}
/// Initiate an async_read for at least num_bytes bytes into buf
/**
* Initiates an async_read request for at least num_bytes bytes. The input
* will be read into buf. A maximum of len bytes will be input. When the
* operation is complete, handler will be called with the status and number
* of bytes read.
*
* This method may or may not call handler from within the initial call. The
* application should be prepared to accept either.
*
* The application should never call this method a second time before it has
* been called back for the first read. If this is done, the second read
* will be called back immediately with a double_read error.
*
* If num_bytes or len are zero handler will be called back immediately
* indicating success.
*
* @param num_bytes Don't call handler until at least this many bytes have
* been read.
* @param buf The buffer to read bytes into
* @param len The size of buf. At maximum, this many bytes will be read.
* @param handler The callback to invoke when the operation is complete or
* ends in an error
*/
void async_read_at_least(size_t num_bytes, char * buf, size_t len,
read_handler handler)
{
m_alog->write(log::alevel::devel, "stub_con async_read_at_least");
handler(make_error_code(error::not_implemented), 0);
}
/// Asyncronous Transport Write
/**
* Write len bytes in buf to the output stream. Call handler to report
* success or failure. handler may or may not be called during async_write,
* but it must be safe for this to happen.
*
* Will return 0 on success.
*
* @param buf buffer to read bytes from
* @param len number of bytes to write
* @param handler Callback to invoke with operation status.
*/
void async_write(char const * buf, size_t len, write_handler handler) {
m_alog->write(log::alevel::devel,"stub_con async_write");
handler(make_error_code(error::not_implemented));
}
/// Asyncronous Transport Write (scatter-gather)
/**
* Write a sequence of buffers to the output stream. Call handler to report
* success or failure. handler may or may not be called during async_write,
* but it must be safe for this to happen.
*
* Will return 0 on success.
*
* @param bufs vector of buffers to write
* @param handler Callback to invoke with operation status.
*/
void async_write(std::vector<buffer> const & bufs, write_handler handler) {
m_alog->write(log::alevel::devel,"stub_con async_write buffer list");
handler(make_error_code(error::not_implemented));
}
/// Set Connection Handle
/**
* @param hdl The new handle
*/
void set_handle(connection_hdl hdl) {}
/// Call given handler back within the transport's event system (if present)
/**
* Invoke a callback within the transport's event system if it has one. If
* it doesn't, the handler will be invoked immediately before this function
* returns.
*
* @param handler The callback to invoke
*
* @return Whether or not the transport was able to register the handler for
* callback.
*/
lib::error_code dispatch(dispatch_handler handler) {
handler();
return lib::error_code();
}
/// Perform cleanup on socket shutdown_handler
/**
* @param h The `shutdown_handler` to call back when complete
*/
void async_shutdown(shutdown_handler handler) {
handler(lib::error_code());
}
private:
// member variables!
lib::shared_ptr<alog_type> m_alog;
lib::shared_ptr<elog_type> m_elog;
};
} // namespace stub
} // namespace transport
} // namespace websocketpp
#endif // WEBSOCKETPP_TRANSPORT_STUB_CON_HPP

View File

@ -0,0 +1,140 @@
/*
* Copyright (c) 2014, 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_TRANSPORT_STUB_HPP
#define WEBSOCKETPP_TRANSPORT_STUB_HPP
#include <websocketpp/common/memory.hpp>
#include <websocketpp/logger/levels.hpp>
#include <websocketpp/transport/base/endpoint.hpp>
#include <websocketpp/transport/stub/connection.hpp>
namespace websocketpp {
namespace transport {
namespace stub {
template <typename config>
class endpoint {
public:
/// Type of this endpoint transport component
typedef endpoint type;
/// Type of a pointer to this endpoint transport component
typedef lib::shared_ptr<type> ptr;
/// Type of this endpoint's concurrency policy
typedef typename config::concurrency_type concurrency_type;
/// Type of this endpoint's error logging policy
typedef typename config::elog_type elog_type;
/// Type of this endpoint's access logging policy
typedef typename config::alog_type alog_type;
/// Type of this endpoint transport component's associated connection
/// transport component.
typedef stub::connection<config> transport_con_type;
/// Type of a shared pointer to this endpoint transport component's
/// associated connection transport component
typedef typename transport_con_type::ptr transport_con_ptr;
// generate and manage our own io_service
explicit endpoint()
{
//std::cout << "transport::iostream::endpoint constructor" << std::endl;
}
/// Set whether or not endpoint can create secure connections
/**
* TODO: docs
*
* Setting this value only indicates whether or not the endpoint is capable
* of producing and managing secure connections. Connections produced by
* this endpoint must also be individually flagged as secure if they are.
*
* @since 0.3.0-alpha4
*
* @param value Whether or not the endpoint can create secure connections.
*/
void set_secure(bool value) {}
/// Tests whether or not the underlying transport is secure
/**
* TODO: docs
*
* @return Whether or not the underlying transport is secure
*/
bool is_secure() const {
return false;
}
protected:
/// Initialize logging
/**
* The loggers are located in the main endpoint class. As such, the
* transport doesn't have direct access to them. This method is called
* by the endpoint constructor to allow shared logging from the transport
* component. These are raw pointers to member variables of the endpoint.
* In particular, they cannot be used in the transport constructor as they
* haven't been constructed yet, and cannot be used in the transport
* destructor as they will have been destroyed by then.
*
* @param a A pointer to the access logger to use.
* @param e A pointer to the error logger to use.
*/
void init_logging(alog_type * a, elog_type * e) {}
/// Initiate a new connection
/**
* @param tcon A pointer to the transport connection component of the
* connection to connect.
* @param u A URI pointer to the URI to connect to.
* @param cb The function to call back with the results when complete.
*/
void async_connect(transport_con_ptr tcon, uri_ptr u, connect_handler cb) {
cb(make_error_code(error::not_implemented));
}
/// Initialize a connection
/**
* Init is called by an endpoint once for each newly created connection.
* It's purpose is to give the transport policy the chance to perform any
* transport specific initialization that couldn't be done via the default
* constructor.
*
* @param tcon A pointer to the transport portion of the connection.
* @return A status code indicating the success or failure of the operation
*/
lib::error_code init(transport_con_ptr tcon) {
return make_error_code(error::not_implemented);
}
private:
};
} // namespace stub
} // namespace transport
} // namespace websocketpp
#endif // WEBSOCKETPP_TRANSPORT_STUB_HPP

Some files were not shown because too many files have changed in this diff Show More