Compare commits

..

12 Commits

Author SHA1 Message Date
Peter Thorson 51a692ffcc Merge pull request #86 from blindmatrix/master
some makefile fixes
2012-03-14 04:44:24 -07:00
Sven Almgren 0195101f31 Use ldconfig for all OS other then Darwin 2012-03-14 11:33:40 +01:00
Sven Almgren 37d611e267 Changed how Make decides if lfconfig should be called 2012-03-14 04:57:08 +01:00
Sven Almgren 9d585b635e Allow building with -j 2012-03-14 04:21:54 +01:00
Sven Almgren 3770302154 Updated Makefile to allow specifying extra CXXFLAGS and LDFLAGS 2012-03-14 04:17:05 +01:00
Peter Thorson e5b87e66bc Merge pull request #45 from muhler/patch-1
Fixed some typos.
2011-11-24 08:15:52 -08:00
muhler 186ae090c6 Fixed some typos. 2011-11-23 00:28:47 +01:00
Peter Thorson ec28725873 ignore binaries 2011-11-05 18:55:09 -05:00
Peter Thorson 4f7470840e fixes #41 issues compiling on Ubuntu 2011-11-05 23:49:18 +00:00
Peter Thorson 6c6977e48f resolves issues differentiating between no close and 1005 close code. Updates server default logging settings 2011-10-30 08:06:50 -05:00
Peter Thorson 23501149e0 fixes client host header 2011-10-29 13:31:59 -05:00
Peter Thorson 511930ac89 adjusts close behavior 2011-10-29 13:31:48 -05:00
258 changed files with 10385 additions and 32777 deletions
-18
View File
@@ -1,18 +0,0 @@
# Lineendings
*.sln eol=crlf
*.vcproj eol=crlf
*.vcxproj* eol=crlf
# Whitespace rules
# strict (no trailing, no tabs)
*.cpp whitespace=trailing-space,space-before-tab,tab-in-indent,cr-at-eol
*.hpp whitespace=trailing-space,space-before-tab,tab-in-indent,cr-at-eol
*.c whitespace=trailing-space,space-before-tab,tab-in-indent,cr-at-eol
*.h whitespace=trailing-space,space-before-tab,tab-in-indent,cr-at-eol
# normal (no trailing)
*.sql whitespace=trailing-space,space-before-tab,cr-at-eol
*.txt whitespace=trailing-space,space-before-tab,cr-at-eol
# special files which must ignore whitespace
*.patch whitespace=-trailing-space
+3 -55
View File
@@ -1,7 +1,3 @@
# make .git* files visible to git
!.gitignore
!.gitattributes
.DS_Store
#vim stuff
@@ -10,32 +6,10 @@
*.o
*.so
*.so.?
*.so.?.?.?
*.a
*.dylib
lib/*
# CMake
*.cmake
*.dir
CMakeFiles
INSTALL.*
ZERO_CHECK.*
CMakeCache.txt
install_manifest.txt
# Windows/Visual Studio
*.vcproj*
*.sln
*.suo
*.ncb
*/Debug/*
*/*/Debug/*
*/Release/*
*/*/Release/*
*/RelWithDebInfo/*
*/*/RelWithDebInfo/*
*.dylib.?.?.?
objs_shared/
objs_static/
@@ -44,37 +18,11 @@ examples/chat_server/chat_server
examples/echo_server/echo_server
examples/chat_client/chat_client
examples/echo_client/echo_client
test/basic/tests
libwebsocketpp.dylib.0.1.0
websocketpp.xcodeproj/xcuserdata/*
websocketpp.xcodeproj/project.xcworkspace/xcuserdata/*
policy_based_notes.hpp
examples/echo_server_tls/echo_server_tls
examples/fuzzing_client/fuzzing_client
examples/stress_client/stress_client
examples/broadcast_server_tls/broadcast_server
test/basic/perf
examples/echo_server_tls/echo_server_tls
examples/concurrent_server/concurrent_server
examples/fuzzing_server_tls/fuzzing_server
examples/wsperf/wsperf
.sconsign.dblite
build/
doxygen/
examples/wsperf/wsperf_client
*.out
*.log
examples/echo_server/echo_server_old
-22
View File
@@ -1,22 +0,0 @@
language: cpp
compiler:
- gcc
before_install:
- sudo apt-get install libboost-regex1.48-dev libboost-system1.48-dev libboost-thread1.48-dev libboost-test1.48-dev libboost-random1.48-dev -y
env:
global:
- BOOST_INCLUDES=/usr/include
- BOOST_LIBS=/usr/lib
script: scons -j 2 && scons test
branches:
only:
- master
- permessage-deflate
- experimental
- 0.3.x-cmake
notifications:
recipients:
- travis@zaphoyd.com
email:
on_success: change
on_failure: always
-237
View File
@@ -1,237 +0,0 @@
############ Setup project and cmake
# Project name
project (websocketpp)
# Minimum cmake requirement. We should require a quite recent
# cmake for the dependency find macros etc. to be up to date.
cmake_minimum_required (VERSION 2.6)
set (WEBSOCKETPP_MAJOR_VERSION 0)
set (WEBSOCKETPP_MINOR_VERSION 3)
set (WEBSOCKETPP_PATCH_VERSION 0)
set (WEBSOCKETPP_VERSION ${WEBSOCKETPP_MAJOR_VERSION}.${WEBSOCKETPP_MINOR_VERSION}.${WEBSOCKETPP_PATCH_VERSION})
set(INSTALL_INCLUDE_DIR include CACHE PATH "Installation directory for header files")
if (WIN32 AND NOT CYGWIN)
set (DEF_INSTALL_CMAKE_DIR cmake)
else ()
set (DEF_INSTALL_CMAKE_DIR lib/cmake/websocketpp)
endif ()
set (INSTALL_CMAKE_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE PATH "Installation directory for CMake files")
# Make relative paths absolute (needed later on)
foreach (p INCLUDE CMAKE)
set (var INSTALL_${p}_DIR)
if (NOT IS_ABSOLUTE "${${var}}")
set (${var} "${CMAKE_INSTALL_PREFIX}/${${var}}")
endif ()
endforeach ()
# Set CMake library search policy
if (COMMAND cmake_policy)
cmake_policy (SET CMP0003 NEW)
cmake_policy (SET CMP0005 NEW)
endif ()
# Disable unnecessary build types
set (CMAKE_CONFIGURATION_TYPES "Release;RelWithDebInfo;Debug" CACHE STRING "Configurations" FORCE)
# Include our cmake macros
set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
include (CMakeHelpers)
############ Paths
set (WEBSOCKETPP_ROOT ${CMAKE_CURRENT_SOURCE_DIR})
set (WEBSOCKETPP_INCLUDE ${WEBSOCKETPP_ROOT}/websocketpp)
set (WEBSOCKETPP_BUILD_ROOT ${CMAKE_CURRENT_BINARY_DIR})
set (WEBSOCKETPP_BIN ${WEBSOCKETPP_BUILD_ROOT}/bin)
set (WEBSOCKETPP_LIB ${WEBSOCKETPP_BUILD_ROOT}/lib)
# CMake install step prefix. I assume linux users want the prefix to
# be the default /usr or /usr/local so this is only adjusted on Windows.
# - Windows: Build the INSTALL project in your solution file.
# - Linux/OSX: make install.
if (MSVC)
set (CMAKE_INSTALL_PREFIX "${WEBSOCKETPP_ROOT}/install")
endif ()
############ Build customization
# Override from command line "CMake -D<OPTION>=TRUE/FALSE/0/1/ON/OFF"
option (ENABLE_CPP11 "Build websocketpp with CPP11 features enabled." TRUE)
option (BUILD_EXAMPLES "Build websocketpp examples." FALSE)
option (BUILD_TESTS "Build websocketpp tests." FALSE)
if (BUILD_TESTS OR BUILD_EXAMPLES)
############ Compiler specific setup
set (WEBSOCKETPP_PLATFORM_LIBS "")
set (WEBSOCKETPP_PLATFORM_TSL_LIBS "")
set (WEBSOCKETPP_BOOST_LIBS "")
# VC9 and C++11 reasoning
if (ENABLE_CPP11 AND MSVC AND MSVC90)
message("* Detected Visual Studio 9 2008, disabling C++11 support.")
set (ENABLE_CPP11 FALSE)
endif ()
# Detect clang. Not officially reported by cmake.
execute_process(COMMAND "${CMAKE_CXX_COMPILER}" "-v" ERROR_VARIABLE CXX_VER_STDERR)
if ("${CXX_VER_STDERR}" MATCHES ".*clang.*")
set (CMAKE_COMPILER_IS_CLANGXX 1)
endif ()
# C++11 defines
if (ENABLE_CPP11)
add_definitions (-D_WEBSOCKETPP_CPP11_STL_)
endif ()
# Visual studio
if (MSVC)
set (WEBSOCKETPP_BOOST_LIBS system thread)
set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /GL /Gy /GF /Ox /Ob2 /Ot /Oi /MP /arch:SSE2 /fp:fast")
set (CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG /INCREMENTAL:NO /OPT:REF /OPT:ICF")
add_definitions (/W3 /wd4996 /wd4995 /wd4355)
add_definitions (-DUNICODE -D_UNICODE)
add_definitions (-D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS)
add_definitions (-DNOMINMAX)
endif ()
# g++
if (CMAKE_COMPILER_IS_GNUCXX)
set (WEBSOCKETPP_PLATFORM_LIBS pthread rt)
set (WEBSOCKETPP_PLATFORM_TSL_LIBS ssl crypto)
set (WEBSOCKETPP_BOOST_LIBS system thread)
set (CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-std=c++0x")
if (NOT APPLE)
add_definitions (-DNDEBUG -Wall -Wcast-align) # todo: should we use CMAKE_C_FLAGS for these?
endif ()
# Try to detect version. Note: Not tested!
execute_process (COMMAND ${CMAKE_CXX_COMPILER} "-dumpversion" OUTPUT_VARIABLE GCC_VERSION)
if ("${GCC_VERSION}" STRGREATER "4.4.0")
message("* C++11 support partially enabled due to GCC version ${GCC_VERSION}")
set (WEBSOCKETPP_BOOST_LIBS system thread)
endif ()
endif ()
# clang
if (CMAKE_COMPILER_IS_CLANGXX)
if (NOT APPLE)
set (WEBSOCKETPP_PLATFORM_LIBS pthread rt)
else()
set (WEBSOCKETPP_PLATFORM_LIBS pthread)
endif()
set (WEBSOCKETPP_PLATFORM_TSL_LIBS ssl crypto)
set (WEBSOCKETPP_BOOST_LIBS system thread)
set (CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-std=c++0x -stdlib=libc++") # todo: is libc++ really needed here?
if (NOT APPLE)
add_definitions (-DNDEBUG -Wall -Wno-padded) # todo: should we use CMAKE_C_FLAGS for these?
endif ()
endif ()
# OSX, can override above.
if (APPLE)
add_definitions (-DNDEBUG -Wall)
endif ()
if (BUILD_EXAMPLES)
list (APPEND WEBSOCKETPP_BOOST_LIBS random)
endif()
############ Dependencies
# Set BOOST_ROOT env variable or pass with cmake -DBOOST_ROOT=path.
# BOOST_ROOT can also be defined by a previous run from cmake cache.
if (NOT "$ENV{BOOST_ROOT_CPP11}" STREQUAL "")
# Scons documentation for BOOST_ROOT_CPP11:
# "look for optional second boostroot compiled with clang's libc++ STL library
# this prevents warnings/errors when linking code built with two different
# incompatible STL libraries."
file (TO_CMAKE_PATH "$ENV{BOOST_ROOT_CPP11}" BOOST_ROOT)
set (BOOST_ROOT ${BOOST_ROOT} CACHE PATH "BOOST_ROOT dependency path" FORCE)
endif ()
if ("${BOOST_ROOT}" STREQUAL "")
file (TO_CMAKE_PATH "$ENV{BOOST_ROOT}" BOOST_ROOT)
# Cache BOOST_ROOT for runs that do not define $ENV{BOOST_ROOT}.
set (BOOST_ROOT ${BOOST_ROOT} CACHE PATH "BOOST_ROOT dependency path" FORCE)
endif ()
message ("* Configuring Boost")
message (STATUS "-- Using BOOST_ROOT")
message (STATUS " " ${BOOST_ROOT})
if (MSVC)
set (Boost_USE_MULTITHREADED TRUE)
set (Boost_USE_STATIC_LIBS TRUE)
else ()
set (Boost_USE_MULTITHREADED FALSE)
set (Boost_USE_STATIC_LIBS FALSE)
endif ()
set (Boost_FIND_REQUIRED TRUE)
set (Boost_FIND_QUIETLY TRUE)
set (Boost_DEBUG FALSE)
set (Boost_USE_MULTITHREADED TRUE)
set (Boost_ADDITIONAL_VERSIONS "1.39.0" "1.40.0" "1.41.0" "1.42.0" "1.43.0" "1.44.0" "1.46.1") # todo: someone who knows better spesify these!
find_package (Boost 1.39.0 COMPONENTS "${WEBSOCKETPP_BOOST_LIBS}")
if (Boost_FOUND)
# Boost is a project wide global dependency.
include_directories (${Boost_INCLUDE_DIRS})
link_directories (${Boost_LIBRARY_DIRS})
# Pretty print status
message (STATUS "-- Include Directories")
foreach (include_dir ${Boost_INCLUDE_DIRS})
message (STATUS " " ${include_dir})
endforeach ()
message (STATUS "-- Library Directories")
foreach (library_dir ${Boost_LIBRARY_DIRS})
message (STATUS " " ${library_dir})
endforeach ()
message (STATUS "-- Libraries")
foreach (boost_lib ${Boost_LIBRARIES})
message (STATUS " " ${boost_lib})
endforeach ()
message ("")
else ()
message (FATAL_ERROR "Failed to find required dependency: boost")
endif ()
find_package(OpenSSL)
endif()
############ Add projects
# Add main library
add_subdirectory (websocketpp)
# Add examples
if (BUILD_EXAMPLES)
add_subdirectory (examples)
endif ()
# Add tests
if (BUILD_TESTS)
add_subdirectory (test)
endif ()
print_used_build_config()
export (PACKAGE websocketpp)
configure_file (websocketpp-config.cmake.in "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/websocketpp-config.cmake" @ONLY)
configure_file (websocketpp-configVersion.cmake.in "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/websocketpp-configVersion.cmake" @ONLY)
# Install the websocketpp-config.cmake and websocketpp-configVersion.cmake
install (FILES
"${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/websocketpp-config.cmake"
"${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/websocketpp-configVersion.cmake"
DESTINATION "${INSTALL_CMAKE_DIR}" COMPONENT dev)
-145
View File
@@ -1,145 +0,0 @@
Main Library:
Copyright (c) 2013, Peter Thorson. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the WebSocket++ Project nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Bundled Libraries:
****** Base 64 Library (base64/base64.hpp) ******
base64.hpp is a repackaging of the base64.cpp and base64.h files into a
single header suitable for use as a header only library. This conversion was
done by Peter Thorson (webmaster@zaphoyd.com) in 2012. All modifications to
the code are redistributed under the same license as the original, which is
listed below.
base64.cpp and base64.h
Copyright (C) 2004-2008 René Nyffenegger
This source code is provided 'as-is', without any express or implied
warranty. In no event will the author be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this source code must not be misrepresented; you must not
claim that you wrote the original source code. If you use this source code
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original source code.
3. This notice may not be removed or altered from any source distribution.
René Nyffenegger rene.nyffenegger@adp-gmbh.ch
****** SHA1 Library (sha1/sha1.hpp) ******
sha1.hpp is a repackaging of the sha1.cpp and sha1.h files from the shallsha1
library (http://code.google.com/p/smallsha1/) into a single header suitable for
use as a header only library. This conversion was done by Peter Thorson
(webmaster@zaphoyd.com) in 2013. All modifications to the code are redistributed
under the same license as the original, which is listed below.
Copyright (c) 2011, Micael Hildenborg
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Micael Hildenborg nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
****** MD5 Library (common/md5.hpp) ******
md5.hpp is a reformulation of the md5.h and md5.c code from
http://www.opensource.apple.com/source/cups/cups-59/cups/md5.c to allow it to
function as a component of a header only library. This conversion was done by
Peter Thorson (webmaster@zaphoyd.com) in 2012 for the WebSocket++ project. The
changes are released under the same license as the original (listed below)
Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved.
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
L. Peter Deutsch
ghost@aladdin.com
****** UTF8 Validation logic (utf8_validation.hpp) ******
utf8_validation.hpp is adapted from code originally written by Bjoern Hoehrmann
<bjoern@hoehrmann.de>. See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for
details.
The original license:
Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-1874
View File
File diff suppressed because it is too large Load Diff
+205
View File
@@ -0,0 +1,205 @@
################################################################################
#
# Copyright (c) 2011, Peter Thorson. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of the WebSocket++ Project nor the
# names of its contributors may be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# This Makefile was derived from a similar one included in the libjson project
# It's authors were Jonathan Wallace and Bernhard Fluehmann.
objects = websocket_server_session.o websocket_client_session.o websocket_session.o websocket_server.o websocket_client.o websocket_frame.o \
network_utilities.o sha1.o base64.o
libs = -lboost_system -lboost_date_time -lboost_regex -lboost_random
OS=$(shell uname)
# Defaults
ifeq ($(OS), Darwin)
cxxflags_default = -c -O2 -DNDEBUG
else
cxxflags_default = -c -O2 -DNDEBUG
endif
cxxflags_small = -c
cxxflags_debug = -c -g
cxxflags_shared = -f$(PIC)
libname = libwebsocketpp
libname_hdr = websocketpp
libname_debug = $(libname)
suffix_shared = so
suffix_shared_darwin = dylib
suffix_static = a
major_version = 0
minor_version = 1.0
objdir = objs
# Variables
prefix ?= /usr/local
exec_prefix ?= $(prefix)
libdir ?= lib
includedir ?= include
srcdir ?= src
CXX ?= c++
AR ?= ar
PIC ?= PIC
BUILD_TYPE ?= default
SHARED ?= 1
ifneq ($(OS),Darwin)
ldconfig = ldconfig
else
ldconfig =
endif
# Internal Variables
inst_path = $(exec_prefix)/$(libdir)
include_path = $(prefix)/$(includedir)
# BUILD_TYPE specific settings
ifeq ($(BUILD_TYPE), debug)
CXXFLAGS := $(cxxflags_debug) $(CXXFLAGS_EXTRA)
libname := $(libname_debug)
else
CXXFLAGS := $(cxxflags_default) $(CXXFLAGS_EXTRA)
endif
# SHARED specific settings
ifeq ($(SHARED), 1)
ifeq ($(OS), Darwin)
libname_shared = $(libname).$(suffix_shared_darwin)
else
libname_shared = $(libname).$(suffix_shared)
endif
libname_shared_major_version = $(libname_shared).$(major_version)
lib_target = $(libname_shared_major_version).$(minor_version)
objdir := $(objdir)_shared
CXXFLAGS := $(CXXFLAGS) $(cxxflags_shared)
else
lib_target = $(libname).$(suffix_static)
objdir := $(objdir)_static
endif
# Phony targets
.PHONY: all banner installdirs install install_headers clean uninstall \
uninstall_headers
# Targets
all: banner $(lib_target)
@echo "============================================================"
@echo "Done"
@echo "============================================================"
banner:
@echo "============================================================"
@echo "libwebsocketpp version: "$(major_version).$(minor_version) "target: "$(target) "OS: "$(OS)
@echo "============================================================"
installdirs: banner
mkdir -p $(objdir)
# Libraries
ifeq ($(SHARED),1)
$(lib_target): banner installdirs $(addprefix $(objdir)/, $(objects))
@echo "Link "
cd $(objdir) ; \
if test "$(OS)" = "Darwin" ; then \
$(CXX) -dynamiclib $(libs) $(LDFLAGS) -Wl,-dylib_install_name -Wl,$(libname_shared_major_version) -o $@ $(objects) ; \
else \
$(CXX) -shared $(libs) $(LDFLAGS) -Wl,-soname,$(libname_shared_major_version) -o $@ $(objects) ; \
fi ; \
mv -f $@ ../
@echo "Link: Done"
else
$(lib_target): banner installdirs $(addprefix $(objdir)/, $(objects))
@echo "Archive"
cd $(objdir) ; \
$(AR) -cvq $@ $(objects) ; \
mv -f $@ ../
@echo "Archive: Done"
endif
# Compile object files
$(objdir)/sha1.o: $(srcdir)/sha1/sha1.cpp installdirs
$(CXX) $< -o $@ $(CXXFLAGS)
$(objdir)/base64.o: $(srcdir)/base64/base64.cpp installdirs
$(CXX) $< -o $@ $(CXXFLAGS)
$(objdir)/%.o: $(srcdir)/%.cpp installdirs
$(CXX) $< -o $@ $(CXXFLAGS)
ifeq ($(SHARED),1)
install: banner install_headers $(lib_target)
@echo "Install shared library"
cp -f ./$(lib_target) $(inst_path)
cd $(inst_path) ; \
ln -sf $(lib_target) $(libname_shared_major_version) ; \
ln -sf $(libname_shared_major_version) $(libname_shared)
$(ldconfig)
@echo "Install shared library: Done."
else
install: banner install_headers $(lib_target)
@echo "Install static library"
cp -f ./$(lib_target) $(inst_path)
@echo "Install static library: Done."
endif
install_headers: banner
@echo "Install header files"
mkdir -p $(include_path)/$(libname_hdr)
# cp -f ./*.hpp $(include_path)/$(libname_hdr)
cp -f ./$(srcdir)/*.hpp $(include_path)/$(libname_hdr)
mkdir -p $(include_path)/$(libname_hdr)/base64
cp -f ./$(srcdir)/base64/base64.h $(include_path)/$(libname_hdr)/base64
mkdir -p $(include_path)/$(libname_hdr)/sha1
cp -f ./$(srcdir)/sha1/sha1.h $(include_path)/$(libname_hdr)/sha1
chmod -R a+r $(include_path)/$(libname_hdr)
find $(include_path)/$(libname_hdr) -type d -exec chmod a+x {} \;
@echo "Install header files: Done."
clean: banner
@echo "Clean library and object folder"
rm -rf $(objdir)
rm -f $(lib_target)
@echo "Clean library and object folder: Done"
ifeq ($(SHARED),1)
uninstall: banner uninstall_headers
@echo "Uninstall shared library"
rm -f $(inst_path)/$(libname_shared)
rm -f $(inst_path)/$(libname_shared_major_version)
rm -f $(inst_path)/$(lib_target)
ldconfig
@echo "Uninstall shared library: Done"
else
uninstall: banner uninstall_headers
@echo "Uninstall static library"
rm -f $(inst_path)/$(lib_target)
@echo "Uninstall static library: Done"
endif
uninstall_headers: banner
@echo "Uninstall header files"
rm -rf $(include_path)/$(libname)
@echo "Uninstall header files: Done"
-236
View File
@@ -1,236 +0,0 @@
import os, sys, commands
env = Environment(ENV = os.environ)
# figure out a better way to configure this
if os.environ.has_key('CXX'):
env['CXX'] = os.environ['CXX']
if os.environ.has_key('DEBUG'):
env['DEBUG'] = os.environ['DEBUG']
if os.environ.has_key('CXXFLAGS'):
#env['CXXFLAGS'] = os.environ['CXXFLAGS']
env.Append(CXXFLAGS = os.environ['CXXFLAGS'])
if os.environ.has_key('LINKFLAGS'):
#env['LDFLAGS'] = os.environ['LDFLAGS']
env.Append(LINKFLAGS = os.environ['LINKFLAGS'])
## Boost
##
## Note: You need to either set BOOSTROOT to the root of a stock Boost distribution
## or set BOOST_INCLUDES and BOOST_LIBS if Boost comes with your OS distro e.g. and
## needs BOOST_INCLUDES=/usr/include/boost and BOOST_LIBS=/usr/lib like Ubuntu.
##
if os.environ.has_key('BOOSTROOT'):
os.environ['BOOST_ROOT'] = os.environ['BOOSTROOT']
if os.environ.has_key('BOOST_ROOT'):
env['BOOST_INCLUDES'] = os.environ['BOOST_ROOT']
env['BOOST_LIBS'] = os.path.join(os.environ['BOOST_ROOT'], 'stage', 'lib')
elif os.environ.has_key('BOOST_INCLUDES') and os.environ.has_key('BOOST_LIBS'):
env['BOOST_INCLUDES'] = os.environ['BOOST_INCLUDES']
env['BOOST_LIBS'] = os.environ['BOOST_LIBS']
else:
raise SCons.Errors.UserError, "Neither BOOST_ROOT, nor BOOST_INCLUDES + BOOST_LIBS was set!"
if os.environ.has_key('WSPP_ENABLE_CPP11'):
env['WSPP_ENABLE_CPP11'] = True
else:
env['WSPP_ENABLE_CPP11'] = False
boost_linkshared = False
def boostlibs(libnames,localenv):
if localenv['PLATFORM'].startswith('win'):
# Win/VC++ supports autolinking. nothing to do.
# http://www.boost.org/doc/libs/1_49_0/more/getting_started/windows.html#auto-linking
return []
else:
libs = []
prefix = localenv['SHLIBPREFIX'] if boost_linkshared else localenv['LIBPREFIX']
suffix = localenv['SHLIBSUFFIX'] if boost_linkshared else localenv['LIBSUFFIX']
for name in libnames:
lib = File(os.path.join(localenv['BOOST_LIBS'], '%sboost_%s%s' % (prefix, name, suffix)))
libs.append(lib)
return libs
if env['PLATFORM'].startswith('win'):
env.Append(CPPDEFINES = ['WIN32',
'NDEBUG',
'WIN32_LEAN_AND_MEAN',
'_WIN32_WINNT=0x0600',
'_CONSOLE',
'BOOST_TEST_DYN_LINK',
'NOMINMAX',
'_WEBSOCKETPP_CPP11_MEMORY_',
'_WEBSOCKETPP_CPP11_FUNCTIONAL_'])
arch_flags = '/arch:SSE2'
opt_flags = '/Ox /Oi /fp:fast'
warn_flags = '/W3 /wd4996 /wd4995 /wd4355'
env['CCFLAGS'] = '%s /EHsc /GR /GS- /MD /nologo %s %s' % (warn_flags, arch_flags, opt_flags)
env['LINKFLAGS'] = '/INCREMENTAL:NO /MANIFEST /NOLOGO /OPT:REF /OPT:ICF /MACHINE:X86'
elif env['PLATFORM'] == 'posix':
if env.has_key('DEBUG'):
env.Append(CCFLAGS = ['-g', '-O0'])
else:
env.Append(CPPDEFINES = ['NDEBUG'])
env.Append(CCFLAGS = ['-O1', '-fomit-frame-pointer'])
env.Append(CCFLAGS = ['-Wall'])
#env['LINKFLAGS'] = ''
elif env['PLATFORM'] == 'darwin':
if env.has_key('DEBUG'):
env.Append(CCFLAGS = ['-g', '-O0'])
else:
env.Append(CPPDEFINES = ['NDEBUG'])
env.Append(CCFLAGS = ['-O1', '-fomit-frame-pointer'])
env.Append(CCFLAGS = ['-Wall'])
#env['LINKFLAGS'] = ''
if env['PLATFORM'].startswith('win'):
#env['LIBPATH'] = env['BOOST_LIBS']
pass
else:
env['LIBPATH'] = ['/usr/lib',
'/usr/local/lib'] #, env['BOOST_LIBS']
# Compiler specific warning flags
if env['CXX'].startswith('g++'):
#env.Append(CCFLAGS = ['-Wconversion'])
env.Append(CCFLAGS = ['-Wcast-align'])
elif env['CXX'].startswith('clang++'):
#env.Append(CCFLAGS = ['-Wcast-align'])
#env.Append(CCFLAGS = ['-Wglobal-constructors'])
#env.Append(CCFLAGS = ['-Wconversion'])
env.Append(CCFLAGS = ['-Wno-padded'])
# Wpadded
# Wsign-conversion
platform_libs = []
tls_libs = []
tls_build = False
if env['PLATFORM'] == 'posix':
platform_libs = ['pthread', 'rt']
tls_libs = ['ssl', 'crypto']
tls_build = True
elif env['PLATFORM'] == 'darwin':
tls_libs = ['ssl', 'crypto']
tls_build = True
elif env['PLATFORM'].startswith('win'):
# Win/VC++ supports autolinking. nothing to do.
pass
## Append WebSocket++ path
env.Append(CPPPATH = ['#'])
##### Set up C++11 environment
polyfill_libs = [] # boost libraries used as drop in replacements for incomplete
# C++11 STL implementations
env_cpp11 = env.Clone ()
if env_cpp11['CXX'].startswith('g++'):
# TODO: check g++ version
GCC_VERSION = commands.getoutput(env_cpp11['CXX'] + ' -dumpversion')
if GCC_VERSION > "4.4.0":
print "C++11 build environment partially enabled"
env_cpp11.Append(WSPP_CPP11_ENABLED = "true",CXXFLAGS = ['-std=c++0x'],TOOLSET = ['g++'],CPPDEFINES = ['_WEBSOCKETPP_CPP11_STL_'])
else:
print "C++11 build environment is not supported on this version of G++"
elif env_cpp11['CXX'].startswith('clang++'):
print "C++11 build environment enabled"
env_cpp11.Append(WSPP_CPP11_ENABLED = "true",CXXFLAGS = ['-std=c++0x','-stdlib=libc++'],LINKFLAGS = ['-stdlib=libc++'],TOOLSET = ['clang++'],CPPDEFINES = ['_WEBSOCKETPP_CPP11_STL_'])
# look for optional second boostroot compiled with clang's libc++ STL library
# this prevents warnings/errors when linking code built with two different
# incompatible STL libraries.
if os.environ.has_key('BOOST_ROOT_CPP11'):
env_cpp11['BOOST_INCLUDES'] = os.environ['BOOST_ROOT_CPP11']
env_cpp11['BOOST_LIBS'] = os.path.join(os.environ['BOOST_ROOT_CPP11'], 'stage', 'lib')
elif os.environ.has_key('BOOST_INCLUDES_CPP11') and os.environ.has_key('BOOST_LIBS_CPP11'):
env_cpp11['BOOST_INCLUDES'] = os.environ['BOOST_INCLUDES_CPP11']
env_cpp11['BOOST_LIBS'] = os.environ['BOOST_LIBS_CPP11']
else:
print "C++11 build environment disabled"
# if the build system is known to allow the isystem modifier for library include
# values then use it for the boost libraries. Otherwise just add them to the
# regular CPPPATH values.
if env['CXX'].startswith('g++') or env['CXX'].startswith('clang'):
env.Append(CPPFLAGS = '-isystem ' + env['BOOST_INCLUDES'])
else:
env.Append(CPPPATH = [env['BOOST_INCLUDES']])
env.Append(LIBPATH = [env['BOOST_LIBS']])
# if the build system is known to allow the isystem modifier for library include
# values then use it for the boost libraries. Otherwise just add them to the
# regular CPPPATH values.
if env_cpp11['CXX'].startswith('g++') or env_cpp11['CXX'].startswith('clang'):
env_cpp11.Append(CPPFLAGS = '-isystem ' + env_cpp11['BOOST_INCLUDES'])
else:
env_cpp11.Append(CPPPATH = [env_cpp11['BOOST_INCLUDES']])
env_cpp11.Append(LIBPATH = [env_cpp11['BOOST_LIBS']])
releasedir = 'build/release/'
debugdir = 'build/debug/'
testdir = 'build/test/'
builddir = releasedir
Export('env')
Export('env_cpp11')
Export('platform_libs')
Export('boostlibs')
Export('tls_libs')
Export('polyfill_libs')
## END OF CONFIG !!
## TARGETS:
if not env['PLATFORM'].startswith('win'):
# Unit tests, add test folders with SConscript files to to_test list.
to_test = ['utility','http','logger','random','processors','message_buffer','extension','transport/iostream','transport/asio','roles','endpoint','connection','transport'] #,'http','processors','connection'
for t in to_test:
new_tests = SConscript('#/test/'+t+'/SConscript',variant_dir = testdir + t, duplicate = 0)
for a in new_tests:
new_alias = Alias('test', [a], a.abspath)
AlwaysBuild(new_alias)
# Main test application
#main = SConscript('#/examples/dev/SConscript',variant_dir = builddir + 'dev',duplicate = 0)
# echo_server
echo_server = SConscript('#/examples/echo_server/SConscript',variant_dir = builddir + 'echo_server',duplicate = 0)
# echo_server_tls
if tls_build:
echo_server_tls = SConscript('#/examples/echo_server_tls/SConscript',variant_dir = builddir + 'echo_server_tls',duplicate = 0)
# broadcast_server
broadcast_server = SConscript('#/examples/broadcast_server/SConscript',variant_dir = builddir + 'broadcast_server',duplicate = 0)
# testee_server
testee_server = SConscript('#/examples/testee_server/SConscript',variant_dir = builddir + 'testee_server',duplicate = 0)
# testee_client
testee_client = SConscript('#/examples/testee_client/SConscript',variant_dir = builddir + 'testee_client',duplicate = 0)
# utility_client
utility_client = SConscript('#/examples/utility_client/SConscript',variant_dir = builddir + 'utility_client',duplicate = 0)
# subprotocol_server
subprotocol_server = SConscript('#/examples/subprotocol_server/SConscript',variant_dir = builddir + 'subprotocol_server',duplicate = 0)
if not env['PLATFORM'].startswith('win'):
# iostream_server
iostream_server = SConscript('#/examples/iostream_server/SConscript',variant_dir = builddir + 'iostream_server',duplicate = 0)
# telemetry_client
telemetry_client = SConscript('#/examples/telemetry_client/SConscript',variant_dir = builddir + 'telemetry_client',duplicate = 0)
# print_server
print_server = SConscript('#/examples/print_server/SConscript',variant_dir = builddir + 'print_server',duplicate = 0)
-83
View File
@@ -1,83 +0,0 @@
HEAD
- Adds URI method to extract query string from URI. Thank you Banaan for code.
#298
- Numerous performance improvements. Including: tuned default buffer sizes based
on profiling, caching of handler binding for async reads/writes, non-malloc
allocators for read/write handlers, disabling of a number of questionably
useful range sanity checks in tight inner loops.
- Adds a compile time switch to asio transport config to disable certain
multithreading features (some locks, asio strands)
0.3.0-alpha4 - 2013-10-11
- HTTP requests ending normally are no longer logged as errors. Thank you Banaan
for reporting. #294
- Eliminates spurious expired timers in certain error conditions. Thank you
Banaan for reporting. #295
- Consolidates all bundled library licenses into the COPYING file. #294
- Updates bundled sha1 library to one with a cleaner interface and more
straight-forward license. Thank you lotodore for reporting and Evgeni Golov
for reviewing. #294
- Re-introduces strands to asio transport, allowing `io_service` thread pools to
be used (with some limitations).
- Removes endpoint code that kept track of a connection list that was never used
anywhere. Removes a lock and reduces connection creation/deletion complexity
from O(log n) to O(1) in the number of connections.
- A number of internal changes to transport APIs
- Deprecates iostream transport `readsome` in favor of `read_some` which is more
consistent with the naming of the rest of the library.
- Adds preliminary signaling to iostream transport of eof and fatal transport
errors
- Updates transport code to use shared pointers rather than raw pointers to
prevent asio from retaining pointers to connection methods after the
connection goes out of scope. #293 Thank you otaras for reporting.
- Fixes an issue where custom headers couldn't be set for client connections
Thank you Jerry Win and Wolfram Schroers for reporting.
- Fixes a compile error on visual studio when using interrupts. Thank you Javier
Rey Neira for reporting this.
- Adds new 1012 and 1013 close codes per IANA registry
- Add `set_remote_endpoint` method to iostream transport.
- Add `set_secure` method to iostream transport.
- Fix typo in .gitattributes file. Thank you jstarasov for reporting this. #280
- Add missing locale include. Thank you Toninoso for reporting this. #281
- Refactors `asio_transport` endpoint and adds full documentation and exception
free varients of all methods.
- Removes `asio_transport` endpoint method cancel(). Use `stop_listen()` instead
- Wrap internal `io_service` `run_one()` method
- Suppress error when trying to shut down a connection that was already closed
0.3.0-alpha3 - 2013-07-16
- Minor refactor to bundled sha1 library
- HTTP header comparisons are now case insensitive. #220, #275
- Refactors URI to be exception free and not use regular expressions. This
eliminates the dependency on boost or C++11 regex libraries allowing native
C++11 usage on GCC 4.4 and higher and significantly reduces staticly built
binary sizes.
- Updates handling of Server and User-Agent headers to better handle custom
settings and allow suppression of these headers for security purposes.
- Fix issue where pong timeout handler always fired. Thank you Steven Klassen
for reporting this bug.
- Add ping and pong endpoint wrapper methods
- Add `get_request()` pass through method to connection to allow calling methods
specific to the HTTP policy in use.
- Fix issue compile error with `WEBSOCKETPP_STRICT_MASKING` enabled and another
issue where `WEBSOCKETPP_STRICT_MASKING` was not applied to incoming messages.
Thank you Petter Norby for reporting and testing these bugs. #264
- Add additional macro guards for use with boost_config. Thank you breyed
for testing and code. #261
0.3.0-alpha2 - 2013-06-09
- Fix a regression that caused servers being sent two close frames in a row
to end a connection uncleanly. #259
- Fix a regression that caused spurious frames following a legitimate close
frames to erroneously trigger handlers. #258
- Change default HTTP response error code when no http_handler is defined from
500/Internal Server Error to 426/Upgrade Required
- Remove timezone from logger timestamp to work around issues with the Windows
implimentation of strftime. Thank you breyed for testing and code. #257
- Switch integer literals to char literals to improve VCPP compatibility.
Thank you breyed for testing and code. #257
- Add MSVCPP warning suppression for the bundled SHA1 library. Thank you breyed
for testing and code. #257
0.3.0-alpha1 - 2013-06-09
- Initial Release
-78
View File
@@ -1,78 +0,0 @@
# Print build configuration
macro (print_used_build_config)
message ("\n=========== Used Build Configuration =============\n")
message (STATUS "ENABLE_CPP11 = " ${ENABLE_CPP11})
message (STATUS "BUILD_EXAMPLES = " ${BUILD_EXAMPLES})
message (STATUS "BUILD_TESTS = " ${BUILD_TESTS})
message ("")
message (STATUS "WEBSOCKETPP_ROOT = " ${WEBSOCKETPP_ROOT})
message (STATUS "WEBSOCKETPP_BIN = " ${WEBSOCKETPP_BIN})
message (STATUS "WEBSOCKETPP_LIB = " ${WEBSOCKETPP_LIB})
message (STATUS "Install prefix = " ${CMAKE_INSTALL_PREFIX})
message ("")
message (STATUS "WEBSOCKETPP_BOOST_LIBS = ${WEBSOCKETPP_BOOST_LIBS}")
message (STATUS "WEBSOCKETPP_PLATFORM_LIBS = ${WEBSOCKETPP_PLATFORM_LIBS}")
message (STATUS "WEBSOCKETPP_PLATFORM_TSL_LIBS = ${WEBSOCKETPP_PLATFORM_TSL_LIBS}")
message ("")
endmacro ()
# Adds the given folder_name into the source files of the current project.
# Use this macro when your module contains .cpp and .h files in several subdirectories.
# Your sources variable needs to be WSPP_SOURCE_FILES and headers variable WSPP_HEADER_FILES.
macro(add_source_folder folder_name)
file(GLOB H_FILES_IN_FOLDER_${folder_name} ${folder_name}/*.hpp ${folder_name}/*.h)
file(GLOB CPP_FILES_IN_FOLDER_${folder_name} ${folder_name}/*.cpp ${folder_name}/*.c)
source_group("Header Files\\${folder_name}" FILES ${H_FILES_IN_FOLDER_${folder_name}})
source_group("Source Files\\${folder_name}" FILES ${CPP_FILES_IN_FOLDER_${folder_name}})
set(WSPP_HEADER_FILES ${WSPP_HEADER_FILES} ${H_FILES_IN_FOLDER_${folder_name}})
set(WSPP_SOURCE_FILES ${WSPP_SOURCE_FILES} ${CPP_FILES_IN_FOLDER_${folder_name}})
endmacro()
# Initialize target.
macro (init_target NAME)
set (TARGET_NAME ${NAME})
message ("** " ${TARGET_NAME})
# Include our own module path. This makes #include "x.h"
# work in project subfolders to include the main directory headers.
include_directories (${CMAKE_CURRENT_SOURCE_DIR})
endmacro ()
# Build executable for executables
macro (build_executable TARGET_NAME)
set (TARGET_LIB_TYPE "EXECUTABLE")
message (STATUS "-- Build Type:")
message (STATUS " " ${TARGET_LIB_TYPE})
add_executable (${TARGET_NAME} ${ARGN})
include_directories (${WEBSOCKETPP_ROOT} ${WEBSOCKETPP_INCLUDE})
set_target_properties (${TARGET_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${WEBSOCKETPP_BIN})
set_target_properties (${TARGET_NAME} PROPERTIES DEBUG_POSTFIX d)
endmacro ()
# Finalize target for all types
macro (final_target)
if ("${TARGET_LIB_TYPE}" STREQUAL "EXECUTABLE")
install (TARGETS ${TARGET_NAME}
RUNTIME DESTINATION "bin"
CONFIGURATIONS ${CMAKE_CONFIGURATION_TYPES})
endif ()
# install headers, directly from current source dir and look for subfolders with headers
file (GLOB_RECURSE TARGET_INSTALL_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.hpp)
foreach (hppfile ${TARGET_INSTALL_HEADERS})
get_filename_component (currdir ${hppfile} PATH)
install (FILES ${hppfile} DESTINATION "include/${TARGET_NAME}/${currdir}")
endforeach()
endmacro ()
macro (link_boost)
target_link_libraries (${TARGET_NAME} ${Boost_LIBRARIES})
endmacro ()
macro (link_openssl)
target_link_libraries (${TARGET_NAME} ${OPENSSL_SSL_LIBRARY} ${OPENSSL_CRYPTO_LIBRARY})
endmacro ()
-52
View File
@@ -1,52 +0,0 @@
#include <set>
#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/server.hpp>
typedef websocketpp::server<websocketpp::config::asio> server;
using websocketpp::connection_hdl;
using websocketpp::lib::placeholders::_1;
using websocketpp::lib::placeholders::_2;
using websocketpp::lib::bind;
class broadcast_server {
public:
broadcast_server() {
m_server.init_asio();
m_server.set_open_handler(bind(&broadcast_server::on_open,this,::_1));
m_server.set_close_handler(bind(&broadcast_server::on_close,this,::_1));
m_server.set_message_handler(bind(&broadcast_server::on_message,this,::_1,::_2));
}
void on_open(connection_hdl hdl) {
m_connections.insert(hdl);
}
void on_close(connection_hdl hdl) {
m_connections.erase(hdl);
}
void on_message(connection_hdl hdl, server::message_ptr msg) {
for (auto it : m_connections) {
m_server.send(it,msg);
}
}
void run(uint16_t port) {
m_server.listen(port);
m_server.start_accept();
m_server.run();
}
private:
typedef std::set<connection_hdl,std::owner_less<connection_hdl>> con_list;
server m_server;
con_list m_connections;
};
int main() {
broadcast_server server;
server.run(9002);
}
-65
View File
@@ -1,65 +0,0 @@
#include <functional>
#include <mutex>
#include <set>
#include <thread>
#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/server.hpp>
typedef websocketpp::server<websocketpp::config::asio> server;
using websocketpp::connection_hdl;
class count_server {
public:
count_server() : m_count(0) {
m_server.init_asio();
m_server.set_open_handler(bind(&count_server::on_open,this,_1));
m_server.set_close_handler(bind(&count_server::on_close,this,_1));
}
void on_open(connection_hdl hdl) {
std::lock_guard<std::mutex> lock(m_mutex);
m_connections.insert(hdl);
}
void on_close(connection_hdl hdl) {
std::lock_guard<std::mutex> lock(m_mutex);
m_connections.erase(hdl);
}
void count() {
while (1) {
sleep(1);
m_count++;
std::stringstream ss;
ss << m_count;
std::lock_guard<std::mutex> lock(m_mutex);
for (auto it : m_connections) {
m_server.send(it,ss.str(),websocketpp::frame::opcode::text);
}
}
}
void run(uint16_t port) {
m_server.listen(port);
m_server.start_accept();
m_server.run();
}
private:
typedef std::set<connection_hdl,std::owner_less<connection_hdl>> con_list;
int m_count;
server m_server;
con_list m_connections;
std::mutex m_mutex;
};
int main() {
count_server server;
std::thread t(std::bind(&count_server::count,&server));
server.run(9002);
}
-6
View File
@@ -1,6 +0,0 @@
file (GLOB SDIRS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *)
foreach (SUBDIR ${SDIRS})
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/CMakeLists.txt")
add_subdirectory (${SUBDIR})
endif ()
endforeach ()
@@ -1,88 +0,0 @@
#include <iostream>
#include <map>
#include <exception>
#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/server.hpp>
typedef websocketpp::server<websocketpp::config::asio> server;
using websocketpp::connection_hdl;
using websocketpp::lib::placeholders::_1;
using websocketpp::lib::placeholders::_2;
using websocketpp::lib::bind;
struct connection_data {
int sessionid;
std::string name;
};
class print_server {
public:
print_server() : m_next_sessionid(1) {
m_server.init_asio();
m_server.set_open_handler(bind(&print_server::on_open,this,::_1));
m_server.set_close_handler(bind(&print_server::on_close,this,::_1));
m_server.set_message_handler(bind(&print_server::on_message,this,::_1,::_2));
}
void on_open(connection_hdl hdl) {
connection_data data;
data.sessionid = m_next_sessionid++;
data.name = "";
m_connections[hdl] = data;
}
void on_close(connection_hdl hdl) {
connection_data& data = get_data_from_hdl(hdl);
std::cout << "Closing connection " << data.name
<< " with sessionid " << data.sessionid << std::endl;
m_connections.erase(hdl);
}
void on_message(connection_hdl hdl, server::message_ptr msg) {
connection_data& data = get_data_from_hdl(hdl);
if (data.name == "") {
data.name = msg->get_payload();
std::cout << "Setting name of connection with sessionid "
<< data.sessionid << " to " << data.name << std::endl;
} else {
std::cout << "Got a message from connection " << data.name
<< " with sessionid " << data.sessionid << std::endl;
}
}
connection_data& get_data_from_hdl(connection_hdl hdl) {
auto it = m_connections.find(hdl);
if (it == m_connections.end()) {
// this connection is not in the list. This really shouldn't happen
// and probably means something else is wrong.
throw std::invalid_argument("No data available for session");
}
return it->second;
}
void run(uint16_t port) {
m_server.listen(port);
m_server.start_accept();
m_server.run();
}
private:
typedef std::map<connection_hdl,connection_data,std::owner_less<connection_hdl>> con_list;
int m_next_sessionid;
server m_server;
con_list m_connections;
};
int main() {
print_server server;
server.run(9002);
}
-23
View File
@@ -1,23 +0,0 @@
## Broadcast Server example
##
Import('env')
Import('env_cpp11')
Import('boostlibs')
Import('platform_libs')
Import('polyfill_libs')
env = env.Clone ()
env_cpp11 = env_cpp11.Clone ()
prgs = []
# if a C++11 environment is available build using that, otherwise use boost
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]
prgs += env_cpp11.Program('broadcast_server', ["broadcast_server.cpp"], LIBS = ALL_LIBS)
else:
ALL_LIBS = boostlibs(['system','thread'],env) + [platform_libs] + [polyfill_libs]
prgs += env.Program('broadcast_server', ["broadcast_server.cpp"], LIBS = ALL_LIBS)
Return('prgs')
@@ -1,158 +0,0 @@
#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/server.hpp>
#include <iostream>
/*#include <boost/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition_variable.hpp>*/
#include <websocketpp/common/thread.hpp>
typedef websocketpp::server<websocketpp::config::asio> server;
using websocketpp::connection_hdl;
using websocketpp::lib::placeholders::_1;
using websocketpp::lib::placeholders::_2;
using websocketpp::lib::bind;
using websocketpp::lib::thread;
using websocketpp::lib::mutex;
using websocketpp::lib::unique_lock;
using websocketpp::lib::condition_variable;
/* on_open insert connection_hdl into channel
* on_close remove connection_hdl from channel
* on_message queue send to all channels
*/
enum action_type {
SUBSCRIBE,
UNSUBSCRIBE,
MESSAGE
};
struct action {
action(action_type t, connection_hdl h) : type(t), hdl(h) {}
action(action_type t, server::message_ptr m) : type(t), msg(m) {}
action_type type;
websocketpp::connection_hdl hdl;
server::message_ptr msg;
};
class broadcast_server {
public:
broadcast_server() {
// Initialize Asio Transport
m_server.init_asio();
// Register handler callbacks
m_server.set_open_handler(bind(&broadcast_server::on_open,this,::_1));
m_server.set_close_handler(bind(&broadcast_server::on_close,this,::_1));
m_server.set_message_handler(bind(&broadcast_server::on_message,this,::_1,::_2));
}
void run(uint16_t port) {
// listen on specified port
m_server.listen(port);
// Start the server accept loop
m_server.start_accept();
// Start the ASIO io_service run loop
try {
m_server.run();
} catch (const std::exception & e) {
std::cout << e.what() << std::endl;
} catch (websocketpp::lib::error_code e) {
std::cout << e.message() << std::endl;
} catch (...) {
std::cout << "other exception" << std::endl;
}
}
void on_open(connection_hdl hdl) {
unique_lock<mutex> lock(m_action_lock);
//std::cout << "on_open" << std::endl;
m_actions.push(action(SUBSCRIBE,hdl));
lock.unlock();
m_action_cond.notify_one();
}
void on_close(connection_hdl hdl) {
unique_lock<mutex> lock(m_action_lock);
//std::cout << "on_close" << std::endl;
m_actions.push(action(UNSUBSCRIBE,hdl));
lock.unlock();
m_action_cond.notify_one();
}
void on_message(connection_hdl hdl, server::message_ptr msg) {
// queue message up for sending by processing thread
unique_lock<mutex> lock(m_action_lock);
//std::cout << "on_message" << std::endl;
m_actions.push(action(MESSAGE,msg));
lock.unlock();
m_action_cond.notify_one();
}
void process_messages() {
while(1) {
unique_lock<mutex> lock(m_action_lock);
while(m_actions.empty()) {
m_action_cond.wait(lock);
}
action a = m_actions.front();
m_actions.pop();
lock.unlock();
if (a.type == SUBSCRIBE) {
unique_lock<mutex> lock(m_connection_lock);
m_connections.insert(a.hdl);
} else if (a.type == UNSUBSCRIBE) {
unique_lock<mutex> lock(m_connection_lock);
m_connections.erase(a.hdl);
} else if (a.type == MESSAGE) {
unique_lock<mutex> lock(m_connection_lock);
con_list::iterator it;
for (it = m_connections.begin(); it != m_connections.end(); ++it) {
m_server.send(*it,a.msg);
}
} else {
// undefined.
}
}
}
private:
typedef std::set<connection_hdl,std::owner_less<connection_hdl>> con_list;
server m_server;
con_list m_connections;
std::queue<action> m_actions;
mutex m_action_lock;
mutex m_connection_lock;
condition_variable m_action_cond;
};
int main() {
try {
broadcast_server server;
// Start a thread to run the processing loop
thread t(bind(&broadcast_server::process_messages,&server));
// Run the asio loop with the main thread
server.run(9002);
t.join();
} catch (std::exception & e) {
std::cout << e.what() << std::endl;
}
}
+23
View File
@@ -0,0 +1,23 @@
CFLAGS = -O2
LDFLAGS =
CXX ?= c++
SHARED ?= "1"
ifeq ($(SHARED), 1)
LDFLAGS := $(LDFLAGS) -lboost_system -lboost_thread -lwebsocketpp
else
LDFLAGS := $(LDFLAGS) -lboost_system -lboost_thread -lboost_date_time -lboost_regex -lboost_random ../../libwebsocketpp.a
endif
chat_client: chat_client.o chat_client_handler.o
$(CXX) $(CFLAGS) $^ -o $@ $(LDFLAGS)
%.o: %.cpp
$(CXX) -c $(CFLAGS) -o $@ $^
# cleanup by removing generated files
#
.PHONY: clean
clean:
rm -f *.o chat_client
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, Peter Thorson. All rights reserved.
* Copyright (c) 2011, Peter Thorson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -11,10 +11,10 @@
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@@ -22,28 +22,57 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*/
//#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE transport_asio_base
#include <boost/test/unit_test.hpp>
#include "chat_client_handler.hpp"
#include "../../src/websocketpp.hpp"
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <iostream>
#include <websocketpp/transport/asio/base.hpp>
using boost::asio::ip::tcp;
using namespace websocketchat;
BOOST_AUTO_TEST_CASE( blank_error ) {
websocketpp::lib::error_code ec;
int main(int argc, char* argv[]) {
std::string uri;
if (argc != 2) {
std::cout << "Usage: `chat_client ws_uri`" << std::endl;
} else {
uri = argv[1];
}
chat_client_handler_ptr c(new chat_client_handler());
try {
boost::asio::io_service io_service;
websocketpp::client_ptr client(new websocketpp::client(io_service,c));
client->init();
BOOST_CHECK( !ec );
}
BOOST_AUTO_TEST_CASE( asio_error ) {
using websocketpp::transport::asio::error::make_error_code;
using websocketpp::transport::asio::error::general;
websocketpp::lib::error_code ec = make_error_code(general);
BOOST_CHECK( ec == general );
BOOST_CHECK( ec.value() == 1 );
client->set_header("User Agent","WebSocket++/2011-09-25");
client->add_subprotocol("com.zaphoyd.websocketpp.chat");
client->set_origin("http://zaphoyd.com");
client->connect(uri);
boost::thread t(boost::bind(&boost::asio::io_service::run, &io_service));
char line[512];
while (std::cin.getline(line, 512)) {
c->send(line);
}
t.join();
} catch (std::exception& e) {
std::cerr << "Exception: " << e.what() << std::endl;
}
return 0;
}
+177
View File
@@ -0,0 +1,177 @@
<!doctype html>
<html>
<head>
<script type="text/javascript" src="jquery-1.6.3.min.js"></script>
</head>
<body>
<script type="text/javascript">
var ws;
var url;
$(document).ready(init);
function init() {
$(document).keypress(function(event) {
if ( event.which == 13 ) {
event.preventDefault();
send();
}
});
}
function connect() {
url = $("#server_url").val();
console.log(url);
if ("WebSocket" in window) {
ws = new WebSocket(url);
} else if ("MozWebSocket" in window) {
ws = new MozWebSocket(url);
} else {
chat_message("This Browser does not support WebSockets");
return;
}
ws.onopen = function(e) {
chat_message("A connection to "+url+" has been opened.");
$("#server_url").attr("disabled",true);
$("#toggle_connect").html("Disconnect");
};
ws.onerror = function(e) {
chat_message("An error occured, see console log for more details.");
console.log(e);
};
ws.onclose = function(e) {
chat_message("The connection to "+url+" was closed.");
};
ws.onmessage = function(e) {
var message = JSON.parse(e.data);
if (message.type == "msg") {
chat_message(message.value,message.sender);
} else if (message.type == "participants") {
var o = "<ul>";
for (var p in message.value) {
o += "<li>"+message.value[p]+"</li>";
}
o += "</ul>";
$("#participants").html(o);
}
};
}
function chat_message(message,sender) {
if (arguments.length == 1) {
sender = "";
}
var style;
if (sender == "") {
style = "client";
} else if (sender == "server") {
style = "server";
sender = "["+sender+"]";
} else {
style = "message";
sender = "["+sender+"]";
}
$("#messages").append("<span class='"+style+"'><span class='sender'>"+sender+"</span> <span class='msg'>"+message+"</span></span><br />");
$("#messages").prop({ scrollTop: $("#messages").prop("scrollHeight") });
}
function disconnect() {
ws.close();
$("#server_url").removeAttr("disabled");
$("#toggle_connect").html("Connect");
$("#participants").html("");
}
function toggle_connect() {
if ($("#server_url").attr("disabled") != "disabled") {
connect();
} else {
disconnect();
}
}
function send() {
if (ws === undefined || ws.readyState != 1) {
chat_message("Websocket is not avaliable for writing");
return;
}
ws.send($("#msg").val());
$("#msg").val("");
}
</script>
<style>
body,html {
margin: 0px;
padding: 0px;
height: 100%;
background-color: #999;
font-family: sans-serif;
font-size: 14px;
}
h3 {
}
#controls {
padding: 4px;
float:right;
width: 300px;
}
input {
width: 200px;
}
#messages {
height: 100%;
overflow: auto;
background-color: black;
}
#messages .client {
color: #ccc;
}
#messages .server {
color: yellow;
}
#messages .message {
color: white;
}
</style>
<div id="controls">
<div id="server">
<input type="text" name="server_url" id="server_url" value="ws://thor-websocket.zaphoyd.net:9000/chat" />
<button id="toggle_connect" onclick="toggle_connect();">Connect</button>
</div>
<div id="message_input"><input type="text" name="msg" id="msg" value="Hello World!" />
<button onclick="send();">Send</button></div>
<h3>Chat Participants</h3>
<div id="participants"></div>
</div>
<div id="messages"></div>
</body>
</html>
@@ -0,0 +1,171 @@
/*
* Copyright (c) 2011, Peter Thorson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "chat_client_handler.hpp"
#include <boost/algorithm/string/replace.hpp>
using websocketchat::chat_client_handler;
using websocketpp::client_session_ptr;
void chat_client_handler::on_open(session_ptr s) {
// not sure if anything needs to happen here.
m_session = s;
std::cout << "Successfully connected" << std::endl;
}
void chat_client_handler::on_close(session_ptr s) {
// not sure if anything needs to happen here either.
m_session = client_session_ptr();
std::cout << "client was disconnected" << std::endl;
}
void chat_client_handler::on_message(session_ptr s,const std::string &msg) {
//std::cout << "message from server: " << msg << std::endl;
decode_server_msg(msg);
}
// CLIENT API
// client api methods will be called from outside the io_service.run thread
// they need to be careful to not touch unsyncronized member variables.
void chat_client_handler::send(const std::string &msg) {
if (!m_session) {
std::cerr << "Error: no connected session" << std::endl;
return;
}
m_session->io_service().post(boost::bind(&chat_client_handler::do_send, this, msg));
}
void chat_client_handler::close() {
if (!m_session) {
std::cerr << "Error: no connected session" << std::endl;
return;
}
m_session->io_service().post(boost::bind(&chat_client_handler::do_close,this));
}
// END CLIENT API
void chat_client_handler::do_send(const std::string &msg) {
if (!m_session) {
std::cerr << "Error: no connected session" << std::endl;
return;
}
// check for local commands
if (msg == "/list") {
std::cout << "list all participants" << std::endl;
} else if (msg == "/close") {
do_close();
} else {
m_session->send(msg);
}
}
void chat_client_handler::do_close() {
if (!m_session) {
std::cerr << "Error: no connected session" << std::endl;
return;
}
m_session->close(websocketpp::session::CLOSE_STATUS_GOING_AWAY,"");
}
// {"type":"participants","value":[<participant>,...]}
// {"type":"msg","sender":"<sender>","value":"<msg>" }
void chat_client_handler::decode_server_msg(const std::string &msg) {
// for messages of type participants, erase and rebuild m_participants
// for messages of type msg, print out message
// NOTE: The chat server was written with the intention of the client having a built in
// JSON parser. To keep external dependencies low for this demonstration chat client I am
// parsing the server messages by hand.
std::string::size_type start = 9;
std::string::size_type end;
if (msg.substr(0,start) != "{\"type\":\"") {
// ignore
std::cout << "invalid message" << std::endl;
return;
}
if (msg.substr(start,15) == "msg\",\"sender\":\"") {
// parse message
std::string sender;
std::string message;
start += 15;
end = msg.find("\"",start);
while (end != std::string::npos) {
if (msg[end-1] == '\\') {
sender += msg.substr(start,end-start-1) + "\"";
start = end+1;
end = msg.find("\"",start);
} else {
sender += msg.substr(start,end-start);
start = end;
break;
}
}
if (msg.substr(start,11) != "\",\"value\":\"") {
std::cout << "invalid message" << std::endl;
return;
}
start += 11;
end = msg.find("\"",start);
while (end != std::string::npos) {
if (msg[end-1] == '\\') {
message += msg.substr(start,end-start-1) + "\"";
start = end+1;
end = msg.find("\"",start);
} else {
message += msg.substr(start,end-start);
start = end;
break;
}
}
std::cout << "[" << sender << "] " << message << std::endl;
} else if (msg.substr(start,23) == "participants\",\"value\":[") {
// parse participants
std::cout << "participants message" << std::endl;
} else {
// unknown message type
std::cout << "unknown message" << std::endl;
}
}
@@ -0,0 +1,94 @@
/*
* Copyright (c) 2011, Peter Thorson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef CHAT_CLIENT_HANDLER_HPP
#define CHAT_CLIENT_HANDLER_HPP
// com.zaphoyd.websocketpp.chat protocol
//
// client messages:
// alias [UTF8 text, 16 characters max]
// msg [UTF8 text]
//
// server messages:
// {"type":"msg","sender":"<sender>","value":"<msg>" }
// {"type":"participants","value":[<participant>,...]}
#include <boost/shared_ptr.hpp>
#include "../../src/websocketpp.hpp"
#include "../../src/websocket_connection_handler.hpp"
#include <map>
#include <string>
#include <queue>
using websocketpp::session_ptr;
namespace websocketchat {
class chat_client_handler : public websocketpp::connection_handler {
public:
chat_client_handler() {}
virtual ~chat_client_handler() {}
// ignored for clients?
void validate(session_ptr s) {}
// connection to chat room complete
void on_open(session_ptr s);
// connection to chat room closed
void on_close(session_ptr s);
// got a new message from server
void on_message(session_ptr s,const std::string &msg);
// ignore messages
void on_message(session_ptr s,const std::vector<unsigned char> &data) {}
// CLIENT API
void send(const std::string &msg);
void close();
private:
// Client API internal
void do_send(const std::string &msg);
void do_close();
void decode_server_msg(const std::string &msg);
// list of other chat participants
std::set<std::string> m_participants;
std::queue<std::string> m_msg_queue;
session_ptr m_session;
};
typedef boost::shared_ptr<chat_client_handler> chat_client_handler_ptr;
}
#endif // CHAT_CLIENT_HANDLER_HPP
File diff suppressed because one or more lines are too long
+23
View File
@@ -0,0 +1,23 @@
CFLAGS = -O2
LDFLAGS =
CXX ?= c++
SHARED ?= "1"
ifeq ($(SHARED), 1)
LDFLAGS := $(LDFLAGS) -lboost_system -lboost_date_time -lwebsocketpp
else
LDFLAGS := $(LDFLAGS) -lboost_system -lboost_date_time -lboost_regex -lboost_random -lboost_program_options ../../libwebsocketpp.a
endif
chat_server: chat_server.o chat.o
$(CXX) $(CFLAGS) $^ -o $@ $(LDFLAGS)
%.o: %.cpp
$(CXX) -c $(CFLAGS) -o $@ $^
# cleanup by removing generated files
#
.PHONY: clean
clean:
rm -f *.o chat_server
+192
View File
@@ -0,0 +1,192 @@
/*
* Copyright (c) 2011, Peter Thorson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "chat.hpp"
#include <boost/algorithm/string/replace.hpp>
using websocketchat::chat_server_handler;
using websocketpp::session_ptr;
void chat_server_handler::validate(session_ptr client) {
std::stringstream err;
// We only know about the chat resource
if (client->get_resource() != "/chat") {
err << "Request for unknown resource " << client->get_resource();
throw(websocketpp::handshake_error(err.str(),404));
}
// Require specific origin example
if (client->get_origin() != "http://zaphoyd.com") {
err << "Request from unrecognized origin: " << client->get_origin();
throw(websocketpp::handshake_error(err.str(),403));
}
}
void chat_server_handler::on_open(session_ptr client) {
std::cout << "client " << client << " joined the lobby." << std::endl;
m_connections.insert(std::pair<session_ptr,std::string>(client,get_con_id(client)));
// send user list and signon message to all clients
send_to_all(serialize_state());
client->send(encode_message("server","Welcome, use the /alias command to set a name, /help for a list of other commands."));
send_to_all(encode_message("server",m_connections[client]+" has joined the chat."));
}
void chat_server_handler::on_close(session_ptr client) {
std::map<session_ptr,std::string>::iterator it = m_connections.find(client);
if (it == m_connections.end()) {
// this client has already disconnected, we can ignore this.
// this happens during certain types of disconnect where there is a
// deliberate "soft" disconnection preceeding the "hard" socket read
// fail or disconnect ack message.
return;
}
std::cout << "client " << client << " left the lobby." << std::endl;
const std::string alias = it->second;
m_connections.erase(it);
// send user list and signoff message to all clients
send_to_all(serialize_state());
send_to_all(encode_message("server",alias+" has left the chat."));
}
void chat_server_handler::on_message(session_ptr client,const std::string &msg) {
std::cout << "message from client " << client << ": " << msg << std::endl;
// check for special command messages
if (msg == "/help") {
// print command list
client->send(encode_message("server","avaliable commands:<br />&nbsp;&nbsp;&nbsp;&nbsp;/help - show this help<br />&nbsp;&nbsp;&nbsp;&nbsp;/alias foo - set alias to foo",false));
return;
}
if (msg.substr(0,7) == "/alias ") {
std::string response;
std::string alias;
if (msg.size() == 7) {
response = "You must enter an alias.";
client->send(encode_message("server",response));
return;
} else {
alias = msg.substr(7);
}
response = m_connections[client] + " is now known as "+alias;
// store alias pre-escaped so we don't have to do this replacing every time this
// user sends a message
// escape JSON characters
boost::algorithm::replace_all(alias,"\\","\\\\");
boost::algorithm::replace_all(alias,"\"","\\\"");
// escape HTML characters
boost::algorithm::replace_all(alias,"&","&amp;");
boost::algorithm::replace_all(alias,"<","&lt;");
boost::algorithm::replace_all(alias,">","&gt;");
m_connections[client] = alias;
// set alias
send_to_all(serialize_state());
send_to_all(encode_message("server",response));
return;
}
// catch other slash commands
if (msg[0] == '/') {
client->send(encode_message("server","unrecognized command"));
return;
}
// create JSON message to send based on msg
send_to_all(encode_message(m_connections[client],msg));
}
// {"type":"participants","value":[<participant>,...]}
std::string chat_server_handler::serialize_state() {
std::stringstream s;
s << "{\"type\":\"participants\",\"value\":[";
std::map<session_ptr,std::string>::iterator it;
for (it = m_connections.begin(); it != m_connections.end(); it++) {
s << "\"" << (*it).second << "\"";
if (++it != m_connections.end()) {
s << ",";
}
it--;
}
s << "]}";
return s.str();
}
// {"type":"msg","sender":"<sender>","value":"<msg>" }
std::string chat_server_handler::encode_message(std::string sender,std::string msg,bool escape) {
std::stringstream s;
// escape JSON characters
boost::algorithm::replace_all(msg,"\\","\\\\");
boost::algorithm::replace_all(msg,"\"","\\\"");
// escape HTML characters
if (escape) {
boost::algorithm::replace_all(msg,"&","&amp;");
boost::algorithm::replace_all(msg,"<","&lt;");
boost::algorithm::replace_all(msg,">","&gt;");
}
s << "{\"type\":\"msg\",\"sender\":\"" << sender
<< "\",\"value\":\"" << msg << "\"}";
return s.str();
}
std::string chat_server_handler::get_con_id(session_ptr s) {
std::stringstream endpoint;
endpoint << s->socket().remote_endpoint();
return endpoint.str();
}
void chat_server_handler::send_to_all(std::string data) {
std::map<session_ptr,std::string>::iterator it;
for (it = m_connections.begin(); it != m_connections.end(); it++) {
(*it).first->send(data);
}
}
+83
View File
@@ -0,0 +1,83 @@
/*
* Copyright (c) 2011, Peter Thorson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef CHAT_HPP
#define CHAT_HPP
// com.zaphoyd.websocketpp.chat protocol
//
// client messages:
// alias [UTF8 text, 16 characters max]
// msg [UTF8 text]
//
// server messages:
// {"type":"msg","sender":"<sender>","value":"<msg>" }
// {"type":"participants","value":[<participant>,...]}
#include <boost/shared_ptr.hpp>
#include "../../src/websocketpp.hpp"
#include "../../src/websocket_connection_handler.hpp"
#include <map>
#include <string>
#include <vector>
namespace websocketchat {
class chat_server_handler : public websocketpp::connection_handler {
public:
chat_server_handler() {}
virtual ~chat_server_handler() {}
void validate(websocketpp::session_ptr client);
// add new connection to the lobby
void on_open(websocketpp::session_ptr client);
// someone disconnected from the lobby, remove them
void on_close(websocketpp::session_ptr client);
void on_message(websocketpp::session_ptr client,const std::string &msg);
// lobby will ignore binary messages
void on_message(websocketpp::session_ptr client,
const std::vector<unsigned char> &data) {}
private:
std::string serialize_state();
std::string encode_message(std::string sender,std::string msg,bool escape = true);
std::string get_con_id(websocketpp::session_ptr s);
void send_to_all(std::string data);
// list of outstanding connections
std::map<websocketpp::session_ptr,std::string> m_connections;
};
typedef boost::shared_ptr<chat_server_handler> chat_server_handler_ptr;
}
#endif // CHAT_HPP
+177
View File
@@ -0,0 +1,177 @@
<!doctype html>
<html>
<head>
<script type="text/javascript" src="jquery-1.6.3.min.js"></script>
</head>
<body>
<script type="text/javascript">
var ws;
var url;
$(document).ready(init);
function init() {
$(document).keypress(function(event) {
if ( event.which == 13 ) {
event.preventDefault();
send();
}
});
}
function connect() {
url = $("#server_url").val();
console.log(url);
if ("WebSocket" in window) {
ws = new WebSocket(url);
} else if ("MozWebSocket" in window) {
ws = new MozWebSocket(url);
} else {
chat_message("This Browser does not support WebSockets");
return;
}
ws.onopen = function(e) {
chat_message("A connection to "+url+" has been opened.");
$("#server_url").attr("disabled",true);
$("#toggle_connect").html("Disconnect");
};
ws.onerror = function(e) {
chat_message("An error occured, see console log for more details.");
console.log(e);
};
ws.onclose = function(e) {
chat_message("The connection to "+url+" was closed.");
};
ws.onmessage = function(e) {
var message = JSON.parse(e.data);
if (message.type == "msg") {
chat_message(message.value,message.sender);
} else if (message.type == "participants") {
var o = "<ul>";
for (var p in message.value) {
o += "<li>"+message.value[p]+"</li>";
}
o += "</ul>";
$("#participants").html(o);
}
};
}
function chat_message(message,sender) {
if (arguments.length == 1) {
sender = "";
}
var style;
if (sender == "") {
style = "client";
} else if (sender == "server") {
style = "server";
sender = "["+sender+"]";
} else {
style = "message";
sender = "["+sender+"]";
}
$("#messages").append("<span class='"+style+"'><span class='sender'>"+sender+"</span> <span class='msg'>"+message+"</span></span><br />");
$("#messages").prop({ scrollTop: $("#messages").prop("scrollHeight") });
}
function disconnect() {
ws.close();
$("#server_url").removeAttr("disabled");
$("#toggle_connect").html("Connect");
$("#participants").html("");
}
function toggle_connect() {
if ($("#server_url").attr("disabled") != "disabled") {
connect();
} else {
disconnect();
}
}
function send() {
if (ws === undefined || ws.readyState != 1) {
chat_message("Websocket is not avaliable for writing");
return;
}
ws.send($("#msg").val());
$("#msg").val("");
}
</script>
<style>
body,html {
margin: 0px;
padding: 0px;
height: 100%;
background-color: #999;
font-family: sans-serif;
font-size: 14px;
}
h3 {
}
#controls {
padding: 4px;
float:right;
width: 300px;
}
input {
width: 200px;
}
#messages {
height: 100%;
overflow: auto;
background-color: black;
}
#messages .client {
color: #ccc;
}
#messages .server {
color: yellow;
}
#messages .message {
color: white;
}
</style>
<div id="controls">
<div id="server">
<input type="text" name="server_url" id="server_url" value="ws://thor-websocket.zaphoyd.net:9000/chat" />
<button id="toggle_connect" onclick="toggle_connect();">Connect</button>
</div>
<div id="message_input"><input type="text" name="msg" id="msg" value="Hello World!" />
<button onclick="send();">Send</button></div>
<h3>Chat Participants</h3>
<div id="participants"></div>
</div>
<div id="messages"></div>
</body>
</html>
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Peter Thorson. All rights reserved.
* Copyright (c) 2011, Peter Thorson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -11,10 +11,10 @@
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@@ -22,51 +22,63 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*/
//#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE message
#include <boost/test/unit_test.hpp>
#include "chat.hpp"
#include "../../src/websocketpp.hpp"
#include <boost/asio.hpp>
#include <iostream>
#include <string>
#include <websocketpp/message_buffer/message.hpp>
using boost::asio::ip::tcp;
using namespace websocketchat;
template <typename message>
struct stub {
typedef websocketpp::lib::weak_ptr<stub> weak_ptr;
typedef websocketpp::lib::shared_ptr<stub> ptr;
stub() : recycled(false) {}
bool recycle(message * msg) {
this->recycled = true;
return false;
int main(int argc, char* argv[]) {
std::string host = "localhost";
short port = 9003;
std::string full_host;
if (argc == 3) {
// TODO: input validation?
host = argv[1];
port = atoi(argv[2]);
}
bool recycled;
};
BOOST_AUTO_TEST_CASE( basic_size_check ) {
typedef websocketpp::message_buffer::message<stub> message_type;
typedef stub<message_type> stub_type;
stub_type::ptr s(new stub_type());
message_type::ptr msg(new message_type(s,websocketpp::frame::opcode::TEXT,500));
BOOST_CHECK(msg->get_payload().capacity() >= 500);
std::stringstream temp;
temp << host << ":" << port;
full_host = temp.str();
chat_server_handler_ptr chat_handler(new chat_server_handler());
try {
boost::asio::io_service io_service;
tcp::endpoint endpoint(tcp::v6(), port);
websocketpp::server_ptr server(
new websocketpp::server(io_service,endpoint,chat_handler)
);
// setup server settings
server->add_host(host);
server->add_host(full_host);
// Chat server should only be receiving small text messages, reduce max
// message size limit slightly to save memory, improve performance, and
// guard against DoS attacks.
server->set_max_message_size(0xFFFF); // 64KiB
// start the server
server->start_accept();
std::cout << "Starting chat server on " << full_host << std::endl;
io_service.run();
} catch (std::exception& e) {
std::cerr << "Exception: " << e.what() << std::endl;
}
return 0;
}
BOOST_AUTO_TEST_CASE( recycle ) {
typedef websocketpp::message_buffer::message<stub> message_type;
typedef stub<message_type> stub_type;
stub_type::ptr s(new stub_type());
message_type::ptr msg(new message_type(s,websocketpp::frame::opcode::TEXT,500));
BOOST_CHECK(s->recycled == false);
BOOST_CHECK(msg->recycle() == false);
BOOST_CHECK(s->recycled == true);
}
File diff suppressed because one or more lines are too long
-18
View File
@@ -1,18 +0,0 @@
## Main development example
##
Import('env')
Import('env_cpp11')
Import('boostlibs')
Import('platform_libs')
Import('polyfill_libs')
env_cpp11 = env_cpp11.Clone ()
prgs = []
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
BOOST_LIBS_CPP11 = boostlibs(['unit_test_framework','system','timer','chrono'],env_cpp11) + [platform_libs] + [polyfill_libs]
prgs += env_cpp11.Program('main', ["main.cpp"], LIBS = BOOST_LIBS_CPP11)
Return('prgs')
-200
View File
@@ -1,200 +0,0 @@
//#ifndef _WEBSOCKETPP_CPP11_STL_
// #define _WEBSOCKETPP_CPP11_STL_
//#endif
#include <random>
#include <boost/timer/timer.hpp>
#include <websocketpp/config/core.hpp>
//#include <websocketpp/security/none.hpp>
//#include <websocketpp/concurrency/none.hpp>
//#include <websocketpp/concurrency/stl.hpp>
//#include <websocketpp/transport/iostream.hpp>
#include <websocketpp/server.hpp>
#include <iostream>
#include <sstream>
//typedef websocketpp::concurrency::stl concurrency;
//typedef websocketpp::transport::iostream<concurrency> transport;
//typedef websocketpp::server<concurrency,transport> server;
typedef websocketpp::server<websocketpp::config::core> server;
/*class handler : public server::handler {
bool validate(connection_ptr con) {
std::cout << "handler validate" << std::endl;
if (con->get_origin() != "http://www.example.com") {
con->set_status(websocketpp::http::status_code::FORBIDDEN);
return false;
}
return true;
}
void http(connection_ptr con) {
std::cout << "handler http" << std::endl;
}
void on_load(connection_ptr con, ptr old_handler) {
std::cout << "handler on_load" << std::endl;
}
void on_unload(connection_ptr con, ptr new_handler) {
std::cout << "handler on_unload" << std::endl;
}
void on_open(connection_ptr con) {
std::cout << "handler on_open" << std::endl;
}
void on_fail(connection_ptr con) {
std::cout << "handler on_fail" << std::endl;
}
void on_message(connection_ptr con, message_ptr msg) {
std::cout << "handler on_message" << std::endl;
}
void on_close(connection_ptr con) {
std::cout << "handler on_close" << std::endl;
}
};*/
int main() {
typedef websocketpp::message_buffer::message<websocketpp::message_buffer::alloc::con_msg_manager>
message_type;
typedef websocketpp::message_buffer::alloc::con_msg_manager<message_type>
con_msg_man_type;
con_msg_man_type::ptr manager(new con_msg_man_type());
size_t foo = 1024;
message_type::ptr input = manager->get_message(websocketpp::frame::opcode::TEXT,foo);
message_type::ptr output = manager->get_message(websocketpp::frame::opcode::TEXT,foo);
websocketpp::frame::masking_key_type key;
std::random_device dev;
key.i = 0x12345678;
double m = 18094238402394.0824923;
/*std::cout << "Some Math" << std::endl;
{
boost::timer::auto_cpu_timer t;
for (int i = 0; i < foo; i++) {
m /= 1.001;
}
}*/
std::cout << m << std::endl;
std::cout << "Random Gen" << std::endl;
{
boost::timer::auto_cpu_timer t;
input->get_raw_payload().replace(0,foo,foo,'\0');
output->get_raw_payload().replace(0,foo,foo,'\0');
}
std::cout << "Out of place accelerated" << std::endl;
{
boost::timer::auto_cpu_timer t;
websocketpp::frame::word_mask_exact(reinterpret_cast<uint8_t*>(const_cast<char*>(input->get_raw_payload().data())), reinterpret_cast<uint8_t*>(const_cast<char*>(output->get_raw_payload().data())), foo, key);
}
std::cout << websocketpp::utility::to_hex(input->get_payload().c_str(),20) << std::endl;
std::cout << websocketpp::utility::to_hex(output->get_payload().c_str(),20) << std::endl;
input->get_raw_payload().replace(0,foo,foo,'\0');
output->get_raw_payload().replace(0,foo,foo,'\0');
std::cout << "In place accelerated" << std::endl;
{
boost::timer::auto_cpu_timer t;
websocketpp::frame::word_mask_exact(reinterpret_cast<uint8_t*>(const_cast<char*>(input->get_raw_payload().data())), reinterpret_cast<uint8_t*>(const_cast<char*>(input->get_raw_payload().data())), foo, key);
}
std::cout << websocketpp::utility::to_hex(input->get_payload().c_str(),20) << std::endl;
std::cout << websocketpp::utility::to_hex(output->get_payload().c_str(),20) << std::endl;
input->get_raw_payload().replace(0,foo,foo,'\0');
output->get_raw_payload().replace(0,foo,foo,'\0');
std::cout << "Out of place byte by byte" << std::endl;
{
boost::timer::auto_cpu_timer t;
websocketpp::frame::byte_mask(input->get_raw_payload().begin(), input->get_raw_payload().end(), output->get_raw_payload().begin(), key);
}
std::cout << websocketpp::utility::to_hex(input->get_payload().c_str(),20) << std::endl;
std::cout << websocketpp::utility::to_hex(output->get_payload().c_str(),20) << std::endl;
input->get_raw_payload().replace(0,foo,foo,'\0');
output->get_raw_payload().replace(0,foo,foo,'\0');
std::cout << "In place byte by byte" << std::endl;
{
boost::timer::auto_cpu_timer t;
websocketpp::frame::byte_mask(input->get_raw_payload().begin(), input->get_raw_payload().end(), input->get_raw_payload().begin(), key);
}
std::cout << websocketpp::utility::to_hex(input->get_payload().c_str(),20) << std::endl;
std::cout << websocketpp::utility::to_hex(output->get_payload().c_str(),20) << std::endl;
input->get_raw_payload().replace(0,foo,foo,'a');
output->get_raw_payload().replace(0,foo,foo,'b');
std::cout << "Copy" << std::endl;
{
boost::timer::auto_cpu_timer t;
std::copy(input->get_raw_payload().begin(), input->get_raw_payload().end(), output->get_raw_payload().begin());
}
std::cout << websocketpp::utility::to_hex(input->get_payload().c_str(),20) << std::endl;
std::cout << websocketpp::utility::to_hex(output->get_payload().c_str(),20) << std::endl;
/*server::handler::ptr h(new handler());
server test_server(h);
server::connection_ptr con;
std::stringstream output;
test_server.register_ostream(&output);
con = test_server.get_connection();
con->start();
//foo.handle_accept(con,true);
std::stringstream input;
input << "GET / HTTP/1.1\r\nHost: www.example.com\r\nConnection: upgrade\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 13\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\nOrigin: http://www.example.com\r\n\r\n";
//input << "GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n";
input >> *con;
std::stringstream input2;
input2 << "messageabc2";
input2 >> *con;
std::stringstream input3;
input3 << "messageabc3";
input3 >> *con;
std::stringstream input4;
input4 << "close";
input4 >> *con;
std::cout << "connection output:" << std::endl;
std::cout << output.str() << std::endl;*/
}
+23
View File
@@ -0,0 +1,23 @@
CFLAGS = -O2
LDFLAGS =
CXX ?= c++
SHARED ?= "1"
ifeq ($(SHARED), 1)
LDFLAGS := $(LDFLAGS) -lboost_system -lboost_thread -lwebsocketpp
else
LDFLAGS := $(LDFLAGS) -lboost_system -lboost_thread -lboost_date_time -lboost_regex -lboost_random -lboost_program_options ../../libwebsocketpp.a
endif
echo_client: echo_client.o echo_client_handler.o
$(CXX) $(CFLAGS) $^ -o $@ $(LDFLAGS)
%.o: %.cpp
$(CXX) -c $(CFLAGS) -o $@ $^
# cleanup by removing generated files
#
.PHONY: clean
clean:
rm -f *.o echo_client
+90
View File
@@ -0,0 +1,90 @@
/*
* Copyright (c) 2011, Peter Thorson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "echo_client_handler.hpp"
#include "../../src/websocketpp.hpp"
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <iostream>
using boost::asio::ip::tcp;
using namespace websocketecho;
int main(int argc, char* argv[]) {
std::string uri;
/*if (argc != 2) {
std::cout << "Usage: `echo_client test_url`" << std::endl;
} else {
uri = argv[1];
}*/
echo_client_handler_ptr c(new echo_client_handler());
try {
boost::asio::io_service io_service;
websocketpp::client_ptr client(new websocketpp::client(io_service,c));
client->init();
client->set_header("User Agent","WebSocket++/2011-10-27");
client->connect("ws://localhost:9001/getCaseCount");
io_service.run();
std::cout << "case count: " << c->m_case_count << std::endl;
for (int i = 1; i <= c->m_case_count; i++) {
io_service.reset();
client->set_alog_level(websocketpp::ALOG_OFF);
client->set_elog_level(websocketpp::LOG_OFF);
client->init();
client->set_header("User Agent","WebSocket++/2011-10-27");
std::stringstream url;
url << "ws://localhost:9001/runCase?case=" << i << "&agent=\"WebSocket++Snapshot/2011-10-27\"";
client->connect(url.str());
io_service.run();
}
std::cout << "done" << std::endl;
} catch (std::exception& e) {
std::cerr << "Exception: " << e.what() << std::endl;
}
return 0;
}
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, Peter Thorson. All rights reserved.
* Copyright (c) 2011, Peter Thorson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -11,10 +11,10 @@
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@@ -22,36 +22,35 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*/
#include "connection_tu2.hpp"
#include "echo_client_handler.hpp"
void echo_func(server* s, websocketpp::connection_hdl hdl, message_ptr msg) {
s->send(hdl, msg->get_payload(), msg->get_opcode());
#include <boost/algorithm/string/replace.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
using websocketecho::echo_client_handler;
using websocketpp::client_session_ptr;
void echo_client_handler::on_open(session_ptr s) {
std::cout << " Successfully connected (handshake complete): " << s->get_resource() << std::endl;
}
std::string run_server_test(std::string input) {
server test_server;
return run_server_test(test_server,input);
void echo_client_handler::on_close(session_ptr s) {
std::cout << " client was disconnected (WS state is now CLOSED)" << std::endl;
}
std::string run_server_test(server & s, std::string input) {
server::connection_ptr con;
std::stringstream output;
s.clear_access_channels(websocketpp::log::alevel::all);
s.clear_error_channels(websocketpp::log::elevel::all);
s.register_ostream(&output);
con = s.get_connection();
con->start();
std::stringstream channel;
channel << input;
channel >> *con;
return output.str();
void echo_client_handler::on_message(session_ptr s,const std::string &msg) {
if (s->get_resource() == "/getCaseCount") {
std::cout << "Detected " << msg << " test cases." << std::endl;
m_case_count = atoi(msg.c_str());
} else {
s->send(msg);
}
}
void echo_client_handler::on_message(session_ptr s,
const std::vector<unsigned char> &data) {
s->send(data);
}
@@ -11,10 +11,10 @@
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@@ -22,52 +22,56 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*/
//#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE utility
#include <boost/test/unit_test.hpp>
#include <iostream>
#ifndef ECHO_CLIENT_HANDLER_HPP
#define ECHO_CLIENT_HANDLER_HPP
// com.zaphoyd.websocketpp.chat protocol
//
// client messages:
// alias [UTF8 text, 16 characters max]
// msg [UTF8 text]
//
// server messages:
// {"type":"msg","sender":"<sender>","value":"<msg>" }
// {"type":"participants","value":[<participant>,...]}
#include <boost/shared_ptr.hpp>
#include "../../src/websocketpp.hpp"
#include "../../src/websocket_connection_handler.hpp"
#include <map>
#include <string>
#include <queue>
#include <websocketpp/utilities.hpp>
using websocketpp::session_ptr;
BOOST_AUTO_TEST_SUITE ( utility )
namespace websocketecho {
BOOST_AUTO_TEST_CASE( substr_found ) {
std::string haystack = "abc123";
std::string needle = "abc";
class echo_client_handler : public websocketpp::connection_handler {
public:
echo_client_handler() : m_case_count(0) {}
virtual ~echo_client_handler() {}
// connection to chat room complete
void on_open(session_ptr s);
// connection to chat room closed
void on_close(session_ptr sn);
// got a new message from server
void on_message(session_ptr s,const std::string &msg);
// ignore messages
void on_message(session_ptr s,const std::vector<unsigned char> &data);
int m_case_count;
};
typedef boost::shared_ptr<echo_client_handler> echo_client_handler_ptr;
BOOST_CHECK(websocketpp::utility::ci_find_substr(haystack,needle) ==haystack.begin());
}
BOOST_AUTO_TEST_CASE( substr_found_ci ) {
std::string haystack = "abc123";
std::string needle = "aBc";
BOOST_CHECK(websocketpp::utility::ci_find_substr(haystack,needle) ==haystack.begin());
}
BOOST_AUTO_TEST_CASE( substr_not_found ) {
std::string haystack = "abd123";
std::string needle = "abcd";
BOOST_CHECK(websocketpp::utility::ci_find_substr(haystack,needle) == haystack.end());
}
BOOST_AUTO_TEST_CASE( to_lower ) {
std::string in = "AbCd";
BOOST_CHECK_EQUAL(websocketpp::utility::to_lower(in), "abcd");
}
BOOST_AUTO_TEST_CASE( string_replace_all ) {
std::string source = "foo \"bar\" baz";
std::string dest = "foo \\\"bar\\\" baz";
using websocketpp::utility::string_replace_all;
BOOST_CHECK_EQUAL(string_replace_all(source,"\"","\\\""),dest);
}
BOOST_AUTO_TEST_SUITE_END()
#endif // ECHO_CLIENT_HANDLER_HPP
-10
View File
@@ -1,10 +0,0 @@
file (GLOB SOURCE_FILES *.cpp)
file (GLOB HEADER_FILES *.hpp)
init_target (echo_server)
build_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})
link_boost ()
final_target ()
+23
View File
@@ -0,0 +1,23 @@
CFLAGS = -O2
LDFLAGS =
CXX ?= c++
SHARED ?= "1"
ifeq ($(SHARED), 1)
LDFLAGS := $(LDFLAGS) -lboost_system -lboost_date_time -lwebsocketpp
else
LDFLAGS := $(LDFLAGS) -lboost_system -lboost_date_time -lboost_regex -lboost_random -lboost_program_options ../../libwebsocketpp.a
endif
echo_server: echo_server.o echo.o
$(CXX) $(CFLAGS) $^ -o $@ $(LDFLAGS)
%.o: %.cpp
$(CXX) -c $(CFLAGS) -o $@ $^
# cleanup by removing generated files
#
.PHONY: clean
clean:
rm -f *.o echo_server
-23
View File
@@ -1,23 +0,0 @@
## Main development example
##
Import('env')
Import('env_cpp11')
Import('boostlibs')
Import('platform_libs')
Import('polyfill_libs')
env = env.Clone ()
env_cpp11 = env_cpp11.Clone ()
prgs = []
# if a C++11 environment is available build using that, otherwise use boost
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]
prgs += env_cpp11.Program('echo_server', ["echo_server.cpp"], LIBS = ALL_LIBS)
else:
ALL_LIBS = boostlibs(['system'],env) + [platform_libs] + [polyfill_libs]
prgs += env.Program('echo_server', ["echo_server.cpp"], LIBS = ALL_LIBS)
Return('prgs')
@@ -11,10 +11,10 @@
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@@ -22,16 +22,20 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*/
//#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE extension
#include <boost/test/unit_test.hpp>
#include <string>
#include "echo.hpp"
#include <websocketpp/extensions/extension.hpp>
using websocketecho::echo_server_handler;
BOOST_AUTO_TEST_CASE( blank ) {
BOOST_CHECK( true );
void echo_server_handler::validate(websocketpp::session_ptr client) {}
void echo_server_handler::on_message(websocketpp::session_ptr client, const std::string &msg) {
client->send(msg);
}
void echo_server_handler::on_message(websocketpp::session_ptr client,
const std::vector<unsigned char> &data) {
client->send(data);
}
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, Peter Thorson. All rights reserved.
* Copyright (c) 2011, Peter Thorson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -11,10 +11,10 @@
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@@ -22,42 +22,44 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*/
#ifndef WEBSOCKETPP_LOGGER_STUB_HPP
#define WEBSOCKETPP_LOGGER_STUB_HPP
#ifndef ECHO_SERVER_HANDLER_HPP
#define ECHO_SERVER_HANDLER_HPP
#include "../../src/websocketpp.hpp"
#include "../../src/websocket_connection_handler.hpp"
#include <boost/shared_ptr.hpp>
#include <iostream>
#include <string>
#include <vector>
#include <websocketpp/common/cpp11.hpp>
#include <websocketpp/logger/levels.hpp>
using websocketpp::session_ptr;
namespace websocketpp {
namespace log {
namespace websocketecho {
/// Stub logger that ignores all input
class stub {
class echo_server_handler : public websocketpp::connection_handler {
public:
explicit stub(std::ostream * out) {}
stub(level c, std::ostream * out) {}
_WEBSOCKETPP_CONSTEXPR_TOKEN_ stub() {}
void set_channels(level channels) {}
void clear_channels(level channels) {}
void write(level channel, std::string const & msg) {}
void write(level channel, char const * msg) {}
_WEBSOCKETPP_CONSTEXPR_TOKEN_ bool static_test(level channel) const {
return false;
}
bool dynamic_test(level channel) {
return false;
}
echo_server_handler() {}
virtual ~echo_server_handler() {}
// The echo server allows all domains is protocol free.
void validate(session_ptr client);
// an echo server is stateless.
// The handler has no need to keep track of connected clients.
void on_fail(session_ptr client) {}
void on_open(session_ptr client) {}
void on_close(session_ptr client) {}
// both text and binary messages are echoed back to the sending client.
void on_message(session_ptr client,const std::string &msg);
void on_message(session_ptr client,
const std::vector<unsigned char> &data);
};
} // log
} // websocketpp
typedef boost::shared_ptr<echo_server_handler> echo_server_handler_ptr;
#endif // WEBSOCKETPP_LOGGER_STUB_HPP
}
#endif // ECHO_SERVER_HANDLER_HPP
+94
View File
@@ -0,0 +1,94 @@
<!doctype html>
<html>
<head>
</head>
<body>
<script type="text/javascript">
var ws;
var url;
function connect() {
url = document.getElementById("server_url").value;
console.log(url);
if ("WebSocket" in window) {
ws = new WebSocket(url);
} else if ("MozWebSocket" in window) {
ws = new MozWebSocket(url);
} else {
document.getElementById("messages").innerHTML += "This Browser does not support WebSockets<br />";
return;
}
ws.onopen = function(e) {
document.getElementById("messages").innerHTML += "Client: A connection to "+ws.URL+" has been opened.<br />";
document.getElementById("server_url").disabled = true;
document.getElementById("toggle_connect").innerHTML = "Disconnect";
};
ws.onerror = function(e) {
document.getElementById("messages").innerHTML += "Client: An error occured, see console log for more details.<br />";
console.log(e);
};
ws.onclose = function(e) {
document.getElementById("messages").innerHTML += "Client: The connection to "+url+" was closed.<br />";
};
ws.onmessage = function(e) {
document.getElementById("messages").innerHTML += "Server: "+e.data+"<br />";
};
}
function disconnect() {
ws.close();
document.getElementById("server_url").disabled = false;
document.getElementById("toggle_connect").innerHTML = "Connect";
}
function toggle_connect() {
if (document.getElementById("server_url").disabled === false) {
connect();
} else {
disconnect();
}
}
function send() {
if (ws === undefined || ws.readyState != 1) {
document.getElementById("messages").innerHTML += "Client: Websocket is not avaliable for writing<br />";
return;
}
ws.send(document.getElementById("msg").value);
document.getElementById("msg").value = "";
}
</script>
<style>
body,html {
margin: 0px;
padding: 0px;
}
#controls {
float:right;
background-color: #999;
}
</style>
<div id="controls">
<div id="server">
<input type="text" name="server_url" id="server_url" value="ws://localhost:5000" />
<button id="toggle_connect" onclick="toggle_connect();">Connect</button>
</div>
<div id="message_input"><input type="text" name="msg" id="msg" value="Hello World!" />
<button onclick="send();">Send</button></div>
</div>
<div id="messages"></div>
</body>
</html>
-37
View File
@@ -1,37 +0,0 @@
/*
* Copyright (c) 2012, Peter Thorson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef WEBSOCKETPP_ECHO_SERVER_HANDLER_HPP
#define WEBSOCKETPP_ECHO_SERVER_HANDLER_HPP
class echo_handler : public server::handler {
void on_message(connection_ptr con, std::string msg) {
con->write(msg);
}
};
#endif // WEBSOCKETPP_ECHO_SERVER_HANDLER_HPP
+83 -53
View File
@@ -1,60 +1,90 @@
#include <websocketpp/config/asio_no_tls.hpp>
/*
* Copyright (c) 2011, Peter Thorson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <websocketpp/server.hpp>
#include "echo.hpp"
#include "../../src/websocketpp.hpp"
#include <boost/asio.hpp>
#include <iostream>
typedef websocketpp::server<websocketpp::config::asio> server;
using websocketpp::lib::placeholders::_1;
using websocketpp::lib::placeholders::_2;
using websocketpp::lib::bind;
// pull out the type of messages sent by our config
typedef server::message_ptr message_ptr;
// Define a callback to handle incoming messages
void on_message(server* s, websocketpp::connection_hdl hdl, message_ptr msg) {
std::cout << "on_message called with hdl: " << hdl.lock().get()
<< " and message: " << msg->get_payload()
<< std::endl;
try {
s->send(hdl, msg->get_payload(), msg->get_opcode());
} catch (const websocketpp::lib::error_code& e) {
std::cout << "Echo failed because: " << e
<< "(" << e.message() << ")" << std::endl;
}
}
int main() {
// Create a server endpoint
server echo_server;
using boost::asio::ip::tcp;
int main(int argc, char* argv[]) {
std::string host = "localhost";
short port = 9002;
std::string full_host;
if (argc == 3) {
// TODO: input validation?
host = argv[1];
port = atoi(argv[2]);
}
std::stringstream temp;
temp << host << ":" << port;
full_host = temp.str();
websocketecho::echo_server_handler_ptr echo_handler(new websocketecho::echo_server_handler());
try {
// Set logging settings
echo_server.set_access_channels(websocketpp::log::alevel::all);
echo_server.clear_access_channels(websocketpp::log::alevel::frame_payload);
// Initialize ASIO
echo_server.init_asio();
// Register our message handler
echo_server.set_message_handler(bind(&on_message,&echo_server,::_1,::_2));
// Listen on port 9002
echo_server.listen(9002);
// Start the server accept loop
echo_server.start_accept();
// Start the ASIO io_service run loop
echo_server.run();
} catch (const std::exception & e) {
std::cout << e.what() << std::endl;
} catch (websocketpp::lib::error_code e) {
std::cout << e.message() << std::endl;
} catch (...) {
std::cout << "other exception" << std::endl;
}
boost::asio::io_service io_service;
tcp::endpoint endpoint(tcp::v6(), port);
websocketpp::server_ptr server(
new websocketpp::server(io_service,endpoint,echo_handler)
);
//server->parse_command_line(argc, argv);
// setup server settings
//server->set_alog_level(websocketpp::ALOG_OFF);
//server->set_elog_level(websocketpp::LOG_OFF);
server->add_host(host);
server->add_host(full_host);
// bump up max message size to maximum since we may be using the echo
// server to test performance and protocol extremes.
server->set_max_message_size(websocketpp::frame::PAYLOAD_64BIT_LIMIT);
// start the server
server->start_accept();
std::cout << "Starting echo server on " << full_host << std::endl;
// start asio
io_service.run();
} catch (std::exception& e) {
std::cerr << "Exception: " << e.what() << std::endl;
}
return 0;
}
Binary file not shown.
-15
View File
@@ -1,15 +0,0 @@
file (GLOB SOURCE_FILES *.cpp)
file (GLOB HEADER_FILES *.hpp)
if (OPENSSL_FOUND)
init_target (echo_server_tls)
build_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})
link_boost ()
link_openssl()
final_target ()
endif()
-24
View File
@@ -1,24 +0,0 @@
## Main development example
##
Import('env')
Import('env_cpp11')
Import('boostlibs')
Import('platform_libs')
Import('polyfill_libs')
Import('tls_libs')
env = env.Clone ()
env_cpp11 = env_cpp11.Clone ()
prgs = []
# if a C++11 environment is available build using that, otherwise use boost
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs] + [tls_libs]
prgs += env_cpp11.Program('echo_server_tls', ["echo_server_tls.cpp"], LIBS = ALL_LIBS)
else:
ALL_LIBS = boostlibs(['system'],env) + [platform_libs] + [polyfill_libs] + [tls_libs]
prgs += env.Program('echo_server_tls', ["echo_server_tls.cpp"], LIBS = ALL_LIBS)
Return('prgs')
@@ -1,37 +0,0 @@
/*
* Copyright (c) 2012, Peter Thorson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef WEBSOCKETPP_ECHO_SERVER_HANDLER_HPP
#define WEBSOCKETPP_ECHO_SERVER_HANDLER_HPP
class echo_handler : public server::handler {
void on_message(connection_ptr con, std::string msg) {
con->write(msg);
}
};
#endif // WEBSOCKETPP_ECHO_SERVER_HANDLER_HPP
@@ -1,72 +0,0 @@
#include <websocketpp/config/asio.hpp>
#include <websocketpp/server.hpp>
#include <iostream>
typedef websocketpp::server<websocketpp::config::asio_tls> server;
using websocketpp::lib::placeholders::_1;
using websocketpp::lib::placeholders::_2;
using websocketpp::lib::bind;
// pull out the type of messages sent by our config
typedef websocketpp::config::asio::message_type::ptr message_ptr;
typedef websocketpp::lib::shared_ptr<boost::asio::ssl::context> context_ptr;
void on_message(server* s, websocketpp::connection_hdl hdl, message_ptr msg) {
std::cout << "on_message called with hdl: " << hdl.lock().get()
<< " and message: " << msg->get_payload()
<< std::endl;
try {
s->send(hdl, msg->get_payload(), msg->get_opcode());
} catch (const websocketpp::lib::error_code& e) {
std::cout << "Echo failed because: " << e
<< "(" << e.message() << ")" << std::endl;
}
}
std::string get_password() {
return "test";
}
context_ptr on_tls_init(websocketpp::connection_hdl hdl) {
std::cout << "on_tls_init called with hdl: " << hdl.lock().get() << std::endl;
context_ptr ctx(new boost::asio::ssl::context(boost::asio::ssl::context::tlsv1));
try {
ctx->set_options(boost::asio::ssl::context::default_workarounds |
boost::asio::ssl::context::no_sslv2 |
boost::asio::ssl::context::single_dh_use);
ctx->set_password_callback(bind(&get_password));
ctx->use_certificate_chain_file("server.pem");
ctx->use_private_key_file("server.pem", boost::asio::ssl::context::pem);
} catch (std::exception& e) {
std::cout << e.what() << std::endl;
}
return ctx;
}
int main() {
// Create a server endpoint
server echo_server;
// Initialize ASIO
echo_server.init_asio();
// Register our message handler
echo_server.set_message_handler(bind(&on_message,&echo_server,::_1,::_2));
echo_server.set_tls_init_handler(bind(&on_tls_init,::_1));
// Listen on port 9002
echo_server.listen(9002);
// Start the server accept loop
echo_server.start_accept();
// Start the ASIO io_service run loop
echo_server.run();
}
-58
View File
@@ -1,58 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,A0ED66EF872A48A9
gXuvKojXzApVhhPVNdRliiajbC4PtwQG5c8TA7JADLgwOR7o9t6KtXEr37bDRpvB
9aO9P+SJaK5OOp3XKPGthOdqv+tvCRTlmzmC8GjPLBX389DWT2xoGu7JkGwDtdSm
rnF49Rlp5bfjpACk5xKNiKeDo1CWfeEJzw9Kto0g+5eMaEdors64oPzjXs3geA2g
TxCJSHv9qSX6++pCLKKCUTbyzidAxV/Zb0AAubt5V40QKqX4HhSwwstFnTaX3tlb
3QOdY+y04VIkM6d7qN5W8M7NzRkMpZ1qBpQcUMpkhQcRzWP2wub5AAff9D2GntRd
4Dz1vn3u41U3Okdr0CNj+iH7byCzuokoAhk6ZQEN6WB+GTpGgfBXdtUZrfpb0MKm
UNYP5AF2AmUqJRXhViTDVtu/V2tHF3LGuNT+W2Dz+spFZEq0byEO0N858eR0dikc
6jOASvNQbSwD0+mkgBC1gXKKU3ngj2gpJUwljeACdWFd8N2egrZfyI05CmX7vPNC
NXbs7k2buWNdjP4/D8IM+HDVidWzQa/kG/qokXKqllem9Egg37lUucwnP3cX2/Hw
U2mfaBWzeZtqc+GqRp08rYIql+Reai3sUYlQMnNk01prVY47UQb+dxuqjaxGV5Xx
Xkx0s2mfQnNRjL4S7Hjhqelufi6GpkCQ2EGsPpA+6K1ztZ0ame9Q2BE1SXeM/6vU
rxT5nRrCxueyXAyQSGcqMX9//gSeK8WWBqG/c1IAMVDa0NWrJeOJhSziE+ta3B0m
bHAPBY6vh0iB3lLdRlbUOPbC6R1TpxMOs+6Vbs2+OTifFpvOVymEoZq/nroyg68P
vn5uCKogwWA7o8EArf/UTlIwWJmH9bgILdZKld4wMel2HQg16RDzm+mEXAJi52a/
FC+fgfphdxltmUJ+rqOyR4AHULjaTWUQqTIB6sdlzgmES1nXAiE71zX//KFqomar
O60SPPk3C1bs0x5DsvmGJa8SIfDhyd+D7NPyqwEKqrZsaotYGklNkfqxa6pa8mrc
ejxquW1PK4FvBk26+osu5a90Jih0PcQM7DUMMr2WHdTiMSXWAiK2ToYF8Itt25Qv
Cd0CsSYw9CJkXNr1u1+mObheaY9QYOmztnSJLy4ZO2JsMhqNwuAueIcwmhXOREq7
kzlnGMgJcuSeAS/OBNj8Zgx0c7QQ0kzc+YmnOCsqoMtPsu/CsXJ4iJiM3Tki/2jT
bywrTiQwE6R3a/87GREOREX+WLicZBWX3k9/4tBL5XSe1p5wPpuIRQUDvAGNfNHP
JN7kujDF4SehilF1qtvCygAwvxHFDj+EwhXKNDKJzoZZIM15rAk3k92n2j6nz1qH
a3xOU05yydOlO6F6w51I1QoDddmkzCRNB0TeO3D6rekHsCK1aDWmC+qRcm2ZFtVz
sY6fdZN2NEmMQokIh9Opi1f8CSYSizPESMzdu2SF0xVO9n/IGIkn1ksK04O2BZo0
X3LBPHLfCRsQNY1eF17bj07fYU2oPZKs/XzJiwxkqK6LFvpeAVaYrtg9fqRO/UVe
QhUIj3BL550ocEpa15xLehLrmwzYiW5zwGjSHQ4EgZluGLCwyKGTh4QswEJRA9Rt
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIE0DCCA7igAwIBAgIJAM5MuKJezXq0MA0GCSqGSIb3DQEBBQUAMIGgMQswCQYD
VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xGDAW
BgNVBAoTD1phcGhveWQgU3R1ZGlvczEUMBIGA1UECxMLV2ViU29ja2V0KysxFjAU
BgNVBAMTDVBldGVyIFRob3Jzb24xJDAiBgkqhkiG9w0BCQEWFXdlYm1hc3RlckB6
YXBob3lkLmNvbTAeFw0xMTExMTUyMTIwMDZaFw0xMjExMTQyMTIwMDZaMIGgMQsw
CQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28x
GDAWBgNVBAoTD1phcGhveWQgU3R1ZGlvczEUMBIGA1UECxMLV2ViU29ja2V0Kysx
FjAUBgNVBAMTDVBldGVyIFRob3Jzb24xJDAiBgkqhkiG9w0BCQEWFXdlYm1hc3Rl
ckB6YXBob3lkLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANR0
tdwAnIB8I9qRZ7QbzEWY95RpM7GIn0u/9oH90PzdHiE0rXSkKT+yw3XUzH0iw5t0
5dEwSC+srSP5Vm4cA6kXc94agVVaPW89tGcdP4fHptCruSrzQsDXELCPl5UUvMpA
YUcGisdXYPN/EeOoqb9wKWxoW5mREsyyeWWS89fYN5qU/d0QpbSvEWghqLbL/ZS2
hOlXT9LufOeA+vHiV1/T/h5xC7ecIH02YDQw1EnqxbPmkLPcWThztLS9FiufNDRM
Rhcoaj2b9VDHvDwdbeA0T5v5qNdG34LaapYOelxzQMOtM0f9Dgqehodyxl2qm9mR
lq432dlOEzDnVCPNHwECAwEAAaOCAQkwggEFMB0GA1UdDgQWBBTTPKfNMnKOykhv
+vKS7vql5JsMyzCB1QYDVR0jBIHNMIHKgBTTPKfNMnKOykhv+vKS7vql5JsMy6GB
pqSBozCBoDELMAkGA1UEBhMCVVMxETAPBgNVBAgTCElsbGlub2lzMRAwDgYDVQQH
EwdDaGljYWdvMRgwFgYDVQQKEw9aYXBob3lkIFN0dWRpb3MxFDASBgNVBAsTC1dl
YlNvY2tldCsrMRYwFAYDVQQDEw1QZXRlciBUaG9yc29uMSQwIgYJKoZIhvcNAQkB
FhV3ZWJtYXN0ZXJAemFwaG95ZC5jb22CCQDOTLiiXs16tDAMBgNVHRMEBTADAQH/
MA0GCSqGSIb3DQEBBQUAA4IBAQB+SH0s/hrv5VYqgX6SNLzxdSLvCVsUkCdTpxwY
wOJ84XmYcXDMhKDtZqLtOtN6pfEwVusFlC9mkieuunztCnWNmsSG83RuljJPjFSi
1d4Id4bKEQkQ4cfnjoHKivRrViWLnxuNnLzC6tpyGH/35kKWhhr6T58AXerFgVw3
mHvLPTr1DuhdAZA0ZuvuseVAFFAjI3RetSySwHJE3ak8KswDVfLi6E3XxMVsIWTS
/iFsC2WwoZQlljya2V/kRYIhu+uCdqJ01wunn2BvmURPSgr4GTBF0FQ9JGpNbXxM
TAU7oQJgyFc5sCcuEgPTO0dWVQTvdZVgay4tkmduKDRkmJBF
-----END CERTIFICATE-----
@@ -1,87 +0,0 @@
#include <iostream>
#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/server.hpp>
struct connection_data {
int sessionid;
std::string name;
};
struct custom_config : public websocketpp::config::asio {
// pull default settings from our core config
typedef websocketpp::config::asio core;
typedef core::concurrency_type concurrency_type;
typedef core::request_type request_type;
typedef core::response_type response_type;
typedef core::message_type message_type;
typedef core::con_msg_manager_type con_msg_manager_type;
typedef core::endpoint_msg_manager_type endpoint_msg_manager_type;
typedef core::alog_type alog_type;
typedef core::elog_type elog_type;
typedef core::rng_type rng_type;
typedef core::transport_type transport_type;
typedef core::endpoint_base endpoint_base;
// Set a custom connection_base class
typedef connection_data connection_base;
};
typedef websocketpp::server<custom_config> server;
typedef server::connection_ptr connection_ptr;
using websocketpp::connection_hdl;
using websocketpp::lib::placeholders::_1;
using websocketpp::lib::placeholders::_2;
using websocketpp::lib::bind;
class print_server {
public:
print_server() : m_next_sessionid(1) {
m_server.init_asio();
m_server.set_open_handler(bind(&print_server::on_open,this,::_1));
m_server.set_close_handler(bind(&print_server::on_close,this,::_1));
m_server.set_message_handler(bind(&print_server::on_message,this,::_1,::_2));
}
void on_open(connection_hdl hdl) {
connection_ptr con = m_server.get_con_from_hdl(hdl);
con->sessionid = m_next_sessionid++;
}
void on_close(connection_hdl hdl) {
connection_ptr con = m_server.get_con_from_hdl(hdl);
std::cout << "Closing connection " << con->name
<< " with sessionid " << con->sessionid << std::endl;
}
void on_message(connection_hdl hdl, server::message_ptr msg) {
connection_ptr con = m_server.get_con_from_hdl(hdl);
if (con->name == "") {
con->name = msg->get_payload();
std::cout << "Setting name of connection with sessionid "
<< con->sessionid << " to " << con->name << std::endl;
} else {
std::cout << "Got a message from connection " << con->name
<< " with sessionid " << con->sessionid << std::endl;
}
}
void run(uint16_t port) {
m_server.listen(port);
m_server.start_accept();
m_server.run();
}
private:
int m_next_sessionid;
server m_server;
};
int main() {
print_server server;
server.run(9002);
}
@@ -1,42 +0,0 @@
#include <iostream>
#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/server.hpp>
typedef websocketpp::server<websocketpp::config::asio> server;
using websocketpp::connection_hdl;
using websocketpp::lib::placeholders::_1;
using websocketpp::lib::placeholders::_2;
using websocketpp::lib::bind;
using websocketpp::lib::ref;
void custom_on_msg(server & s, connection_hdl hdl, server::message_ptr msg) {
std::cout << "Message sent to custom handler" << std::endl;
}
void default_on_msg(server & s, connection_hdl hdl, server::message_ptr msg) {
std::cout << "Message sent to default handler" << std::endl;
if (msg->get_payload() == "upgrade") {
// Upgrade our connection_hdl to a full connection_ptr
server::connection_ptr con = s.get_con_from_hdl(hdl);
// Change the on message handler for this connection only to
// custom_on_mesage
con->set_message_handler(bind(&custom_on_msg,ref(s),::_1,::_2));
std::cout << "Upgrading connection to custom handler" << std::endl;
}
}
int main() {
server s;
s.set_message_handler(bind(&default_on_msg,ref(s),::_1,::_2));
s.init_asio();
s.listen(9002);
s.start_accept();
s.run();
}
-23
View File
@@ -1,23 +0,0 @@
## iostream server example
##
Import('env')
Import('env_cpp11')
Import('boostlibs')
Import('platform_libs')
Import('polyfill_libs')
env = env.Clone ()
env_cpp11 = env_cpp11.Clone ()
prgs = []
# if a C++11 environment is available build using that, otherwise use boost
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]
prgs += env_cpp11.Program('iostream_server', ["iostream_server.cpp"], LIBS = ALL_LIBS)
else:
ALL_LIBS = boostlibs(['system'],env) + [platform_libs] + [polyfill_libs]
prgs += env.Program('iostream_server', ["iostream_server.cpp"], LIBS = ALL_LIBS)
Return('prgs')
@@ -1,93 +0,0 @@
#include <websocketpp/config/core.hpp>
#include <websocketpp/server.hpp>
#include <iostream>
#include <fstream>
typedef websocketpp::server<websocketpp::config::core> server;
using websocketpp::lib::placeholders::_1;
using websocketpp::lib::placeholders::_2;
using websocketpp::lib::bind;
// pull out the type of messages sent by our config
typedef server::message_ptr message_ptr;
// Define a callback to handle incoming messages
void on_message(server* s, websocketpp::connection_hdl hdl, message_ptr msg) {
if (msg->get_opcode() == websocketpp::frame::opcode::text) {
s->get_alog().write(websocketpp::log::alevel::app,
"Text Message Received: "+msg->get_payload());
} else {
s->get_alog().write(websocketpp::log::alevel::app,
"Binary Message Received: "+websocketpp::utility::to_hex(msg->get_payload()));
}
try {
s->send(hdl, msg->get_payload(), msg->get_opcode());
} catch (const websocketpp::lib::error_code& e) {
s->get_alog().write(websocketpp::log::alevel::app,
"Echo Failed: "+e.message());
}
}
int main() {
server s;
std::ofstream log;
try {
// set up access channels to only log interesting things
s.clear_access_channels(websocketpp::log::alevel::all);
s.set_access_channels(websocketpp::log::alevel::connect);
s.set_access_channels(websocketpp::log::alevel::disconnect);
s.set_access_channels(websocketpp::log::alevel::app);
// Log to a file rather than stdout, as we are using stdout for real
// output
log.open("output.log");
s.get_alog().set_ostream(&log);
s.get_elog().set_ostream(&log);
// print all output to stdout
s.register_ostream(&std::cout);
// Register our message handler
s.set_message_handler(bind(&on_message,&s,::_1,::_2));
server::connection_ptr con = s.get_connection();
con->start();
// C++ iostream's don't support the idea of asynchronous i/o. As such
// there are two input strategies demonstrated here. Buffered I/O will
// read from stdin in chunks until EOF. This works very well for
// replaying canned connections as would be done in automated testing.
//
// If the server is being used live however, assuming input is being
// piped from elsewhere in realtime, this strategy will result in small
// messages being buffered forever. The non-buffered strategy below
// reads characters from stdin one at a time. This is inefficient and
// for more serious uses should be replaced with a platform specific
// asyncronous i/o technique like select, poll, IOCP, etc
bool buffered_io = false;
if (buffered_io) {
std::cin >> *con;
con->eof();
} else {
char a;
while(std::cin.get(a)) {
con->read_some(&a,1);
}
con->eof();
}
} catch (const std::exception & e) {
std::cout << e.what() << std::endl;
} catch (websocketpp::lib::error_code e) {
std::cout << e.message() << std::endl;
} catch (...) {
std::cout << "other exception" << std::endl;
}
log.close();
}
-10
View File
@@ -1,10 +0,0 @@
file (GLOB SOURCE_FILES *.cpp)
file (GLOB HEADER_FILES *.hpp)
init_target (print_server)
build_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})
link_boost ()
final_target ()
-23
View File
@@ -1,23 +0,0 @@
## Print server example
##
Import('env')
Import('env_cpp11')
Import('boostlibs')
Import('platform_libs')
Import('polyfill_libs')
env = env.Clone ()
env_cpp11 = env_cpp11.Clone ()
prgs = []
# if a C++11 environment is available build using that, otherwise use boost
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]
prgs += env_cpp11.Program('print_server', ["print_server.cpp"], LIBS = ALL_LIBS)
else:
ALL_LIBS = boostlibs(['system'],env) + [platform_libs] + [polyfill_libs]
prgs += env.Program('print_server', ["print_server.cpp"], LIBS = ALL_LIBS)
Return('prgs')
-22
View File
@@ -1,22 +0,0 @@
#include <iostream>
#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/server.hpp>
typedef websocketpp::server<websocketpp::config::asio> server;
void on_message(websocketpp::connection_hdl hdl, server::message_ptr msg) {
std::cout << msg->get_payload() << std::endl;
}
int main() {
server print_server;
print_server.set_message_handler(&on_message);
print_server.init_asio();
print_server.listen(9002);
print_server.start_accept();
print_server.run();
}
@@ -1,51 +0,0 @@
#include <set>
#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/server.hpp>
typedef websocketpp::server<websocketpp::config::asio> server;
using websocketpp::connection_hdl;
using websocketpp::lib::placeholders::_1;
using websocketpp::lib::placeholders::_2;
using websocketpp::lib::bind;
class broadcast_server {
public:
broadcast_server() {
m_server.init_asio();
m_server.set_open_handler(bind(&broadcast_server::on_open,this,::_1));
m_server.set_close_handler(bind(&broadcast_server::on_close,this,::_1));
m_server.set_message_handler(bind(&broadcast_server::on_message,this,::_1,::_2));
}
void on_open(connection_hdl hdl) {
m_connections.insert(hdl);
}
void on_close(connection_hdl hdl) {
m_connections.erase(hdl);
}
void on_message(connection_hdl hdl, server::message_ptr msg) {
for (auto it : m_connections) {
m_server.send(it,msg);
}
}
void run(uint16_t port) {
m_server.listen(port);
m_server.start_accept();
m_server.run();
}
private:
typedef std::set<connection_hdl,std::owner_less<connection_hdl>> con_list;
server m_server;
con_list m_connections;
};
int main() {
broadcast_server server;
server.run(9002);
}
-11
View File
@@ -1,11 +0,0 @@
file (GLOB SOURCE_FILES *.cpp)
file (GLOB HEADER_FILES *.hpp)
init_target (sip_client)
build_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})
link_boost ()
final_target ()
-22
View File
@@ -1,22 +0,0 @@
Checkout the project from git
At the top level, run cmake:
cmake -G 'Unix Makefiles' \
-D BUILD_EXAMPLES=ON \
-D WEBSOCKETPP_ROOT=/tmp/cm1 \
-D ENABLE_CPP11=OFF .
and then make the example:
make -C examples/sip_client
Now run it:
bin/sip_client ws://ws-server:80
It has been tested against the repro SIP proxy from reSIProcate
http://www.resiprocate.org/WebRTC_and_SIP_Over_WebSockets
-23
View File
@@ -1,23 +0,0 @@
## SIP client example
##
Import('env')
Import('env_cpp11')
Import('boostlibs')
Import('platform_libs')
Import('polyfill_libs')
env = env.Clone ()
env_cpp11 = env_cpp11.Clone ()
prgs = []
# if a C++11 environment is avaliable build using that, otherwise use boost
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]
prgs += env_cpp11.Program('sip_client', ["sip_client.cpp"], LIBS = ALL_LIBS)
else:
ALL_LIBS = boostlibs(['system','random'],env) + [platform_libs] + [polyfill_libs]
prgs += env.Program('sip_client', ["sip_client.cpp"], LIBS = ALL_LIBS)
Return('prgs')
-88
View File
@@ -1,88 +0,0 @@
#include <condition_variable>
#include <websocketpp/config/asio_no_tls_client.hpp>
#include <websocketpp/client.hpp>
#include <iostream>
#include <boost/thread/thread.hpp>
typedef websocketpp::client<websocketpp::config::asio_client> client;
using websocketpp::lib::placeholders::_1;
using websocketpp::lib::placeholders::_2;
using websocketpp::lib::bind;
// pull out the type of messages sent by our config
typedef websocketpp::config::asio_client::message_type::ptr message_ptr;
// Create a server endpoint
client sip_client;
bool received;
void on_open(client* c, websocketpp::connection_hdl hdl) {
// now it is safe to use the connection
std::cout << "connection ready" << std::endl;
received=false;
// Send a SIP OPTIONS message to the server:
std::string SIP_msg="OPTIONS sip:carol@chicago.com SIP/2.0\r\nVia: SIP/2.0/WS df7jal23ls0d.invalid;rport;branch=z9hG4bKhjhs8ass877\r\nMax-Forwards: 70\r\nTo: <sip:carol@chicago.com>\r\nFrom: Alice <sip:alice@atlanta.com>;tag=1928301774\r\nCall-ID: a84b4c76e66710\r\nCSeq: 63104 OPTIONS\r\nContact: <sip:alice@pc33.atlanta.com>\r\nAccept: application/sdp\r\nContent-Length: 0\r\n\r\n";
sip_client.send(hdl, SIP_msg.c_str(), websocketpp::frame::opcode::text);
}
void on_message(client* c, websocketpp::connection_hdl hdl, message_ptr msg) {
client::connection_ptr con = sip_client.get_con_from_hdl(hdl);
std::cout << "Received a reply:" << std::endl;
fwrite(msg->get_payload().c_str(), msg->get_payload().size(), 1, stdout);
received=true;
}
int main(int argc, char* argv[]) {
std::string uri = "ws://localhost:9001";
if (argc == 2) {
uri = argv[1];
}
try {
// We expect there to be a lot of errors, so suppress them
sip_client.clear_access_channels(websocketpp::log::alevel::all);
sip_client.clear_error_channels(websocketpp::log::elevel::all);
// Initialize ASIO
sip_client.init_asio();
// Register our handlers
sip_client.set_open_handler(bind(&on_open,&sip_client,::_1));
sip_client.set_message_handler(bind(&on_message,&sip_client,::_1,::_2));
websocketpp::lib::error_code ec;
client::connection_ptr con = sip_client.get_connection(uri, ec);
// Specify the SIP subprotocol:
con->add_subprotocol("sip");
sip_client.connect(con);
// Start the ASIO io_service run loop
sip_client.run();
while(!received) {
boost::this_thread::sleep(boost::posix_time::milliseconds(100));
}
std::cout << "done" << std::endl;
} catch (const std::exception & e) {
std::cout << e.what() << std::endl;
} catch (websocketpp::lib::error_code e) {
std::cout << e.message() << std::endl;
} catch (...) {
std::cout << "other exception" << std::endl;
}
}
-23
View File
@@ -1,23 +0,0 @@
## Main development example
##
Import('env')
Import('env_cpp11')
Import('boostlibs')
Import('platform_libs')
Import('polyfill_libs')
env = env.Clone ()
env_cpp11 = env_cpp11.Clone ()
prgs = []
# if a C++11 environment is available build using that, otherwise use boost
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]
prgs += env_cpp11.Program('subprotocol_server', ["subprotocol_server.cpp"], LIBS = ALL_LIBS)
else:
ALL_LIBS = boostlibs(['system'],env) + [platform_libs] + [polyfill_libs]
prgs += env.Program('subprotocol_server', ["subprotocol_server.cpp"], LIBS = ALL_LIBS)
Return('prgs')
@@ -1,52 +0,0 @@
#include <iostream>
#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/server.hpp>
typedef websocketpp::server<websocketpp::config::asio> server;
using websocketpp::connection_hdl;
using websocketpp::lib::placeholders::_1;
using websocketpp::lib::placeholders::_2;
using websocketpp::lib::bind;
using websocketpp::lib::ref;
bool validate(server & s, connection_hdl hdl) {
server::connection_ptr con = s.get_con_from_hdl(hdl);
std::cout << "Cache-Control: " << con->get_request_header("Cache-Control") << std::endl;
const std::vector<std::string> & subp_requests = con->get_requested_subprotocols();
std::vector<std::string>::const_iterator it;
for (it = subp_requests.begin(); it != subp_requests.end(); ++it) {
std::cout << "Requested: " << *it << std::endl;
}
if (subp_requests.size() > 0) {
con->select_subprotocol(subp_requests[0]);
}
return true;
}
int main() {
try {
server s;
s.set_validate_handler(bind(&validate,ref(s),::_1));
s.init_asio();
s.listen(9005);
s.start_accept();
s.run();
} catch (const std::exception & e) {
std::cout << e.what() << std::endl;
} catch (websocketpp::lib::error_code e) {
std::cout << e.message() << std::endl;
} catch (...) {
std::cout << "other exception" << std::endl;
}
}
-10
View File
@@ -1,10 +0,0 @@
file (GLOB SOURCE_FILES *.cpp)
file (GLOB HEADER_FILES *.hpp)
init_target (telemetry_client)
build_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})
link_boost ()
final_target ()
-23
View File
@@ -1,23 +0,0 @@
## Telemetry client example
##
Import('env')
Import('env_cpp11')
Import('boostlibs')
Import('platform_libs')
Import('polyfill_libs')
env = env.Clone ()
env_cpp11 = env_cpp11.Clone ()
prgs = []
# if a C++11 environment is available build using that, otherwise use boost
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]
prgs += env_cpp11.Program('telemetry_client', ["telemetry_client.cpp"], LIBS = ALL_LIBS)
else:
ALL_LIBS = boostlibs(['system','random'],env) + [platform_libs] + [polyfill_libs]
prgs += env.Program('telemetry_client', ["telemetry_client.cpp"], LIBS = ALL_LIBS)
Return('prgs')
@@ -1,156 +0,0 @@
#include <websocketpp/config/asio_no_tls_client.hpp>
#include <websocketpp/client.hpp>
// This header pulls in the WebSocket++ abstracted thread support that will
// select between boost::thread and std::thread based on how the build system
// is configured.
#include <websocketpp/common/thread.hpp>
/**
* The telemetry client connects to a WebSocket server and sends a message every
* second containing an integer count. This example can be used as the basis for
* programs where a client connects and pushes data for logging, stress/load
* testing, etc.
*/
class telemetry_client {
public:
typedef websocketpp::client<websocketpp::config::asio_client> client;
typedef websocketpp::lib::lock_guard<websocketpp::lib::mutex> scoped_lock;
telemetry_client() : m_open(false),m_done(false) {
// set up access channels to only log interesting things
m_client.clear_access_channels(websocketpp::log::alevel::all);
m_client.set_access_channels(websocketpp::log::alevel::connect);
m_client.set_access_channels(websocketpp::log::alevel::disconnect);
m_client.set_access_channels(websocketpp::log::alevel::app);
// Initialize the Asio transport policy
m_client.init_asio();
// Bind the handlers we are using
using websocketpp::lib::placeholders::_1;
using websocketpp::lib::bind;
m_client.set_open_handler(bind(&telemetry_client::on_open,this,::_1));
m_client.set_close_handler(bind(&telemetry_client::on_close,this,::_1));
m_client.set_fail_handler(bind(&telemetry_client::on_fail,this,::_1));
}
// This method will block until the connection is complete
void run(const std::string & uri) {
// Create a new connection to the given URI
websocketpp::lib::error_code ec;
client::connection_ptr con = m_client.get_connection(uri, ec);
if (ec) {
m_client.get_alog().write(websocketpp::log::alevel::app,
"Get Connection Error: "+ec.message());
return;
}
// Grab a handle for this connection so we can talk to it in a thread
// safe manor after the event loop starts.
m_hdl = con->get_handle();
// Queue the connection. No DNS queries or network connections will be
// made until the io_service event loop is run.
m_client.connect(con);
// Create a thread to run the ASIO io_service event loop
websocketpp::lib::thread asio_thread(&client::run, &m_client);
// Create a thread to run the telemetry loop
websocketpp::lib::thread telemetry_thread(&telemetry_client::telemetry_loop,this);
asio_thread.join();
telemetry_thread.join();
}
// The open handler will signal that we are ready to start sending telemetry
void on_open(websocketpp::connection_hdl hdl) {
m_client.get_alog().write(websocketpp::log::alevel::app,
"Connection opened, starting telemetry!");
scoped_lock guard(m_lock);
m_open = true;
}
// The close handler will signal that we should stop sending telemetry
void on_close(websocketpp::connection_hdl hdl) {
m_client.get_alog().write(websocketpp::log::alevel::app,
"Connection closed, stopping telemetry!");
scoped_lock guard(m_lock);
m_done = true;
}
// The fail handler will signal that we should stop sending telemetry
void on_fail(websocketpp::connection_hdl hdl) {
m_client.get_alog().write(websocketpp::log::alevel::app,
"Connection failed, stopping telemetry!");
scoped_lock guard(m_lock);
m_done = true;
}
void telemetry_loop() {
uint64_t count = 0;
std::stringstream val;
websocketpp::lib::error_code ec;
while(1) {
bool wait = false;
{
scoped_lock guard(m_lock);
// If the connection has been closed, stop generating telemetry
if (m_done) {break;}
// If the connection hasn't been opened yet wait a bit and retry
if (!m_open) {
wait = true;
}
}
if (wait) {
sleep(1);
continue;
}
val.str("");
val << "count is " << count++;
m_client.get_alog().write(websocketpp::log::alevel::app, val.str());
m_client.send(m_hdl,val.str(),websocketpp::frame::opcode::text,ec);
// The most likely error that we will get is that the connection is
// not in the right state. Usually this means we tried to send a
// message to a connection that was closed or in the process of
// closing. While many errors here can be easily recovered from,
// in this simple example, we'll stop the telemetry loop.
if (ec) {
m_client.get_alog().write(websocketpp::log::alevel::app,
"Send Error: "+ec.message());
break;
}
sleep(1);
}
}
private:
client m_client;
websocketpp::connection_hdl m_hdl;
websocketpp::lib::mutex m_lock;
bool m_open;
bool m_done;
};
int main(int argc, char* argv[]) {
telemetry_client c;
std::string uri = "ws://localhost:9002";
if (argc == 2) {
uri = argv[1];
}
c.run(uri);
}
-11
View File
@@ -1,11 +0,0 @@
file (GLOB SOURCE_FILES *.cpp)
file (GLOB HEADER_FILES *.hpp)
init_target (testee_client)
build_executable (${TARGET_NAME} ${SOURCE_FILES} ${HEADER_FILES})
link_boost ()
final_target ()
-23
View File
@@ -1,23 +0,0 @@
## Autobahn test client example
##
Import('env')
Import('env_cpp11')
Import('boostlibs')
Import('platform_libs')
Import('polyfill_libs')
env = env.Clone ()
env_cpp11 = env_cpp11.Clone ()
prgs = []
# if a C++11 environment is available build using that, otherwise use boost
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs]
prgs += env_cpp11.Program('testee_client', ["testee_client.cpp"], LIBS = ALL_LIBS)
else:
ALL_LIBS = boostlibs(['system','random'],env) + [platform_libs] + [polyfill_libs]
prgs += env.Program('testee_client', ["testee_client.cpp"], LIBS = ALL_LIBS)
Return('prgs')
-84
View File
@@ -1,84 +0,0 @@
#include <websocketpp/config/asio_no_tls_client.hpp>
#include <websocketpp/client.hpp>
#include <iostream>
typedef websocketpp::client<websocketpp::config::asio_client> client;
using websocketpp::lib::placeholders::_1;
using websocketpp::lib::placeholders::_2;
using websocketpp::lib::bind;
// pull out the type of messages sent by our config
typedef websocketpp::config::asio_client::message_type::ptr message_ptr;
int case_count = 0;
void on_message(client* c, websocketpp::connection_hdl hdl, message_ptr msg) {
client::connection_ptr con = c->get_con_from_hdl(hdl);
if (con->get_resource() == "/getCaseCount") {
std::cout << "Detected " << msg->get_payload() << " test cases."
<< std::endl;
case_count = atoi(msg->get_payload().c_str());
} else {
c->send(hdl, msg->get_payload(), msg->get_opcode());
}
}
int main(int argc, char* argv[]) {
// Create a server endpoint
client c;
std::string uri = "ws://localhost:9001";
if (argc == 2) {
uri = argv[1];
}
try {
// We expect there to be a lot of errors, so suppress them
c.clear_access_channels(websocketpp::log::alevel::all);
c.clear_error_channels(websocketpp::log::elevel::all);
// Initialize ASIO
c.init_asio();
// Register our handlers
c.set_message_handler(bind(&on_message,&c,::_1,::_2));
websocketpp::lib::error_code ec;
client::connection_ptr con = c.get_connection(uri+"/getCaseCount", ec);
c.connect(con);
// Start the ASIO io_service run loop
c.run();
std::cout << "case count: " << case_count << std::endl;
for (int i = 1; i <= case_count; i++) {
c.reset();
std::stringstream url;
url << uri << "/runCase?case=" << i << "&agent="
<< websocketpp::user_agent;
con = c.get_connection(url.str(), ec);
c.connect(con);
c.run();
}
std::cout << "done" << std::endl;
} catch (const std::exception & e) {
std::cout << e.what() << std::endl;
} catch (websocketpp::lib::error_code e) {
std::cout << e.message() << std::endl;
} catch (...) {
std::cout << "other exception" << std::endl;
}
}
-24
View File
@@ -1,24 +0,0 @@
## Autobahn Testee Server
##
Import('env')
Import('env_cpp11')
Import('boostlibs')
Import('platform_libs')
Import('polyfill_libs')
Import('tls_libs')
env = env.Clone ()
env_cpp11 = env_cpp11.Clone ()
prgs = []
# if a C++11 environment is available build using that, otherwise use boost
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs] + [tls_libs]
prgs += env_cpp11.Program('testee_server', ["testee_server.cpp"], LIBS = ALL_LIBS)
else:
ALL_LIBS = boostlibs(['system'],env) + [platform_libs] + [polyfill_libs] + [tls_libs]
prgs += env.Program('testee_server', ["testee_server.cpp"], LIBS = ALL_LIBS)
Return('prgs')
-167
View File
@@ -1,167 +0,0 @@
/*
* Copyright (c) 2013, Peter Thorson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
//#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/config/asio.hpp>
#include <websocketpp/server.hpp>
#include <websocketpp/message_buffer/fixed.hpp>
#include <iostream>
typedef websocketpp::lib::shared_ptr<boost::asio::ssl::context> context_ptr;
std::string get_password() {
return "test";
}
context_ptr on_tls_init(websocketpp::connection_hdl hdl) {
//std::cout << "on_tls_init called with hdl: " << hdl.lock().get() << std::endl;
context_ptr ctx(new boost::asio::ssl::context(boost::asio::ssl::context::tlsv1));
try {
ctx->set_options(boost::asio::ssl::context::default_workarounds |
boost::asio::ssl::context::no_sslv2 |
boost::asio::ssl::context::single_dh_use);
ctx->set_password_callback(bind(&get_password));
ctx->use_certificate_chain_file("server.pem");
ctx->use_private_key_file("server.pem", boost::asio::ssl::context::pem);
} catch (std::exception& e) {
std::cout << e.what() << std::endl;
}
return ctx;
}
struct testee_config : public websocketpp::config::asio {
// pull default settings from our core config
typedef websocketpp::config::asio core;
typedef core::concurrency_type concurrency_type;
typedef core::request_type request_type;
typedef core::response_type response_type;
typedef core::message_type message_type;
typedef core::con_msg_manager_type con_msg_manager_type;
typedef core::endpoint_msg_manager_type endpoint_msg_manager_type;
//typedef websocketpp::message_buffer::fixed::policy::message message_type;
//typedef websocketpp::message_buffer::fixed::policy::con_msg_manager con_msg_manager_type;
////typedef websocketpp::message_buffer::fixed::policy::con_msg_manager endpoint_msg_manager_type;
//typedef websocketpp::message_buffer::fixed::policy::endpoint_msg_manager endpoint_msg_manager_type;
typedef core::alog_type alog_type;
typedef core::elog_type elog_type;
typedef core::rng_type rng_type;
typedef core::endpoint_base endpoint_base;
static bool const enable_multithreading = true;
struct transport_config : public core::transport_config {
typedef core::concurrency_type concurrency_type;
typedef core::elog_type elog_type;
typedef core::alog_type alog_type;
typedef core::request_type request_type;
typedef core::response_type response_type;
static bool const enable_multithreading = true;
};
typedef websocketpp::transport::asio::endpoint<transport_config>
transport_type;
static const websocketpp::log::level elog_level =
websocketpp::log::elevel::none;
static const websocketpp::log::level alog_level =
websocketpp::log::alevel::none;
};
typedef websocketpp::server<testee_config> server;
using websocketpp::lib::placeholders::_1;
using websocketpp::lib::placeholders::_2;
using websocketpp::lib::bind;
// pull out the type of messages sent by our config
typedef server::message_ptr message_ptr;
// Define a callback to handle incoming messages
void on_message(server* s, websocketpp::connection_hdl hdl, message_ptr msg) {
s->send(hdl, msg->get_payload(), msg->get_opcode());
}
int main(int argc, char * argv[]) {
// Create a server endpoint
server testee_server;
short port = 9002;
size_t num_threads = 1;
if (argc == 3) {
port = atoi(argv[1]);
num_threads = atoi(argv[2]);
}
try {
// Total silence
//testee_server.clear_access_channels(websocketpp::log::alevel::all);
//testee_server.clear_error_channels(websocketpp::log::alevel::all);
// Initialize ASIO
testee_server.init_asio();
// Register our message handler
testee_server.set_message_handler(bind(&on_message,&testee_server,::_1,::_2));
//testee_server.set_tls_init_handler(bind(&on_tls_init,::_1));
// Listen on port
testee_server.listen(port);
// Start the server accept loop
testee_server.start_accept();
// Start the ASIO io_service run loop
if (num_threads == 1) {
testee_server.run();
} else {
typedef websocketpp::lib::shared_ptr<websocketpp::lib::thread> thread_ptr;
std::vector<thread_ptr> ts;
for (size_t i = 0; i < num_threads; i++) {
ts.push_back(thread_ptr(new websocketpp::lib::thread(&server::run, &testee_server)));
}
for (size_t i = 0; i < num_threads; i++) {
ts[i]->join();
}
}
} catch (const std::exception & e) {
std::cout << "exception: " << e.what() << std::endl;
} catch (websocketpp::lib::error_code e) {
std::cout << "error code: " << e.message() << std::endl;
} catch (...) {
std::cout << "other exception" << std::endl;
}
}
-24
View File
@@ -1,24 +0,0 @@
## Utility client example
##
Import('env')
Import('env_cpp11')
Import('boostlibs')
Import('platform_libs')
Import('polyfill_libs')
Import('tls_libs')
env = env.Clone ()
env_cpp11 = env_cpp11.Clone ()
prgs = []
# if a C++11 environment is available build using that, otherwise use boost
if env_cpp11.has_key('WSPP_CPP11_ENABLED'):
ALL_LIBS = boostlibs(['system'],env_cpp11) + [platform_libs] + [polyfill_libs] + [tls_libs]
prgs += env_cpp11.Program('utility_client', ["utility_client.cpp"], LIBS = ALL_LIBS)
else:
ALL_LIBS = boostlibs(['system','random'],env) + [platform_libs] + [polyfill_libs] + [tls_libs]
prgs += env.Program('utility_client', ["utility_client.cpp"], LIBS = ALL_LIBS)
Return('prgs')
-166
View File
@@ -1,166 +0,0 @@
/**
* This example is presently used as a scratch space. It may or may not be broken
* at any given time.
*/
#include <websocketpp/config/asio_client.hpp>
#include <websocketpp/client.hpp>
#include <iostream>
#include <chrono>
typedef websocketpp::client<websocketpp::config::asio_tls_client> client;
using websocketpp::lib::placeholders::_1;
using websocketpp::lib::placeholders::_2;
using websocketpp::lib::bind;
// pull out the type of messages sent by our config
typedef websocketpp::config::asio_tls_client::message_type::ptr message_ptr;
typedef websocketpp::lib::shared_ptr<boost::asio::ssl::context> context_ptr;
typedef client::connection_ptr connection_ptr;
class perftest {
public:
typedef perftest type;
typedef std::chrono::duration<int,std::micro> dur_type;
perftest () {
m_endpoint.set_access_channels(websocketpp::log::alevel::none);
m_endpoint.set_error_channels(websocketpp::log::elevel::none);
// Initialize ASIO
m_endpoint.init_asio();
// Register our handlers
m_endpoint.set_tls_init_handler(bind(&type::on_tls_init,this,::_1));
m_endpoint.set_tcp_pre_init_handler(bind(&type::on_tcp_pre_init,this,::_1));
m_endpoint.set_tcp_post_init_handler(bind(&type::on_tcp_post_init,this,::_1));
m_endpoint.set_socket_init_handler(bind(&type::on_socket_init,this,::_1));
m_endpoint.set_message_handler(bind(&type::on_message,this,::_1,::_2));
m_endpoint.set_open_handler(bind(&type::on_open,this,::_1));
m_endpoint.set_close_handler(bind(&type::on_close,this,::_1));
}
void start(std::string uri) {
websocketpp::lib::error_code ec;
client::connection_ptr con = m_endpoint.get_connection(uri, ec);
if (ec) {
m_endpoint.get_alog().write(websocketpp::log::alevel::app,ec.message());
}
//con->set_proxy("http://humupdates.uchicago.edu:8443");
m_endpoint.connect(con);
// Start the ASIO io_service run loop
m_start = std::chrono::high_resolution_clock::now();
m_endpoint.run();
}
void on_tcp_pre_init(websocketpp::connection_hdl hdl) {
m_tcp_pre_init = std::chrono::high_resolution_clock::now();
}
void on_tcp_post_init(websocketpp::connection_hdl hdl) {
m_tcp_post_init = std::chrono::high_resolution_clock::now();
}
void on_socket_init(websocketpp::connection_hdl hdl) {
m_socket_init = std::chrono::high_resolution_clock::now();
}
context_ptr on_tls_init(websocketpp::connection_hdl hdl) {
context_ptr ctx(new boost::asio::ssl::context(boost::asio::ssl::context::tlsv1));
try {
ctx->set_options(boost::asio::ssl::context::default_workarounds |
boost::asio::ssl::context::no_sslv2 |
boost::asio::ssl::context::single_dh_use);
} catch (std::exception& e) {
std::cout << e.what() << std::endl;
}
return ctx;
}
void on_open(websocketpp::connection_hdl hdl) {
m_open = std::chrono::high_resolution_clock::now();
client::connection_ptr con = m_endpoint.get_con_from_hdl(hdl);
m_msg = con->get_message(websocketpp::frame::opcode::text,64);
m_msg->append_payload(std::string(60,'*'));
m_msg_count = 1;
//m_message_stamps.reserve(1000);
m_con_start = std::chrono::high_resolution_clock::now();
m_endpoint.send(hdl, m_msg);
//m_endpoint.send(hdl, "", websocketpp::frame::opcode::text);
}
void on_message(websocketpp::connection_hdl hdl, message_ptr msg) {
if (m_msg_count == 1000) {
m_message = std::chrono::high_resolution_clock::now();
m_endpoint.close(hdl,websocketpp::close::status::going_away,"");
} else {
m_msg_count++;
m_endpoint.send(hdl, m_msg);
}
}
void on_close(websocketpp::connection_hdl hdl) {
m_close = std::chrono::high_resolution_clock::now();
std::cout << "Socket Init: " << std::chrono::duration_cast<dur_type>(m_socket_init-m_start).count() << std::endl;
std::cout << "TCP Pre Init: " << std::chrono::duration_cast<dur_type>(m_tcp_pre_init-m_start).count() << std::endl;
std::cout << "TCP Post Init: " << std::chrono::duration_cast<dur_type>(m_tcp_post_init-m_start).count() << std::endl;
std::cout << "Open: " << std::chrono::duration_cast<dur_type>(m_open-m_start).count() << std::endl;
std::cout << "Start: " << std::chrono::duration_cast<dur_type>(m_con_start-m_start).count() << std::endl;
std::cout << "Message: " << std::chrono::duration_cast<dur_type>(m_message-m_start).count() << std::endl;
std::cout << "Close: " << std::chrono::duration_cast<dur_type>(m_close-m_start).count() << std::endl;
std::cout << std::endl;
std::cout << "Message: " << std::chrono::duration_cast<dur_type>(m_message-m_con_start).count() << std::endl;
std::cout << "Close: " << std::chrono::duration_cast<dur_type>(m_close-m_message).count() << std::endl;
}
private:
client m_endpoint;
client::message_ptr m_msg;
size_t m_msg_count;
std::chrono::high_resolution_clock::time_point m_start;
std::chrono::high_resolution_clock::time_point m_tcp_pre_init;
std::chrono::high_resolution_clock::time_point m_tcp_post_init;
std::chrono::high_resolution_clock::time_point m_socket_init;
std::vector<std::chrono::high_resolution_clock::time_point> m_message_stamps;
std::chrono::high_resolution_clock::time_point m_con_start;
std::chrono::high_resolution_clock::time_point m_open;
std::chrono::high_resolution_clock::time_point m_message;
std::chrono::high_resolution_clock::time_point m_close;
};
int main(int argc, char* argv[]) {
std::string uri = "wss://echo.websocket.org";
if (argc == 2) {
uri = argv[1];
}
try {
perftest endpoint;
endpoint.start(uri);
} catch (const std::exception & e) {
std::cout << e.what() << std::endl;
} catch (websocketpp::lib::error_code e) {
std::cout << e.message() << std::endl;
} catch (...) {
std::cout << "other exception" << std::endl;
}
}
+23
View File
@@ -0,0 +1,23 @@
Copyright (c) 2011, Peter Thorson. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the WebSocket++ Project nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-45
View File
@@ -1,45 +0,0 @@
WebSocket++ (0.3.0-alpha4)
==========================
WebSocket++ is a header only C++ library that implements RFC6455 The WebSocket
Protocol. It allows integrating WebSocket client and server functionality into
C++ programs. It uses interchangeable network transport modules including one
based on C++ iostreams and one based on Boost Asio.
Major Features
==============
* Full support for RFC6455
* Partial support for Hixie 76 / Hybi 00, 07-17 draft specs (server only)
* Message/event based interface
* Supports secure WebSockets (TLS), IPv6, and explicit proxies.
* Flexible dependency management (C++11 Standard Library or Boost)
* Interchangeable network transport modules (iostream and Boost Asio)
* Portable/cross platform (Posix/Windows, 32/64bit, Intel/ARM/PPC)
* Thread-safe
Get Involved
============
[![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://www.zaphoyd.com/websocketpp/manual/
**GitHub Repository**
https://github.com/zaphoyd/websocketpp/
**Announcements Mailing List**
http://groups.google.com/group/websocketpp-announcements/
**IRC Channel**
#websocketpp (freenode)
**Discussion / Development / Support Mailing List / Forum**
http://groups.google.com/group/websocketpp/
Author
======
Peter Thorson - websocketpp@zaphoyd.com
+348
View File
@@ -0,0 +1,348 @@
How to use this library
WebSocket++ is a C++ websocket server library implemented using the Boost Asio networking stack. It is designed to provide a simple interface.
Built on Asio's proactor asynchronous event loop.
Building a program using WebSocket++ has two parts
1. Implement a connection handler.
This is done by subclassing websocketpp::connection_handler. Each websocket connection is attached to a connection handler.
The handler implements the following methods:
validate:
Called after the client handshake is received but before the connection is accepted. Allows cookie authentication, origin checking, subprotocol negotiation, etc.
connect:
Called when the connection has been established and writes are allowed.
disconnect:
Called when the connection has been disconnected.
message: text and binary variants
Called when a new websocket message is received.
The handler has access to the following websocket session API:
get_header
returns the value of an HTTP header sent by the client during the handshake.
get_request
returns the resource requested by the client in the handshake.
set_handler:
pass responsibility for this connection to another connection handler.
set_http_error:
reject the connection with a specific HTTP error.
add_header
adds an HTTP header to the server handshake.
set_subprotocol
selects a subprotocol for the connection.
send: text and binary variants
send a websocket message.
ping:
send a ping.
2. Start Asio's event loop with a TCP endpoint and your connection handler
There are two example programs in the examples directory that demonstrate this use pattern.
One is a trivial stateless echo server, the other is a simple web based chat client.
Both include example javascript clients. The echo server is suitable for use with automated
testing suites such as the Autobahn test suite.
By default, a single connection handler object is used for all connections.
If needs require, that default handler can either store per-connection state itself
or create new handlers and pass off responsibility for the connection to them.
How to build this library
Build static library
make
Build and install in system include directories
make install
Available flags:
- SHARED=1: build a shared instead of static library.
- DEBUG=1: build library with no optimizations, suitable for debugging. Debug library
is called libwebsocketpp_dbg
- CXX=*: uses * as the c++ compiler instead of system default
Build tested on
- Mac OS X 10.7 with apple gcc 4.2, macports gcc 4.6, apple llvm/clang, boost 1.47
- Fedora 15, gcc 4.6, boost 1.46
- Ubunutu server, gcc, boost 1.42
Outstanding issues
- Acknowledgement details
- Subprotocol negotiation interface
- check draft 14 issues
- session.cpp - add_header. Decide what should happen with multiple calls to
add header with the same key
- multiple headers of the same value
- Better exception model
- closing handshake reason/ error codes?
- tests for opening/closing handshake
- tests for utf8
- utf8 streaming validation
- more easily configurable frame size limit
- Better system of handling server wide defaults (like hosts, frame limits, etc)
To check
- double check bugs in autobahn (sending wrong localhost:9000 header) not
- checking masking in the 9.x tests
Unimplemented features
- SSL
- frame or streaming based API
- client features
- extension negotiation interface
Acknowledgements
- Boost Asio and other libraries
- base64 library
- sha1 library
- htonll discussion
- build/makefile from libjson
- Autobahn test suite
- testing by Keith Brisson
API spec notes
## Server API ##
websocketpp.hpp
create a websocketpp::server_ptr initialized to a new websocketpp::server object
the server constructor will need three things.
- A boost::asio::io_service object to manage its async operations
- A boost::asio::ip::tcp::endpoint to listen to for new connections
- An object that implements the websocketpp::connection_handler interface to provide callback functions (See Handler API)
After construction, the server object will be in the initialization state.
At this time you can set up server configuration options either via calling individual set option commands
or by loading them in a batch from a configuration file.
The only required option is that at least one host value must be set.
Incoming websocket connections must specify a host value that they wish to connect to
and if the server object does not have that host value in it's list of canonical hosts it will reject the connection.
[note about settings that can be changed live?]
Once the server has been configured the way you want, call the start_accept() method.
This will add the first async call to your io_service. If your io_service was already running,
the server will start accepting connections immediately. If not you will need to call io_service.run() to start it.
Once the server has started it will accept new connections.
A new session object will be created for each connection accepted.
The session will perform the websocket handshake and if it is successful begin reading frames.
The session will continue reading frames until an error occurs or a connection close frame is seen.
The session will notify the handler that it was initialized with (see Handler API) as necessary.
The Session API defines how a handler (or other part of the end application) can interact with the session
(to get information about the session, send messages back to the client, etc).
## Client API ##
include websocketpp.hpp
create a websocketpp::client_ptr initialized to a new websocketpp::client object
the client constructor will need:
- A boost::asio::io_service object to manage its async operations
- An object that implements the websocketpp::connection_handler interface to provide callback functions (See Handler API)
After construction, the client object will be in the initialization state.
At this time you can set up client configuration options either via calling individual set options commands
or by loading them in a batch from a configuration file.
Opening a new connection:
Per the websocket spec, a client can only have one connection in the connecting state at a time.
Client method new_session() will create a new session and return a shared pointer to it.
After this point new_session will throw an exception if you attempt to call it again
before the most recently created session has either successfully connected or failed to connect.
new_session()
- call websocketpp::client::new_session(). This will return a session_ptr
## Handler API ##
The handler API defines the interface that a websocketpp session will use to communicate information
about the session state and new messages to your application.
A client or server must be initialized with a default handler that will be used for all sessions.
The default handler may pass a session off to another handler as necessary.
A handler must implement the following methods:
- validate(session_ptr)
- on_fail(session_ptr)
- on_open(session_ptr)
- on_close(session_ptr)
- on_message(session_ptr,const std::vector<unsigned char> &)
- on_message(session_ptr,const std::string &)
validate will be called after a websocket handshake has been received and before it is accepted.
It provides a handler with the ability to refuse a connection based on application specific logic
(ex: restrict domains or negotiate subprotocols). To reject the connection throw a handshake_error.
Validate is never called for client sessions.
To refuse a client session (ex: if you do not like the set of extensions/subprotocols the server chose)
you can close the connection immediately in the on_open member function.
on_fail is called whenever a session is terminated or failed before it was successfully established.
This happens if there is an error during the handshake process or if the server refused the connection.
on_fail will be the last time a session calls its handler.
If your application will need information from `session` after this function you should either
save the session_ptr somewhere or copy the data out.
on_open is called after the websocket session has been successfully established and is in the OPEN state.
The session is now available to send messages and will begin reading frames
and calling the on_message/on_close/on_error callbacks.
A client may reject the connection by closing the session at this point.
on_close is called whenever an open session is closed for any reason.
This can be due to either endpoint requesting a connection close or an error occurring.
Information about why the session was closed can be extracted from the session itself.
on_close will be the last time a session calls its handler.
If your application will need information from `session` after this function you should either
save the session_ptr somewhere or copy the data out.
on_message (binary version) will be called when a binary message is received.
Message data is passed as a vector of bytes (unsigned char).
Data will not be available after this callback ends so the handler must either
completely process the message or copy it somewhere else for processing later.
TODO: Notes about thread safety
## Session API ##
The Session API allows a handler to look up information about a session
as well as interact with that session (send messages, close the connection, etc).
Session pointers are returned with every handler callback as well as every call to websocketpp::client::connect.
Handler Interface:
- set_handler(connection_handler_ptr)
Handshake Interface:
For the client these methods are valid after the server's handshake has been received.
This is guaranteed to be the case by the time `on_open` is called.
For the server these methods are valid after the client's handshake has been received.
This is guaranteed to be the case by the time `validate` is called.
- const std::string& get_subprotocol() const;
- const std::string& get_resource() const;
- const std::string& get_origin() const;
- std::string get_client_header(const std::string&) const;
- std::string get_server_header(const std::string&) const;
- const std::vector<std::string>& get_extensions() const;
- unsigned int get_version() const;
Frame Interface
- void send(const std::string &);
- void send(const std::vector<unsigned char> &);
- void ping(const std::string &);
- void pong(const std::string &);
These methods are valid only for open connections. They will throw an exception if called from any other state.
WebSocket++ does not queue messages. As such only one send operation can be occurring at once.
TODO: failure behavior. OPTIONS:
- send will throw a `session_busy` exception if busy
- send will return true/false
- a callback could be defined letting the handler know that it is safe to write again.
Session Interface
- void close(uint16_t status,const std::string &reason);
- bool is_server() const;
--------------------------------
screwing around with a policy based refactoring
--------------------------------
template<class WebSocketRole,class Logger>
class endpoint : public WebSocketRole, Logger {
public:
endpoint(connection_handler_ptr);
size_t get_connected_client_count() const;
void set_endpoint(const tcp::endpoint& endpoint); // asio::bind
private:
std::list<session_ptr> m_connections;
connection_handler_ptr m_handler;
boost::asio::io_service m_io_service;
tcp::acceptor m_acceptor;
}
class server_interface {
public:
void add_host(const std::string &host);
void remove_host(const std::string &host);
bool validate_host(const std::string &host) const;
void set_max_message_size(uint64_t size);
bool validate_message_size(uint64_t size) const;
void start() {
// start_accept()
// io_service.run()
}
private:
void start_accept();
void handle_accept(session_ptr session, const boost::system::error_code&)
std::set<std::string> m_hosts;
uint64_t m_max_message_size;
}
class client_interface {
public:
session_ptr connect(const std::string &url);
protected:
private:
}
template<class HandshakePolicy>
class session : public HandshakePolicy {
public:
session();
private:
}
namespace websocketpp {
namespace handshake {
/* a handshake policy must define:
void on_connect();
bool is_server() const;
*/
class server {
}
class client {
}
} // handshake
} // websocketpp
-44
View File
@@ -1,44 +0,0 @@
Complete & Tested:
- Server and client roles pass all Autobahn v0.5.9 test suite tests strictly
- Streaming UTF8 validation
- random number generation
- iostream based transport
- C++11 support
- LLVM/Clang support
- GCC support
- 64 bit support
- 32 bit support
- Logging
- Client role
- message_handler
- ping_handler
- pong_handler
- open_handler
- close_handler
- echo_server & echo_server_tls
Implimented, needs more testing
- TLS support
- External io_service support
- socket_init_handler
- tls_init_handler
- tcp_init_handler
- exception/error handling
- Subprotocol negotiation
- Hybi 00/Hixie 76 legacy protocol support
- Performance tuning
- Outgoing Proxy Support
- PowerPC support
- Visual Studio / Windows support
- Timeouts
- CMake build/install support
- validate_handler
- http_handler
Future feature roadmap
- Extension support
- permessage_compress extension
- Message buffer pool
- flow control
- tutorials & documentation
+123
View File
@@ -0,0 +1,123 @@
/*
base64.cpp and base64.h
Copyright (C) 2004-2008 René Nyffenegger
This source code is provided 'as-is', without any express or implied
warranty. In no event will the author be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this source code must not be misrepresented; you must not
claim that you wrote the original source code. If you use this source code
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original source code.
3. This notice may not be removed or altered from any source distribution.
René Nyffenegger rene.nyffenegger@adp-gmbh.ch
*/
#include "base64.h"
#include <iostream>
static const std::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
static inline bool is_base64(unsigned char c) {
return (isalnum(c) || (c == '+') || (c == '/'));
}
std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) {
std::string ret;
int i = 0;
int j = 0;
unsigned char char_array_3[3];
unsigned char char_array_4[4];
while (in_len--) {
char_array_3[i++] = *(bytes_to_encode++);
if (i == 3) {
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for(i = 0; (i <4) ; i++)
ret += base64_chars[char_array_4[i]];
i = 0;
}
}
if (i)
{
for(j = i; j < 3; j++)
char_array_3[j] = '\0';
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (j = 0; (j < i + 1); j++)
ret += base64_chars[char_array_4[j]];
while((i++ < 3))
ret += '=';
}
return ret;
}
std::string base64_decode(std::string const& encoded_string) {
size_t in_len = encoded_string.size();
int i = 0;
int j = 0;
int in_ = 0;
unsigned char char_array_4[4], char_array_3[3];
std::string ret;
while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
char_array_4[i++] = encoded_string[in_]; in_++;
if (i ==4) {
for (i = 0; i <4; i++)
char_array_4[i] = base64_chars.find(char_array_4[i]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (i = 0; (i < 3); i++)
ret += char_array_3[i];
i = 0;
}
}
if (i) {
for (j = i; j <4; j++)
char_array_4[j] = 0;
for (j = 0; j <4; j++)
char_array_4[j] = base64_chars.find(char_array_4[j]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
}
return ret;
}
+4
View File
@@ -0,0 +1,4 @@
#include <string>
std::string base64_encode(unsigned char const* , unsigned int len);
std::string base64_decode(std::string const& s);
+175
View File
@@ -0,0 +1,175 @@
/*
* Copyright (c) 2011, Peter Thorson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "network_utilities.hpp"
uint64_t htonll(uint64_t src) {
static int typ = TYP_INIT;
unsigned char c;
union {
uint64_t ull;
unsigned char c[8];
} x;
if (typ == TYP_INIT) {
x.ull = 0x01;
typ = (x.c[7] == 0x01ULL) ? TYP_BIGE : TYP_SMLE;
}
if (typ == TYP_BIGE)
return src;
x.ull = src;
c = x.c[0]; x.c[0] = x.c[7]; x.c[7] = c;
c = x.c[1]; x.c[1] = x.c[6]; x.c[6] = c;
c = x.c[2]; x.c[2] = x.c[5]; x.c[5] = c;
c = x.c[3]; x.c[3] = x.c[4]; x.c[4] = c;
return x.ull;
}
uint64_t ntohll(uint64_t src) {
return htonll(src);
}
std::string lookup_http_error_string(int code) {
switch (code) {
case 400:
return "Bad Request";
case 401:
return "Unauthorized";
case 403:
return "Forbidden";
case 404:
return "Not Found";
case 405:
return "Method Not Allowed";
case 406:
return "Not Acceptable";
case 407:
return "Proxy Authentication Required";
case 408:
return "Request Timeout";
case 409:
return "Conflict";
case 410:
return "Gone";
case 411:
return "Length Required";
case 412:
return "Precondition Failed";
case 413:
return "Request Entity Too Large";
case 414:
return "Request-URI Too Long";
case 415:
return "Unsupported Media Type";
case 416:
return "Requested Range Not Satisfiable";
case 417:
return "Expectation Failed";
case 500:
return "Internal Server Error";
case 501:
return "Not Implimented";
case 502:
return "Bad Gateway";
case 503:
return "Service Unavailable";
case 504:
return "Gateway Timeout";
case 505:
return "HTTP Version Not Supported";
default:
return "Unknown";
}
}
std::string lookup_ws_close_status_string(uint16_t code) {
switch (code) {
case 1000:
return "Normal closure";
case 1001:
return "Going away";
case 1002:
return "Protocol error";
case 1003:
return "Unacceptable data";
case 1004:
return "Reserved";
case 1005:
return "No status received";
case 1006:
return "Abnormal closure";
case 1007:
return "Invalid message data";
case 1008:
return "Policy Violation";
case 1009:
return "Message too large";
case 1010:
return "Missing required extensions";
default:
return "Unknown";
}
}
bool websocketpp::ws_uri::parse(const std::string& uri) {
boost::cmatch what;
static const boost::regex expression("(ws|wss)://([^/:\\[]+|\\[[0-9:]+\\])(:\\d{1,5})?(/[^#]*)?");
// TODO: should this split resource into path/query?
if (boost::regex_match(uri.c_str(), what, expression)) {
if (what[1] == "wss") {
secure = true;
} else {
secure = false;
}
host = what[2];
if (what[3] == "") {
port = (secure ? 443 : 80);
} else {
unsigned int t_port = atoi(std::string(what[3]).substr(1).c_str());
if (t_port > 65535) {
return false;
}
port = atoi(std::string(what[3]).substr(1).c_str());
}
if (what[4] == "") {
resource = "/";
} else {
resource = what[4];
}
return true;
} else {
return false;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, Peter Thorson. All rights reserved.
* Copyright (c) 2011, Peter Thorson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -11,10 +11,10 @@
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@@ -22,37 +22,40 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*/
#ifndef WEBSOCKETPP_CONCURRENCY_NONE_HPP
#define WEBSOCKETPP_CONCURRENCY_NONE_HPP
#ifndef NETWORK_UTILITIES_HPP
#define NETWORK_UTILITIES_HPP
#include <stdint.h>
#include <string>
#include <boost/regex.hpp>
// http://www.viva64.com/en/k/0018/
// TODO: impliment stuff from here:
// http://stackoverflow.com/questions/809902/64-bit-ntohl-in-c
#define TYP_INIT 0
#define TYP_SMLE 1
#define TYP_BIGE 2
uint64_t htonll(uint64_t src);
uint64_t ntohll(uint64_t src);
std::string lookup_http_error_string(int code);
std::string lookup_ws_close_status_string(uint16_t code);
namespace websocketpp {
namespace concurrency {
struct ws_uri {
bool parse(const std::string& uri);
namespace none_impl {
class fake_mutex {
public:
fake_mutex() {}
~fake_mutex() {}
bool secure;
std::string host;
uint16_t port;
std::string resource;
};
}
class fake_lock_guard {
public:
explicit fake_lock_guard(fake_mutex foo) {}
~fake_lock_guard() {}
};
} // namespace none_impl
/// Stub Concurrency policy to remove locking in single threaded projects
class none {
public:
typedef none_impl::fake_mutex mutex_type;
typedef none_impl::fake_lock_guard scoped_lock_type;
};
} // namespace concurrency
} // namespace websocketpp
#endif // WEBSOCKETPP_CONCURRENCY_ASYNC_HPP
#endif // NETWORK_UTILITIES_HPP
+41
View File
@@ -0,0 +1,41 @@
#
# Makefile
#
# Copyright (C) 1998, 2009
# Paul E. Jones <paulej@packetizer.com>
# All Rights Reserved.
#
#############################################################################
# $Id: Makefile 12 2009-06-22 19:34:25Z paulej $
#############################################################################
#
# Description:
# This is a makefile for UNIX to build the programs sha, shacmp, and
# shatest
#
#
CC = g++
CFLAGS = -c -O2 -Wall -D_FILE_OFFSET_BITS=64
LIBS =
OBJS = sha1.o
all: sha shacmp shatest
sha: sha.o $(OBJS)
$(CC) -o $@ sha.o $(OBJS) $(LIBS)
shacmp: shacmp.o $(OBJS)
$(CC) -o $@ shacmp.o $(OBJS) $(LIBS)
shatest: shatest.o $(OBJS)
$(CC) -o $@ shatest.o $(OBJS) $(LIBS)
%.o: %.cpp
$(CC) $(CFLAGS) -o $@ $<
clean:
$(RM) *.o sha shacmp shatest
+48
View File
@@ -0,0 +1,48 @@
#
# Makefile.nt
#
# Copyright (C) 1998, 2009
# Paul E. Jones <paulej@packetizer.com>
# All Rights Reserved.
#
#############################################################################
# $Id: Makefile.nt 13 2009-06-22 20:20:32Z paulej $
#############################################################################
#
# Description:
# This is a makefile for Win32 to build the programs sha, shacmp, and
# shatest
#
# Portability Issues:
# Designed to work with Visual C++
#
#
.silent:
!include <win32.mak>
RM = del /q
LIBS = $(conlibs) setargv.obj
CFLAGS = -D _CRT_SECURE_NO_WARNINGS /EHsc /O2 /W3
OBJS = sha1.obj
all: sha.exe shacmp.exe shatest.exe
sha.exe: sha.obj $(OBJS)
$(link) $(conflags) -out:$@ sha.obj $(OBJS) $(LIBS)
shacmp.exe: shacmp.obj $(OBJS)
$(link) $(conflags) -out:$@ shacmp.obj $(OBJS) $(LIBS)
shatest.exe: shatest.obj $(OBJS)
$(link) $(conflags) -out:$@ shatest.obj $(OBJS) $(LIBS)
.cpp.obj:
$(cc) $(CFLAGS) $(cflags) $(cvars) $<
clean:
$(RM) *.obj sha.exe shacmp.exe shatest.exe
+14
View File
@@ -0,0 +1,14 @@
Copyright (C) 1998, 2009
Paul E. Jones <paulej@packetizer.com>
Freeware Public License (FPL)
This software is licensed as "freeware." Permission to distribute
this software in source and binary forms, including incorporation
into other products, is hereby granted without a fee. THIS SOFTWARE
IS PROVIDED 'AS IS' AND WITHOUT ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHOR SHALL NOT BE HELD
LIABLE FOR ANY DAMAGES RESULTING FROM THE USE OF THIS SOFTWARE, EITHER
DIRECTLY OR INDIRECTLY, INCLUDING, BUT NOT LIMITED TO, LOSS OF DATA
OR DATA BEING RENDERED INACCURATE.
+176
View File
@@ -0,0 +1,176 @@
/*
* sha.cpp
*
* Copyright (C) 1998, 2009
* Paul E. Jones <paulej@packetizer.com>
* All Rights Reserved
*
*****************************************************************************
* $Id: sha.cpp 13 2009-06-22 20:20:32Z paulej $
*****************************************************************************
*
* Description:
* This utility will display the message digest (fingerprint) for
* the specified file(s).
*
* Portability Issues:
* None.
*/
#include <stdio.h>
#include <string.h>
#ifdef WIN32
#include <io.h>
#endif
#include <fcntl.h>
#include "sha1.h"
/*
* Function prototype
*/
void usage();
/*
* main
*
* Description:
* This is the entry point for the program
*
* Parameters:
* argc: [in]
* This is the count of arguments in the argv array
* argv: [in]
* This is an array of filenames for which to compute message digests
*
* Returns:
* Nothing.
*
* Comments:
*
*/
int main(int argc, char *argv[])
{
SHA1 sha; // SHA-1 class
FILE *fp; // File pointer for reading files
char c; // Character read from file
unsigned message_digest[5]; // Message digest from "sha"
int i; // Counter
bool reading_stdin; // Are we reading standard in?
bool read_stdin = false; // Have we read stdin?
/*
* Check the program arguments and print usage information if -?
* or --help is passed as the first argument.
*/
if (argc > 1 && (!strcmp(argv[1],"-?") || !strcmp(argv[1],"--help")))
{
usage();
return 1;
}
/*
* For each filename passed in on the command line, calculate the
* SHA-1 value and display it.
*/
for(i = 0; i < argc; i++)
{
/*
* We start the counter at 0 to guarantee entry into the for loop.
* So if 'i' is zero, we will increment it now. If there is no
* argv[1], we will use STDIN below.
*/
if (i == 0)
{
i++;
}
if (argc == 1 || !strcmp(argv[i],"-"))
{
#ifdef WIN32
_setmode(_fileno(stdin), _O_BINARY);
#endif
fp = stdin;
reading_stdin = true;
}
else
{
if (!(fp = fopen(argv[i],"rb")))
{
fprintf(stderr, "sha: unable to open file %s\n", argv[i]);
return 2;
}
reading_stdin = false;
}
/*
* We do not want to read STDIN multiple times
*/
if (reading_stdin)
{
if (read_stdin)
{
continue;
}
read_stdin = true;
}
/*
* Reset the SHA1 object and process input
*/
sha.Reset();
c = fgetc(fp);
while(!feof(fp))
{
sha.Input(c);
c = fgetc(fp);
}
if (!reading_stdin)
{
fclose(fp);
}
if (!sha.Result(message_digest))
{
fprintf(stderr,"sha: could not compute message digest for %s\n",
reading_stdin?"STDIN":argv[i]);
}
else
{
printf( "%08X %08X %08X %08X %08X - %s\n",
message_digest[0],
message_digest[1],
message_digest[2],
message_digest[3],
message_digest[4],
reading_stdin?"STDIN":argv[i]);
}
}
return 0;
}
/*
* usage
*
* Description:
* This function will display program usage information to the user.
*
* Parameters:
* None.
*
* Returns:
* Nothing.
*
* Comments:
*
*/
void usage()
{
printf("usage: sha <file> [<file> ...]\n");
printf("\tThis program will display the message digest (fingerprint)\n");
printf("\tfor files using the Secure Hashing Algorithm (SHA-1).\n");
}
+589
View File
@@ -0,0 +1,589 @@
/*
* sha1.cpp
*
* Copyright (C) 1998, 2009
* Paul E. Jones <paulej@packetizer.com>
* All Rights Reserved.
*
*****************************************************************************
* $Id: sha1.cpp 12 2009-06-22 19:34:25Z paulej $
*****************************************************************************
*
* Description:
* This class implements the Secure Hashing Standard as defined
* in FIPS PUB 180-1 published April 17, 1995.
*
* The Secure Hashing Standard, which uses the Secure Hashing
* Algorithm (SHA), produces a 160-bit message digest for a
* given data stream. In theory, it is highly improbable that
* two messages will produce the same message digest. Therefore,
* this algorithm can serve as a means of providing a "fingerprint"
* for a message.
*
* Portability Issues:
* SHA-1 is defined in terms of 32-bit "words". This code was
* written with the expectation that the processor has at least
* a 32-bit machine word size. If the machine word size is larger,
* the code should still function properly. One caveat to that
* is that the input functions taking characters and character arrays
* assume that only 8 bits of information are stored in each character.
*
* Caveats:
* SHA-1 is designed to work with messages less than 2^64 bits long.
* Although SHA-1 allows a message digest to be generated for
* messages of any number of bits less than 2^64, this implementation
* only works with messages with a length that is a multiple of 8
* bits.
*
*/
#include "sha1.h"
/*
* SHA1
*
* Description:
* This is the constructor for the sha1 class.
*
* Parameters:
* None.
*
* Returns:
* Nothing.
*
* Comments:
*
*/
SHA1::SHA1()
{
Reset();
}
/*
* ~SHA1
*
* Description:
* This is the destructor for the sha1 class
*
* Parameters:
* None.
*
* Returns:
* Nothing.
*
* Comments:
*
*/
SHA1::~SHA1()
{
// The destructor does nothing
}
/*
* Reset
*
* Description:
* This function will initialize the sha1 class member variables
* in preparation for computing a new message digest.
*
* Parameters:
* None.
*
* Returns:
* Nothing.
*
* Comments:
*
*/
void SHA1::Reset()
{
Length_Low = 0;
Length_High = 0;
Message_Block_Index = 0;
H[0] = 0x67452301;
H[1] = 0xEFCDAB89;
H[2] = 0x98BADCFE;
H[3] = 0x10325476;
H[4] = 0xC3D2E1F0;
Computed = false;
Corrupted = false;
}
/*
* Result
*
* Description:
* This function will return the 160-bit message digest into the
* array provided.
*
* Parameters:
* message_digest_array: [out]
* This is an array of five unsigned integers which will be filled
* with the message digest that has been computed.
*
* Returns:
* True if successful, false if it failed.
*
* Comments:
*
*/
bool SHA1::Result(unsigned *message_digest_array)
{
int i; // Counter
if (Corrupted)
{
return false;
}
if (!Computed)
{
PadMessage();
Computed = true;
}
for(i = 0; i < 5; i++)
{
message_digest_array[i] = H[i];
}
return true;
}
/*
* Input
*
* Description:
* This function accepts an array of octets as the next portion of
* the message.
*
* Parameters:
* message_array: [in]
* An array of characters representing the next portion of the
* message.
*
* Returns:
* Nothing.
*
* Comments:
*
*/
void SHA1::Input( const unsigned char *message_array,
unsigned length)
{
if (!length)
{
return;
}
if (Computed || Corrupted)
{
Corrupted = true;
return;
}
while(length-- && !Corrupted)
{
Message_Block[Message_Block_Index++] = (*message_array & 0xFF);
Length_Low += 8;
Length_Low &= 0xFFFFFFFF; // Force it to 32 bits
if (Length_Low == 0)
{
Length_High++;
Length_High &= 0xFFFFFFFF; // Force it to 32 bits
if (Length_High == 0)
{
Corrupted = true; // Message is too long
}
}
if (Message_Block_Index == 64)
{
ProcessMessageBlock();
}
message_array++;
}
}
/*
* Input
*
* Description:
* This function accepts an array of octets as the next portion of
* the message.
*
* Parameters:
* message_array: [in]
* An array of characters representing the next portion of the
* message.
* length: [in]
* The length of the message_array
*
* Returns:
* Nothing.
*
* Comments:
*
*/
void SHA1::Input( const char *message_array,
unsigned length)
{
Input((unsigned char *) message_array, length);
}
/*
* Input
*
* Description:
* This function accepts a single octets as the next message element.
*
* Parameters:
* message_element: [in]
* The next octet in the message.
*
* Returns:
* Nothing.
*
* Comments:
*
*/
void SHA1::Input(unsigned char message_element)
{
Input(&message_element, 1);
}
/*
* Input
*
* Description:
* This function accepts a single octet as the next message element.
*
* Parameters:
* message_element: [in]
* The next octet in the message.
*
* Returns:
* Nothing.
*
* Comments:
*
*/
void SHA1::Input(char message_element)
{
Input((unsigned char *) &message_element, 1);
}
/*
* operator<<
*
* Description:
* This operator makes it convenient to provide character strings to
* the SHA1 object for processing.
*
* Parameters:
* message_array: [in]
* The character array to take as input.
*
* Returns:
* A reference to the SHA1 object.
*
* Comments:
* Each character is assumed to hold 8 bits of information.
*
*/
SHA1& SHA1::operator<<(const char *message_array)
{
const char *p = message_array;
while(*p)
{
Input(*p);
p++;
}
return *this;
}
/*
* operator<<
*
* Description:
* This operator makes it convenient to provide character strings to
* the SHA1 object for processing.
*
* Parameters:
* message_array: [in]
* The character array to take as input.
*
* Returns:
* A reference to the SHA1 object.
*
* Comments:
* Each character is assumed to hold 8 bits of information.
*
*/
SHA1& SHA1::operator<<(const unsigned char *message_array)
{
const unsigned char *p = message_array;
while(*p)
{
Input(*p);
p++;
}
return *this;
}
/*
* operator<<
*
* Description:
* This function provides the next octet in the message.
*
* Parameters:
* message_element: [in]
* The next octet in the message
*
* Returns:
* A reference to the SHA1 object.
*
* Comments:
* The character is assumed to hold 8 bits of information.
*
*/
SHA1& SHA1::operator<<(const char message_element)
{
Input((unsigned char *) &message_element, 1);
return *this;
}
/*
* operator<<
*
* Description:
* This function provides the next octet in the message.
*
* Parameters:
* message_element: [in]
* The next octet in the message
*
* Returns:
* A reference to the SHA1 object.
*
* Comments:
* The character is assumed to hold 8 bits of information.
*
*/
SHA1& SHA1::operator<<(const unsigned char message_element)
{
Input(&message_element, 1);
return *this;
}
/*
* ProcessMessageBlock
*
* Description:
* This function will process the next 512 bits of the message
* stored in the Message_Block array.
*
* Parameters:
* None.
*
* Returns:
* Nothing.
*
* Comments:
* Many of the variable names in this function, especially the single
* character names, were used because those were the names used
* in the publication.
*
*/
void SHA1::ProcessMessageBlock()
{
const unsigned K[] = { // Constants defined for SHA-1
0x5A827999,
0x6ED9EBA1,
0x8F1BBCDC,
0xCA62C1D6
};
int t; // Loop counter
unsigned temp; // Temporary word value
unsigned W[80]; // Word sequence
unsigned A, B, C, D, E; // Word buffers
/*
* Initialize the first 16 words in the array W
*/
for(t = 0; t < 16; t++)
{
W[t] = ((unsigned) Message_Block[t * 4]) << 24;
W[t] |= ((unsigned) Message_Block[t * 4 + 1]) << 16;
W[t] |= ((unsigned) Message_Block[t * 4 + 2]) << 8;
W[t] |= ((unsigned) Message_Block[t * 4 + 3]);
}
for(t = 16; t < 80; t++)
{
W[t] = CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
}
A = H[0];
B = H[1];
C = H[2];
D = H[3];
E = H[4];
for(t = 0; t < 20; t++)
{
temp = CircularShift(5,A) + ((B & C) | ((~B) & D)) + E + W[t] + K[0];
temp &= 0xFFFFFFFF;
E = D;
D = C;
C = CircularShift(30,B);
B = A;
A = temp;
}
for(t = 20; t < 40; t++)
{
temp = CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
temp &= 0xFFFFFFFF;
E = D;
D = C;
C = CircularShift(30,B);
B = A;
A = temp;
}
for(t = 40; t < 60; t++)
{
temp = CircularShift(5,A) +
((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
temp &= 0xFFFFFFFF;
E = D;
D = C;
C = CircularShift(30,B);
B = A;
A = temp;
}
for(t = 60; t < 80; t++)
{
temp = CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
temp &= 0xFFFFFFFF;
E = D;
D = C;
C = CircularShift(30,B);
B = A;
A = temp;
}
H[0] = (H[0] + A) & 0xFFFFFFFF;
H[1] = (H[1] + B) & 0xFFFFFFFF;
H[2] = (H[2] + C) & 0xFFFFFFFF;
H[3] = (H[3] + D) & 0xFFFFFFFF;
H[4] = (H[4] + E) & 0xFFFFFFFF;
Message_Block_Index = 0;
}
/*
* PadMessage
*
* Description:
* According to the standard, the message must be padded to an even
* 512 bits. The first padding bit must be a '1'. The last 64 bits
* represent the length of the original message. All bits in between
* should be 0. This function will pad the message according to those
* rules by filling the message_block array accordingly. It will also
* call ProcessMessageBlock() appropriately. When it returns, it
* can be assumed that the message digest has been computed.
*
* Parameters:
* None.
*
* Returns:
* Nothing.
*
* Comments:
*
*/
void SHA1::PadMessage()
{
/*
* Check to see if the current message block is too small to hold
* the initial padding bits and length. If so, we will pad the
* block, process it, and then continue padding into a second block.
*/
if (Message_Block_Index > 55)
{
Message_Block[Message_Block_Index++] = 0x80;
while(Message_Block_Index < 64)
{
Message_Block[Message_Block_Index++] = 0;
}
ProcessMessageBlock();
while(Message_Block_Index < 56)
{
Message_Block[Message_Block_Index++] = 0;
}
}
else
{
Message_Block[Message_Block_Index++] = 0x80;
while(Message_Block_Index < 56)
{
Message_Block[Message_Block_Index++] = 0;
}
}
/*
* Store the message length as the last 8 octets
*/
Message_Block[56] = (Length_High >> 24) & 0xFF;
Message_Block[57] = (Length_High >> 16) & 0xFF;
Message_Block[58] = (Length_High >> 8) & 0xFF;
Message_Block[59] = (Length_High) & 0xFF;
Message_Block[60] = (Length_Low >> 24) & 0xFF;
Message_Block[61] = (Length_Low >> 16) & 0xFF;
Message_Block[62] = (Length_Low >> 8) & 0xFF;
Message_Block[63] = (Length_Low) & 0xFF;
ProcessMessageBlock();
}
/*
* CircularShift
*
* Description:
* This member function will perform a circular shifting operation.
*
* Parameters:
* bits: [in]
* The number of bits to shift (1-31)
* word: [in]
* The value to shift (assumes a 32-bit integer)
*
* Returns:
* The shifted value.
*
* Comments:
*
*/
unsigned SHA1::CircularShift(int bits, unsigned word)
{
return ((word << bits) & 0xFFFFFFFF) | ((word & 0xFFFFFFFF) >> (32-bits));
}
+89
View File
@@ -0,0 +1,89 @@
/*
* sha1.h
*
* Copyright (C) 1998, 2009
* Paul E. Jones <paulej@packetizer.com>
* All Rights Reserved.
*
*****************************************************************************
* $Id: sha1.h 12 2009-06-22 19:34:25Z paulej $
*****************************************************************************
*
* Description:
* This class implements the Secure Hashing Standard as defined
* in FIPS PUB 180-1 published April 17, 1995.
*
* Many of the variable names in this class, especially the single
* character names, were used because those were the names used
* in the publication.
*
* Please read the file sha1.cpp for more information.
*
*/
#ifndef _SHA1_H_
#define _SHA1_H_
class SHA1
{
public:
SHA1();
virtual ~SHA1();
/*
* Re-initialize the class
*/
void Reset();
/*
* Returns the message digest
*/
bool Result(unsigned *message_digest_array);
/*
* Provide input to SHA1
*/
void Input( const unsigned char *message_array,
unsigned length);
void Input( const char *message_array,
unsigned length);
void Input(unsigned char message_element);
void Input(char message_element);
SHA1& operator<<(const char *message_array);
SHA1& operator<<(const unsigned char *message_array);
SHA1& operator<<(const char message_element);
SHA1& operator<<(const unsigned char message_element);
private:
/*
* Process the next 512 bits of the message
*/
void ProcessMessageBlock();
/*
* Pads the current message block to 512 bits
*/
void PadMessage();
/*
* Performs a circular left shift operation
*/
inline unsigned CircularShift(int bits, unsigned word);
unsigned H[5]; // Message digest buffers
unsigned Length_Low; // Message length in bits
unsigned Length_High; // Message length in bits
unsigned char Message_Block[64]; // 512-bit message blocks
int Message_Block_Index; // Index into message block array
bool Computed; // Is the digest computed?
bool Corrupted; // Is the message digest corruped?
};
#endif
+169
View File
@@ -0,0 +1,169 @@
/*
* shacmp.cpp
*
* Copyright (C) 1998, 2009
* Paul E. Jones <paulej@packetizer.com>
* All Rights Reserved
*
*****************************************************************************
* $Id: shacmp.cpp 12 2009-06-22 19:34:25Z paulej $
*****************************************************************************
*
* Description:
* This utility will compare two files by producing a message digest
* for each file using the Secure Hashing Algorithm and comparing
* the message digests. This function will return 0 if they
* compare or 1 if they do not or if there is an error.
* Errors result in a return code higher than 1.
*
* Portability Issues:
* none.
*
*/
#include <stdio.h>
#include <string.h>
#include "sha1.h"
/*
* Return codes
*/
#define SHA1_COMPARE 0
#define SHA1_NO_COMPARE 1
#define SHA1_USAGE_ERROR 2
#define SHA1_FILE_ERROR 3
/*
* Function prototype
*/
void usage();
/*
* main
*
* Description:
* This is the entry point for the program
*
* Parameters:
* argc: [in]
* This is the count of arguments in the argv array
* argv: [in]
* This is an array of filenames for which to compute message digests
*
* Returns:
* Nothing.
*
* Comments:
*
*/
int main(int argc, char *argv[])
{
SHA1 sha; // SHA-1 class
FILE *fp; // File pointer for reading files
char c; // Character read from file
unsigned message_digest[2][5]; // Message digest for files
int i; // Counter
bool message_match; // Message digest match flag
int returncode;
/*
* If we have two arguments, we will assume they are filenames. If
* we do not have to arguments, call usage() and exit.
*/
if (argc != 3)
{
usage();
return SHA1_USAGE_ERROR;
}
/*
* Get the message digests for each file
*/
for(i = 1; i <= 2; i++)
{
sha.Reset();
if (!(fp = fopen(argv[i],"rb")))
{
fprintf(stderr, "sha: unable to open file %s\n", argv[i]);
return SHA1_FILE_ERROR;
}
c = fgetc(fp);
while(!feof(fp))
{
sha.Input(c);
c = fgetc(fp);
}
fclose(fp);
if (!sha.Result(message_digest[i-1]))
{
fprintf(stderr,"shacmp: could not compute message digest for %s\n",
argv[i]);
return SHA1_FILE_ERROR;
}
}
/*
* Compare the message digest values
*/
message_match = true;
for(i = 0; i < 5; i++)
{
if (message_digest[0][i] != message_digest[1][i])
{
message_match = false;
break;
}
}
if (message_match)
{
printf("Fingerprints match:\n");
returncode = SHA1_COMPARE;
}
else
{
printf("Fingerprints do not match:\n");
returncode = SHA1_NO_COMPARE;
}
printf( "\t%08X %08X %08X %08X %08X\n",
message_digest[0][0],
message_digest[0][1],
message_digest[0][2],
message_digest[0][3],
message_digest[0][4]);
printf( "\t%08X %08X %08X %08X %08X\n",
message_digest[1][0],
message_digest[1][1],
message_digest[1][2],
message_digest[1][3],
message_digest[1][4]);
return returncode;
}
/*
* usage
*
* Description:
* This function will display program usage information to the user.
*
* Parameters:
* None.
*
* Returns:
* Nothing.
*
* Comments:
*
*/
void usage()
{
printf("usage: shacmp <file> <file>\n");
printf("\tThis program will compare the message digests (fingerprints)\n");
printf("\tfor two files using the Secure Hashing Algorithm (SHA-1).\n");
}
+149
View File
@@ -0,0 +1,149 @@
/*
* shatest.cpp
*
* Copyright (C) 1998, 2009
* Paul E. Jones <paulej@packetizer.com>
* All Rights Reserved
*
*****************************************************************************
* $Id: shatest.cpp 12 2009-06-22 19:34:25Z paulej $
*****************************************************************************
*
* Description:
* This file will exercise the SHA1 class and perform the three
* tests documented in FIPS PUB 180-1.
*
* Portability Issues:
* None.
*
*/
#include <iostream>
#include "sha1.h"
using namespace std;
/*
* Define patterns for testing
*/
#define TESTA "abc"
#define TESTB "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
/*
* Function prototype
*/
void DisplayMessageDigest(unsigned *message_digest);
/*
* main
*
* Description:
* This is the entry point for the program
*
* Parameters:
* None.
*
* Returns:
* Nothing.
*
* Comments:
*
*/
int main()
{
SHA1 sha;
unsigned message_digest[5];
/*
* Perform test A
*/
cout << endl << "Test A: 'abc'" << endl;
sha.Reset();
sha << TESTA;
if (!sha.Result(message_digest))
{
cerr << "ERROR-- could not compute message digest" << endl;
}
else
{
DisplayMessageDigest(message_digest);
cout << "Should match:" << endl;
cout << '\t' << "A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D" << endl;
}
/*
* Perform test B
*/
cout << endl << "Test B: " << TESTB << endl;
sha.Reset();
sha << TESTB;
if (!sha.Result(message_digest))
{
cerr << "ERROR-- could not compute message digest" << endl;
}
else
{
DisplayMessageDigest(message_digest);
cout << "Should match:" << endl;
cout << '\t' << "84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1" << endl;
}
/*
* Perform test C
*/
cout << endl << "Test C: One million 'a' characters" << endl;
sha.Reset();
for(int i = 1; i <= 1000000; i++) sha.Input('a');
if (!sha.Result(message_digest))
{
cerr << "ERROR-- could not compute message digest" << endl;
}
else
{
DisplayMessageDigest(message_digest);
cout << "Should match:" << endl;
cout << '\t' << "34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F" << endl;
}
return 0;
}
/*
* DisplayMessageDigest
*
* Description:
* Display Message Digest array
*
* Parameters:
* None.
*
* Returns:
* Nothing.
*
* Comments:
*
*/
void DisplayMessageDigest(unsigned *message_digest)
{
ios::fmtflags flags;
cout << '\t';
flags = cout.setf(ios::hex|ios::uppercase,ios::basefield);
cout.setf(ios::uppercase);
for(int i = 0; i < 5 ; i++)
{
cout << message_digest[i] << ' ';
}
cout << endl;
cout.setf(flags);
}
+40
View File
@@ -0,0 +1,40 @@
// Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
// See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
#include <stdint.h>
namespace utf8_validator {
static const int UTF8_ACCEPT = 0;
static const int UTF8_REJECT = 1;
static const uint8_t utf8d[] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7f
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf
8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df
0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef
0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff
0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2
1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4
1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6
1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8
};
uint32_t inline
decode(uint32_t* state, uint32_t* codep, uint32_t byte) {
uint32_t type = utf8d[byte];
*codep = (*state != UTF8_ACCEPT) ?
(byte & 0x3fu) | (*codep << 6) :
(0xff >> type) & (byte);
*state = utf8d[256 + *state*16 + type];
return *state;
}
} // namespace utf8_validator
+200
View File
@@ -0,0 +1,200 @@
/*
* Copyright (c) 2011, Peter Thorson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "websocketpp.hpp"
#include "websocket_client.hpp"
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <iostream>
using websocketpp::client;
using boost::asio::ip::tcp;
client::client(boost::asio::io_service& io_service,
websocketpp::connection_handler_ptr defc)
: m_elog_level(LOG_OFF),
m_alog_level(ALOG_OFF),
m_state(CLIENT_STATE_NULL),
m_max_message_size(DEFAULT_MAX_MESSAGE_SIZE),
m_io_service(io_service),
m_resolver(io_service),
m_def_con_handler(defc) {}
void client::init() {
// TODO: sanity check whether the session buffer size bound could be reduced
m_client_session = client_session_ptr(
new client_session(
shared_from_this(),
m_io_service,
m_def_con_handler,
m_max_message_size*2
)
);
m_state = CLIENT_STATE_INITIALIZED;
}
void client::connect(const std::string& uri) {
if (m_state != CLIENT_STATE_INITIALIZED) {
throw client_error("connect can only be called after init and before a connection has been established");
}
m_client_session->set_uri(uri);
std::stringstream port;
port << m_client_session->get_port();
tcp::resolver::query query(m_client_session->get_host(),
port.str());
tcp::resolver::iterator iterator = m_resolver.resolve(query);
boost::asio::async_connect(m_client_session->socket(),
iterator,boost::bind(&client::handle_connect,
this,
boost::asio::placeholders::error));
m_state = CLIENT_STATE_CONNECTING;
}
void client::add_subprotocol(const std::string& p) {
if (m_state != CLIENT_STATE_INITIALIZED) {
throw client_error("add_protocol can only be called after init and before connect");
}
m_client_session->add_subprotocol(p);
}
void client::set_header(const std::string& key,const std::string& val) {
if (m_state != CLIENT_STATE_INITIALIZED) {
throw client_error("set_header can only be called after init and before connect");
}
m_client_session->set_header(key,val);
}
void client::set_origin(const std::string& val) {
if (m_state != CLIENT_STATE_INITIALIZED) {
throw client_error("set_origin can only be called after init and before connect");
}
m_client_session->set_origin(val);
}
void client::set_max_message_size(uint64_t val) {
if (val > frame::PAYLOAD_64BIT_LIMIT) {
std::stringstream err;
err << "Invalid maximum message size: " << val;
// TODO: Figure out what the ideal error behavior for this method.
// Options:
// Throw exception
// Log error and set value to maximum allowed
// Log error and leave value at whatever it was before
log(err.str(),LOG_WARN);
//throw client_error(err.str());
}
m_max_message_size = val;
}
bool client::test_elog_level(uint16_t level) {
return (level >= m_elog_level);
}
void client::set_elog_level(uint16_t level) {
std::stringstream msg;
msg << "Error logging level changing from "
<< m_elog_level << " to " << level;
log(msg.str(),LOG_INFO);
m_elog_level = level;
}
bool client::test_alog_level(uint16_t level) {
return ((level & m_alog_level) != 0);
}
void client::set_alog_level(uint16_t level) {
if (test_alog_level(level)) {
return;
}
std::stringstream msg;
msg << "Access logging level " << level << " being set";
access_log(msg.str(),ALOG_INFO);
m_alog_level |= level;
}
void client::unset_alog_level(uint16_t level) {
if (!test_alog_level(level)) {
return;
}
std::stringstream msg;
msg << "Access logging level " << level << " being unset";
access_log(msg.str(),ALOG_INFO);
m_alog_level &= ~level;
}
bool client::validate_message_size(uint64_t val) {
if (val > m_max_message_size) {
return false;
}
return true;
}
void client::log(std::string msg,uint16_t level) {
if (!test_elog_level(level)) {
return;
}
std::cerr << "[Error Log] "
<< boost::posix_time::to_iso_extended_string(
boost::posix_time::second_clock::local_time())
<< " " << msg << std::endl;
}
void client::access_log(std::string msg,uint16_t level) {
if (!test_alog_level(level)) {
return;
}
std::cout << "[Access Log] "
<< boost::posix_time::to_iso_extended_string(
boost::posix_time::second_clock::local_time())
<< " " << msg << std::endl;
}
void client::handle_connect(const boost::system::error_code& error) {
if (!error) {
std::stringstream err;
err << "Successful Connection ";
log(err.str(),LOG_ERROR);
std::cout << boost::posix_time::to_iso_extended_string(boost::posix_time::microsec_clock::local_time()) << " TCP established" << std::endl;
m_state = CLIENT_STATE_CONNECTED;
m_client_session->on_connect();
} else {
std::stringstream err;
err << "An error occurred while establishing a connection: " << error;
log(err.str(),LOG_ERROR);
throw client_error(err.str());
}
}
+135
View File
@@ -0,0 +1,135 @@
/*
* Copyright (c) 2011, Peter Thorson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef WEBSOCKET_CLIENT_HPP
#define WEBSOCKET_CLIENT_HPP
#include <boost/asio.hpp>
#include <boost/shared_ptr.hpp>
#include <set>
namespace websocketpp {
class client;
typedef boost::shared_ptr<client> client_ptr;
}
#include "websocketpp.hpp"
#include "websocket_client_session.hpp"
#include "websocket_connection_handler.hpp"
using boost::asio::ip::tcp;
namespace websocketpp {
class client_error : public std::exception {
public:
client_error(const std::string& msg)
: m_msg(msg) {}
~client_error() throw() {}
virtual const char* what() const throw() {
return m_msg.c_str();
}
private:
std::string m_msg;
};
class client : public boost::enable_shared_from_this<client> {
public:
static const uint16_t CLIENT_STATE_NULL = 0;
static const uint16_t CLIENT_STATE_INITIALIZED = 1;
static const uint16_t CLIENT_STATE_CONNECTING = 2;
static const uint16_t CLIENT_STATE_CONNECTED = 3;
client(boost::asio::io_service& io_service,
connection_handler_ptr defc);
// INTERFACE FOR LOCAL APPLICATIONS
// initializes the session. Methods that affect the opening handshake
// such as add_protocol and set_header must be called after init and
// before connect.
void init();
// starts the connection process. Should be called before
// io_service.run(), connection process will not start until run() has
// been called.
void connect(const std::string& url);
// Adds a protocol to the opening handshake.
// Must be called before connect
void add_subprotocol(const std::string& p);
// Sets the value of the given HTTP header to be sent during the
// opening handshake. Must be called before connect
void set_header(const std::string& key,const std::string& val);
void set_origin(const std::string& val);
void set_max_message_size(uint64_t val);
// Test methods determine if a message of the given level should be
// written. elog shows all values above the level set. alog shows only
// the values explicitly set.
bool test_elog_level(uint16_t level);
void set_elog_level(uint16_t level);
bool test_alog_level(uint16_t level);
void set_alog_level(uint16_t level);
void unset_alog_level(uint16_t level);
// INTERFACE FOR SESSIONS
// Check if message size is within server's acceptable parameters
bool validate_message_size(uint64_t val);
// write to the server's logs
void log(std::string msg,uint16_t level = LOG_ERROR);
void access_log(std::string msg,uint16_t level);
private:
// if no errors starts the session's read loop and returns to the
// start_accept phase.
void handle_connect(const boost::system::error_code& error);
private:
uint16_t m_elog_level;
uint16_t m_alog_level;
uint16_t m_state;
std::set<std::string> m_hosts;
uint64_t m_max_message_size;
boost::asio::io_service& m_io_service;
tcp::resolver m_resolver;
client_session_ptr m_client_session;
connection_handler_ptr m_def_con_handler;
};
}
#endif // WEBSOCKET_CLIENT_HPP
+354
View File
@@ -0,0 +1,354 @@
/*
* Copyright (c) 2011, Peter Thorson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "websocketpp.hpp"
#include "websocket_client_session.hpp"
#include "websocket_frame.hpp"
#include "utf8_validator/utf8_validator.hpp"
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/random.hpp>
#include <boost/random/random_device.hpp>
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <string>
using websocketpp::client_session;
client_session::client_session (websocketpp::client_ptr c,
boost::asio::io_service& io_service,
websocketpp::connection_handler_ptr defc,
uint64_t buf_size)
: session(io_service,defc,buf_size),m_client(c) {}
void client_session::on_connect() {
// TODO: section 4.1: Figure out if we have another connection to this
// host/port pending.
write_handshake();
}
void client_session::set_uri(const std::string& uri) {
if (!m_uri.parse(uri)) {
throw client_error("Invalid WebSocket URI");
}
if (m_uri.secure) {
throw client_error("wss / secure connections are not supported at this time");
}
m_resource = m_uri.resource;
std::stringstream l;
l << "parsed websocket url: secure: " << m_uri.secure << " host: " << m_uri.host
<< " port (final): " << m_uri.port << " resource " << m_uri.resource;
log(l.str(),LOG_DEBUG);
}
bool client_session::get_secure() const {
return m_uri.secure;
}
std::string client_session::get_host() const{
return m_uri.host;
}
uint16_t client_session::get_port() const {
return m_uri.port;
}
void client_session::set_header(const std::string &key,const std::string &val) {
// TODO: prevent use of reserved headers
m_client_headers[key] = val;
}
void client_session::set_origin(const std::string& val) {
// TODO: input validation
m_client_origin = val;
}
void client_session::add_subprotocol(const std::string &val) {
// TODO: input validation
m_client_subprotocols.push_back(val);
}
void client_session::add_extension(const std::string& val) {
// TODO: input validation
m_client_extensions.push_back(val);
}
void client_session::read_handshake() {
boost::asio::async_read_until(
m_socket,
m_buf,
"\r\n\r\n",
boost::bind(
&session::handle_read_handshake,
shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred
)
);
}
void client_session::handle_read_handshake(const boost::system::error_code& e,
std::size_t bytes_transferred) {
if (e) {
log_error("Error reading server handshake",e);
drop_tcp();
return;
}
// parse server handshake
std::istream response_stream(&m_buf);
std::string header;
std::string::size_type end;
// get status line
std::getline(response_stream, header);
if (header[header.size()-1] == '\r') {
header.erase(header.end()-1);
m_server_http_request = header;
m_raw_server_handshake += header+"\n";
}
// get headers
while (std::getline(response_stream, header) && header != "\r") {
if (header[header.size()-1] != '\r') {
continue; // ignore malformed header lines?
} else {
header.erase(header.end()-1);
}
end = header.find(": ",0);
if (end != std::string::npos) {
std::string h = header.substr(0,end);
if (get_server_header(h) == "") {
m_server_headers[h] = header.substr(end+2);
} else {
m_server_headers[h] += ", " + header.substr(end+2);
}
}
m_raw_server_handshake += header+"\n";
}
// temporary debugging
if (m_buf.size() > 0) {
std::stringstream foo;
foo << "bytes left over: " << m_buf.size();
access_log(foo.str(), ALOG_HANDSHAKE);
}
m_client->access_log(m_raw_server_handshake,ALOG_HANDSHAKE);
// handshake error checking
try {
std::stringstream err;
std::string h;
// TODO: allow versions greater than 1.1
if (m_server_http_request.substr(0,9) != "HTTP/1.1 ") {
err << "Websocket handshake has invalid HTTP version: "
<< m_server_http_request.substr(0,9);
throw(handshake_error(err.str(),400));
}
// check the HTTP version
if (m_server_http_request.substr(9,3) != "101") {
err << "Websocket handshake ended with status "
<< m_server_http_request.substr(9);
// TODO: check version header for other supported versions.
throw(handshake_error(err.str(),400));
}
// verify the presence of required headers
h = get_server_header("Upgrade");
if (h == "") {
throw(handshake_error("Required Upgrade header is missing",400));
} else if (!boost::iequals(h,"websocket")) {
err << "Upgrade header was \"" << h << "\" instead of \"websocket\"";
throw(handshake_error(err.str(),400));
}
h = get_server_header("Connection");
if (h == "") {
throw(handshake_error("Required Connection header is missing",400));
} else if (!boost::ifind_first(h,"upgrade")) {
err << "Connection header, \"" << h
<< "\", does not contain required token \"upgrade\"";
throw(handshake_error(err.str(),400));
}
if (get_server_header("Sec-WebSocket-Accept") == "") {
throw(handshake_error("Required Sec-WebSocket-Key header is missing",400));
} else {
// TODO: make a helper function for this.
std::string server_key = m_client_key;
server_key += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
SHA1 sha;
uint32_t message_digest[5];
sha.Reset();
sha << server_key.c_str();
if (!sha.Result(message_digest)) {
m_client->log("Error computing handshake sha1 hash.",LOG_ERROR);
// TODO: close behavior
return;
}
// convert sha1 hash bytes to network byte order because this sha1
// library works on ints rather than bytes
for (int i = 0; i < 5; i++) {
message_digest[i] = htonl(message_digest[i]);
}
server_key = base64_encode(
reinterpret_cast<const unsigned char*>(message_digest),20);
if (server_key != get_server_header("Sec-WebSocket-Accept")) {
m_client->log("Server key does not match",LOG_ERROR);
// TODO: close behavior
return;
}
}
} catch (const handshake_error& e) {
std::stringstream err;
err << "Caught handshake exception: " << e.what();
m_client->access_log(e.what(),ALOG_HANDSHAKE);
m_client->log(err.str(),LOG_ERROR);
// TODO: close behavior
return;
}
log_open_result();
m_state = STATE_OPEN;
if (m_local_interface) {
m_local_interface->on_open(shared_from_this());
}
reset_message();
read_frame();
}
void client_session::write_handshake() {
// generate client handshake.
std::string client_handshake;
client_handshake += "GET "+m_resource+" HTTP/1.1\r\n";
set_header("Upgrade","websocket");
set_header("Connection","Upgrade");
set_header("Sec-WebSocket-Version","13");
std::stringstream h;
h << m_uri.host << ":" << m_uri.port;
set_header("Host",h.str());
if (m_client_origin != "") {
set_header("Origin",m_client_origin);
}
// TODO: generate proper key
m_client_key = "XO4pxrIMLnK1CEVQP9untQ==";
int32_t raw_key[4];
boost::random::random_device rng;
boost::random::variate_generator<boost::random::random_device&, boost::random::uniform_int_distribution<> > gen(rng, boost::random::uniform_int_distribution<>(INT32_MIN,INT32_MAX));
for (int i = 0; i < 4; i++) {
raw_key[i] = gen();
}
m_client_key = base64_encode(reinterpret_cast<unsigned char const*>(raw_key), 16);
m_client->access_log("Client key chosen: "+m_client_key, ALOG_HANDSHAKE);
set_header("Sec-WebSocket-Key",m_client_key);
set_header("User Agent","WebSocket++/2011-09-25");
header_list::iterator it;
for (it = m_client_headers.begin(); it != m_client_headers.end(); it++) {
client_handshake += it->first + ": " + it->second + "\r\n";
}
client_handshake += "\r\n";
m_raw_client_handshake = client_handshake;
// start async write to handle_write_handshake
boost::asio::async_write(
m_socket,
boost::asio::buffer(m_raw_client_handshake),
boost::bind(
&session::handle_write_handshake,
shared_from_this(),
boost::asio::placeholders::error
)
);
}
void client_session::handle_write_handshake(const boost::system::error_code& error) {
if (error) {
log_error("Error writing handshake",error);
drop_tcp();
return;
}
read_handshake();
}
void client_session::log(const std::string& msg, uint16_t level) const {
m_client->log(msg,level);
}
void client_session::access_log(const std::string& msg, uint16_t level) const {
m_client->access_log(msg,level);
}
+135
View File
@@ -0,0 +1,135 @@
/*
* Copyright (c) 2011, Peter Thorson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef WEBSOCKET_CLIENT_SESSION_HPP
#define WEBSOCKET_CLIENT_SESSION_HPP
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#if defined(WIN32)
#include <winsock2.h>
#else
#include <arpa/inet.h>
#endif
#include <algorithm>
#include <exception>
#include <iostream>
#include <map>
#include <set>
#include <sstream>
#include <string>
#include <vector>
namespace websocketpp {
class client_session;
typedef boost::shared_ptr<client_session> client_session_ptr;
}
#include "websocket_session.hpp"
#include "websocket_client.hpp"
using boost::asio::ip::tcp;
namespace websocketpp {
class client_session : public session {
public:
client_session (client_ptr c,
boost::asio::io_service& io_service,
connection_handler_ptr defc,
uint64_t buf_size);
/*** CLIENT INTERFACE ***/
// This function is called when a tcp connection has been established and
// the connection is ready to start the opening handshake.
void on_connect();
/*** HANDSHAKE INTERFACE ***/
void set_uri(const std::string& url);
bool get_secure() const;
std::string get_host() const;
uint16_t get_port() const;
// Set an HTTP header for the outgoing client handshake.
void set_header(const std::string& key,const std::string& val);
// adds a subprotocol. This will result in the appropriate
// Sec-WebSocket-Protocol header being sent with the opening connection.
// Values will be sent in the order they were added. Servers interpret this
// order as the preferred order.
void add_subprotocol(const std::string &val);
// Sets the origin value that will be sent to the server
void set_origin(const std::string &val);
// Adds an extension to the extension list. Extensions are sent in the
// order added
void add_extension(const std::string& val);
/*** SESSION INTERFACE ***/
// see session
bool is_server() const {return false;}
void log(const std::string& msg, uint16_t level) const;
void access_log(const std::string& msg, uint16_t level) const;
protected:
// Opening handshake processors and callbacks.
virtual void write_handshake();
virtual void handle_write_handshake(const boost::system::error_code& e);
virtual void read_handshake();
virtual void handle_read_handshake(const boost::system::error_code& e,
std::size_t bytes_transferred);
private:
protected:
ws_uri m_uri;
// url parts
bool m_secure;
std::string m_host;
uint16_t m_port;
// handshake stuff
std::string m_client_key;
// connection resources
client_ptr m_client;
private:
};
}
#endif // WEBSOCKET_CLIENT_SESSION_HPP
+113
View File
@@ -0,0 +1,113 @@
/*
* Copyright (c) 2011, Peter Thorson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef WEBSOCKET_CONNECTION_HANDLER_HPP
#define WEBSOCKET_CONNECTION_HANDLER_HPP
#include <boost/shared_ptr.hpp>
#include <string>
#include <map>
namespace websocketpp {
class connection_handler;
typedef boost::shared_ptr<connection_handler> connection_handler_ptr;
}
#include "websocket_session.hpp"
namespace websocketpp {
class connection_handler {
public:
// validate will be called after a websocket handshake has been received and
// before it is accepted. It provides a handler the ability to refuse a
// connection based on application specific logic (ex: restrict domains or
// negotiate subprotocols). To reject the connection throw a handshake_error
//
// Validate is never called for client sessions. To refuse a client session
// (ex: if you do not like the set of extensions/subprotocols the server
// chose) you can close the connection immediately in the on_open method.
//
// handshake_error parameters:
// log_message - error message to send to server log
// http_error_code - numeric HTTP error code to return to the client
// http_error_msg - (optional) string HTTP error code to return to the
// client (useful for returning non-standard error codes)
virtual void validate(session_ptr session) {};
// on_open is called after the websocket session has been successfully
// established and is in the OPEN state. The session is now avaliable to
// send messages and will begin reading frames and calling the on_message/
// on_close/on_error callbacks. A client may reject the connection by
// closing the session at this point.
virtual void on_open(session_ptr session) = 0;
// on_close is called whenever an open session is closed for any reason.
// This can be due to either endpoint requesting a connection close or an
// error occuring. Information about why the session was closed can be
// extracted from the session itself.
//
// on_close will be the last time a session calls its handler. If your
// application will need information from `session` after this function you
// should either save the session_ptr somewhere or copy the data out.
virtual void on_close(session_ptr session) = 0;
// on_message (binary version) will be called when a binary message is
// recieved. Message data is passed as a vector of bytes (unsigned char).
// data will not be avaliable after this callback ends so the handler must
// either completely process the message or copy it somewhere else for
// processing later.
virtual void on_message(session_ptr session,
const std::vector<unsigned char> &data) = 0;
// on_message (text version). Identical to on_message except the data
// parameter is a string interpreted as UTF-8. WebSocket++ guarantees that
// this string is valid UTF-8.
virtual void on_message(session_ptr session,const std::string &msg) = 0;
// #### optional error cases ####
// on_fail is called whenever a session is terminated or failed before it
// was successfully established. This happens if there is an error during
// the handshake process or if the server refused the connection.
//
// on_fail will be the last time a session calls its handler. If your
// application will need information from `session` after this function you
// should either save the session_ptr somewhere or copy the data out.
virtual void on_fail(session_ptr session) {};
// experimental
virtual void on_ping_timeout(session_ptr session) {}
};
}
#endif // WEBSOCKET_CONNECTION_HANDLER_HPP
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, Peter Thorson. All rights reserved.
* Copyright (c) 2011, Peter Thorson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -11,10 +11,10 @@
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@@ -22,25 +22,34 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*/
#ifndef WEBSOCKETPP_CONCURRENCY_BASIC_HPP
#define WEBSOCKETPP_CONCURRENCY_BASIC_HPP
#ifndef WEBSOCKET_ENDPOINT_HPP
#define WEBSOCKET_ENDPOINT_HPP
#include <websocketpp/common/thread.hpp>
#include <boost/shared_ptr.hpp>
#include <string>
#include <map>
namespace websocketpp {
namespace concurrency {
class endpoint;
typedef boost::shared_ptr<endpoint> endpoint_ptr;
}
/// Concurrency policy that uses std::mutex / boost::mutex
class basic {
#include "websocket_session.hpp"
namespace websocketpp {
class endpoint : public boost::enable_shared_from_this<endpoint> {
public:
typedef lib::mutex mutex_type;
typedef lib::lock_guard<mutex_type> scoped_lock_type;
virtual bool is_server() = 0;
// log
// access_log
};
} // namespace concurrency
} // namespace websocketpp
#endif // WEBSOCKETPP_CONCURRENCY_BASIC_HPP
}
#endif // WEBSOCKET_ENDPOINT_HPP
+591
View File
@@ -0,0 +1,591 @@
/*
* Copyright (c) 2011, Peter Thorson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "websocketpp.hpp"
#include "websocket_frame.hpp"
#include "websocket_server.hpp"
#include "utf8_validator/utf8_validator.hpp"
#include <iostream>
#include <algorithm>
#if defined(WIN32)
#include <winsock2.h>
#else
#include <arpa/inet.h>
#endif
using websocketpp::frame;
uint8_t frame::get_state() const {
return m_state;
}
uint64_t frame::get_bytes_needed() const {
return m_bytes_needed;
}
void frame::reset() {
m_state = STATE_BASIC_HEADER;
m_bytes_needed = BASIC_HEADER_LENGTH;
m_degraded = false;
m_payload.empty();
memset(m_header,0,MAX_HEADER_LENGTH);
}
// Method invariant: One of the following must always be true even in the case
// of exceptions.
// - m_bytes_needed > 0
// - m-state = STATE_READY
void frame::consume(std::istream &s) {
try {
switch (m_state) {
case STATE_BASIC_HEADER:
s.read(&m_header[BASIC_HEADER_LENGTH-m_bytes_needed],m_bytes_needed);
m_bytes_needed -= s.gcount();
if (m_bytes_needed == 0) {
process_basic_header();
validate_basic_header();
if (m_bytes_needed > 0) {
m_state = STATE_EXTENDED_HEADER;
} else {
process_extended_header();
if (m_bytes_needed == 0) {
m_state = STATE_READY;
process_payload();
} else {
m_state = STATE_PAYLOAD;
}
}
}
break;
case STATE_EXTENDED_HEADER:
s.read(&m_header[get_header_len()-m_bytes_needed],m_bytes_needed);
m_bytes_needed -= s.gcount();
if (m_bytes_needed == 0) {
process_extended_header();
if (m_bytes_needed == 0) {
m_state = STATE_READY;
process_payload();
} else {
m_state = STATE_PAYLOAD;
}
}
break;
case STATE_PAYLOAD:
s.read(reinterpret_cast<char *>(&m_payload[m_payload.size()-m_bytes_needed]),
m_bytes_needed);
m_bytes_needed -= s.gcount();
if (m_bytes_needed == 0) {
m_state = STATE_READY;
process_payload();
}
break;
case STATE_RECOVERY:
// Recovery state discards all bytes that are not the first byte
// of a close frame.
do {
s.read(reinterpret_cast<char *>(&m_header[0]),1);
//std::cout << std::hex << int(static_cast<unsigned char>(m_header[0])) << " ";
if (int(static_cast<unsigned char>(m_header[0])) == 0x88) {
//(BPB0_FIN && CONNECTION_CLOSE)
m_bytes_needed--;
m_state = STATE_BASIC_HEADER;
break;
}
} while (s.gcount() > 0);
//std::cout << std::endl;
break;
default:
break;
}
/*if (s.gcount() == 0) {
throw frame_error("consume read zero bytes",FERR_FATAL_SESSION_ERROR);
}*/
} catch (const frame_error& e) {
// After this point all non-close frames must be considered garbage,
// including the current one. Reset it and put the reading frame into
// a recovery state.
if (m_degraded == true) {
throw frame_error("An error occurred while trying to gracefully recover from a less serious frame error.",FERR_FATAL_SESSION_ERROR);
} else {
reset();
m_state = STATE_RECOVERY;
m_degraded = true;
throw e;
}
}
}
char* frame::get_header() {
return m_header;
}
char* frame::get_extended_header() {
return m_header+BASIC_HEADER_LENGTH;
}
unsigned int frame::get_header_len() const {
unsigned int temp = 2;
if (get_masked()) {
temp += 4;
}
if (get_basic_size() == 126) {
temp += 2;
} else if (get_basic_size() == 127) {
temp += 8;
}
return temp;
}
char* frame::get_masking_key() {
if (m_state != STATE_READY) {
throw frame_error("attempted to get masking_key before reading full header");
}
return m_masking_key;
}
// get and set header bits
bool frame::get_fin() const {
return ((m_header[0] & BPB0_FIN) == BPB0_FIN);
}
void frame::set_fin(bool fin) {
if (fin) {
m_header[0] |= BPB0_FIN;
} else {
m_header[0] &= (0xFF ^ BPB0_FIN);
}
}
// get and set reserved bits
bool frame::get_rsv1() const {
return ((m_header[0] & BPB0_RSV1) == BPB0_RSV1);
}
void frame::set_rsv1(bool b) {
if (b) {
m_header[0] |= BPB0_RSV1;
} else {
m_header[0] &= (0xFF ^ BPB0_RSV1);
}
}
bool frame::get_rsv2() const {
return ((m_header[0] & BPB0_RSV2) == BPB0_RSV2);
}
void frame::set_rsv2(bool b) {
if (b) {
m_header[0] |= BPB0_RSV2;
} else {
m_header[0] &= (0xFF ^ BPB0_RSV2);
}
}
bool frame::get_rsv3() const {
return ((m_header[0] & BPB0_RSV3) == BPB0_RSV3);
}
void frame::set_rsv3(bool b) {
if (b) {
m_header[0] |= BPB0_RSV3;
} else {
m_header[0] &= (0xFF ^ BPB0_RSV3);
}
}
frame::opcode frame::get_opcode() const {
return frame::opcode(m_header[0] & BPB0_OPCODE);
}
void frame::set_opcode(frame::opcode op) {
if (op > 0x0F) {
throw frame_error("invalid opcode",FERR_PROTOCOL_VIOLATION);
}
if (get_basic_size() > BASIC_PAYLOAD_LIMIT &&
is_control()) {
throw frame_error("control frames can't have large payloads",FERR_PROTOCOL_VIOLATION);
}
m_header[0] &= (0xFF ^ BPB0_OPCODE); // clear op bits
m_header[0] |= op; // set op bits
}
bool frame::get_masked() const {
return ((m_header[1] & BPB1_MASK) == BPB1_MASK);
}
void frame::set_masked(bool masked) {
if (masked) {
m_header[1] |= BPB1_MASK;
generate_masking_key();
} else {
m_header[1] &= (0xFF ^ BPB1_MASK);
clear_masking_key();
}
}
uint8_t frame::get_basic_size() const {
return m_header[1] & BPB1_PAYLOAD;
}
size_t frame::get_payload_size() const {
if (m_state != STATE_READY && m_state != STATE_PAYLOAD) {
// problem
throw frame_error("attempted to get payload size before reading full header");
}
return m_payload.size();
}
uint16_t frame::get_close_status() const {
if (get_payload_size() == 0) {
return close::status::NO_STATUS;
} else if (get_payload_size() >= 2) {
char val[2];
val[0] = m_payload[0];
val[1] = m_payload[1];
uint16_t code = ntohs(*(
reinterpret_cast<uint16_t*>(&val[0])
));
// these two codes should never be on the wire
if (code == close::status::NO_STATUS || code == close::status::ABNORMAL_CLOSE) {
throw frame_error("Invalid close status code on the wire");
}
return code;
} else {
return close::status::PROTOCOL_ERROR;
}
}
std::string frame::get_close_msg() const {
if (get_payload_size() > 2) {
uint32_t state = utf8_validator::UTF8_ACCEPT;
uint32_t codep = 0;
validate_utf8(&state,&codep,2);
if (state != utf8_validator::UTF8_ACCEPT) {
throw frame_error("Invalid UTF-8 Data",
frame::FERR_PAYLOAD_VIOLATION);
}
return std::string(m_payload.begin()+2,m_payload.end());
} else {
return std::string();
}
}
std::vector<unsigned char> &frame::get_payload() {
return m_payload;
}
void frame::set_payload(const std::vector<unsigned char> source) {
set_payload_helper(source.size());
std::copy(source.begin(),source.end(),m_payload.begin());
}
void frame::set_payload(const std::string source) {
set_payload_helper(source.size());
std::copy(source.begin(),source.end(),m_payload.begin());
}
bool frame::is_control() const {
return (get_opcode() > MAX_FRAME_OPCODE);
}
void frame::set_payload_helper(size_t s) {
if (s > max_payload_size) {
throw frame_error("requested payload is over implimentation defined limit",FERR_MSG_TOO_BIG);
}
// limits imposed by the websocket spec
if (s > BASIC_PAYLOAD_LIMIT &&
get_opcode() > MAX_FRAME_OPCODE) {
throw frame_error("control frames can't have large payloads",FERR_PROTOCOL_VIOLATION);
}
if (s <= BASIC_PAYLOAD_LIMIT) {
m_header[1] = s;
} else if (s <= PAYLOAD_16BIT_LIMIT) {
m_header[1] = BASIC_PAYLOAD_16BIT_CODE;
// this reinterprets the second pair of bytes in m_header as a
// 16 bit int and writes the payload size there as an integer
// in network byte order
*reinterpret_cast<uint16_t*>(&m_header[BASIC_HEADER_LENGTH]) = htons(s);
} else if (s <= PAYLOAD_64BIT_LIMIT) {
m_header[1] = BASIC_PAYLOAD_64BIT_CODE;
*reinterpret_cast<uint64_t*>(&m_header[BASIC_HEADER_LENGTH]) = htonll(s);
} else {
throw frame_error("payload size limit is 63 bits",FERR_PROTOCOL_VIOLATION);
}
m_payload.resize(s);
}
void frame::set_status(uint16_t status,const std::string message) {
// check for valid statuses
if (close::status::invalid(status)) {
std::stringstream err;
err << "Status code " << status << " is invalid";
throw frame_error(err.str());
}
if (close::status::reserved(status)) {
std::stringstream err;
err << "Status code " << status << " is reserved";
throw frame_error(err.str());
}
m_payload.resize(2+message.size());
char val[2];
*reinterpret_cast<uint16_t*>(&val[0]) = htons(status);
m_header[1] = message.size()+2;
m_payload[0] = val[0];
m_payload[1] = val[1];
std::copy(message.begin(),message.end(),m_payload.begin()+2);
}
std::string frame::print_frame() const {
std::stringstream f;
unsigned int len = get_header_len();
f << "frame: ";
// print header
for (unsigned int i = 0; i < len; i++) {
f << std::hex << (unsigned short)m_header[i] << " ";
}
// print message
if (m_payload.size() > 50) {
f << "[payload of " << m_payload.size() << " bytes]";
} else {
std::vector<unsigned char>::const_iterator it;
for (it = m_payload.begin(); it != m_payload.end(); it++) {
f << *it;
}
}
return f.str();
}
void frame::process_basic_header() {
m_bytes_needed = get_header_len() - BASIC_HEADER_LENGTH;
}
void frame::process_extended_header() {
uint8_t s = get_basic_size();
uint64_t payload_size;
int mask_index = BASIC_HEADER_LENGTH;
if (s <= BASIC_PAYLOAD_LIMIT) {
payload_size = s;
} else if (s == BASIC_PAYLOAD_16BIT_CODE) {
// reinterpret the second two bytes as a 16 bit integer in network
// byte order. Convert to host byte order and store locally.
payload_size = ntohs(*(
reinterpret_cast<uint16_t*>(&m_header[BASIC_HEADER_LENGTH])
));
if (payload_size < s) {
std::stringstream err;
err << "payload length not minimally encoded. Using 16 bit form for payload size: " << payload_size;
m_bytes_needed = payload_size;
throw frame_error(err.str(),
FERR_PROTOCOL_VIOLATION);
}
mask_index += 2;
} else if (s == BASIC_PAYLOAD_64BIT_CODE) {
// reinterpret the second eight bytes as a 64 bit integer in
// network byte order. Convert to host byte order and store.
payload_size = ntohll(*(
reinterpret_cast<uint64_t*>(&m_header[BASIC_HEADER_LENGTH])
));
if (payload_size <= PAYLOAD_16BIT_LIMIT) {
m_bytes_needed = payload_size;
throw frame_error("payload length not minimally encoded",
FERR_PROTOCOL_VIOLATION);
}
mask_index += 8;
} else {
// shouldn't be here
throw frame_error("invalid get_basic_size in process_extended_header");
}
if (get_masked() == 0) {
clear_masking_key();
} else {
// TODO: use this copy line (needs testing)
// std::copy(m_header[mask_index],m_header[mask_index+4],m_masking_key);
m_masking_key[0] = m_header[mask_index+0];
m_masking_key[1] = m_header[mask_index+1];
m_masking_key[2] = m_header[mask_index+2];
m_masking_key[3] = m_header[mask_index+3];
}
if (payload_size > max_payload_size) {
// TODO: frame/message size limits
throw server_error("got frame with payload greater than maximum frame buffer size.");
}
m_payload.resize(payload_size);
m_bytes_needed = payload_size;
}
void frame::process_payload() {
if (get_masked()) {
char *masking_key = &m_header[get_header_len()-4];
for (uint64_t i = 0; i < m_payload.size(); i++) {
m_payload[i] = (m_payload[i] ^ masking_key[i%4]);
}
}
}
void frame::process_payload2() {
// unmask payload one byte at a time
//uint64_t key = (*((uint32_t*)m_masking_key;)) << 32;
//key += *((uint32_t*)m_masking_key);
// might need to switch byte order
uint32_t key = *((uint32_t*)m_masking_key);
// 4
uint64_t i = 0;
uint64_t s = (m_payload.size() / 4);
std::cout << "s: " << s << std::endl;
// chunks of 4
for (i = 0; i < s; i+=4) {
((uint32_t*)(&m_payload[0]))[i] = (((uint32_t*)(&m_payload[0]))[i] ^ key);
}
// finish the last few
for (i = s; i < m_payload.size(); i++) {
m_payload[i] = (m_payload[i] ^ m_masking_key[i%4]);
}
}
void frame::validate_utf8(uint32_t* state,uint32_t* codep, size_t offset) const {
for (size_t i = offset; i < m_payload.size(); i++) {
using utf8_validator::decode;
if (decode(state,codep,m_payload[i]) == utf8_validator::UTF8_REJECT) {
throw frame_error("Invalid UTF-8 Data",FERR_PAYLOAD_VIOLATION);
}
}
}
void frame::validate_basic_header() const {
// check for control frame size
if (get_basic_size() > BASIC_PAYLOAD_LIMIT && is_control()) {
throw frame_error("Control Frame is too large",FERR_PROTOCOL_VIOLATION);
}
// check for reserved opcodes
if (get_rsv1() || get_rsv2() || get_rsv3()) {
throw frame_error("Reserved bit used",FERR_PROTOCOL_VIOLATION);
}
// check for reserved opcodes
opcode op = get_opcode();
if (op > 0x02 && op < 0x08) {
throw frame_error("Reserved opcode used",FERR_PROTOCOL_VIOLATION);
}
if (op > 0x0A) {
throw frame_error("Reserved opcode used",FERR_PROTOCOL_VIOLATION);
}
// check for fragmented control message
if (is_control() && !get_fin()) {
throw frame_error("Fragmented control message",FERR_PROTOCOL_VIOLATION);
}
}
void frame::generate_masking_key() {
//throw "masking key generation not implimented";
int32_t key = m_gen();
//m_masking_key[0] = reinterpret_cast<char*>(&key)[0];
//m_masking_key[1] = reinterpret_cast<char*>(&key)[1];
//m_masking_key[2] = reinterpret_cast<char*>(&key)[2];
//m_masking_key[3] = reinterpret_cast<char*>(&key)[3];
*(reinterpret_cast<int32_t *>(&m_header[get_header_len()-4])) = key;
//std::cout << "maskkey: " << m_masking_key << std::endl;
/* TODO: test and tune
boost::random::random_device rng;
boost::random::uniform_int_distribution<> mask(0,UINT32_MAX);
*(reinterpret_cast<uint32_t *>(m_masking_key)) = mask(rng);
*/
}
void frame::clear_masking_key() {
// this is a no-op as clearing the mask bit also changes the get_header_len
// method to not include these byte ranges. Whenever the masking bit is re-
// set a new key is generated anyways.
}
+203
View File
@@ -0,0 +1,203 @@
/*
* Copyright (c) 2011, Peter Thorson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef WEBSOCKET_FRAME_HPP
#define WEBSOCKET_FRAME_HPP
#include "network_utilities.hpp"
#include <string>
#include <vector>
#include <cstring>
#include <boost/random.hpp>
#include <boost/random/random_device.hpp>
namespace websocketpp {
/* policies to abstract out
- random number generation
- utf8 validation
*/
class frame {
public:
enum opcode_s {
CONTINUATION_FRAME = 0x00,
TEXT_FRAME = 0x01,
BINARY_FRAME = 0x02,
CONNECTION_CLOSE = 0x08,
PING = 0x09,
PONG = 0x0A
};
typedef enum opcode_s opcode;
static const uint8_t MAX_FRAME_OPCODE = 0x07;
static const uint8_t STATE_BASIC_HEADER = 1;
static const uint8_t STATE_EXTENDED_HEADER = 2;
static const uint8_t STATE_PAYLOAD = 3;
static const uint8_t STATE_READY = 4;
static const uint8_t STATE_RECOVERY = 5;
static const uint16_t FERR_FATAL_SESSION_ERROR = 0; // force session end
static const uint16_t FERR_SOFT_SESSION_ERROR = 1; // should log and ignore
static const uint16_t FERR_PROTOCOL_VIOLATION = 2; // must end session
static const uint16_t FERR_PAYLOAD_VIOLATION = 3; // should end session
static const uint16_t FERR_INTERNAL_SERVER_ERROR = 4; // cleanly end session
static const uint16_t FERR_MSG_TOO_BIG = 5;
// basic payload byte flags
static const uint8_t BPB0_OPCODE = 0x0F;
static const uint8_t BPB0_RSV3 = 0x10;
static const uint8_t BPB0_RSV2 = 0x20;
static const uint8_t BPB0_RSV1 = 0x40;
static const uint8_t BPB0_FIN = 0x80;
static const uint8_t BPB1_PAYLOAD = 0x7F;
static const uint8_t BPB1_MASK = 0x80;
static const uint8_t BASIC_PAYLOAD_LIMIT = 0x7D; // 125
static const uint8_t BASIC_PAYLOAD_16BIT_CODE = 0x7E; // 126
static const uint16_t PAYLOAD_16BIT_LIMIT = 0xFFFF; // 2^16, 65535
static const uint8_t BASIC_PAYLOAD_64BIT_CODE = 0x7F; // 127
static const uint64_t PAYLOAD_64BIT_LIMIT = 0x7FFFFFFFFFFFFFFF; // 2^63
static const unsigned int BASIC_HEADER_LENGTH = 2;
static const unsigned int MAX_HEADER_LENGTH = 14;
static const uint8_t extended_header_length = 12;
static const uint64_t max_payload_size = 100000000; // 100MB
// create an empty frame for writing into
frame() : m_gen(m_rng,
boost::random::uniform_int_distribution<>(INT32_MIN,INT32_MAX)),m_degraded(false) {
reset();
}
uint8_t get_state() const;
uint64_t get_bytes_needed() const;
void reset();
void consume(std::istream &s);
// get pointers to underlying buffers
char* get_header();
char* get_extended_header();
unsigned int get_header_len() const;
char* get_masking_key();
// get and set header bits
bool get_fin() const;
void set_fin(bool fin);
bool get_rsv1() const;
void set_rsv1(bool b);
bool get_rsv2() const;
void set_rsv2(bool b);
bool get_rsv3() const;
void set_rsv3(bool b);
opcode get_opcode() const;
void set_opcode(opcode op);
bool get_masked() const;
void set_masked(bool masked);
uint8_t get_basic_size() const;
size_t get_payload_size() const;
uint16_t get_close_status() const;
std::string get_close_msg() const;
std::vector<unsigned char> &get_payload();
void set_payload(const std::vector<unsigned char> source);
void set_payload(const std::string source);
void set_payload_helper(size_t s);
void set_status(uint16_t status,const std::string message = "");
bool is_control() const;
std::string print_frame() const;
// reads basic header, sets and returns m_header_bits_needed
void process_basic_header();
void process_extended_header();
void process_payload();
void process_payload2(); // experiment with more efficient masking code.
void validate_utf8(uint32_t* state,uint32_t* codep,size_t offset = 0) const;
void validate_basic_header() const;
void generate_masking_key();
void clear_masking_key();
private:
uint8_t m_state;
uint64_t m_bytes_needed;
bool m_degraded;
char m_header[MAX_HEADER_LENGTH];
std::vector<unsigned char> m_payload;
char m_masking_key[4];
boost::random::random_device m_rng;
boost::random::variate_generator<boost::random::random_device&,
boost::random::uniform_int_distribution<> >
m_gen;
};
// Exception classes
class frame_error : public std::exception {
public:
frame_error(const std::string& msg,
uint16_t code = frame::FERR_FATAL_SESSION_ERROR)
: m_msg(msg),m_code(code) {}
~frame_error() throw() {}
virtual const char* what() const throw() {
return m_msg.c_str();
}
uint16_t code() const throw() {
return m_code;
}
std::string m_msg;
uint16_t m_code;
};
}
#endif // WEBSOCKET_FRAME_HPP
+202
View File
@@ -0,0 +1,202 @@
/*
* Copyright (c) 2011, Peter Thorson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "websocketpp.hpp"
#include "websocket_server.hpp"
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <iostream>
using websocketpp::server;
server::server(boost::asio::io_service& io_service,
const tcp::endpoint& endpoint,
websocketpp::connection_handler_ptr defc)
: m_elog_level(LOG_ERROR),
m_alog_level(ALOG_CONTROL),
m_max_message_size(DEFAULT_MAX_MESSAGE_SIZE),
m_io_service(io_service),
m_acceptor(io_service, endpoint),
m_def_con_handler(defc),
m_desc("websocketpp::server") {
m_desc.add_options()
("help", "produce help message")
("host,h",po::value<std::vector<std::string> >()->multitoken()->composing(), "hostnames to listen on")
("port,p",po::value<int>(), "port to listen on")
;
}
void server::parse_command_line(int ac, char* av[]) {
po::store(po::parse_command_line(ac,av, m_desc),m_vm);
po::notify(m_vm);
if (m_vm.count("help") ) {
std::cout << m_desc << std::endl;
}
//m_vm["host"].as<std::string>();
const std::vector< std::string > &foo = m_vm["host"].as< std::vector<std::string> >();
for (int i = 0; i < foo.size(); i++) {
std::cout << foo[i] << std::endl;
}
//std::cout << m_vm["host"].as< std::vector<std::string> >() << std::endl;
}
void server::add_host(std::string host) {
m_hosts.insert(host);
}
void server::remove_host(std::string host) {
m_hosts.erase(host);
}
void server::set_max_message_size(uint64_t val) {
if (val > frame::PAYLOAD_64BIT_LIMIT) {
std::stringstream err;
err << "Invalid maximum message size: " << val;
// TODO: Figure out what the ideal error behavior for this method.
// Options:
// Throw exception
// Log error and set value to maximum allowed
// Log error and leave value at whatever it was before
log(err.str(),LOG_WARN);
//throw server_error(err.str());
}
m_max_message_size = val;
}
bool server::test_elog_level(uint16_t level) {
return (level >= m_elog_level);
}
void server::set_elog_level(uint16_t level) {
std::stringstream msg;
msg << "Error logging level changing from "
<< m_elog_level << " to " << level;
log(msg.str(),LOG_INFO);
m_elog_level = level;
}
bool server::test_alog_level(uint16_t level) {
return ((level & m_alog_level) != 0);
}
void server::set_alog_level(uint16_t level) {
if (test_alog_level(level)) {
return;
}
std::stringstream msg;
msg << "Access logging level " << level << " being set";
access_log(msg.str(),ALOG_INFO);
m_alog_level |= level;
}
void server::unset_alog_level(uint16_t level) {
if (!test_alog_level(level)) {
return;
}
std::stringstream msg;
msg << "Access logging level " << level << " being unset";
access_log(msg.str(),ALOG_INFO);
m_alog_level &= ~level;
}
bool server::validate_host(std::string host) {
if (m_hosts.find(host) == m_hosts.end()) {
return false;
}
return true;
}
bool server::validate_message_size(uint64_t val) {
if (val > m_max_message_size) {
return false;
}
return true;
}
void server::log(std::string msg,uint16_t level) {
if (!test_elog_level(level)) {
return;
}
std::cerr << "[Error Log] "
<< boost::posix_time::to_iso_extended_string(
boost::posix_time::second_clock::local_time())
<< " " << msg << std::endl;
}
void server::access_log(std::string msg,uint16_t level) {
if (!test_alog_level(level)) {
return;
}
std::cout << "[Access Log] "
<< boost::posix_time::to_iso_extended_string(
boost::posix_time::second_clock::local_time())
<< " " << msg << std::endl;
}
void server::start_accept() {
// TODO: sanity check whether the session buffer size bound could be reduced
server_session_ptr new_session(new server_session(shared_from_this(),
m_io_service,
m_def_con_handler,
m_max_message_size*2));
m_acceptor.async_accept(
new_session->socket(),
boost::bind(
&server::handle_accept,
this,
new_session,
boost::asio::placeholders::error
)
);
}
void server::handle_accept(websocketpp::server_session_ptr session,
const boost::system::error_code& error) {
if (!error) {
session->on_connect();
} else {
std::stringstream err;
err << "Error accepting socket connection: " << error;
log(err.str(),LOG_ERROR);
throw server_error(err.str());
}
this->start_accept();
}
+129
View File
@@ -0,0 +1,129 @@
/*
* Copyright (c) 2011, Peter Thorson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef WEBSOCKET_SERVER_HPP
#define WEBSOCKET_SERVER_HPP
#include <boost/asio.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/program_options.hpp>
namespace po = boost::program_options;
#include <set>
namespace websocketpp {
class server;
typedef boost::shared_ptr<server> server_ptr;
}
#include "websocketpp.hpp"
#include "websocket_server_session.hpp"
#include "websocket_connection_handler.hpp"
using boost::asio::ip::tcp;
namespace websocketpp {
class server_error : public std::exception {
public:
server_error(const std::string& msg)
: m_msg(msg) {}
~server_error() throw() {}
virtual const char* what() const throw() {
return m_msg.c_str();
}
private:
std::string m_msg;
};
class server : public boost::enable_shared_from_this<server> {
public:
server(boost::asio::io_service& io_service,
const tcp::endpoint& endpoint,
connection_handler_ptr defc);
// creates a new session object and connects the next websocket
// connection to it.
void start_accept();
// INTERFACE FOR LOCAL APPLICATIONS
// Add or remove a host string (host:port) to the list of acceptable
// hosts to accept websocket connections from. Additions/deletions here
// only affect new connections.
void add_host(std::string host);
void remove_host(std::string host);
void set_max_message_size(uint64_t val);
// Test methods determine if a message of the given level should be
// written. elog shows all values above the level set. alog shows only
// the values explicitly set.
bool test_elog_level(uint16_t level);
void set_elog_level(uint16_t level);
bool test_alog_level(uint16_t level);
void set_alog_level(uint16_t level);
void unset_alog_level(uint16_t level);
void parse_command_line(int ac, char* av[]);
// INTERFACE FOR SESSIONS
// Check if this server will respond to this host.
bool validate_host(std::string host);
// Check if message size is within server's acceptable parameters
bool validate_message_size(uint64_t val);
// write to the server's logs
void log(std::string msg,uint16_t level = LOG_ERROR);
void access_log(std::string msg,uint16_t level);
private:
// if no errors starts the session's read loop and returns to the
// start_accept phase.
void handle_accept(server_session_ptr session,
const boost::system::error_code& error);
private:
uint16_t m_elog_level;
uint16_t m_alog_level;
std::set<std::string> m_hosts;
uint64_t m_max_message_size;
boost::asio::io_service& m_io_service;
tcp::acceptor m_acceptor;
connection_handler_ptr m_def_con_handler;
po::options_description m_desc;
po::variables_map m_vm;
};
}
#endif // WEBSOCKET_SERVER_HPP
+362
View File
@@ -0,0 +1,362 @@
/*
* Copyright (c) 2011, Peter Thorson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the WebSocket++ Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "websocketpp.hpp"
#include "websocket_server_session.hpp"
#include "websocket_frame.hpp"
#include "utf8_validator/utf8_validator.hpp"
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/algorithm/string.hpp>
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <string>
using websocketpp::server_session;
server_session::server_session(websocketpp::server_ptr s,
boost::asio::io_service& io_service,
websocketpp::connection_handler_ptr defc,
uint64_t buf_size)
: session(io_service,defc,buf_size),m_server(s) {}
void server_session::on_connect() {
read_handshake();
}
void server_session::set_header(const std::string &key,const std::string &val) {
// TODO: prevent use of reserved headers;
m_server_headers[key] = val;
}
void server_session::select_subprotocol(const std::string& val) {
std::vector<std::string>::iterator it;
it = std::find(m_client_subprotocols.begin(),
m_client_subprotocols.end(),
val);
if (val != "" && it == m_client_subprotocols.end()) {
throw server_error("Attempted to choose a subprotocol not proposed by the client");
}
m_server_subprotocol = val;
}
void server_session::select_extension(const std::string& val) {
if (val == "") {
return;
}
std::vector<std::string>::iterator it;
it = std::find(m_client_extensions.begin(),
m_client_extensions.end(),
val);
if (it == m_client_extensions.end()) {
throw server_error("Attempted to choose an extension not proposed by the client");
}
m_server_extensions.push_back(val);
}
void server_session::read_handshake() {
m_timer.expires_from_now(boost::posix_time::seconds(5));
m_timer.async_wait(
boost::bind(
&session::handle_handshake_expired,
shared_from_this(),
boost::asio::placeholders::error
)
);
boost::asio::async_read_until(
m_socket,
m_buf,
"\r\n\r\n",
boost::bind(
&session::handle_read_handshake,
shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred
)
);
}
void server_session::handle_read_handshake(const boost::system::error_code& e,
std::size_t bytes_transferred) {
std::ostringstream line;
line << &m_buf;
m_raw_client_handshake += line.str();
access_log(m_raw_client_handshake,ALOG_HANDSHAKE);
std::vector<std::string> tokens;
std::string::size_type start = 0;
std::string::size_type end;
// Get request and parse headers
end = m_raw_client_handshake.find("\r\n",start);
while(end != std::string::npos) {
tokens.push_back(m_raw_client_handshake.substr(start, end - start));
start = end + 2;
end = m_raw_client_handshake.find("\r\n",start);
}
for (size_t i = 0; i < tokens.size(); i++) {
if (i == 0) {
m_client_http_request = tokens[i];
}
end = tokens[i].find(": ",0);
if (end != std::string::npos) {
std::string h = tokens[i].substr(0,end);
if (get_client_header(h) == "") {
m_client_headers[h] = tokens[i].substr(end+2);
} else {
m_client_headers[h] += ", " + tokens[i].substr(end+2);
}
}
}
// handshake error checking
try {
std::stringstream err;
std::string h;
// check the method
if (m_client_http_request.substr(0,4) != "GET ") {
err << "Websocket handshake has invalid method: "
<< m_client_http_request.substr(0,4);
throw(handshake_error(err.str(),400));
}
// check the HTTP version
// TODO: allow versions greater than 1.1
end = m_client_http_request.find(" HTTP/1.1",4);
if (end == std::string::npos) {
err << "Websocket handshake has invalid HTTP version";
throw(handshake_error(err.str(),400));
}
m_resource = m_client_http_request.substr(4,end-4);
// verify the presence of required headers
h = get_client_header("Host");
if (h == "") {
throw(handshake_error("Required Host header is missing",400));
} else if (!m_server->validate_host(h)) {
err << "Host " << h << " is not one of this server's names.";
throw(handshake_error(err.str(),400));
}
h = get_client_header("Upgrade");
if (h == "") {
throw(handshake_error("Required Upgrade header is missing",400));
} else if (!boost::iequals(h,"websocket")) {
err << "Upgrade header was " << h << " instead of \"websocket\"";
throw(handshake_error(err.str(),400));
}
h = get_client_header("Connection");
if (h == "") {
throw(handshake_error("Required Connection header is missing",400));
} else if (!boost::ifind_first(h,"upgrade")) {
err << "Connection header, \"" << h
<< "\", does not contain required token \"upgrade\"";
throw(handshake_error(err.str(),400));
}
if (get_client_header("Sec-WebSocket-Key") == "") {
throw(handshake_error("Required Sec-WebSocket-Key header is missing",400));
}
h = get_client_header("Sec-WebSocket-Version");
if (h == "") {
throw(handshake_error("Required Sec-WebSocket-Version header is missing",400));
} else {
m_version = atoi(h.c_str());
if (m_version != 7 && m_version != 8 && m_version != 13) {
err << "This server doesn't support WebSocket protocol version "
<< m_version;
throw(handshake_error(err.str(),400));
}
}
if (m_version < 13) {
h = get_client_header("Sec-WebSocket-Origin");
} else {
h = get_client_header("Origin");
}
if (h != "") {
m_client_origin = h;
}
// TODO: extract subprotocols
// TODO: extract extensions
// optional headers (delegated to the local interface)
if (m_local_interface) {
m_local_interface->validate(shared_from_this());
}
m_server_http_code = 101;
m_server_http_string = "Switching Protocols";
} catch (const handshake_error& e) {
std::stringstream err;
err << "Caught handshake exception: " << e.what();
access_log(e.what(),ALOG_HANDSHAKE);
log(err.str(),LOG_ERROR);
m_server_http_code = e.m_http_error_code;
m_server_http_string = e.m_http_error_msg;
}
write_handshake();
}
void server_session::write_handshake() {
std::stringstream h;
if (m_server_http_code == 101) {
std::string server_key = get_client_header("Sec-WebSocket-Key");
server_key += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
SHA1 sha;
uint32_t message_digest[5];
sha.Reset();
sha << server_key.c_str();
if (sha.Result(message_digest)){
// convert sha1 hash bytes to network byte order because this sha1
// library works on ints rather than bytes
for (int i = 0; i < 5; i++) {
message_digest[i] = htonl(message_digest[i]);
}
server_key = base64_encode(
reinterpret_cast<const unsigned char*>(message_digest),20);
// set handshake accept headers
set_header("Sec-WebSocket-Accept",server_key);
set_header("Upgrade","websocket");
set_header("Connection","Upgrade");
} else {
log("Error computing handshake sha1 hash.",LOG_ERROR);
m_server_http_code = 500;
m_server_http_string = "";
}
}
// hardcoded server headers
set_header("Server","WebSocket++/2011-09-25");
h << "HTTP/1.1 " << m_server_http_code << " "
<< (m_server_http_string != "" ? m_server_http_string :
lookup_http_error_string(m_server_http_code))
<< "\r\n";
header_list::iterator it;
for (it = m_server_headers.begin(); it != m_server_headers.end(); it++) {
h << it->first << ": " << it->second << "\r\n";
}
h << "\r\n";
m_raw_server_handshake = h.str();
// start async write to handle_write_handshake
boost::asio::async_write(
m_socket,
boost::asio::buffer(m_raw_server_handshake),
boost::bind(
&session::handle_write_handshake,
shared_from_this(),
boost::asio::placeholders::error
)
);
}
void server_session::handle_write_handshake(const boost::system::error_code& error) {
if (error) {
log_error("Error writing handshake response",error);
drop_tcp();
return;
}
log_open_result();
if (m_server_http_code != 101) {
std::stringstream err;
err << "Handshake ended with HTTP error: " << m_server_http_code << " "
<< (m_server_http_string != "" ? m_server_http_string : lookup_http_error_string(m_server_http_code));
log(err.str(),LOG_ERROR);
drop_tcp();
// TODO: tell client that connection failed.
return;
}
m_state = STATE_OPEN;
// stop the handshake timer
m_timer.cancel();
if (m_local_interface) {
m_local_interface->on_open(shared_from_this());
}
reset_message();
this->read_frame();
}
void server_session::log(const std::string& msg, uint16_t level) const {
m_server->log(msg,level);
}
void server_session::access_log(const std::string& msg, uint16_t level) const {
m_server->access_log(msg,level);
}

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