Browse Source

Merge pull request #1 from ErnestChen1/master

 【整理】librws 软件包
朱天龙 (Armink) 6 years ago
parent
commit
68b380efbd
65 changed files with 3836 additions and 4419 deletions
  1. 0 32
      .gitignore
  2. 0 30
      .travis.yml
  3. 0 208
      CMakeLists.txt
  4. 29 0
      SConscript
  5. 0 82
      appveyor.yml
  6. 0 28
      builds/android/jni/Android.mk
  7. 0 3
      builds/android/jni/Application.mk
  8. 0 118
      contrib/objc/RWSSocketObjc.h
  9. 0 160
      contrib/objc/RWSSocketObjc.m
  10. 20 0
      examples/SConscript
  11. 228 0
      examples/rws_example.c
  12. 0 30
      librws.podspec
  13. 56 88
      librws/inc/librws.h
  14. 13 4
      librws/inc/rws_common.h
  15. 11 11
      librws/inc/rws_error.h
  16. 74 0
      librws/inc/rws_frame.h
  17. 15 16
      librws/inc/rws_list.h
  18. 5 6
      librws/inc/rws_memory.h
  19. 216 0
      librws/inc/rws_socket.h
  20. 9 10
      librws/inc/rws_string.h
  21. 1 4
      librws/inc/rws_thread.h
  22. 2 5
      librws/src/librws.c
  23. 1 4
      librws/src/rws_common.c
  24. 87 0
      librws/src/rws_error.c
  25. 486 0
      librws/src/rws_frame.c
  26. 32 26
      librws/src/rws_list.c
  27. 35 25
      librws/src/rws_memory.c
  28. 1822 0
      librws/src/rws_socketpriv.c
  29. 428 0
      librws/src/rws_socketpub.c
  30. 24 20
      librws/src/rws_string.c
  31. 242 0
      librws/src/rws_thread.c
  32. 0 68
      src/rws_error.c
  33. 0 266
      src/rws_frame.c
  34. 0 65
      src/rws_frame.h
  35. 0 169
      src/rws_socket.h
  36. 0 725
      src/rws_socketpriv.c
  37. 0 310
      src/rws_socketpub.c
  38. 0 206
      src/rws_thread.c
  39. 0 60
      test/CMakeLists.txt
  40. 0 548
      test/librws_test.xcodeproj/project.pbxproj
  41. 0 7
      test/librws_test.xcodeproj/project.xcworkspace/contents.xcworkspacedata
  42. BIN
      test/librws_test.xcodeproj/project.xcworkspace/xcuserdata/olehkulykov.xcuserdatad/UserInterfaceState.xcuserstate
  43. BIN
      test/librws_test.xcodeproj/project.xcworkspace/xcuserdata/residentevil.xcuserdatad/UserInterfaceState.xcuserstate
  44. 0 5
      test/librws_test.xcodeproj/xcuserdata/olehkulykov.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
  45. 0 101
      test/librws_test.xcodeproj/xcuserdata/olehkulykov.xcuserdatad/xcschemes/librws_test.xcscheme
  46. 0 27
      test/librws_test.xcodeproj/xcuserdata/olehkulykov.xcuserdatad/xcschemes/xcschememanagement.plist
  47. 0 23
      test/librws_test.xcodeproj/xcuserdata/residentevil.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
  48. 0 101
      test/librws_test.xcodeproj/xcuserdata/residentevil.xcuserdatad/xcschemes/librws_test.xcscheme
  49. 0 27
      test/librws_test.xcodeproj/xcuserdata/residentevil.xcuserdatad/xcschemes/xcschememanagement.plist
  50. 0 11
      test/librws_test/AppDelegate.h
  51. 0 39
      test/librws_test/AppDelegate.m
  52. 0 38
      test/librws_test/Assets.xcassets/AppIcon.appiconset/Contents.json
  53. 0 27
      test/librws_test/Base.lproj/LaunchScreen.storyboard
  54. 0 27
      test/librws_test/Base.lproj/Main.storyboard
  55. 0 40
      test/librws_test/Info.plist
  56. 0 8
      test/librws_test/ViewController.h
  57. 0 20
      test/librws_test/ViewController.m
  58. 0 10
      test/librws_test/main.m
  59. 0 24
      test/librws_testTests/Info.plist
  60. 0 68
      test/librws_testTests/ObjcContrib.m
  61. 0 119
      test/librws_testTests/connection.m
  62. 0 67
      test/librws_testTests/creation.m
  63. 0 117
      test/librws_testTests/getterAndSetters.m
  64. 0 103
      test/test_librws_creation.c
  65. 0 83
      test/test_librws_socket_get_set.c

+ 0 - 32
.gitignore

@@ -1,32 +0,0 @@
-# Object files
-*.o
-*.ko
-*.obj
-*.elf
-
-# Precompiled Headers
-*.gch
-*.pch
-
-# Libraries
-*.lib
-*.a
-*.la
-*.lo
-
-# Shared objects (inc. Windows DLLs)
-*.dll
-*.so
-*.so.*
-*.dylib
-
-# Executables
-*.exe
-*.out
-*.app
-*.i*86
-*.x86_64
-*.hex
-
-# Debug files
-*.dSYM/

+ 0 - 30
.travis.yml

@@ -1,30 +0,0 @@
-language: c
-
-env:
-  matrix:
-    - rws_env_matrix=default
-    
-os:
-  - linux
-  - osx
-
-compiler:
-  - gcc
-  - clang
-
-before_script:
-  - mkdir build
-  - cd build
-  - cmake -DCMAKE_INSTALL_PREFIX:PATH=~/librws-install-dir -DCMAKE_BUILD_TYPE=Release ..
-  - cd ..
-
-script:
-  - cd build
-  - make
-  - make test
-  - make install
-
-branches:
-  only:
-    - master
-    - dev

+ 0 - 208
CMakeLists.txt

@@ -1,208 +0,0 @@
-#
-#   Copyright (c) 2014 - 2019 Oleh Kulykov <info@resident.name>
-#
-#   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.
-#
-
-cmake_minimum_required(VERSION 2.8)
-
-
-project(librws)
-
-
-set(PACKAGE "librws")
-set(CPACK_PACKAGE_NAME "${PACKAGE}")
-set(CPACK_PACKAGE_VERSION_MAJOR "1")
-set(CPACK_PACKAGE_VERSION_MINOR "2")
-set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}")
-set(CPACK_PACKAGE_VENDOR "info@resident.name")
-set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${PACKAGE} ${PACKAGE_VERSION}")
-set(SOVERSION "1.2.4")
-set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
-set(VERSION "${CPACK_PACKAGE_VERSION}")
-
-
-include(CheckLibraryExists)
-include(CheckFunctionExists)
-
-include(CheckIncludeFile)
-include(CheckIncludeFileCXX)
-
-include(CheckTypeSize)
-include(CheckSymbolExists)
-
-include(CheckCCompilerFlag)
-include(CheckCXXCompilerFlag)
-
-# COMMAND LINE OPTIONS
-option(RWS_OPT_SHARED "Build shared lib" ON)
-option(RWS_OPT_STATIC "Build static lib" ON)
-option(RWS_OPT_TESTS "Build librws tests" ON)
-
-option(RWS_OPT_APPVEYOR_CI "Build with appveyor ci" OFF)
-
-# C with -fPIC
-check_c_compiler_flag("-fPIC" WITH_FPIC_C)
-if(WITH_FPIC_C)
-	set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
-endif(WITH_FPIC_C)
-
-
-# CXX with -fPIC
-check_cxx_compiler_flag("-fPIC" WITH_FPIC_CXX)
-if(WITH_FPIC_CXX)
-	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
-endif(WITH_FPIC_CXX)
-
-
-if(WIN32)
-	add_definitions(-DWIN32)
-	add_definitions(-D_WIN32)
-	set(RWS_OS_WINDOWS 1)
-endif(WIN32)
-
-
-if(MINGW)
-	set(RWS_COMPILER_MINGW 1)
-endif(MINGW)
-
-
-add_definitions(-DCMAKE_BUILD)
-
-if (RWS_OPT_APPVEYOR_CI)
-	add_definitions(-DRWS_APPVEYOR_CI)
-endif()
-
-include_directories(${CMAKE_CURRENT_SOURCE_DIR})
-
-#check_include_file("netdb.h" RWS_HAVE_NETDB_H)
-#check_include_file("sys/socket.h" RWS_HAVE_SYS_SOCKET_H)
-#check_include_file("sys/types.h" RWS_HAVE_SYS_TYPES_H)
-#check_include_file("netinet/tcp.h" RWS_HAVE_NETINET_TCP_H)
-#check_include_file("unistd.h" RWS_HAVE_UNISTD_H)
-#check_include_file("fcntl.h" RWS_HAVE_FCNTL_H)
-check_include_file("pthread.h" RWS_HAVE_PTHREAD_H)
-
-message(CMAKE_EXTRA_INCLUDE_FILES ": " ${CMAKE_EXTRA_INCLUDE_FILES})
-
-# To check the size of a primitive type:
-check_type_size("void*" RWS_SIZEOF_VOIDP_T)
-if(RWS_SIZEOF_VOIDP_T AND (NOT RWS_VOIDP_TYPE))
-	set(RWS_VOIDP_TYPE void*)
-endif()
-
-if(RWS_SIZEOF_VOIDP_T EQUAL 4)
-	set(RWS_32BIT_PLATFORM 1)
-endif()
-if(RWS_SIZEOF_VOIDP_T EQUAL 8)
-	set(RWS_64BIT_PLATFORM 1)
-endif()
-
-
-# functions
-#check_function_exists(usleep RWS_HAVE_FUNCTION_USLEEP)
-
-#if(RWS_HAVE_PTHREAD_H)
-#check_function_exists(pthread_attr_setscope RWS_HAVE_FUNCTION_PTHREAD_ATTR_SETSCOPE)
-#check_function_exists(pthread_attr_setstacksize RWS_HAVE_FUNCTION_PTHREAD_ATTR_SETSTACKSIZE)
-#check_function_exists(pthread_cancel RWS_HAVE_FUNCTION_PTHREAD_CANCEL)
-#check_function_exists(pthread_setname_np RWS_HAVE_FUNCTION_PTHREAD_SETNAME_NP)
-#check_function_exists(pthread_set_name_np RWS_HAVE_FUNCTION_PTHREAD_SET_NAME_NP)
-#endif(RWS_HAVE_PTHREAD_H)
-
-
-if((NOT RWS_HAVE_PTHREAD_H) AND (NOT WIN32))
-	message(FATAL_ERROR "Can't build librws without any threading support")
-endif()
-
-
-if(NOT DEFINED CMAKE_INSTALL_LIBDIR)
-	set(CMAKE_INSTALL_LIBDIR lib)
-endif(NOT DEFINED CMAKE_INSTALL_LIBDIR)
-
-# Now make sure that you the the build directory on your "Include" path when compiling
-include_directories(${PROJECT_BINARY_DIR})
-
-
-set(LIBRWS_SOURCES src/rws_common.c
-		src/rws_error.c
-		src/rws_frame.c
-		src/librws.c
-		src/rws_list.c
-		src/rws_memory.c
-		src/rws_socketpriv.c
-		src/rws_socketpub.c
-		src/rws_string.c
-		src/rws_thread.c)
-				
-
-set(LIBRWS_HEADERS librws.h)
-
-
-add_definitions(-DRWS_BUILD)
-
-
-if(RWS_OPT_SHARED)
-	add_library(rws SHARED ${LIBRWS_SOURCES} ${LIBRWS_HEADERS})
-	if(MSVC)
-    	# msvc does not append 'lib' - do it here to have consistent name
-	    set_property(TARGET rws PROPERTY PREFIX "lib")
-	set_property(TARGET rws PROPERTY IMPORT_PREFIX "lib")
-	endif()
-endif()
-
-if(RWS_OPT_STATIC)
-	add_library(rws_static STATIC ${LIBRWS_SOURCES} ${LIBRWS_HEADERS})
-	set_property(TARGET rws_static APPEND PROPERTY COMPILE_FLAGS -DLIBRWS_STATIC)
-	if(MSVC)
-    	# msvc does not append 'lib' - do it here to have consistent name
-	    set_target_properties(rws_static PROPERTIES PREFIX "lib")
-	endif()
-endif()
-
-
-
-if(RWS_HAVE_PTHREAD_H)
-	target_link_libraries(rws pthread)
-endif(RWS_HAVE_PTHREAD_H)
-
-
-if(WIN32)
-	target_link_libraries(rws ws2_32)
-endif(WIN32)
-
-
-install(TARGETS rws
-		DESTINATION lib)
-
-install(TARGETS rws_static
-		DESTINATION lib)
-
-install(FILES librws.h 
-		DESTINATION include)
-
-
-if(RWS_OPT_TESTS)
-	enable_testing()
-	add_subdirectory(test)
-
-	# This must always be last!
-	include(CPack)
-endif()
-

+ 29 - 0
SConscript

@@ -0,0 +1,29 @@
+import os
+from building import * 
+
+# get current dir path
+cwd = GetCurrentDir()
+
+# init src and inc vars
+src = []
+inc = []
+
+# add librws common include
+inc = inc + [cwd + '/librws/inc']
+
+# add librws basic code
+src = src + Glob('librws/src/*.c')
+
+# add group to IDE project
+objs = DefineGroup('librws_rtthread', src, depend = ['PKG_USING_LIBRWS', 'RT_USING_PTHREADS'], CPPPATH = inc)
+
+# traversal subscript
+list = os.listdir(cwd)
+if GetDepend(['PKG_USING_LIBRWS', 'RT_USING_PTHREADS']):
+    for d in list:
+        path = os.path.join(cwd, d)
+        if os.path.isfile(os.path.join(path, 'SConscript')):
+            objs = objs + SConscript(os.path.join(d, 'SConscript'))
+
+Return('objs')
+

+ 0 - 82
appveyor.yml

@@ -1,82 +0,0 @@
-version: 1.2.4.{build}
-
-
-os: Visual Studio 2015
-
-
-# Do not build on tags (GitHub only)
-skip_tags: true
-
-
-# branches to build
-branches:
-  only:
-  - master
-  - dev
-
-
-# build platform, i.e. x86, x64, Any CPU. This setting is optional.
-#platform:
-#  - x86
-#  - x64
-
-
-environment:
-  CMAKE_ARGS: -DCMAKE_BUILD_TYPE=Release
-
-  matrix:
-  - platform: x86
-    CMAKE_ARGS: -G"Visual Studio 14" -DRWS_OPT_APPVEYOR_CI=ON -DCMAKE_INSTALL_PREFIX:PATH=c:\dev\librws\librws-install-win-%PLATFORM% -DCMAKE_BUILD_TYPE=Release
-
-  - platform: x64
-    CMAKE_ARGS: -G"Visual Studio 14 Win64" -DRWS_OPT_APPVEYOR_CI=ON -DCMAKE_INSTALL_PREFIX:PATH=c:\dev\librws\librws-install-win-%PLATFORM% -DCMAKE_BUILD_TYPE=Release
-
-
-configuration: Release
-
-
-# clone directory
-clone_folder: c:\dev\librws
-
-
-# scripts that run after cloning repository
-install:
-  - cd c:\dev\librws
-  - md librws-install-win-%PLATFORM%
-
-
-build:
-  parallel: true
-  verbosity: detailed
-
-
-build_script:
-  - cd c:\dev\librws
-  - md build
-  - cd build
-  - cmake %CMAKE_ARGS% ..
-  - cmake --build . --config Release
-  - cmake --build . --config Release --target Install
-  - cd ..
-
-
-after_build:
-  - 7z a -t7z -mx=9 -xr!bin librws-win-%PLATFORM%-%APPVEYOR_REPO_BRANCH%-%APPVEYOR_BUILD_VERSION%.7z c:\dev\librws\librws-install-win-%PLATFORM%
-
-
-artifacts:
-  - path: '*.7z'
-
-
-deploy:
-  - provider: GitHub
-    release: $(appveyor_build_version)
-    description: 'Appveyor CI build artifacts. Compressed install path with binaries, libraries and configured headers'
-    auth_token:
-      secure: 9fCOXiEygRERkV9JN67Rqq6WFwdbSBIllYdZGYcSoFPj1oUAxk3aRi+bWv04l7M5
-    artifact: /.*\.7z/
-    draft: false
-    prerelease: true
-    on:
-      branch: master
-

+ 0 - 28
builds/android/jni/Android.mk

@@ -1,28 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-
-ALL_SOURCES := \
-	../../../src/rws_common.c \
-	../../../src/rws_error.c \
-	../../../src/rws_frame.c \
-	../../../src/librws.c \
-	../../../src/rws_list.c \
-	../../../src/rws_memory.c \
-	../../../src/rws_socketpriv.c \
-	../../../src/rws_socketpub.c \
-	../../../src/rws_string.c \
-	../../../src/rws_thread.c
-
-
-ALL_INCLUDES := $(LOCAL_PATH)/../../../
-
-ALL_CFLAGS := -w
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(ALL_SOURCES)
-LOCAL_C_INCLUDES += $(ALL_INCLUDES)
-LOCAL_CFLAGS += $(ALL_CFLAGS)
-LOCAL_MODULE := librws
-LOCAL_LDLIBS += -llog
-include $(BUILD_SHARED_LIBRARY)
-

+ 0 - 3
builds/android/jni/Application.mk

@@ -1,3 +0,0 @@
-APP_OPTIM := release
-APP_PLATFORM := android-14
-APP_ABI := all

+ 0 - 118
contrib/objc/RWSSocketObjc.h

@@ -1,118 +0,0 @@
-/*
- *   Copyright (c) 2014 - 2019 Oleh Kulykov <info@resident.name>
- *
- *   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.
- */
-
-
-#import <Foundation/Foundation.h>
-
-@class RWSSocketObjc;
-
-/**
- @brief Websocket delegate protocol.
- All methods called from main thread.
- */
-@protocol RWSSocketObjcDelegate <NSObject>
-
-@required
-/**
- @brief Websocket connected.
- @detailed Connection extablished and handshake done.
- Web socket ready to send and receive.
- @param socket Socket object.
- */
-- (void) onRWSSocketConnected:(nonnull RWSSocketObjc *) socket;
-
-
-/**
- @brief Socket client disconnected.
- @detailed Internal socket already freed and dealocated.
- Connect once again.
- @param socket Socket object.
- @param error Disconnect error.
- */
-- (void) onRWSSocketDisconnected:(nonnull RWSSocketObjc *) socket
-					   withError:(nullable NSError *) error;
-
-@optional
-/**
- @brief Socket received non empty text.
- @param socket Socket object.
- @param text Non empty text.
- */
-- (void) onRWSSocket:(nonnull RWSSocketObjc *) socket receivedText:(nonnull NSString *) text;
-
-
-
-/**
- @brief Socket received non empty binary data.
- @param socket Socket object.
- @param text Non binary data.
- */
-- (void) onRWSSocket:(nonnull RWSSocketObjc *) socket receivedData:(nonnull NSData *) data;
-
-@end
-
-
-/**
- @brief Objective-C web socket wrapper.
- @detailed Internal implementation use C library part.
- */
-@interface RWSSocketObjc : NSObject
-
-
-/**
- @brief Weak read/write reference to delegate object.
- */
-@property (nullable, nonatomic, weak) id<RWSSocketObjcDelegate> delegate;
-
-
-/**
- @brief Check websocket exists and connected.
- */
-@property (nonatomic, readonly) BOOL isConnected;
-
-
-/**
- @brief Send text to connected web socket.
- @detailed Add text frame to send queue.
- @param text Text for sending.
- @return YES - socket exist, connected and text not empty, othervice NO.
- */
-- (BOOL) sendText:(nonnull NSString *) text;
-
-
-/**
- @brief Connect to server.
- @detailed Remove previos socket object and make new connection.
- @return YES - started connection sequence, othervice NO.
- */
-- (BOOL) connect;
-
-
-/**
- @brief Initialize web socket with destination url.
- @param url Connection URL. Should not be nil.
- @return Websocket object or nil on error.
- */
-- (nullable id) initWithURL:(nonnull NSURL *) url;
-
-
-@end

+ 0 - 160
contrib/objc/RWSSocketObjc.m

@@ -1,160 +0,0 @@
-/*
- *   Copyright (c) 2014 - 2019 Oleh Kulykov <info@resident.name>
- *
- *   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.
- */
-
-
-#import "RWSSocketObjc.h"
-#include "../../librws.h"
-
-@interface RWSSocketObjc() {
-@private
-	rws_socket _socket;
-	__strong NSURL * _url;
-}
-
-@end
-
-@implementation RWSSocketObjc
-
-- (void) onDisconnected {
-	rws_error error = rws_socket_get_error(_socket);
-	_socket = NULL;
-	
-	NSError * err = nil;
-	if (error) {
-		err = [NSError errorWithDomain:@"RWSSocket"
-								  code:rws_error_get_code(error)
-							  userInfo:@{ NSLocalizedDescriptionKey : [NSString stringWithUTF8String:rws_error_get_description(error)] }];
-	}
-	
-	id<RWSSocketObjcDelegate> d = self.delegate;
-	if (d && [d respondsToSelector:@selector(onRWSSocketDisconnected:withError:)]) {
-		dispatch_async(dispatch_get_main_queue(), ^{
-			[d onRWSSocketDisconnected:self withError:err];
-		});
-	}
-}
-
-static void onRWSSocketObjcConnected(rws_socket socket) {
-	RWSSocketObjc * s = (__bridge RWSSocketObjc *)rws_socket_get_user_object(socket);
-	id<RWSSocketObjcDelegate> d = s ? [s delegate] : nil;
-	if (d && [d respondsToSelector:@selector(onRWSSocketConnected:)]) {
-		dispatch_async(dispatch_get_main_queue(), ^{
-			[d onRWSSocketConnected:s];
-		});
-	}
-}
-
-static void onRWSSocketObjcDisconnected(rws_socket socket) {
-	RWSSocketObjc * s = (__bridge RWSSocketObjc *)rws_socket_get_user_object(socket);
-	if (s) {
-		[s onDisconnected];
-	}
-}
-
-static void onRWSSocketObjcRecvdText(rws_socket socket, const char * text, const unsigned int length) {
-	RWSSocketObjc * s = (__bridge RWSSocketObjc *)rws_socket_get_user_object(socket);
-	id<RWSSocketObjcDelegate> d = s ? [s delegate] : nil;
-	if (text && length && d && [d respondsToSelector:@selector(onRWSSocket:receivedText:)]) {
-		NSString * t = [NSString stringWithUTF8String:text];
-		dispatch_async(dispatch_get_main_queue(), ^{
-			[d onRWSSocket:s receivedText:t];
-		});
-	}
-}
-
-static void onRWSSocketObjcRecvdBin(rws_socket socket, const void * data, const unsigned int length) {
-	RWSSocketObjc * s = (__bridge RWSSocketObjc *)rws_socket_get_user_object(socket);
-	id<RWSSocketObjcDelegate> d = s ? [s delegate] : nil;
-	if (data && length && d && [d respondsToSelector:@selector(onRWSSocket:receivedData:)]) {
-		NSData * dt = [NSData dataWithBytes:data length:length];
-		dispatch_async(dispatch_get_main_queue(), ^{
-			[d onRWSSocket:s receivedData:dt];
-		});
-	}
-}
-
-- (BOOL) sendText:(NSString *) text {
-	if (text && [text length]) {
-		if (rws_socket_send_text(_socket, [text UTF8String])) {
-			return YES;
-		}
-	}
-	return NO;
-}
-
-- (void) cleanup {
-	if (_socket) {
-		rws_socket_set_user_object(_socket, NULL);
-		rws_socket_disconnect_and_release(_socket);
-		_socket = NULL;
-	}
-}
-
-- (BOOL) connect {
-	[self cleanup];
-	if (!_url) {
-		return NO;
-	}
-	
-	_socket = rws_socket_create();
-	rws_socket_set_scheme(_socket, [[_url scheme] UTF8String]);
-	rws_socket_set_host(_socket, [[_url host] UTF8String]);
-	rws_socket_set_port(_socket, [[_url port] intValue]);
-	
-	NSString * path = [_url path];
-	if (!path || [path length] == 0) {
-		path = @"/";
-	}
-	rws_socket_set_path(_socket, [path UTF8String]);
-	
-	rws_socket_set_user_object(_socket, (__bridge void *)self);
-	
-	rws_socket_set_on_disconnected(_socket, &onRWSSocketObjcDisconnected);
-	rws_socket_set_on_connected(_socket, &onRWSSocketObjcConnected);
-	rws_socket_set_on_received_text(_socket, &onRWSSocketObjcRecvdText);
-	rws_socket_set_on_received_bin(_socket, &onRWSSocketObjcRecvdBin);
-	
-	return rws_socket_connect(_socket) ? YES : NO;
-}
-
-- (BOOL) isConnected {
-	return rws_socket_is_connected(_socket) ? YES : NO;
-}
-
-- (nullable id) initWithURL:(nonnull NSURL *) url {
-	self = [super init];
-	if (self && url) {
-		_url = url;
-		return self;
-	}
-	return nil;
-}
-
-- (id) init {
-	return nil;
-}
-
-- (void) dealloc {
-	[self cleanup];
-}
-
-@end

+ 20 - 0
examples/SConscript

@@ -0,0 +1,20 @@
+import os
+from building import * 
+
+# get current dir path
+cwd = GetCurrentDir()
+
+# init src and inc vars
+src = []
+inc = []
+
+# add librws common include
+inc = inc + [cwd]
+
+# add librws basic code
+src = src + Glob('./*.c')
+
+# add group to IDE project
+objs = DefineGroup('librws_example', src, depend = ['LIBRWS_USING_EXAMPLE'], CPPPATH = inc)
+
+Return('objs')

+ 228 - 0
examples/rws_example.c

@@ -0,0 +1,228 @@
+//  The MIT License (MIT)
+//  Copyright (c) 2018 liu2guang <liuguang@rt-thread.com>
+
+//  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.
+
+#include <rtthread.h>
+#include <librws.h>
+#include <string.h>
+#include <stdlib.h>
+
+#if (RTTHREAD_VERSION < 30100)
+#define DBG_SECTION_NAME "[LIBRWS.Test] "
+#else
+#define DBG_SECTION_NAME "LIBRWS.Test"
+#endif
+#define DBG_ENABLE
+#define DBG_LEVEL DBG_LOG
+#define DBG_COLOR
+#include <rtdbg.h>
+
+struct librws_app
+{
+    rt_bool_t init;
+    rws_socket *socket;
+};
+typedef struct librws_app *librws_app_t;
+
+static librws_app_t app;
+
+static void onopen(rws_socket socket)
+{
+    LOG_D("websocket connected. ");
+}
+
+static void onclose(rws_socket socket)
+{
+    rws_error error = rws_socket_get_error(socket);
+
+    if (error)
+    {
+        LOG_E("websocket disconnect, error: %i, %s ", rws_error_get_code(error), rws_error_get_description(error));
+    }
+    else
+    {
+        LOG_D("websocket disconnect! ");
+    }
+
+    rws_socket_disconnect_and_release(app->socket);
+
+    app->init = RT_FALSE;
+}
+
+static void onmessage_text(rws_socket socket, const char *text, const unsigned int len)
+{
+    char *buff = RT_NULL;
+
+    buff = (char *)rt_malloc(2048);
+
+    rt_memset(buff, 0x00, 2048);
+    rt_memcpy(buff, text, len);
+
+    LOG_D("message(txt), %d(byte): %s ", len, buff);
+
+    if (buff != RT_NULL)
+    {
+        rt_free(buff);
+    }
+}
+
+static void onmessage_bin(rws_socket socket, const void *data, const unsigned int len)
+{
+    char *buff = RT_NULL;
+
+    buff = (char *)rt_malloc(2048);
+
+    rt_memset(buff, 0x00, 2048);
+    rt_memcpy(buff, data, len);
+
+    LOG_D("message(bin), %d(byte): %s ", len, buff);
+
+    if (buff != RT_NULL)
+    {
+        rt_free(buff);
+    }
+}
+
+// rws_connect ws echo.websocket.org 80
+// rws_connect wss echo.websocket.org 443
+// rws_send "hello tls!"
+static int _rws_connect(int argc, char *argv[])
+{
+    int port = -1;
+    rws_bool ret = rws_false;
+
+    if (argc < 3)
+    {
+        LOG_E("the msh cmd format: rws_conn ws/wss host [port]. ");
+        return RT_EOK;
+    }
+
+    if (app->init == RT_TRUE)
+    {
+        LOG_E("the websocket connection has been opened. ");
+        return (-RT_EBUSY);
+    }
+
+    app = (librws_app_t)rt_malloc_align(sizeof(struct librws_app), 4);
+    if (app == RT_NULL)
+    {
+        LOG_E("librws_conn cmd memory malloc failed. ");
+        return (-RT_ENOMEM);
+    }
+
+    rt_memset(app, 0x00, sizeof(struct librws_app));
+
+    app->socket = rws_socket_create();
+    if (app->socket == RT_NULL)
+    {
+        LOG_E("librws socket create failed. ");
+        return (-RT_ERROR);
+    }
+
+    if (strcmp(argv[1], "ws") == 0)
+    {
+        port = ((argv[3] == RT_NULL) ? (80) : (atoi(argv[3])));
+        rws_socket_set_url(app->socket, "ws", argv[2], port, "/");
+    }
+    else if (strcmp(argv[1], "wss") == 0)
+    {
+        port = ((argv[3] == RT_NULL) ? (443) : (atoi(argv[3])));
+        rws_socket_set_url(app->socket, "wss", argv[2], port, "/");
+    }
+    else
+    {
+        LOG_E("protocol types are not supported, only support ws/wss. ");
+        return (-RT_EINVAL);
+    }
+
+    rws_socket_set_on_connected(app->socket, &onopen);
+    rws_socket_set_on_disconnected(app->socket, &onclose);
+    rws_socket_set_on_received_text(app->socket, &onmessage_text);
+    rws_socket_set_on_received_bin(app->socket, &onmessage_bin);
+
+    /* set custom mode */
+    rws_socket_set_custom_mode(app->socket);
+
+    ret = rws_socket_connect(app->socket);
+    if (ret == rws_false)
+    {
+        if (strcmp(argv[1], "ws") == 0)
+        {
+            LOG_E("connect %s://%s:%d/ failed. ", argv[1], argv[2], port);
+        }
+        else if (strcmp(argv[1], "wss") == 0)
+        {
+            LOG_E("connect %s://%s:%d/ failed. ", argv[1], argv[2], port);
+        }
+    }
+    else
+    {
+        if (strcmp(argv[1], "ws") == 0)
+        {
+            LOG_D("try connect %s://%s:%d/ ", argv[1], argv[2], port);
+        }
+        else if (strcmp(argv[1], "wss") == 0)
+        {
+            LOG_D("try connect %s://%s:%d/ ", argv[1], argv[2], port);
+        }
+    }
+
+    app->init = RT_TRUE;
+
+    return RT_EOK;
+}
+MSH_CMD_EXPORT_ALIAS(_rws_connect, rws_connect, websocket connect);
+
+static int _rws_disconnect(int argc, char *argv[])
+{
+    if (app->init == RT_FALSE)
+    {
+        LOG_W("no websocket connection. ");
+        return (-RT_ERROR);
+    }
+
+    rws_socket_disconnect_and_release(app->socket);
+    LOG_I("try disconnect websocket connection. ");
+
+    return RT_EOK;
+}
+MSH_CMD_EXPORT_ALIAS(_rws_disconnect, rws_disconnect, websocket disconnect);
+
+static int _rws_send(int argc, char *argv[])
+{
+    if (argc == 1)
+    {
+        LOG_E("The command format: rws_send \"content\". ");
+        return RT_EOK;
+    }
+
+    if (app->init == RT_FALSE)
+    {
+        LOG_W("no websocket connection. ");
+        return (-RT_ERROR);
+    }
+
+    LOG_W("string = %s, len = %d", argv[1], rt_strlen(argv[1]));
+
+    rws_socket_send_text(app->socket, argv[1]);
+
+    return RT_EOK;
+}
+MSH_CMD_EXPORT_ALIAS(_rws_send, rws_send, websocket send text);

+ 0 - 30
librws.podspec

@@ -1,30 +0,0 @@
-Pod::Spec.new do |s|
-
-# Common settings
-  s.name         = "librws"
-  s.version      = "1.2.4"
-  s.summary      = " Tiny, cross platform websocket client C library"
-  s.description  = <<-DESC
-Tiny, cross platform websocket client C library.
-- No additional dependecies, exceprt pthread on unix-like platforms and Win threads on Windows
-- Single header library interface librws.h with public methods
-- Thread safe
-- Send/receive logic in background thread
-                      DESC
-  s.homepage     = "https://github.com/OlehKulykov/librws"
-  s.license      = { :type => 'MIT', :file => 'LICENSE' }
-  s.author       = { "Oleh Kulykov" => "info@resident.name" }
-  s.source       = { :git => 'https://github.com/OlehKulykov/librws.git', :tag => s.version.to_s }
-
-# Platforms
-  s.ios.deployment_target = "7.0"
-  s.osx.deployment_target = "10.7"
-  s.watchos.deployment_target = '2.0'
-  s.tvos.deployment_target = '9.0'
-
-# Build  
-  s.source_files = '*.h', 'src/*.{h,c}', 'contrib/objc/*.{h,m}'
-  s.public_header_files = '*.h', 'contrib/objc/*.h'
-  s.requires_arc = true
-  s.libraries = 'pthread', 'stdc++'
-end

+ 56 - 88
librws.h → librws/inc/librws.h

@@ -1,5 +1,5 @@
 /*
 /*
- *   Copyright (c) 2014 - 2019 Oleh Kulykov <info@resident.name>
+ *   Copyright (c) 2014 - 2017 Kulykov Oleh <info@resident.name>
  *
  *
  *   Permission is hereby granted, free of charge, to any person obtaining a copy
  *   Permission is hereby granted, free of charge, to any person obtaining a copy
  *   of this software and associated documentation files (the "Software"), to deal
  *   of this software and associated documentation files (the "Software"), to deal
@@ -20,25 +20,20 @@
  *   THE SOFTWARE.
  *   THE SOFTWARE.
  */
  */
 
 
-
 #ifndef __LIBRWS_H__
 #ifndef __LIBRWS_H__
-#define __LIBRWS_H__ 1
-
+#define __LIBRWS_H__
 
 
 #include <stdio.h>
 #include <stdio.h>
 
 
-
 #define RWS_VERSION_MAJOR 1
 #define RWS_VERSION_MAJOR 1
 #define RWS_VERSION_MINOR 2
 #define RWS_VERSION_MINOR 2
 #define RWS_VERSION_PATCH 4
 #define RWS_VERSION_PATCH 4
 
 
-
 // check windows
 // check windows
 #if defined(WIN32) || defined(_WIN32) || defined(WIN32_LEAN_AND_MEAN) || defined(_WIN64) || defined(WIN64)
 #if defined(WIN32) || defined(_WIN32) || defined(WIN32_LEAN_AND_MEAN) || defined(_WIN64) || defined(WIN64)
 #define RWS_OS_WINDOWS 1
 #define RWS_OS_WINDOWS 1
 #endif
 #endif
 
 
-
 // extern
 // extern
 #if defined(__cplusplus) || defined(_cplusplus)
 #if defined(__cplusplus) || defined(_cplusplus)
 #define RWS_EXTERN extern "C"
 #define RWS_EXTERN extern "C"
@@ -46,7 +41,6 @@
 #define RWS_EXTERN extern
 #define RWS_EXTERN extern
 #endif
 #endif
 
 
-
 // attribute
 // attribute
 #if defined(__GNUC__)
 #if defined(__GNUC__)
 #if (__GNUC__ >= 4)
 #if (__GNUC__ >= 4)
@@ -58,13 +52,11 @@
 #endif
 #endif
 #endif
 #endif
 
 
-
 // check attrib and define empty if not defined
 // check attrib and define empty if not defined
 #if !defined(RWS_ATTRIB)
 #if !defined(RWS_ATTRIB)
 #define RWS_ATTRIB
 #define RWS_ATTRIB
 #endif
 #endif
 
 
-
 // dll api
 // dll api
 #if defined(RWS_OS_WINDOWS)
 #if defined(RWS_OS_WINDOWS)
 #if defined(RWS_BUILD)
 #if defined(RWS_BUILD)
@@ -74,63 +66,54 @@
 #endif
 #endif
 #endif
 #endif
 
 
-
 // check dll api and define empty if not defined
 // check dll api and define empty if not defined
 #if !defined(RWS_DYLIB_API)
 #if !defined(RWS_DYLIB_API)
 #define RWS_DYLIB_API
 #define RWS_DYLIB_API
 #endif
 #endif
 
 
-
 // combined lib api
 // combined lib api
 #define RWS_API(return_type) RWS_EXTERN RWS_ATTRIB RWS_DYLIB_API return_type
 #define RWS_API(return_type) RWS_EXTERN RWS_ATTRIB RWS_DYLIB_API return_type
 
 
-
 // types
 // types
 
 
 /**
 /**
  @brief Boolean type as unsigned byte type.
  @brief Boolean type as unsigned byte type.
  */
  */
 typedef unsigned char rws_bool;
 typedef unsigned char rws_bool;
-#define rws_true 1
-#define rws_false 0
 
 
+#define rws_true  1
+#define rws_false 0
 
 
 /**
 /**
  @brief Type of all public objects.
  @brief Type of all public objects.
  */
  */
-typedef void* rws_handle;
-
+typedef void *rws_handle;
 
 
 /**
 /**
  @brief Socket handle.
  @brief Socket handle.
  */
  */
-typedef struct rws_socket_struct * rws_socket;
-
+typedef rws_handle rws_socket;
 
 
 /**
 /**
  @brief Error object handle.
  @brief Error object handle.
  */
  */
-typedef struct rws_error_struct * rws_error;
-
+typedef rws_handle rws_error;
 
 
 /**
 /**
  @brief Mutex object handle.
  @brief Mutex object handle.
  */
  */
 typedef rws_handle rws_mutex;
 typedef rws_handle rws_mutex;
 
 
-
 /**
 /**
  @brief Thread object handle.
  @brief Thread object handle.
  */
  */
-typedef struct rws_thread_struct * rws_thread;
-
+typedef rws_handle rws_thread;
 
 
 /**
 /**
  @brief Callback type of thread function.
  @brief Callback type of thread function.
  @param user_object User object provided during thread creation.
  @param user_object User object provided during thread creation.
  */
  */
-typedef void (*rws_thread_funct)(void * user_object);
-
+typedef void (*rws_thread_funct)(void *user_object);
 
 
 /**
 /**
  @brief Callback type of socket object.
  @brief Callback type of socket object.
@@ -138,15 +121,13 @@ typedef void (*rws_thread_funct)(void * user_object);
  */
  */
 typedef void (*rws_on_socket)(rws_socket socket);
 typedef void (*rws_on_socket)(rws_socket socket);
 
 
-
 /**
 /**
  @brief Callback type on socket receive text frame.
  @brief Callback type on socket receive text frame.
  @param socket Socket object.
  @param socket Socket object.
  @param text Pointer to reseived text.
  @param text Pointer to reseived text.
  @param length Received text lenght without null terminated char.
  @param length Received text lenght without null terminated char.
  */
  */
-typedef void (*rws_on_socket_recvd_text)(rws_socket socket, const char * text, const unsigned int length);
-
+typedef void (*rws_on_socket_recvd_text)(rws_socket socket, const char *text, const unsigned int length);
 
 
 /**
 /**
  @brief Callback type on socket receive binary frame.
  @brief Callback type on socket receive binary frame.
@@ -154,8 +135,7 @@ typedef void (*rws_on_socket_recvd_text)(rws_socket socket, const char * text, c
  @param data Received binary data.
  @param data Received binary data.
  @param length Received binary data lenght.
  @param length Received binary data lenght.
  */
  */
-typedef void (*rws_on_socket_recvd_bin)(rws_socket socket, const void * data, const unsigned int length);
-
+typedef void (*rws_on_socket_recvd_bin)(rws_socket socket, const void *data, const unsigned int length);
 
 
 // socket
 // socket
 
 
@@ -165,7 +145,6 @@ typedef void (*rws_on_socket_recvd_bin)(rws_socket socket, const void * data, co
  */
  */
 RWS_API(rws_socket) rws_socket_create(void);
 RWS_API(rws_socket) rws_socket_create(void);
 
 
-
 /**
 /**
  @brief Set socket connect URL.
  @brief Set socket connect URL.
  @param socket Socket object.
  @param socket Socket object.
@@ -179,10 +158,10 @@ RWS_API(rws_socket) rws_socket_create(void);
  @endcode
  @endcode
  */
  */
 RWS_API(void) rws_socket_set_url(rws_socket socket,
 RWS_API(void) rws_socket_set_url(rws_socket socket,
-								 const char * scheme,
-								 const char * host,
-								 const int port,
-								 const char * path);
+                                 const char *scheme,
+                                 const char *host,
+                                 const int port,
+                                 const char *path);
 
 
 /**
 /**
  @brief Set socket connect URL scheme string.
  @brief Set socket connect URL scheme string.
@@ -193,8 +172,7 @@ RWS_API(void) rws_socket_set_url(rws_socket socket,
  rws_socket_set_scheme(socket, "ws");
  rws_socket_set_scheme(socket, "ws");
  @endcode
  @endcode
  */
  */
-RWS_API(void) rws_socket_set_scheme(rws_socket socket, const char * scheme);
-
+RWS_API(void) rws_socket_set_scheme(rws_socket socket, const char *scheme);
 
 
 /**
 /**
  @brief Get socket connect URL scheme string.
  @brief Get socket connect URL scheme string.
@@ -203,7 +181,6 @@ RWS_API(void) rws_socket_set_scheme(rws_socket socket, const char * scheme);
  */
  */
 RWS_API(const char *) rws_socket_get_scheme(rws_socket socket);
 RWS_API(const char *) rws_socket_get_scheme(rws_socket socket);
 
 
-
 /**
 /**
  @brief Set socket connect URL scheme string.
  @brief Set socket connect URL scheme string.
  @param socket Socket object.
  @param socket Socket object.
@@ -212,8 +189,7 @@ RWS_API(const char *) rws_socket_get_scheme(rws_socket socket);
  rws_socket_set_host(socket, "echo.websocket.org");
  rws_socket_set_host(socket, "echo.websocket.org");
  @endcode
  @endcode
  */
  */
-RWS_API(void) rws_socket_set_host(rws_socket socket, const char * host);
-
+RWS_API(void) rws_socket_set_host(rws_socket socket, const char *host);
 
 
 /**
 /**
  @brief Get socket connect URL host string.
  @brief Get socket connect URL host string.
@@ -222,7 +198,6 @@ RWS_API(void) rws_socket_set_host(rws_socket socket, const char * host);
  */
  */
 RWS_API(const char *) rws_socket_get_host(rws_socket socket);
 RWS_API(const char *) rws_socket_get_host(rws_socket socket);
 
 
-
 /**
 /**
  @brief Set socket connect URL port.
  @brief Set socket connect URL port.
  @param socket Socket object.
  @param socket Socket object.
@@ -233,7 +208,6 @@ RWS_API(const char *) rws_socket_get_host(rws_socket socket);
  */
  */
 RWS_API(void) rws_socket_set_port(rws_socket socket, const int port);
 RWS_API(void) rws_socket_set_port(rws_socket socket, const int port);
 
 
-
 /**
 /**
  @brief Get socket connect URL port.
  @brief Get socket connect URL port.
  @param socket Socket object.
  @param socket Socket object.
@@ -241,7 +215,6 @@ RWS_API(void) rws_socket_set_port(rws_socket socket, const int port);
  */
  */
 RWS_API(int) rws_socket_get_port(rws_socket socket);
 RWS_API(int) rws_socket_get_port(rws_socket socket);
 
 
-
 /**
 /**
  @brief Set socket connect URL path string.
  @brief Set socket connect URL path string.
  @param socket Socket object.
  @param socket Socket object.
@@ -251,8 +224,7 @@ RWS_API(int) rws_socket_get_port(rws_socket socket);
  rws_socket_set_path(socket, "/path"); // some path
  rws_socket_set_path(socket, "/path"); // some path
  @endcode
  @endcode
  */
  */
-RWS_API(void) rws_socket_set_path(rws_socket socket, const char * path);
-
+RWS_API(void) rws_socket_set_path(rws_socket socket, const char *path);
 
 
 /**
 /**
  @brief Get socket connect URL path string.
  @brief Get socket connect URL path string.
@@ -261,7 +233,6 @@ RWS_API(void) rws_socket_set_path(rws_socket socket, const char * path);
  */
  */
 RWS_API(const char *) rws_socket_get_path(rws_socket socket);
 RWS_API(const char *) rws_socket_get_path(rws_socket socket);
 
 
-
 /**
 /**
  @brief Get socket last error object handle.
  @brief Get socket last error object handle.
  @param socket Socket object.
  @param socket Socket object.
@@ -269,7 +240,6 @@ RWS_API(const char *) rws_socket_get_path(rws_socket socket);
  */
  */
 RWS_API(rws_error) rws_socket_get_error(rws_socket socket);
 RWS_API(rws_error) rws_socket_get_error(rws_socket socket);
 
 
-
 /**
 /**
  @brief Start connection.
  @brief Start connection.
  @detailed This method can generate error object.
  @detailed This method can generate error object.
@@ -278,7 +248,6 @@ RWS_API(rws_error) rws_socket_get_error(rws_socket socket);
  */
  */
 RWS_API(rws_bool) rws_socket_connect(rws_socket socket);
 RWS_API(rws_bool) rws_socket_connect(rws_socket socket);
 
 
-
 /**
 /**
  @brief Disconnect socket.
  @brief Disconnect socket.
  @detailed Cleanup prev. send messages and start disconnection sequence.
  @detailed Cleanup prev. send messages and start disconnection sequence.
@@ -288,7 +257,6 @@ RWS_API(rws_bool) rws_socket_connect(rws_socket socket);
  */
  */
 RWS_API(void) rws_socket_disconnect_and_release(rws_socket socket);
 RWS_API(void) rws_socket_disconnect_and_release(rws_socket socket);
 
 
-
 /**
 /**
  @brief Check is socket has connection to host and handshake(sucessfully done).
  @brief Check is socket has connection to host and handshake(sucessfully done).
  @detailed Thread safe getter.
  @detailed Thread safe getter.
@@ -297,7 +265,6 @@ RWS_API(void) rws_socket_disconnect_and_release(rws_socket socket);
  */
  */
 RWS_API(rws_bool) rws_socket_is_connected(rws_socket socket);
 RWS_API(rws_bool) rws_socket_is_connected(rws_socket socket);
 
 
-
 /**
 /**
  @brief Send text to connect socket.
  @brief Send text to connect socket.
  @detailed Thread safe method.
  @detailed Thread safe method.
@@ -305,16 +272,24 @@ RWS_API(rws_bool) rws_socket_is_connected(rws_socket socket);
  @param text Text string for sending.
  @param text Text string for sending.
  @return rws_true - socket and text exists and placed to send queue, otherwice rws_false.
  @return rws_true - socket and text exists and placed to send queue, otherwice rws_false.
  */
  */
-RWS_API(rws_bool) rws_socket_send_text(rws_socket socket, const char * text);
+RWS_API(rws_bool) rws_socket_send_text(rws_socket socket, const char *text);
 
 
+/**
+ @brief Send bin to connect socket.
+ @detailed Thread safe method.
+ @param socket Socket object.
+ @param bin bin string for sending.
+ @param opcode opcode for frame
+ @return rws_true - socket and bin exists and placed to send queue, otherwice rws_false.
+ */
+RWS_API(rws_bool) rws_socket_send_bin(rws_socket socket, void *data, size_t len, int opcode, rws_bool is_fin);
 
 
 /**
 /**
  @brief Set socket user defined object pointer for identificating socket object.
  @brief Set socket user defined object pointer for identificating socket object.
  @param socket Socket object.
  @param socket Socket object.
  @param user_object Void pointer to user object.
  @param user_object Void pointer to user object.
  */
  */
-RWS_API(void) rws_socket_set_user_object(rws_socket socket, void * user_object);
-
+RWS_API(void) rws_socket_set_user_object(rws_socket socket, void *user_object);
 
 
 /**
 /**
  @brief Get socket user defined object.
  @brief Get socket user defined object.
@@ -323,60 +298,53 @@ RWS_API(void) rws_socket_set_user_object(rws_socket socket, void * user_object);
  */
  */
 RWS_API(void *) rws_socket_get_user_object(rws_socket socket);
 RWS_API(void *) rws_socket_get_user_object(rws_socket socket);
 
 
-
 RWS_API(void) rws_socket_set_on_connected(rws_socket socket, rws_on_socket callback);
 RWS_API(void) rws_socket_set_on_connected(rws_socket socket, rws_on_socket callback);
 
 
-
 RWS_API(void) rws_socket_set_on_disconnected(rws_socket socket, rws_on_socket callback);
 RWS_API(void) rws_socket_set_on_disconnected(rws_socket socket, rws_on_socket callback);
 
 
-
 RWS_API(void) rws_socket_set_on_received_text(rws_socket socket, rws_on_socket_recvd_text callback);
 RWS_API(void) rws_socket_set_on_received_text(rws_socket socket, rws_on_socket_recvd_text callback);
 
 
-
 RWS_API(void) rws_socket_set_on_received_bin(rws_socket socket, rws_on_socket_recvd_bin callback);
 RWS_API(void) rws_socket_set_on_received_bin(rws_socket socket, rws_on_socket_recvd_bin callback);
 
 
+#ifdef LIBRWS_USING_MBED_TLS
+    RWS_API(void) rws_socket_set_server_cert(rws_socket socket, const char *server_cert, int server_cert_len);
+#endif
 
 
 // error
 // error
-
-typedef enum _rws_error_code {
-	rws_error_code_none = 0,
-	
-	rws_error_code_missed_parameter,
-	
-	rws_error_code_send_handshake,
-	rws_error_code_parse_handshake,
-	rws_error_code_read_write_socket,
-	rws_error_code_connect_to_host,
-	
-	/**
-	 @brief Connection was closed by endpoint.
-	 Reasons: an endpoint shutting down, an endpoint having received a frame too large, or an
-	 endpoint having received a frame that does not conform to the format expected by the endpoint.
-	 */
-	rws_error_code_connection_closed,
-	
-	
+typedef enum _rws_error_code
+{
+    rws_error_code_none = 0,
+
+    rws_error_code_missed_parameter,
+
+    rws_error_code_send_handshake,
+    rws_error_code_parse_handshake,
+    rws_error_code_read_write_socket,
+    rws_error_code_connect_to_host,
+
+    /**
+     @brief Connection was closed by endpoint.
+     Reasons: an endpoint shutting down, an endpoint having received a frame too large, or an
+     endpoint having received a frame that does not conform to the format expected by the endpoint.
+     */
+    rws_error_code_connection_closed,
 } rws_error_code;
 } rws_error_code;
 
 
-
 /**
 /**
  @return 0 - if error is empty or no error, otherwice error code.
  @return 0 - if error is empty or no error, otherwice error code.
  */
  */
 RWS_API(int) rws_error_get_code(rws_error error);
 RWS_API(int) rws_error_get_code(rws_error error);
 
 
-
 /**
 /**
  @return 0 - if error is empty or no error, otherwice HTTP error.
  @return 0 - if error is empty or no error, otherwice HTTP error.
  */
  */
 RWS_API(int) rws_error_get_http_error(rws_error error);
 RWS_API(int) rws_error_get_http_error(rws_error error);
 
 
-
 /**
 /**
  @brief Get description of the error object.
  @brief Get description of the error object.
  */
  */
 RWS_API(const char *) rws_error_get_description(rws_error error);
 RWS_API(const char *) rws_error_get_description(rws_error error);
 
 
-
 // mutex
 // mutex
 
 
 /**
 /**
@@ -384,37 +352,37 @@ RWS_API(const char *) rws_error_get_description(rws_error error);
  */
  */
 RWS_API(rws_mutex) rws_mutex_create_recursive(void);
 RWS_API(rws_mutex) rws_mutex_create_recursive(void);
 
 
-
 /**
 /**
  @brief Lock mutex object.
  @brief Lock mutex object.
  */
  */
 RWS_API(void) rws_mutex_lock(rws_mutex mutex);
 RWS_API(void) rws_mutex_lock(rws_mutex mutex);
 
 
-
 /**
 /**
  @brief Unlock mutex object.
  @brief Unlock mutex object.
  */
  */
 RWS_API(void) rws_mutex_unlock(rws_mutex mutex);
 RWS_API(void) rws_mutex_unlock(rws_mutex mutex);
 
 
-
-
 /**
 /**
  @brief Unlock mutex object.
  @brief Unlock mutex object.
  */
  */
 RWS_API(void) rws_mutex_delete(rws_mutex mutex);
 RWS_API(void) rws_mutex_delete(rws_mutex mutex);
 
 
-
 // thread
 // thread
 
 
 /**
 /**
  @brief Create thread object that start immidiatelly.
  @brief Create thread object that start immidiatelly.
  */
  */
-RWS_API(rws_thread) rws_thread_create(rws_thread_funct thread_function, void * user_object);
-
+RWS_API(rws_thread) rws_thread_create(rws_thread_funct thread_function, void *user_object);
 
 
 /**
 /**
  @brief Pause current thread for a number of milliseconds.
  @brief Pause current thread for a number of milliseconds.
  */
  */
 RWS_API(void) rws_thread_sleep(const unsigned int millisec);
 RWS_API(void) rws_thread_sleep(const unsigned int millisec);
 
 
+/* RT-Thread Team add */
+RWS_API(void) rws_socket_set_custom_mode(rws_socket socket);
+
+#define RWS_RECEIVE_HEADER_BUFF_SIZE  (  14)
+#define RWS_RECEIVE_PAYLOAD_BUFF_SIZE (2048)
+
 #endif
 #endif

+ 13 - 4
src/rws_common.h → librws/inc/rws_common.h

@@ -1,5 +1,5 @@
 /*
 /*
- *   Copyright (c) 2014 - 2019 Oleh Kulykov <info@resident.name>
+ *   Copyright (c) 2014 - 2017 Kulykov Oleh <info@resident.name>
  *
  *
  *   Permission is hereby granted, free of charge, to any person obtaining a copy
  *   Permission is hereby granted, free of charge, to any person obtaining a copy
  *   of this software and associated documentation files (the "Software"), to deal
  *   of this software and associated documentation files (the "Software"), to deal
@@ -20,15 +20,25 @@
  *   THE SOFTWARE.
  *   THE SOFTWARE.
  */
  */
 
 
-
 #ifndef __RWS_COMMON_H__
 #ifndef __RWS_COMMON_H__
 #define __RWS_COMMON_H__ 1
 #define __RWS_COMMON_H__ 1
 
 
 #include <stdio.h>
 #include <stdio.h>
+#include <rtthread.h>
+
+#if (RTTHREAD_VERSION <= 30100)
+#define DBG_SECTION_NAME "[LIBRWS] "
+#else
+#define DBG_SECTION_NAME "LIBRWS"
+#endif
+#define DBG_ENABLE
+#define DBG_LEVEL DBG_INFO
+#define DBG_COLOR
+#include <rtdbg.h>
+#define DBG_FUNCTION_NUM 20
 
 
 /* check os */
 /* check os */
 /* gcc -dM -E - < /dev/null */
 /* gcc -dM -E - < /dev/null */
-
 /* check windows */
 /* check windows */
 #if !defined(RWS_OS_WINDOWS)
 #if !defined(RWS_OS_WINDOWS)
 #if defined(WIN32) || defined(_WIN32) || defined(WIN32_LEAN_AND_MEAN) || defined(_WIN64) || defined(WIN64)
 #if defined(WIN32) || defined(_WIN32) || defined(WIN32_LEAN_AND_MEAN) || defined(_WIN64) || defined(WIN64)
@@ -66,4 +76,3 @@
 #endif
 #endif
 
 
 #endif
 #endif
-

+ 11 - 11
src/rws_error.h → librws/inc/rws_error.h

@@ -1,5 +1,5 @@
 /*
 /*
- *   Copyright (c) 2014 - 2019 Oleh Kulykov <info@resident.name>
+ *   Copyright (c) 2014 - 2017 Kulykov Oleh <info@resident.name>
  *
  *
  *   Permission is hereby granted, free of charge, to any person obtaining a copy
  *   Permission is hereby granted, free of charge, to any person obtaining a copy
  *   of this software and associated documentation files (the "Software"), to deal
  *   of this software and associated documentation files (the "Software"), to deal
@@ -20,24 +20,24 @@
  *   THE SOFTWARE.
  *   THE SOFTWARE.
  */
  */
 
 
-
 #ifndef __RWS_ERROR_H__
 #ifndef __RWS_ERROR_H__
 #define __RWS_ERROR_H__ 1
 #define __RWS_ERROR_H__ 1
 
 
 #include "rws_string.h"
 #include "rws_string.h"
 
 
-struct rws_error_struct {
-	int code;
-	int http_error;
-	char * description;
-};
+typedef struct _rws_error_struct
+{
+    int code;
+    int http_error;
+    char *description;
+} _rws_error;
 
 
-rws_error rws_error_create(void);
+_rws_error *rws_error_create(void);
 
 
-rws_error rws_error_new_code_descr(const int code, const char * description);
+_rws_error *rws_error_new_code_descr(const int code, const char *description);
 
 
-void rws_error_delete(rws_error error);
+void rws_error_delete(_rws_error *error);
 
 
-void rws_error_delete_clean(rws_error * error);
+void rws_error_delete_clean(_rws_error **error);
 
 
 #endif
 #endif

+ 74 - 0
librws/inc/rws_frame.h

@@ -0,0 +1,74 @@
+/*
+ *   Copyright (c) 2014 - 2017 Kulykov Oleh <info@resident.name>
+ *
+ *   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.
+ */
+
+#ifndef __RWS_FRAME_H__
+#define __RWS_FRAME_H__ 1
+
+#include "librws.h"
+#include "rws_common.h"
+
+typedef enum _rws_opcode
+{
+    rws_opcode_continuation = 0x0,     // %x0 denotes a continuation frame
+    rws_opcode_text_frame = 0x1,       // %x1 denotes a text frame
+    rws_opcode_binary_frame = 0x2,     // %x2 denotes a binary frame
+    rws_opcode_connection_close = 0x8, // %x8 denotes a connection close
+    rws_opcode_ping = 0x9,             // %x9 denotes a ping
+    rws_opcode_pong = 0xA              // %xA denotes a pong
+} rws_opcode;
+
+typedef struct _rws_frame_struct
+{
+    void *data;
+    size_t data_size;
+    rws_opcode opcode;
+    unsigned char mask[4];
+    rws_bool is_masked;
+    rws_bool is_finished;
+    unsigned char header_size;
+} _rws_frame;
+
+size_t rws_check_recv_frame_size(const void *data, const size_t data_size);
+
+_rws_frame *rws_frame_create_with_recv_data(const void *data, const size_t data_size);
+
+// data - should be null, and setted by newly created. 'data' & 'data_size' can be null
+void rws_frame_fill_with_send_data(_rws_frame *f, const void *data, const size_t data_size);
+
+// combine datas of 2 frames. combined is 'to' /
+void rws_frame_combine_datas(_rws_frame *to, _rws_frame *from);
+
+_rws_frame *rws_frame_create(void);
+
+void rws_frame_delete(_rws_frame *f);
+
+void rws_frame_delete_clean(_rws_frame **f);
+
+/* RT-Thread Team add */
+size_t rws_frame_get_header_size(const char *data, const size_t len);
+
+size_t rws_frame_get_payload_len(const char *data, const size_t len);
+
+rws_opcode rws_frame_get_opcode(const char *data, const size_t len);
+
+void rws_frame_fill_with_send_bin(_rws_frame *f, const void *data, const size_t data_size, rws_bool is_fin);
+#endif

+ 15 - 16
src/rws_list.h → librws/inc/rws_list.h

@@ -1,5 +1,5 @@
 /*
 /*
- *   Copyright (c) 2014 - 2019 Oleh Kulykov <info@resident.name>
+ *   Copyright (c) 2014 - 2017 Kulykov Oleh <info@resident.name>
  *
  *
  *   Permission is hereby granted, free of charge, to any person obtaining a copy
  *   Permission is hereby granted, free of charge, to any person obtaining a copy
  *   of this software and associated documentation files (the "Software"), to deal
  *   of this software and associated documentation files (the "Software"), to deal
@@ -20,32 +20,31 @@
  *   THE SOFTWARE.
  *   THE SOFTWARE.
  */
  */
 
 
-
 #ifndef __RWS_LIST_H__
 #ifndef __RWS_LIST_H__
 #define __RWS_LIST_H__ 1
 #define __RWS_LIST_H__ 1
 
 
 #include <stdio.h>
 #include <stdio.h>
 
 
-typedef union _rws_node_value_union {
-	void * object;
-	char * string;
-	int int_value;
-	unsigned int uint_value;
+typedef union _rws_node_value_union
+{
+    void *object;
+    char *string;
+    int int_value;
+    unsigned int uint_value;
 } _rws_node_value;
 } _rws_node_value;
 
 
-typedef struct _rws_node_struct {
-	_rws_node_value value;
-	struct _rws_node_struct * next;
+typedef struct _rws_node_struct
+{
+    _rws_node_value value;
+    struct _rws_node_struct *next;
 } _rws_node, _rws_list;
 } _rws_node, _rws_list;
 
 
+_rws_list *rws_list_create(void);
 
 
-_rws_list * rws_list_create(void);
-
-void rws_list_delete(_rws_list * list);
+void rws_list_delete(_rws_list *list);
 
 
-void rws_list_delete_clean(_rws_list ** list);
+void rws_list_delete_clean(_rws_list **list);
 
 
-void rws_list_append(_rws_list * list, _rws_node_value value);
+void rws_list_append(_rws_list *list, _rws_node_value value);
 
 
 #endif
 #endif
-

+ 5 - 6
src/rws_memory.h → librws/inc/rws_memory.h

@@ -1,5 +1,5 @@
 /*
 /*
- *   Copyright (c) 2014 - 2019 Oleh Kulykov <info@resident.name>
+ *   Copyright (c) 2014 - 2017 Kulykov Oleh <info@resident.name>
  *
  *
  *   Permission is hereby granted, free of charge, to any person obtaining a copy
  *   Permission is hereby granted, free of charge, to any person obtaining a copy
  *   of this software and associated documentation files (the "Software"), to deal
  *   of this software and associated documentation files (the "Software"), to deal
@@ -20,7 +20,6 @@
  *   THE SOFTWARE.
  *   THE SOFTWARE.
  */
  */
 
 
-
 #ifndef __RWS_MEMORY_H__
 #ifndef __RWS_MEMORY_H__
 #define __RWS_MEMORY_H__ 1
 #define __RWS_MEMORY_H__ 1
 
 
@@ -29,13 +28,13 @@
 #include "rws_common.h"
 #include "rws_common.h"
 
 
 // size > 0 => malloc
 // size > 0 => malloc
-void * rws_malloc(const size_t size);
+void *rws_malloc(const size_t size);
 
 
 // size > 0 => malloc
 // size > 0 => malloc
-void * rws_malloc_zero(const size_t size);
+void *rws_malloc_zero(const size_t size);
 
 
-void rws_free(void * mem);
+void rws_free(void *mem);
 
 
-void rws_free_clean(void ** mem);
+void rws_free_clean(void **mem);
 
 
 #endif
 #endif

+ 216 - 0
librws/inc/rws_socket.h

@@ -0,0 +1,216 @@
+/*
+ *   Copyright (c) 2014 - 2017 Kulykov Oleh <info@resident.name>
+ *
+ *   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.
+ */
+
+#ifndef __RWS_SOCKET_H__
+#define __RWS_SOCKET_H__ 1
+
+#include "rws_common.h"
+
+#if defined(RWS_OS_WINDOWS)
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#else
+#include <netdb.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+    //#include <netinet/tcp.h>
+#include <fcntl.h>
+#include <unistd.h>
+#endif
+
+#include <assert.h>
+#include <errno.h>
+
+#include "rws_error.h"
+#include "rws_thread.h"
+#include "rws_frame.h"
+#include "rws_list.h"
+
+#ifdef LIBRWS_USING_MBED_TLS
+#include "mbedtls/net.h"
+#include "mbedtls/ssl.h"
+#include "mbedtls/certs.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/debug.h"
+#endif
+
+#if defined(RWS_OS_WINDOWS)
+    typedef SOCKET rws_socket_t;
+#define RWS_INVALID_SOCKET INVALID_SOCKET
+#define RWS_SOCK_CLOSE(sock) closesocket(sock)
+#else
+    typedef int rws_socket_t;
+#define RWS_INVALID_SOCKET -1
+#define RWS_SOCK_CLOSE(sock) close(sock)
+#endif
+
+#ifdef LIBRWS_USING_MBED_TLS
+typedef struct _rws_ssl_struct
+{
+    mbedtls_ssl_context ssl_ctx; /* mbedtls ssl context */
+    mbedtls_net_context net_ctx; /* Fill in socket id */
+    mbedtls_ssl_config ssl_conf; /* SSL configuration */
+    mbedtls_entropy_context entropy;
+    mbedtls_ctr_drbg_context ctr_drbg;
+    mbedtls_x509_crt_profile profile;
+    mbedtls_x509_crt cacert;
+    mbedtls_x509_crt clicert;
+    mbedtls_pk_context pkey;
+} _rws_ssl;
+#endif
+
+static const char *k_rws_socket_min_http_ver = "1.1";
+static const char *k_rws_socket_sec_websocket_accept = "Sec-WebSocket-Accept";
+
+typedef struct _rws_socket_struct
+{
+    int port;
+    rws_socket_t socket;
+    char *scheme;
+    char *host;
+    char *path;
+
+    char *sec_ws_accept; // "Sec-WebSocket-Accept" field from handshake
+
+    rws_thread work_thread;
+
+    int command;
+
+    unsigned int next_message_id;
+
+    rws_bool is_connected; // sock connected + handshake done
+
+    void *user_object;
+    rws_on_socket on_connected;
+    rws_on_socket on_disconnected;
+    rws_on_socket_recvd_text on_recvd_text;
+    rws_on_socket_recvd_bin on_recvd_bin;
+
+    void *received;
+    size_t received_size; // size of 'received' memory
+    size_t received_len;  // length of actualy readed message
+
+    _rws_list *send_frames;
+    _rws_list *recvd_frames;
+
+    _rws_error *error;
+
+    rws_mutex work_mutex;
+    rws_mutex send_mutex;
+
+    int custom_mode;
+    char *header_buff;
+    char *payload_buff;
+
+#ifdef LIBRWS_USING_MBED_TLS
+    const char *server_cert; /**< Server certification. */
+    const char *client_cert; /**< Client certification. */
+    const char *client_pk;   /**< Client private key. */
+    int server_cert_len;     /**< Server certification lenght, server_cert buffer size. */
+    int client_cert_len;     /**< Client certification lenght, client_cert buffer size. */
+    int client_pk_len;       /**< Client private key lenght, client_pk buffer size. */
+    _rws_ssl *ssl;           /**< SSL content. */
+#endif
+} _rws_socket;
+
+rws_bool rws_socket_process_handshake_responce(_rws_socket *s);
+
+// receive raw data from socket
+rws_bool rws_socket_recv(_rws_socket *s);
+
+/* RT-Thread Team add */
+rws_bool rws_socket_recv_custom(_rws_socket *s);
+
+// send raw data to socket
+rws_bool rws_socket_send(_rws_socket *s, const void *data, const size_t data_size);
+
+_rws_frame *rws_socket_last_unfin_recvd_frame_by_opcode(_rws_socket *s, const rws_opcode opcode);
+
+void rws_socket_process_bin_or_text_frame(_rws_socket *s, _rws_frame *frame);
+
+void rws_socket_process_ping_frame(_rws_socket *s, _rws_frame *frame);
+
+void rws_socket_process_conn_close_frame(_rws_socket *s, _rws_frame *frame);
+
+void rws_socket_process_received_frame(_rws_socket *s, _rws_frame *frame);
+
+void rws_socket_idle_recv(_rws_socket *s);
+
+void rws_socket_idle_send(_rws_socket *s);
+
+void rws_socket_wait_handshake_responce(_rws_socket *s);
+
+unsigned int rws_socket_get_next_message_id(_rws_socket *s);
+
+void rws_socket_send_ping(_rws_socket *s);
+
+void rws_socket_send_disconnect(_rws_socket *s);
+
+void rws_socket_send_handshake(_rws_socket *s);
+
+struct addrinfo *rws_socket_connect_getaddr_info(_rws_socket *s);
+
+void rws_socket_connect_to_host(_rws_socket *s);
+
+rws_bool rws_socket_create_start_work_thread(_rws_socket *s);
+
+void rws_socket_close(_rws_socket *s);
+
+void rws_socket_resize_received(_rws_socket *s, const size_t size);
+
+void rws_socket_append_recvd_frames(_rws_socket *s, _rws_frame *frame);
+
+void rws_socket_append_send_frames(_rws_socket *s, _rws_frame *frame);
+
+rws_bool rws_socket_send_text_priv(_rws_socket *s, const char *text);
+
+rws_bool rws_socket_send_bin_priv(_rws_socket *s, const char *data, size_t len, rws_opcode opcode, rws_bool is_fin);
+
+void rws_socket_inform_recvd_frames(_rws_socket *s);
+
+void rws_socket_set_option(rws_socket_t s, int option, int value);
+
+void rws_socket_delete_all_frames_in_list(_rws_list *list_with_frames);
+
+void rws_socket_check_write_error(_rws_socket *s, int error_num);
+
+void rws_socket_delete(_rws_socket *s);
+
+#ifdef LIBRWS_USING_MBED_TLS
+    void rws_debug(void *ctx, int level, const char *file, int line, const char *str);
+    int rws_ssl_conn(_rws_socket *s);
+    int rws_ssl_close(_rws_socket *s);
+#endif
+
+#define COMMAND_IDLE -1
+#define COMMAND_NONE 0
+#define COMMAND_CONNECT_TO_HOST 1
+#define COMMAND_SEND_HANDSHAKE 2
+#define COMMAND_WAIT_HANDSHAKE_RESPONCE 3
+#define COMMAND_INFORM_CONNECTED 4
+#define COMMAND_INFORM_DISCONNECTED 5
+#define COMMAND_DISCONNECT 6
+
+#define COMMAND_END 9999
+
+#endif

+ 9 - 10
src/rws_string.h → librws/inc/rws_string.h

@@ -1,5 +1,5 @@
 /*
 /*
- *   Copyright (c) 2014 - 2019 Oleh Kulykov <info@resident.name>
+ *   Copyright (c) 2014 - 2017 Kulykov Oleh <info@resident.name>
  *
  *
  *   Permission is hereby granted, free of charge, to any person obtaining a copy
  *   Permission is hereby granted, free of charge, to any person obtaining a copy
  *   of this software and associated documentation files (the "Software"), to deal
  *   of this software and associated documentation files (the "Software"), to deal
@@ -20,7 +20,6 @@
  *   THE SOFTWARE.
  *   THE SOFTWARE.
  */
  */
 
 
-
 #ifndef __RWS_STRING_H__
 #ifndef __RWS_STRING_H__
 #define __RWS_STRING_H__ 1
 #define __RWS_STRING_H__ 1
 
 
@@ -30,21 +29,21 @@
 #include "rws_common.h"
 #include "rws_common.h"
 
 
 #if defined(_MSC_VER)
 #if defined(_MSC_VER)
-#define rws_sprintf(s,l,f,...) sprintf_s(s,l,f,__VA_ARGS__)
-#define rws_sscanf(s,f,...) sscanf_s(s,f,__VA_ARGS__)
+#define rws_sprintf(s, l, f, ...) sprintf_s(s, l, f, __VA_ARGS__)
+#define rws_sscanf(s, f, ...) sscanf_s(s, f, __VA_ARGS__)
 #define rws_strerror(e) strerror(e)
 #define rws_strerror(e) strerror(e)
 #else
 #else
-#define rws_sprintf(s,l,f,...) sprintf(s,f,__VA_ARGS__)
-#define rws_sscanf(s,f,...) sscanf(s,f,__VA_ARGS__)
+#define rws_sprintf(s, l, f, ...) sprintf(s, f, __VA_ARGS__)
+#define rws_sscanf(s, f, ...) sscanf(s, f, __VA_ARGS__)
 #define rws_strerror(e) strerror(e)
 #define rws_strerror(e) strerror(e)
 #endif
 #endif
 
 
-char * rws_string_copy(const char * str);
+char *rws_string_copy(const char *str);
 
 
-char * rws_string_copy_len(const char * str, const size_t len);
+char *rws_string_copy_len(const char *str, const size_t len);
 
 
-void rws_string_delete(char * str);
+void rws_string_delete(char *str);
 
 
-void rws_string_delete_clean(char ** str);
+void rws_string_delete_clean(char **str);
 
 
 #endif
 #endif

+ 1 - 4
src/rws_thread.h → librws/inc/rws_thread.h

@@ -1,5 +1,5 @@
 /*
 /*
- *   Copyright (c) 2014 - 2019 Oleh Kulykov <info@resident.name>
+ *   Copyright (c) 2014 - 2017 Kulykov Oleh <info@resident.name>
  *
  *
  *   Permission is hereby granted, free of charge, to any person obtaining a copy
  *   Permission is hereby granted, free of charge, to any person obtaining a copy
  *   of this software and associated documentation files (the "Software"), to deal
  *   of this software and associated documentation files (the "Software"), to deal
@@ -20,12 +20,9 @@
  *   THE SOFTWARE.
  *   THE SOFTWARE.
  */
  */
 
 
-
 #ifndef __RWS_THREAD_H__
 #ifndef __RWS_THREAD_H__
 #define __RWS_THREAD_H__ 1
 #define __RWS_THREAD_H__ 1
 
 
 #include <stdio.h>
 #include <stdio.h>
 
 
-
 #endif
 #endif
-

+ 2 - 5
src/librws.c → librws/src/librws.c

@@ -1,5 +1,5 @@
 /*
 /*
- *   Copyright (c) 2014 - 2019 Oleh Kulykov <info@resident.name>
+ *   Copyright (c) 2014 - 2017 Kulykov Oleh <info@resident.name>
  *
  *
  *   Permission is hereby granted, free of charge, to any person obtaining a copy
  *   Permission is hereby granted, free of charge, to any person obtaining a copy
  *   of this software and associated documentation files (the "Software"), to deal
  *   of this software and associated documentation files (the "Software"), to deal
@@ -20,7 +20,4 @@
  *   THE SOFTWARE.
  *   THE SOFTWARE.
  */
  */
 
 
-
-#include "../librws.h"
-
-
+#include "librws.h"

+ 1 - 4
src/rws_common.c → librws/src/rws_common.c

@@ -1,5 +1,5 @@
 /*
 /*
- *   Copyright (c) 2014 - 2019 Oleh Kulykov <info@resident.name>
+ *   Copyright (c) 2014 - 2017 Kulykov Oleh <info@resident.name>
  *
  *
  *   Permission is hereby granted, free of charge, to any person obtaining a copy
  *   Permission is hereby granted, free of charge, to any person obtaining a copy
  *   of this software and associated documentation files (the "Software"), to deal
  *   of this software and associated documentation files (the "Software"), to deal
@@ -20,7 +20,4 @@
  *   THE SOFTWARE.
  *   THE SOFTWARE.
  */
  */
 
 
-
 #include "rws_common.h"
 #include "rws_common.h"
-
-

+ 87 - 0
librws/src/rws_error.c

@@ -0,0 +1,87 @@
+/*
+ *   Copyright (c) 2014 - 2017 Kulykov Oleh <info@resident.name>
+ *
+ *   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.
+ */
+
+#include "librws.h"
+#include "rws_error.h"
+#include "rws_string.h"
+#include "rws_memory.h"
+
+// private
+_rws_error *rws_error_create(void)
+{
+    return (_rws_error *)rws_malloc_zero(sizeof(_rws_error));
+}
+
+_rws_error *rws_error_new_code_descr(const int code, const char *description)
+{
+    _rws_error *e = (_rws_error *)rws_malloc_zero(sizeof(_rws_error));
+    e->code = code;
+    e->description = rws_string_copy(description);
+    return e;
+}
+
+void rws_error_delete(_rws_error *error)
+{
+    if (error)
+    {
+        rws_string_delete(error->description);
+        rws_free(error);
+    }
+}
+
+void rws_error_delete_clean(_rws_error **error)
+{
+    if (error)
+    {
+        _rws_error *er = *error;
+        if (er)
+        {
+            LOG_I("code:%d http_error:%d [%s]", er->code, er->http_error, er->description);
+        }
+        // else
+        // {
+        //     LOG_I("null");
+        // }
+
+        rws_error_delete(*error);
+        *error = NULL;
+    }
+}
+
+// public
+int rws_error_get_code(rws_error error)
+{
+    _rws_error *e = (_rws_error *)error;
+    return e ? e->code : 0;
+}
+
+int rws_error_get_http_error(rws_error error)
+{
+    _rws_error *e = (_rws_error *)error;
+    return e ? e->http_error : 0;
+}
+
+const char *rws_error_get_description(rws_error error)
+{
+    _rws_error *e = (_rws_error *)error;
+    return e ? e->description : NULL;
+}

+ 486 - 0
librws/src/rws_frame.c

@@ -0,0 +1,486 @@
+/*
+ *   Copyright (c) 2014 - 2017 Kulykov Oleh <info@resident.name>
+ *
+ *   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.
+ */
+
+#include "rws_frame.h"
+#include "rws_memory.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <time.h>
+
+_rws_frame *rws_frame_create_with_recv_data(const void *data, const size_t data_size)
+{
+    if (data && data_size >= 2)
+    {
+        const unsigned char *udata = (const unsigned char *)data;
+
+        const rws_opcode opcode = (rws_opcode)(udata[0] & 0x0f);
+        const unsigned int is_finshd = (udata[0] >> 7) & 0x01;
+        const unsigned int is_masked = (udata[1] >> 7) & 0x01;
+        const unsigned int payload = udata[1] & 0x7f;
+        unsigned int header_size = is_masked ? 6 : 2;
+
+        unsigned int expected_size = 0, mask_pos = 0;
+        size_t index = 0;
+        _rws_frame *frame = NULL;
+        const unsigned char *actual_udata = NULL;
+        unsigned char *unmasked = NULL;
+
+        switch (payload)
+        {
+        case 126:
+            header_size += 2;
+            break;
+        case 127:
+            header_size += 8;
+            break;
+        default:
+            break;
+        }
+
+        if (data_size < header_size)
+        {
+            return NULL;
+        }
+
+        switch (payload)
+        {
+        case 126:
+            expected_size |= ((unsigned int)udata[2]) << 8;
+            expected_size |= (unsigned int)udata[3];
+            mask_pos = 4;
+            break;
+
+        case 127:
+            expected_size |= ((unsigned int)udata[6]) << 24;
+            expected_size |= ((unsigned int)udata[7]) << 16;
+            expected_size |= ((unsigned int)udata[8]) << 8;
+            expected_size |= (unsigned int)udata[9];
+            mask_pos = 10;
+            break;
+
+        default:
+            if (payload <= 125)
+            {
+                mask_pos = 2;
+                expected_size = payload;
+            }
+            break;
+        }
+
+        frame = rws_frame_create();
+
+        frame->opcode = opcode;
+        if (is_finshd)
+            frame->is_finished = rws_true;
+        frame->header_size = (unsigned char)header_size;
+
+        if (is_masked)
+        {
+            frame->is_masked = rws_true;
+            memcpy(frame->mask, &udata[mask_pos], 4);
+        }
+
+        if (opcode == rws_opcode_connection_close || opcode == rws_opcode_pong)
+        {
+            return frame;
+        }
+
+        if (!is_finshd)
+        {
+            frame->is_finished = rws_false;
+        }
+
+        if (expected_size > 0)
+        {
+            frame->data = rws_malloc(expected_size);
+            frame->data_size = expected_size;
+            actual_udata = udata + header_size;
+            if (is_masked)
+            {
+                unmasked = (unsigned char *)frame->data;
+                for (index = 0; index < expected_size; index++)
+                {
+                    *unmasked = *actual_udata ^ frame->mask[index & 0x3];
+                    unmasked++;
+                    actual_udata++;
+                }
+            }
+            else
+            {
+                memcpy(frame->data, actual_udata, expected_size);
+            }
+        }
+        return frame;
+    }
+    return NULL;
+}
+
+void rws_frame_create_header(_rws_frame *f, unsigned char *header, const size_t data_size)
+{
+    const unsigned int size = (unsigned int)data_size;
+
+    *header++ = 0x80 | f->opcode;
+    if (size < 126)
+    {
+        *header++ = (size & 0xff) | (f->is_masked ? 0x80 : 0);
+        f->header_size = 2;
+    }
+    else if (size < 65536)
+    {
+        *header++ = 126 | (f->is_masked ? 0x80 : 0);
+        *header++ = (size >> 8) & 0xff;
+        *header++ = size & 0xff;
+        f->header_size = 4;
+    }
+    else
+    {
+        *header++ = 127 | (f->is_masked ? 0x80 : 0);
+
+        *(unsigned int *)header = 0;
+        header += 4;
+
+        *header++ = (size >> 24) & 0xff;
+        *header++ = (size >> 16) & 0xff;
+        *header++ = (size >> 8) & 0xff;
+        *header++ = size & 0xff;
+        f->header_size = 10;
+    }
+
+    if (f->is_masked)
+    {
+        memcpy(header, f->mask, 4);
+        f->header_size += 4;
+    }
+}
+
+/* 使用需要发送的数据填充数据帧 */
+void rws_frame_fill_with_send_data(_rws_frame *f, const void *data, const size_t data_size)
+{
+    unsigned char header[16];
+    unsigned char *frame = NULL;
+    unsigned char mask[4];
+    size_t index = 0;
+
+    rws_frame_create_header(f, header, data_size);
+    f->data_size = data_size + f->header_size;
+    f->data = rws_malloc(f->data_size);
+    frame = (unsigned char *)f->data;
+    memcpy(frame, header, f->header_size);
+
+    if (data)
+    {
+        // have data to send
+        frame += f->header_size;
+        memcpy(frame, data, data_size);
+
+        if (f->is_masked)
+        {
+            memcpy(mask, &f->mask, 4);
+            for (index = 0; index < data_size; index++)
+            {
+                *frame = *frame ^ mask[index & 0x3];
+                frame++;
+            }
+        }
+    }
+    f->is_finished = rws_true;
+}
+
+void rws_frame_create_header_bin(_rws_frame *f, unsigned char *header, const size_t data_size, rws_bool is_fin)
+{
+    const unsigned int size = (unsigned int)data_size;
+
+    if (is_fin == rws_true)
+    {
+        *header++ = 0x80 | f->opcode;
+    }
+    else
+    {
+        *header++ = 0x00 | f->opcode;
+    }
+
+    if (size < 126)
+    {
+        *header++ = (size & 0xff) | (f->is_masked ? 0x80 : 0);
+        f->header_size = 2;
+    }
+    else if (size < 65536)
+    {
+        *header++ = 126 | (f->is_masked ? 0x80 : 0);
+        *header++ = (size >> 8) & 0xff;
+        *header++ = size & 0xff;
+        f->header_size = 4;
+    }
+    else
+    {
+        *header++ = 127 | (f->is_masked ? 0x80 : 0);
+
+        *(unsigned int *)header = 0;
+        header += 4;
+
+        *header++ = (size >> 24) & 0xff;
+        *header++ = (size >> 16) & 0xff;
+        *header++ = (size >> 8) & 0xff;
+        *header++ = size & 0xff;
+        f->header_size = 10;
+    }
+
+    if (f->is_masked)
+    {
+        memcpy(header, f->mask, 4);
+        f->header_size += 4;
+    }
+}
+
+void rws_frame_fill_with_send_bin(_rws_frame *f, const void *data, const size_t data_size, rws_bool is_fin)
+{
+    unsigned char header[16];
+    unsigned char *frame = NULL;
+    unsigned char mask[4];
+    size_t index = 0;
+
+    rws_frame_create_header_bin(f, header, data_size, is_fin);
+    f->data_size = data_size + f->header_size;
+    f->data = rws_malloc(f->data_size);
+    frame = (unsigned char *)f->data;
+    memcpy(frame, header, f->header_size);
+
+    if (data) // have data to send
+    {
+        frame += f->header_size;
+        memcpy(frame, data, data_size);
+
+        if (f->is_masked)
+        {
+            memcpy(mask, &f->mask, 4);
+            for (index = 0; index < data_size; index++)
+            {
+                *frame = *frame ^ mask[index & 0x3];
+                frame++;
+            }
+        }
+    }
+    f->is_finished = is_fin;
+
+    LOG_D("send frame---->opcode=%d, fin=%d, len=%4d", f->opcode, f->is_finished, data_size);
+}
+
+void rws_frame_combine_datas(_rws_frame *to, _rws_frame *from)
+{
+    unsigned char *comb_data = (unsigned char *)rws_malloc(to->data_size + from->data_size);
+    if (comb_data)
+    {
+        if (to->data && to->data_size)
+        {
+            memcpy(comb_data, to->data, to->data_size);
+        }
+        comb_data += to->data_size;
+        if (from->data && from->data_size)
+        {
+            memcpy(comb_data, from->data, from->data_size);
+        }
+    }
+    rws_free(to->data);
+    to->data = comb_data;
+    to->data_size += from->data_size;
+}
+
+_rws_frame *rws_frame_create(void)
+{
+    _rws_frame *f = (_rws_frame *)rws_malloc_zero(sizeof(_rws_frame));
+
+    union
+    {
+        unsigned int ui;
+        unsigned char b[4];
+    } mask_union;
+
+    assert(sizeof(unsigned int) == 4);
+
+    // mask_union.ui = 2018915346;
+
+    mask_union.ui = (rand() / (RAND_MAX / 2) + 1) * rand();
+    memcpy(f->mask, mask_union.b, 4);
+
+    return f;
+}
+
+void rws_frame_delete(_rws_frame *f)
+{
+    if (f)
+    {
+        rws_free(f->data);
+        rws_free(f);
+    }
+}
+
+void rws_frame_delete_clean(_rws_frame **f)
+{
+    if (f)
+    {
+        rws_frame_delete(*f);
+        *f = NULL;
+    }
+}
+
+size_t rws_check_recv_frame_size(const void *data, const size_t data_size)
+{
+    if (data && data_size >= 2)
+    {
+        const unsigned char *udata = (const unsigned char *)data;
+        //        const unsigned int is_finshd = (udata[0] >> 7) & 0x01;
+        const unsigned int is_masked = (udata[1] >> 7) & 0x01;
+        const unsigned int payload = udata[1] & 0x7f;
+        unsigned int header_size = is_masked ? 6 : 2;
+
+        unsigned int expected_size = 0;
+
+        switch (payload)
+        {
+        case 126:
+            header_size += 2;
+            break;
+        case 127:
+            header_size += 8;
+            break;
+        default:
+            break;
+        }
+
+        if (data_size < header_size)
+        {
+            return 0;
+        }
+
+        switch (payload)
+        {
+        case 126:
+            expected_size |= ((unsigned int)udata[2]) << 8;
+            expected_size |= (unsigned int)udata[3];
+            break;
+
+        case 127:
+            expected_size |= ((unsigned int)udata[6]) << 24;
+            expected_size |= ((unsigned int)udata[7]) << 16;
+            expected_size |= ((unsigned int)udata[8]) <<  8;
+            expected_size |= ((unsigned int)udata[9]) <<  0;
+            break;
+
+        default:
+            if (payload <= 125)
+            {
+                expected_size = payload;
+            }
+            break;
+        }
+
+        const unsigned int nPackSize = expected_size + header_size;
+        return (nPackSize <= data_size) ? nPackSize : 0;
+    }
+    return 0;
+}
+
+/* RT-Thread Team add */
+
+/* Todo */
+// mask + < 126payload = 6
+// mask + 126 = 6 + 2 = 8
+// mask + 127 = 6 + 8 = 14
+
+// < 126payload = 2
+// 126 = 2 + 2 = 4
+// 127 = 2 + 8 = 10
+size_t rws_frame_get_header_size(const char *data, const size_t len)
+{
+    const unsigned int is_masked = (data[1] >> 7) & 0x01;
+    unsigned int header_size = is_masked ? 6 : 2;
+    const unsigned int payload_len = data[1] & 0x7f;
+
+    switch (payload_len)
+    {
+    case 126:
+        header_size += 2;
+        break;
+    case 127:
+        header_size += 8;
+        break;
+    default:
+        header_size += 0;
+        break;
+    }
+
+    return header_size;
+}
+
+/* Todo */
+size_t rws_frame_get_payload_len(const char *data, const size_t len)
+{
+    unsigned int expected_size = 0;
+    const unsigned int payload = data[1] & 0x7f;
+
+    switch (payload)
+    {
+    case 126:
+        expected_size |= ((unsigned int)data[2]) << 8;
+        expected_size |= ((unsigned int)data[3]);
+        break;
+
+    case 127:
+        expected_size |= ((unsigned int)data[6]) << 24;
+        expected_size |= ((unsigned int)data[7]) << 16;
+        expected_size |= ((unsigned int)data[8]) <<  8;
+        expected_size |= ((unsigned int)data[9]) <<  0;
+        break;
+
+    default:
+        if (payload <= 125)
+        {
+            expected_size = payload;
+        }
+        break;
+    }
+
+    LOG_D("[T:%.8d, L:%.5d, %*.*s] rws_frame_get_payload_len = %d", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__, expected_size);
+    return expected_size;
+}
+
+/* Todo */
+size_t rws_frame_get_frame_len(const char *data, const size_t len)
+{
+    size_t header_size = 0;
+    size_t payload_len = 0;
+
+    header_size = rws_frame_get_header_size(data, len);
+    payload_len = rws_frame_get_payload_len(data, len);
+
+    LOG_D("[T:%.8d, L:%.5d, %*.*s] rws_frame_get_frame_len = %d", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__, (header_size + payload_len));
+    return (header_size + payload_len);
+}
+
+rws_opcode rws_frame_get_opcode(const char *data, const size_t len)
+{
+    rws_opcode opcode = (rws_opcode)((unsigned int)data[0] & 0x0f);
+
+    return opcode;
+}

+ 32 - 26
src/rws_list.c → librws/src/rws_list.c

@@ -1,5 +1,5 @@
 /*
 /*
- *   Copyright (c) 2014 - 2019 Oleh Kulykov <info@resident.name>
+ *   Copyright (c) 2014 - 2017 Kulykov Oleh <info@resident.name>
  *
  *
  *   Permission is hereby granted, free of charge, to any person obtaining a copy
  *   Permission is hereby granted, free of charge, to any person obtaining a copy
  *   of this software and associated documentation files (the "Software"), to deal
  *   of this software and associated documentation files (the "Software"), to deal
@@ -20,38 +20,44 @@
  *   THE SOFTWARE.
  *   THE SOFTWARE.
  */
  */
 
 
-
 #include "rws_list.h"
 #include "rws_list.h"
 #include "rws_memory.h"
 #include "rws_memory.h"
 
 
-_rws_list * rws_list_create(void) {
-	return (_rws_list *)rws_malloc_zero(sizeof(_rws_list));
+_rws_list *rws_list_create(void)
+{
+    return (_rws_list *)rws_malloc_zero(sizeof(_rws_list));
 }
 }
 
 
-void rws_list_delete(_rws_list * list) {
-	_rws_list * cur = list;
-	while (cur) {
-		_rws_list * prev = cur;
-		cur = cur->next;
-		rws_free(prev);
-	}
+void rws_list_delete(_rws_list *list)
+{
+    _rws_list *cur = list;
+    while (cur)
+    {
+        _rws_list *prev = cur;
+        cur = cur->next;
+        rws_free(prev);
+    }
 }
 }
 
 
-void rws_list_delete_clean(_rws_list ** list) {
-	if (list) {
-		rws_list_delete(*list);
-		*list = NULL;
-	}
+void rws_list_delete_clean(_rws_list **list)
+{
+    if (list)
+    {
+        rws_list_delete(*list);
+        *list = NULL;
+    }
 }
 }
 
 
-void rws_list_append(_rws_list * list, _rws_node_value value) {
-	if (list) {
-		_rws_list * cur = list;
-		while (cur->next) {
-			cur = cur->next;
-		}
-		cur->next = (_rws_node *)rws_malloc_zero(sizeof(_rws_node));
-		cur->next->value = value;
-	}
+void rws_list_append(_rws_list *list, _rws_node_value value)
+{
+    if (list)
+    {
+        _rws_list *cur = list;
+        while (cur->next)
+        {
+            cur = cur->next;
+        }
+        cur->next = (_rws_node *)rws_malloc_zero(sizeof(_rws_node));
+        cur->next->value = value;
+    }
 }
 }
-

+ 35 - 25
src/rws_memory.c → librws/src/rws_memory.c

@@ -1,5 +1,5 @@
 /*
 /*
- *   Copyright (c) 2014 - 2019 Oleh Kulykov <info@resident.name>
+ *   Copyright (c) 2014 - 2017 Kulykov Oleh <info@resident.name>
  *
  *
  *   Permission is hereby granted, free of charge, to any person obtaining a copy
  *   Permission is hereby granted, free of charge, to any person obtaining a copy
  *   of this software and associated documentation files (the "Software"), to deal
  *   of this software and associated documentation files (the "Software"), to deal
@@ -20,39 +20,49 @@
  *   THE SOFTWARE.
  *   THE SOFTWARE.
  */
  */
 
 
-
 #include "rws_memory.h"
 #include "rws_memory.h"
 #include <string.h>
 #include <string.h>
 #include <stdlib.h>
 #include <stdlib.h>
 #include <assert.h>
 #include <assert.h>
 
 
-void * rws_malloc(const size_t size) {
-	if (size > 0) {
-		void * mem = malloc(size);
-		assert(mem);
-		return mem;
-	}
-	return NULL;
-}
+void *rws_malloc(const size_t size)
+{
+    if (size > 0)
+    {
+        void *mem = malloc(size);
+        // assert(mem);
+        // rt_kprintf("rws_malloc size = %d, mem = 0x%.8x\n", size, (int)mem);
 
 
-void * rws_malloc_zero(const size_t size) {
-	void * mem = rws_malloc(size);
-	if (mem) {
-		memset(mem, 0, size);
-	}
-	return mem;
+        return mem;
+    }
+
+    return NULL;
 }
 }
 
 
-void rws_free(void * mem) {
-	if (mem) {
-		free(mem);
-	}
+void *rws_malloc_zero(const size_t size)
+{
+    void *mem = rws_malloc(size);
+    if (mem)
+    {
+        memset(mem, 0, size);
+    }
+    return mem;
 }
 }
 
 
-void rws_free_clean(void ** mem) {
-	if (mem) {
-		rws_free(*mem);
-		*mem = NULL;
-	}
+void rws_free(void *mem)
+{
+    if (mem)
+    {
+        free(mem);
+        // rt_kprintf("rws_free mem = 0x%.8x\n", (int)mem);
+    }
 }
 }
 
 
+void rws_free_clean(void **mem)
+{
+    if (mem)
+    {
+        rws_free(*mem);
+        *mem = NULL;
+    }
+}

+ 1822 - 0
librws/src/rws_socketpriv.c

@@ -0,0 +1,1822 @@
+/*
+ *   Copyright (c) 2014 - 2017 Kulykov Oleh <info@resident.name>
+ *
+ *   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.
+ */
+
+#include "librws.h"
+#include "rws_socket.h"
+#include "rws_memory.h"
+#include "rws_string.h"
+#include <sys/time.h>
+#include <netdb.h>
+
+/* Todo: 需要导出到Kconfig中的 */
+#define RWS_CONNECT_RETRY_DELAY ( 200) /* 重试延时(单位?) */
+#define RWS_CONNECT_ATTEMPS     (   5) /* 尝试次数? */
+#define RWS_RECEIVE_BUFF_SIZE   (2048) /* 接受buff分配内存大小 */
+
+#ifndef RWS_OS_WINDOWS
+#define WSAEWOULDBLOCK EAGAIN
+#define WSAEINPROGRESS EINPROGRESS
+#endif
+
+#if ((DBG_LEVEL) == (DBG_LOG))
+    static void hexdump(const rt_uint8_t *p, rt_size_t len);
+#endif
+
+unsigned int rws_socket_get_next_message_id(_rws_socket *s)
+{
+    const unsigned int mess_id = ++s->next_message_id;
+
+    if (mess_id > 9999999)
+    {
+        s->next_message_id = 0;
+    }
+
+    return mess_id;
+}
+
+void rws_socket_send_ping(_rws_socket *s)
+{
+    char buff[16];
+    size_t len = 0;
+    _rws_frame *frame = rws_frame_create();
+
+    len = rws_sprintf(buff, 16, "%u", rws_socket_get_next_message_id(s));
+
+    frame->is_masked = rws_true;
+    frame->opcode = rws_opcode_ping;
+    rws_frame_fill_with_send_data(frame, buff, len);
+    rws_socket_append_send_frames(s, frame);
+}
+
+void rws_socket_inform_recvd_frames(_rws_socket *s)
+{
+    rws_bool is_all_finished = rws_true;
+    _rws_frame *frame = NULL;
+    _rws_node *cur = s->recvd_frames;
+
+    while (cur)
+    {
+        frame = (_rws_frame *)cur->value.object;
+        if (frame)
+        {
+            if (frame->is_finished)
+            {
+                switch (frame->opcode)
+                {
+                case rws_opcode_text_frame:
+                    if (s->on_recvd_text)
+                    {
+                        s->on_recvd_text(s, (const char *)frame->data, (unsigned int)frame->data_size);
+                    }
+                    break;
+                case rws_opcode_binary_frame:
+                    if (s->on_recvd_bin)
+                    {
+                        s->on_recvd_bin(s, frame->data, (unsigned int)frame->data_size);
+                    }
+                    break;
+                default:
+                    break;
+                }
+
+                rws_frame_delete(frame);
+                cur->value.object = NULL;
+            }
+            else
+            {
+                is_all_finished = rws_false;
+            }
+        }
+        cur = cur->next;
+    }
+    if (is_all_finished)
+    {
+        rws_list_delete_clean(&s->recvd_frames);
+    }
+}
+
+void rws_socket_read_handshake_responce_value(const char *str, char **value)
+{
+    const char *s = NULL;
+    size_t len = 0;
+
+    while (*str == ':' || *str == ' ')
+    {
+        str++;
+    }
+    s = str;
+    while (*s != '\r' && *s != '\n')
+    {
+        s++;
+        len++;
+    }
+    if (len > 0)
+    {
+        *value = rws_string_copy_len(str, len);
+    }
+}
+
+rws_bool rws_socket_process_handshake_responce(_rws_socket *s)
+{
+    const char *str = (const char *)s->received;
+    const char *sub = NULL;
+    float http_ver = -1;
+    int http_code = -1;
+
+    rws_error_delete_clean(&s->error);
+    sub = strstr(str, "HTTP/");
+    if (!sub)
+    {
+        return rws_false;
+    }
+
+    sub += 5;
+    if (rws_sscanf(sub, "%f %i", &http_ver, &http_code) != 2)
+    {
+        http_ver = -1;
+        http_code = -1;
+    }
+
+    // "Sec-WebSocket-Accept"
+    sub = strstr(str, k_rws_socket_sec_websocket_accept);
+    if (sub)
+    {
+        sub += strlen(k_rws_socket_sec_websocket_accept);
+        rws_socket_read_handshake_responce_value(sub, &s->sec_ws_accept);
+    }
+
+    // "Sec-WebSocket-Accept"
+    sub = strstr(str, "sec-websocket-accept");
+    if (sub)
+    {
+        sub += strlen(k_rws_socket_sec_websocket_accept);
+        rws_socket_read_handshake_responce_value(sub, &s->sec_ws_accept);
+    }
+
+    if (http_code != 101 || !s->sec_ws_accept)
+    {
+        s->error = rws_error_new_code_descr(rws_error_code_parse_handshake,
+                                            (http_code != 101) ? "HTPP code not found or non 101" : "Accept key not found");
+        return rws_false;
+    }
+    return rws_true;
+}
+
+// need close socket on error
+rws_bool rws_socket_send(_rws_socket *s, const void *data, const size_t data_size)
+{
+    int sended = -1, error_number = -1;
+    rws_error_delete_clean(&s->error);
+
+#ifdef LIBRWS_USING_MBED_TLS
+    if (s->scheme && strcmp(s->scheme, "wss") == 0)
+    {
+        LOG_D("[T:%.8d, L:%.5d, %*.*s] try send data with tls", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+        sended = mbedtls_ssl_write(&(s->ssl->ssl_ctx), (const unsigned char *)data, (int)data_size);
+    }
+    else
+#endif /* LIBRWS_USING_MBED_TLS */
+    {
+        LOG_D("[T:%.8d, L:%.5d, %*.*s] try send data", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+        sended = (int)send(s->socket, data, (int)data_size, 0);
+    }
+
+    if (sended > 0)
+    {
+        LOG_D("[T:%.8d, L:%.5d, %*.*s] send %d bytes data", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__, sended);
+    }
+    else
+    {
+        LOG_E("[T:%.8d, L:%.5d, %*.*s] send error = %d", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__, sended);
+    }
+
+#if defined(RWS_OS_WINDOWS)
+    error_number = WSAGetLastError();
+#else
+    error_number = errno;
+#endif
+    LOG_D("[T:%.8d, L:%.5d, %*.*s] current error_number = %d", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__, error_number);
+
+    if (sended > 0)
+    {
+        return rws_true;
+    }
+
+    rws_socket_check_write_error(s, error_number);
+    if (s->error)
+    {
+        LOG_E("[T:%.8d, L:%.5d, %*.*s] send error close websocket connection, %s", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__, s->error->description);
+        rws_socket_close(s);
+        return rws_false;
+    }
+    return rws_true;
+}
+
+rws_bool rws_socket_recv(_rws_socket *s)
+{
+    rws_bool result = rws_true;
+    int is_reading = 1, error_number = -1, len = -1;
+    char *received = NULL;
+    size_t total_len = 0;
+    // char *buff = 0;
+
+    LOG_D("[T:%.8d, L:%.5d, %*.*s] receive data", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+    rws_error_delete_clean(&s->error);
+    LOG_D("[T:%.8d, L:%.5d, %*.*s] delete error info", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+
+    // buff = rws_malloc(RWS_RECEIVE_BUFF_SIZE);
+    if (!s->payload_buff)
+    {
+        LOG_E("[T:%.8d, L:%.5d, %*.*s] recv buff malloc fail, no memory", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+        result = rws_false;
+        goto _exit;
+    }
+    else
+    {
+        rt_memset(s->payload_buff, 0x00, RWS_RECEIVE_BUFF_SIZE);
+    }
+
+    while (is_reading)
+    {
+#ifdef LIBRWS_USING_MBED_TLS
+        if (s->scheme && strcmp(s->scheme, "wss") == 0)
+        {
+            LOG_D("[T:%.8d, L:%.5d, %*.*s] try recv data with tls", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+            len = mbedtls_ssl_read(&(s->ssl->ssl_ctx), (unsigned char *)(s->payload_buff), RWS_RECEIVE_BUFF_SIZE);
+        }
+        else
+#endif /* LIBRWS_USING_MBED_TLS */
+        {
+            LOG_D("[T:%.8d, L:%.5d, %*.*s] try recv data", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+            len = (int)recv(s->socket, s->payload_buff, RWS_RECEIVE_BUFF_SIZE, 0);
+        }
+
+        if (len >= 0)
+        {
+            LOG_D("[T:%.8d, L:%.5d, %*.*s] recv %d bytes data", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__, len);
+        }
+        else if (len == -1)
+        {
+            LOG_D("[T:%.8d, L:%.5d, %*.*s] no data recv", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+        }
+
+#ifdef LIBRWS_USING_MBED_TLS
+        else if ((len != MBEDTLS_ERR_SSL_WANT_READ) && (len != MBEDTLS_ERR_NET_RECV_FAILED))
+        {
+            LOG_E("[T:%.8d, L:%.5d, %*.*s] recv error = %d", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__, len);
+        }
+#else
+        else
+        {
+            LOG_E("[T:%.8d, L:%.5d, %*.*s] recv error = %d", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__, len);
+        }
+#endif /* LIBRWS_USING_MBED_TLS */
+
+#if defined(RWS_OS_WINDOWS)
+        error_number = WSAGetLastError();
+#else
+        error_number = errno;
+#endif
+        LOG_D("[T:%.8d, L:%.5d, %*.*s] current error_number = %d", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__, error_number);
+
+        if (len > 0)
+        {
+            total_len += len;
+            if (s->received_size - s->received_len < len)
+            {
+                LOG_D("[T:%.8d, L:%.5d, %*.*s] s->received_size = %d, s->received_len = %d", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__, s->received_size, s->received_len);
+                LOG_D("[T:%.8d, L:%.5d, %*.*s] reallocate (s->received) memory, size = %d", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__, s->received_size + len);
+                rws_socket_resize_received(s, s->received_size + len);
+            }
+            received = (char *)s->received;
+            if (s->received_len)
+            {
+                received += s->received_len;
+            }
+            memcpy(received, s->payload_buff, len);
+            s->received_len += len;
+        }
+        else
+        {
+            LOG_D("[T:%.8d, L:%.5d, %*.*s] ready exit recv complete", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+            is_reading = 0;
+        }
+    }
+
+    if (error_number != WSAEWOULDBLOCK && error_number != WSAEINPROGRESS && error_number != 0)
+    {
+        LOG_E("[T:%.8d, L:%.5d, %*.*s] recv data failed", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+
+        s->error = rws_error_new_code_descr(rws_error_code_read_write_socket, "Failed read/write socket");
+        // rws_socket_close(s);
+
+        result = rws_false;
+    }
+    else
+    {
+        LOG_D("[T:%.8d, L:%.5d, %*.*s] recv data complete", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+    }
+
+_exit:
+    return result;
+}
+
+/* RT-Thread Team add */
+#if ((DBG_LEVEL) == (DBG_LOG))
+static void hexdump(const rt_uint8_t *p, rt_size_t len)
+{
+    unsigned char *buf = (unsigned char *)p;
+    int i, j;
+
+    rt_kprintf("Dump 0x%.8x %dBytes\n", (int)p, len);
+    rt_kprintf("Offset    0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F\n");
+
+    for (i = 0; i < len; i += 16)
+    {
+        rt_kprintf("%08X: ", i + (int)p);
+
+        for (j = 0; j < 16; j++)
+        {
+            if (i + j < len)
+            {
+                rt_kprintf("%02X ", buf[i + j]);
+            }
+            else
+            {
+                rt_kprintf("   ");
+            }
+        }
+        rt_kprintf(" ");
+
+        for (j = 0; j < 16; j++)
+        {
+            if (i + j < len)
+            {
+                rt_kprintf("%c", ((unsigned int)((buf[i + j]) - ' ') < 127u - ' ') ? buf[i + j] : '.');
+            }
+        }
+        rt_kprintf("\n");
+    }
+}
+#endif
+
+rws_bool rws_socket_recv_custom(_rws_socket *s)
+{
+    rws_bool result = rws_true;
+    int error_number = -1, len = -1;
+
+    //size_t frame_len   = 0;                       /* 需要接收的数据帧长度 */
+
+    // char *header_buff  = 0;                      /* 帧头buff */
+    size_t header_len  = 0;                         /* 帧头长度 */
+    size_t header_ptr  = 0;                         /* 帧头buff写指针 */
+
+    // char *payload_buff = 0;                      /* 负载buff */
+    size_t payload_len = 0;                         /* 负载长度 */
+    size_t payload_ptr = 0;                         /* 负载buff写指针 */
+
+    size_t total_len   = 0;                         /* 当前接收的总长度 */
+    rws_opcode opcode  = rws_opcode_continuation;   /* 解析出来的数据帧类型 */
+    //int is_parsed      = 0;                       /* 帧头是否解析完毕 */
+
+    LOG_D("[T:%.8d, L:%.5d, %*.*s] receive data", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+    rws_error_delete_clean(&s->error);
+    LOG_D("[T:%.8d, L:%.5d, %*.*s] delete error info", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+
+    /* 分配帧头buff */
+    // header_buff = rws_malloc(RWS_RECEIVE_HEADER_BUFF_SIZE);
+    if (!s->header_buff)
+    {
+        LOG_E("[T:%.8d, L:%.5d, %*.*s] header buff is null", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+        result = rws_false;
+        goto _exit;
+    }
+    else
+    {
+        rt_memset(s->header_buff, 0x00, RWS_RECEIVE_HEADER_BUFF_SIZE);
+    }
+
+    /* 分配负载buff */
+    // payload_buff = rws_malloc(RWS_RECEIVE_PAYLOAD_BUFF_SIZE);
+    if (!s->payload_buff)
+    {
+        LOG_E("[T:%.8d, L:%.5d, %*.*s] payload buff is null", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+        result = rws_false;
+        goto _exit;
+    }
+    else
+    {
+        rt_memset(s->payload_buff, 0x00, RWS_RECEIVE_PAYLOAD_BUFF_SIZE);
+    }
+
+    /* 尝试从TCP中读取数据帧头进行解析 */
+    size_t overlength = 2;
+
+    while (overlength > 0)
+    {
+        /* 这里读取2字节的帧头 */
+#ifdef LIBRWS_USING_MBED_TLS
+        if (s->scheme && strcmp(s->scheme, "wss") == 0)
+        {
+            LOG_D("[T:%.8d, L:%.5d, %*.*s] try read header 2 bytes data in tls mode", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+            len = mbedtls_ssl_read(&(s->ssl->ssl_ctx), (unsigned char *)s->header_buff + header_ptr, overlength);
+        }
+        else
+#endif /* LIBRWS_USING_MBED_TLS */
+        {
+            LOG_D("[T:%.8d, L:%.5d, %*.*s] try read header 2 bytes data in normal mode", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+            len = (int)recv(s->socket, s->header_buff + header_ptr, overlength, 0);
+        }
+
+        if (len > 0)
+        {
+            overlength -= len;
+            total_len += len;
+            header_ptr += len;
+            LOG_D("[T:%.8d, L:%.5d, %*.*s] read %d byte(s) date, overlength is %d, total read len is %d", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__, len, overlength, total_len);
+        }
+
+        /* 第一次就没有读到数据就退出接收, 等待下一次啊 IDLE 进入后再尝试读取数据 */
+        else
+        {
+            LOG_D("[T:%.8d, L:%.5d, %*.*s] no data, quit recv, wait until next IDLE to try", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+            goto _quit;
+        }
+    }
+
+    LOG_D("[T:%.8d, L:%.5d, %*.*s] read header 2 bytes date succeed, [%.2x, %.2x]", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__, s->header_buff[0], s->header_buff[1]);
+
+    /* 尝试解析帧头数据有多少字节 */
+    header_len = rws_frame_get_header_size(s->header_buff, 2);
+    LOG_D("[T:%.8d, L:%.5d, %*.*s] header len is %d", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__, header_len);
+
+    /* 尝试解析数据的格式 */
+    opcode = rws_frame_get_opcode(s->header_buff, 2);
+
+    switch (opcode) /* 打印数据帧格式 */
+    {
+    case rws_opcode_continuation:
+        LOG_D("[T:%.8d, L:%.5d, %*.*s] opcode = 0(rws_opcode_continuation)", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+        break;
+
+    case rws_opcode_text_frame:
+        LOG_D("[T:%.8d, L:%.5d, %*.*s] opcode = 1(rws_opcode_text_frame)", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+        break;
+
+    case rws_opcode_binary_frame:
+        LOG_D("[T:%.8d, L:%.5d, %*.*s] opcode = 2(rws_opcode_binary_frame)", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+        break;
+
+    case rws_opcode_connection_close:
+        LOG_D("[T:%.8d, L:%.5d, %*.*s] opcode = 8(rws_opcode_connection_close)", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+        break;
+
+    case rws_opcode_ping:
+        LOG_D("[T:%.8d, L:%.5d, %*.*s] opcode = 9(rws_opcode_ping)", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+        break;
+
+    case rws_opcode_pong:
+        LOG_D("[T:%.8d, L:%.5d, %*.*s] opcode = 10(rws_opcode_pong)", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+        break;
+
+    default:
+        LOG_D("[T:%.8d, L:%.5d, %*.*s] opcode = %d", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__, opcode);
+        break;
+    }
+
+    /* 尝试解析负载数据有多少字节 */
+    const unsigned int payload = (s->header_buff[1] & 0x7f);
+
+    /* 说明帧头只有2字节, s->header_buff[1] 中第7位就是 payload 负载数据长度 */
+    if (payload < 126)
+    {
+        payload_len = payload;
+    }
+
+    /* 说明帧头有扩张2字节, s->header_buff[2..3] 中就是 payload 负载数据长度 */
+    else if (payload == 126)
+    {
+        size_t payload_expand_overlength = 2;
+
+        /* 帧长有2字节的扩展, 阻塞式再读2字节扩展 */
+        while (payload_expand_overlength > 0)
+        {
+#ifdef LIBRWS_USING_MBED_TLS
+            if (s->scheme && strcmp(s->scheme, "wss") == 0)
+            {
+                LOG_D("[T:%.8d, L:%.5d, %*.*s] try read header payload length data in tls mode", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+                len = mbedtls_ssl_read(&(s->ssl->ssl_ctx), (unsigned char *)(s->header_buff) + header_ptr, payload_expand_overlength);
+            }
+            else
+#endif /* LIBRWS_USING_MBED_TLS */
+            {
+                LOG_D("[T:%.8d, L:%.5d, %*.*s] try read header payload length data in normal mode", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+                len = (int)recv(s->socket, s->header_buff + header_ptr, payload_expand_overlength, 0);
+            }
+
+            if (len > 0)
+            {
+                payload_expand_overlength -= len;
+                total_len += len;
+                header_ptr += len;
+                LOG_D("[T:%.8d, L:%.5d, %*.*s] read %d byte(s) date, payload_expand_overlength is %d, total read len is %d", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__, len, payload_expand_overlength, total_len);
+            }
+            else
+            {
+                LOG_D("[T:%.8d, L:%.5d, %*.*s] no data, then try to read", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+            }
+        }
+
+        payload_len |= ((unsigned int)(s->header_buff[2])) << 8;
+        payload_len |= ((unsigned int)(s->header_buff[3])) << 0;
+    }
+
+    else if (payload == 127)
+    {
+        /* Todo */
+        LOG_D("[T:%.8d, L:%.5d, %*.*s] Todo", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+        while (1);
+    }
+
+    LOG_D("[T:%.8d, L:%.5d, %*.*s] payload len is %d", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__, payload_len);
+
+    /* 读取帧头剩余字节数据 */
+    size_t frame_header_overlength = header_len - total_len;
+
+    while (frame_header_overlength > 0)
+    {
+#ifdef LIBRWS_USING_MBED_TLS
+        if (s->scheme && strcmp(s->scheme, "wss") == 0)
+        {
+            LOG_D("[T:%.8d, L:%.5d, %*.*s] try read header overlength data in tls mode", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+            len = mbedtls_ssl_read(&(s->ssl->ssl_ctx), (unsigned char *)(s->header_buff) + header_ptr, frame_header_overlength);
+        }
+        else
+#endif /* LIBRWS_USING_MBED_TLS */
+        {
+            LOG_D("[T:%.8d, L:%.5d, %*.*s] try read header overlength data in normal mode", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+            len = (int)recv(s->socket, s->header_buff + header_ptr, frame_header_overlength, 0);
+        }
+
+        if (len > 0)
+        {
+            frame_header_overlength -= len;
+            total_len += len;
+            header_ptr += len;
+            LOG_D("[T:%.8d, L:%.5d, %*.*s] read %d byte(s) date, frame_header_overlength is %d, total read len is %d", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__, len, frame_header_overlength, total_len);
+        }
+        else
+        {
+            LOG_D("[T:%.8d, L:%.5d, %*.*s] no data, then try to read", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+        }
+    }
+
+    /* 正常解析负载数据 */
+    total_len = 0;
+    size_t payload_overlength = payload_len;
+    size_t unpack_overlength = RWS_RECEIVE_PAYLOAD_BUFF_SIZE;
+
+    /* 触发空数据帧回调 */
+    if (payload_overlength == 0)
+    {
+        if (opcode == rws_opcode_continuation)
+        {
+            LOG_I("[T:%.8d, L:%.5d, %*.*s] bin frame data addr = 0x%.8x, len = %d", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__, s->payload_buff, payload_ptr);
+
+            /* 调试信息 */
+#if ((DBG_LEVEL) == (DBG_LOG))
+            LOG_I("[T:%.8d, L:%.5d, %*.*s] bin content: ", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+            hexdump(s->payload_buff, 16);
+#endif
+
+            if (s->on_recvd_bin)
+            {
+                LOG_I("[T:%.8d, L:%.5d, %*.*s] call bin callback", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+                s->on_recvd_bin(s, s->payload_buff, (unsigned int)(payload_ptr));
+                LOG_I("[T:%.8d, L:%.5d, %*.*s] call bin callback end", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+            }
+        }
+    }
+
+    /* 非空数据帧 */
+    while (payload_overlength > 0)
+    {
+        payload_ptr = 0;
+
+        /* 这里是按照天猫bin音频数据2K进行拆包回调的 */
+        if (payload_overlength < RWS_RECEIVE_PAYLOAD_BUFF_SIZE)
+        {
+            unpack_overlength = payload_overlength;
+        }
+        else
+        {
+            unpack_overlength = RWS_RECEIVE_PAYLOAD_BUFF_SIZE;
+        }
+
+        /* 阻塞式将负载数据的2K读出来 */
+        while (unpack_overlength > 0)
+        {
+#ifdef LIBRWS_USING_MBED_TLS
+            if (s->scheme && strcmp(s->scheme, "wss") == 0)
+            {
+                LOG_D("[T:%.8d, L:%.5d, %*.*s] try read payload data with tls mode", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+                len = mbedtls_ssl_read(&(s->ssl->ssl_ctx), (unsigned char *)(s->payload_buff) + payload_ptr, unpack_overlength);
+            }
+            else
+#endif /* LIBRWS_USING_MBED_TLS */
+            {
+                LOG_D("[T:%.8d, L:%.5d, %*.*s] try read payload data with normal mode", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+                len = (int)recv(s->socket, s->payload_buff + payload_ptr, unpack_overlength, 0);
+            }
+
+            if (len > 0)
+            {
+                unpack_overlength -= len;
+                payload_overlength -= len;
+                payload_ptr += len;
+                total_len += len;
+                LOG_D("[T:%.8d, L:%.5d, %*.*s] read %d byte(s) date, unpack_overlength is %d, payload_overlength is %d, total read len is %d", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__, len, unpack_overlength, payload_overlength, total_len);
+            }
+
+            /* 读不出来数据有可能是2种情况, 1: 帧结束了, 2: 数据帧未结束但是数据还没到来 */
+            else
+            {
+                /* 读取到的数据已经大于等于帧的长度 */
+                if (total_len >= payload_len)
+                {
+                    /* 这里最后的拆包数据需要产生回调 */
+                    goto _callback;
+                }
+                else
+                {
+                    LOG_D("[T:%.8d, L:%.5d, %*.*s] no data, then try to read", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+                }
+            }
+        }
+
+_callback:
+        /* 2K数据接收完毕被拆分, 触发回调 */
+        if (opcode == rws_opcode_text_frame)
+        {
+            LOG_I("[T:%.8d, L:%.5d, %*.*s] txt frame data addr = 0x%.8x, len = %d", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__, s->payload_buff, payload_ptr);
+            LOG_I("[T:%.8d, L:%.5d, %*.*s] txt content = %*.*s ", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__, payload_ptr, payload_ptr, s->payload_buff);
+
+            if (s->on_recvd_text)
+            {
+                LOG_I("[T:%.8d, L:%.5d, %*.*s] call txt callback", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+                s->on_recvd_text(s, s->payload_buff, (unsigned int)(payload_ptr));
+                LOG_I("[T:%.8d, L:%.5d, %*.*s] call txt callback end", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+            }
+        }
+        else if (opcode == rws_opcode_binary_frame || opcode == rws_opcode_continuation) /* Todo */
+        {
+            LOG_I("[T:%.8d, L:%.5d, %*.*s] bin frame data addr = 0x%.8x, len = %d", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__, s->payload_buff, payload_ptr);
+
+            /* 调试信息 */
+#if ((DBG_LEVEL) == (DBG_LOG))
+            LOG_I("[T:%.8d, L:%.5d, %*.*s] bin content: ", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+            hexdump(s->payload_buff, 16);
+#endif
+
+            if (s->on_recvd_bin)
+            {
+                LOG_I("[T:%.8d, L:%.5d, %*.*s] call bin callback", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+                s->on_recvd_bin(s, s->payload_buff, (unsigned int)(payload_ptr));
+                LOG_I("[T:%.8d, L:%.5d, %*.*s] call bin callback end", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+            }
+        }
+    }
+
+_quit:
+#if defined(RWS_OS_WINDOWS)
+    error_number = WSAGetLastError();
+#else
+    error_number = errno;
+#endif
+
+    if (error_number != WSAEWOULDBLOCK && error_number != WSAEINPROGRESS && error_number != 0)
+    {
+        LOG_W("[T:%.8d, L:%.5d, %*.*s] current error_number = %d", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__, error_number);
+
+        LOG_E("[T:%.8d, L:%.5d, %*.*s] recv data failed", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+
+        s->error = rws_error_new_code_descr(rws_error_code_read_write_socket, "Failed read/write socket");
+        // rws_socket_close(s);
+
+        result = rws_false;
+    }
+    else
+    {
+        LOG_D("[T:%.8d, L:%.5d, %*.*s] recv data complete", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+    }
+
+_exit:
+    return result;
+}
+
+_rws_frame *rws_socket_last_unfin_recvd_frame_by_opcode(_rws_socket *s, const rws_opcode opcode)
+{
+    _rws_frame *last = NULL;
+    _rws_frame *frame = NULL;
+    _rws_node *cur = s->recvd_frames;
+    while (cur)
+    {
+        frame = (_rws_frame *)cur->value.object;
+        if (frame)
+        {
+            //  [FIN=0,opcode !=0 ],[FIN=0,opcode ==0 ],....[FIN=1,opcode ==0 ]
+            if (!frame->is_finished /*&& frame->opcode == opcode*/)
+            {
+                last = frame;
+            }
+        }
+        cur = cur->next;
+    }
+    return last;
+}
+
+void rws_socket_process_bin_or_text_frame(_rws_socket *s, _rws_frame *frame)
+{
+    _rws_frame *last_unfin = rws_socket_last_unfin_recvd_frame_by_opcode(s, frame->opcode);
+    if (last_unfin)
+    {
+        rws_frame_combine_datas(last_unfin, frame);
+        last_unfin->is_finished = frame->is_finished;
+        rws_frame_delete(frame);
+    }
+    else if (frame->data && frame->data_size)
+    {
+        rws_socket_append_recvd_frames(s, frame);
+    }
+    else
+    {
+        rws_frame_delete(frame);
+    }
+}
+
+void rws_socket_process_ping_frame(_rws_socket *s, _rws_frame *frame)
+{
+    _rws_frame *pong_frame = rws_frame_create();
+    pong_frame->opcode = rws_opcode_pong;
+    pong_frame->is_masked = rws_true;
+    rws_frame_fill_with_send_data(pong_frame, frame->data, frame->data_size);
+    rws_frame_delete(frame);
+    rws_socket_append_send_frames(s, pong_frame);
+}
+
+void rws_socket_process_conn_close_frame(_rws_socket *s, _rws_frame *frame)
+{
+    s->command = COMMAND_INFORM_DISCONNECTED;
+    s->error = rws_error_new_code_descr(rws_error_code_connection_closed, "Connection was closed by endpoint");
+    //rws_socket_close(s);
+    rws_frame_delete(frame);
+}
+
+void rws_socket_process_received_frame(_rws_socket *s, _rws_frame *frame)
+{
+    switch (frame->opcode)
+    {
+    case rws_opcode_ping:
+        rws_socket_process_ping_frame(s, frame);
+        break;
+    case rws_opcode_text_frame:
+    case rws_opcode_binary_frame:
+    case rws_opcode_continuation:
+        rws_socket_process_bin_or_text_frame(s, frame);
+        break;
+    case rws_opcode_connection_close:
+        rws_socket_process_conn_close_frame(s, frame);
+        break;
+    default:
+        // unprocessed => delete
+        rws_frame_delete(frame);
+        break;
+    }
+}
+
+void rws_socket_idle_recv(_rws_socket *s)
+{
+    _rws_frame *frame = NULL;
+
+    if (s->custom_mode != 0x1234)
+    {
+        if (!rws_socket_recv(s))
+        {
+            // sock already closed
+            if (s->error)
+            {
+                s->command = COMMAND_INFORM_DISCONNECTED;
+            }
+            return;
+        }
+
+        const size_t nframe_size = rws_check_recv_frame_size(s->received, s->received_len);
+        if (nframe_size)
+        {
+            frame = rws_frame_create_with_recv_data(s->received, nframe_size);
+            if (frame)
+            {
+                rws_socket_process_received_frame(s, frame);
+            }
+
+            if (nframe_size == s->received_len)
+            {
+                s->received_len = 0;
+            }
+            else if (s->received_len > nframe_size)
+            {
+                const size_t nLeftLen = s->received_len - nframe_size;
+                memmove((char *)s->received, (char *)s->received + nframe_size, nLeftLen);
+                s->received_len = nLeftLen;
+            }
+        }
+    }
+
+    /* RT-Thread Team add */
+    else
+    {
+        if (!rws_socket_recv_custom(s))
+        {
+            // sock already closed, Todo
+            if (s->error)
+            {
+                s->command = COMMAND_INFORM_DISCONNECTED;
+            }
+            return;
+        }
+    }
+}
+
+void rws_socket_idle_send(_rws_socket *s)
+{
+    _rws_node *cur = NULL;
+    rws_bool sending = rws_true;
+    _rws_frame *frame = NULL;
+
+    rws_mutex_lock(s->send_mutex);
+    cur = s->send_frames;
+    if (cur)
+    {
+        while (cur && s->is_connected && sending)
+        {
+            frame = (_rws_frame *)cur->value.object;
+            cur->value.object = NULL;
+            if (frame)
+            {
+                sending = rws_socket_send(s, frame->data, frame->data_size);
+            }
+            rws_frame_delete(frame);
+            cur = cur->next;
+        }
+        rws_list_delete_clean(&s->send_frames);
+        if (s->error)
+        {
+            s->command = COMMAND_INFORM_DISCONNECTED;
+        }
+    }
+    rws_mutex_unlock(s->send_mutex);
+}
+
+void rws_socket_wait_handshake_responce(_rws_socket *s)
+{
+    LOG_I("[T:%.8d, L:%.5d, %*.*s] try wait recv handshake responce", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+
+    /* Todo */
+    if (!rws_socket_recv(s))
+    {
+        LOG_D("[T:%.8d, L:%.5d, %*.*s] no find handshake responce", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+
+        if (s->error)
+        {
+            LOG_E("[T:%.8d, L:%.5d, %*.*s] recv responce failed, handshake failed, error = %d", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__, s->error);
+            LOG_I("[T:%.8d, L:%.5d, %*.*s] try inform websocket disconnect", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+            s->command = COMMAND_INFORM_DISCONNECTED;
+        }
+
+        return;
+    }
+
+    if (s->received_len == 0)
+    {
+        LOG_D("[T:%.8d, L:%.5d, %*.*s] handshake responce len is empty, len = 0", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+        return;
+    }
+
+    LOG_I("[T:%.8d, L:%.5d, %*.*s] try process handshake responce", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+    if (rws_socket_process_handshake_responce(s))
+    {
+        s->received_len = 0;
+        s->is_connected = rws_true;
+        s->command = COMMAND_INFORM_CONNECTED;
+
+        LOG_D("[T:%.8d, L:%.5d, %*.*s] process handshake responce succeed", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+        LOG_I("[T:%.8d, L:%.5d, %*.*s] try inform websocket connect", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+    }
+    else
+    {
+        rws_socket_close(s);
+        s->command = COMMAND_INFORM_DISCONNECTED;
+
+        LOG_E("[T:%.8d, L:%.5d, %*.*s] process handshake responce failed", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+        LOG_I("[T:%.8d, L:%.5d, %*.*s] try inform websocket disconnect", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+    }
+}
+
+void rws_socket_send_disconnect(_rws_socket *s)
+{
+    char buff[16];
+    size_t len = 0;
+    _rws_frame *frame = rws_frame_create();
+
+    len = rws_sprintf(buff, 16, "%u", rws_socket_get_next_message_id(s));
+
+    frame->is_masked = rws_true;
+    frame->opcode = rws_opcode_connection_close;
+    rws_frame_fill_with_send_data(frame, buff, len);
+    rws_socket_send(s, frame->data, frame->data_size);
+    rws_frame_delete(frame);
+    s->command = COMMAND_END;
+    rws_thread_sleep(RWS_CONNECT_RETRY_DELAY); // little bit wait after send message
+}
+
+void rws_socket_send_handshake(_rws_socket *s)
+{
+    char buff[512];
+    char *ptr = buff;
+    size_t writed = 0;
+    writed = rws_sprintf(ptr, 512, "GET %s HTTP/%s\r\n", s->path, k_rws_socket_min_http_ver);
+
+    if (s->port == 80)
+    {
+        writed += rws_sprintf(ptr + writed, 512 - writed, "Host: %s\r\n", s->host);
+    }
+    else
+    {
+        writed += rws_sprintf(ptr + writed, 512 - writed, "Host: %s:%i\r\n", s->host, s->port);
+    }
+
+    writed += rws_sprintf(ptr + writed, 512 - writed,
+                          "Upgrade: websocket\r\n"
+                          "Connection: Upgrade\r\n"
+                          "Origin: %s://%s\r\n",
+                          s->scheme, s->host);
+
+    writed += rws_sprintf(ptr + writed, 512 - writed,
+                          "Sec-WebSocket-Key: %s\r\n"
+                          "Sec-WebSocket-Protocol: chat, superchat\r\n"
+                          "Sec-WebSocket-Version: 13\r\n"
+                          "\r\n",
+                          "dGhlIHNhbXBsZSBub25jZQ==");
+
+    if (rws_socket_send(s, buff, writed))
+    {
+        s->command = COMMAND_WAIT_HANDSHAKE_RESPONCE;
+    }
+    else
+    {
+        if (s->error)
+        {
+            s->error->code = rws_error_code_send_handshake;
+        }
+        else
+        {
+            s->error = rws_error_new_code_descr(rws_error_code_send_handshake, "Send handshake");
+        }
+        rws_socket_close(s);
+        s->command = COMMAND_INFORM_DISCONNECTED;
+    }
+}
+
+struct addrinfo *rws_socket_connect_getaddr_info(_rws_socket *s)
+{
+    struct addrinfo hints;
+    char portstr[16];
+    struct addrinfo *result = NULL;
+    int ret = 0, retry_number = 0;
+#if defined(RWS_OS_WINDOWS)
+    WSADATA wsa;
+#endif
+
+    rws_error_delete_clean(&s->error);
+
+#if defined(RWS_OS_WINDOWS)
+    memset(&wsa, 0, sizeof(WSADATA));
+    if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
+    {
+        s->error = rws_error_new_code_descr(rws_error_code_connect_to_host, "Failed initialise winsock");
+        s->command = COMMAND_INFORM_DISCONNECTED;
+        return NULL;
+    }
+#endif
+
+    rws_sprintf(portstr, 16, "%i", s->port);
+
+    while (++retry_number < RWS_CONNECT_ATTEMPS)
+    {
+        result = NULL;
+        memset(&hints, 0, sizeof(hints));
+        hints.ai_family = AF_UNSPEC;
+        hints.ai_socktype = SOCK_STREAM;
+
+        LOG_D("[T:%.8d, L:%.5d, %*.*s] port is %s", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__, portstr);
+        LOG_D("[T:%.8d, L:%.5d, %*.*s] retry_number is %d", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__, retry_number);
+
+        ret = getaddrinfo(s->host, portstr, &hints, &result);
+
+        LOG_D("[T:%.8d, L:%.5d, %*.*s] getaddrinfo ret: %d result:0x%08X", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__, ret, result);
+
+        if (ret == 0 && result)
+        {
+            return result;
+        }
+
+        if (result)
+        {
+            freeaddrinfo(result);
+        }
+
+        rws_thread_sleep(RWS_CONNECT_RETRY_DELAY);
+    }
+
+#if defined(RWS_OS_WINDOWS)
+    WSACleanup();
+#endif
+
+    s->error = rws_error_new_code_descr(rws_error_code_connect_to_host, "Failed connect to host");
+    // s->error = rws_error_new_code_descr(rws_error_code_connect_to_host,
+    //                                     (last_ret > 0) ? gai_strerror(last_ret) : "Failed connect to host");
+
+    s->command = COMMAND_INFORM_DISCONNECTED;
+    LOG_I("[T:%.8d, L:%.5d, %*.*s] try inform websocket disconnect", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+
+    return NULL;
+}
+
+void rws_socket_connect_to_host(_rws_socket *s)
+{
+    struct addrinfo *result = NULL;
+    struct addrinfo *p = NULL;
+    rws_socket_t sock = RWS_INVALID_SOCKET;
+    int retry_number = 0;
+#if defined(RWS_OS_WINDOWS)
+    unsigned long iMode = 0;
+#endif
+
+    result = rws_socket_connect_getaddr_info(s);
+    if (!result)
+    {
+        LOG_E("[T:%.8d, L:%.5d, %*.*s] websocket connect failed", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+        return;
+    }
+
+    while ((++retry_number < RWS_CONNECT_ATTEMPS) && (sock == RWS_INVALID_SOCKET))
+    {
+        LOG_I("[T:%.8d, L:%.5d, %*.*s] retry_number is %d", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__, retry_number);
+
+        for (p = result; p != NULL; p = p->ai_next)
+        {
+            LOG_I("[T:%.8d, L:%.5d, %*.*s] socket to: ai_family = %d, ai_socktype = %d, ai_protocol = %d", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__, p->ai_family, p->ai_socktype, p->ai_protocol);
+
+            sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
+            if (sock != RWS_INVALID_SOCKET)
+            {
+                rws_socket_set_option(sock, SO_ERROR, 1);     // When an error occurs on a socket, set error variable so_error and notify process
+                rws_socket_set_option(sock, SO_KEEPALIVE, 1); // Periodically test if connection is alive
+
+                {
+                    struct timeval timeout;
+
+                    timeout.tv_sec  = 1;
+                    timeout.tv_usec = 0;
+                    setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (void *)&timeout, sizeof(timeout));
+                    setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (void *)&timeout, sizeof(timeout));
+                }
+
+                LOG_I("[T:%.8d, L:%.5d, %*.*s] connect to: ai_add = 0x%08X, ai_addrlen = %d", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__, (int)p->ai_addr, p->ai_addrlen);
+
+                if (connect(sock, p->ai_addr, p->ai_addrlen) == 0)
+                {
+                    s->received_len = 0;
+                    s->socket = sock;
+#if defined(RWS_OS_WINDOWS)
+                    // If iMode != 0, non-blocking mode is enabled.
+                    iMode = 1;
+                    ioctlsocket(s->socket, FIONBIO, &iMode);
+#else
+                    // fcntl(s->socket, F_SETFL, O_NONBLOCK);
+
+                    {
+                        struct timeval timeout;
+
+                        timeout.tv_sec  = 3;
+                        timeout.tv_usec = 0;
+                        setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (void *)&timeout, sizeof(timeout));
+
+                        timeout.tv_sec  = 0;
+                        timeout.tv_usec = 1000;
+                        setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (void *)&timeout, sizeof(timeout));
+                    }
+#endif
+                    LOG_I("[T:%.8d, L:%.5d, %*.*s] socket break", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+
+                    break;
+                }
+
+                LOG_E("[T:%.8d, L:%.5d, %*.*s] socket connect failed", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+                RWS_SOCK_CLOSE(sock);
+            }
+            else
+            {
+                LOG_I("[T:%.8d, L:%.5d, %*.*s] socket create failed", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+            }
+        }
+
+        if (sock == RWS_INVALID_SOCKET)
+        {
+            rws_thread_sleep(RWS_CONNECT_RETRY_DELAY);
+        }
+    }
+
+    freeaddrinfo(result);
+
+    if (s->socket == RWS_INVALID_SOCKET)
+    {
+#if defined(RWS_OS_WINDOWS)
+        WSACleanup();
+#endif
+        s->error = rws_error_new_code_descr(rws_error_code_connect_to_host, "Failed connect to host");
+        s->command = COMMAND_INFORM_DISCONNECTED;
+
+        LOG_I("[T:%.8d, L:%.5d, %*.*s] try inform websocket disconnect", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+    }
+    else
+    {
+        s->command = COMMAND_SEND_HANDSHAKE;
+
+        LOG_I("[T:%.8d, L:%.5d, %*.*s] try send handshake", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+    }
+}
+
+static void rws_socket_work_th_func(void *user_object)
+{
+    _rws_socket *s = (_rws_socket *)user_object;
+    size_t loop_number = 0;
+
+    LOG_I("[T:%.8d, L:%.5d, %*.*s] this websocket work host is %s//%s:%d", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__, s->scheme, s->host, s->port);
+
+    while (s->command < COMMAND_END)
+    {
+        loop_number++;
+
+        rws_mutex_lock(s->work_mutex);
+
+        switch (s->command)
+        {
+        case COMMAND_CONNECT_TO_HOST:
+            LOG_I("[T:%.8d, L:%.5d, %*.*s] try connect to %s//%s:%d", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__, s->scheme, s->host, s->port);
+
+#ifdef LIBRWS_USING_MBED_TLS
+            if (s->scheme && strcmp(s->scheme, "wss") == 0)
+            {
+#if !defined(RWS_OS_WINDOWS)
+                rws_ssl_conn(s);
+#else
+                LOG_E("[T:%.8d, L:%.5d, %*.*s] no support window", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+
+                s->socket == RWS_INVALID_SOCKET;
+                s->command = COMMAND_INFORM_DISCONNECTED;
+#endif
+                break;
+            }
+            else
+#endif /* LIBRWS_USING_MBED_TLS */
+            {
+                rws_socket_connect_to_host(s);
+            }
+
+            LOG_I("[T:%.8d, L:%.5d, %*.*s] try connect to %s//%s:%d end", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__, s->scheme, s->host, s->port);
+
+            break;
+
+        case COMMAND_SEND_HANDSHAKE:
+            LOG_I("[T:%.8d, L:%.5d, %*.*s] COMMAND_SEND_HANDSHAKE", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+            rws_socket_send_handshake(s);
+            LOG_D("[T:%.8d, L:%.5d, %*.*s] COMMAND_SEND_HANDSHAKE end", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+            break;
+
+        case COMMAND_WAIT_HANDSHAKE_RESPONCE:
+            LOG_I("[T:%.8d, L:%.5d, %*.*s] COMMAND_WAIT_HANDSHAKE_RESPONCE", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+            rws_socket_wait_handshake_responce(s);
+            LOG_D("[T:%.8d, L:%.5d, %*.*s] COMMAND_WAIT_HANDSHAKE_RESPONCE end", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+            break;
+
+        case COMMAND_DISCONNECT:
+            LOG_I("[T:%.8d, L:%.5d, %*.*s] COMMAND_DISCONNECT", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+            rws_socket_send_disconnect(s);
+            LOG_D("[T:%.8d, L:%.5d, %*.*s] COMMAND_DISCONNECT end", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+            break;
+
+        case COMMAND_IDLE:
+            // LOG_D("[T:%.8d, L:%.5d, %*.*s] COMMAND_IDLE, loop = %d", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__, loop_number);
+            if (loop_number >= 400) // 400 4s 3 = 12s
+            {
+                loop_number = 0;
+
+                if (s->is_connected)
+                {
+                    LOG_I("[T:%.8d, L:%.5d, %*.*s] send ping frame", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+                    rws_socket_send_ping(s);
+                    // LOG_I("[T:%.8d, L:%.5d, %*.*s] send ping frame end", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+                }
+            }
+
+            if (s->is_connected)
+            {
+                LOG_D("[T:%.8d, L:%.5d, %*.*s] call rws_socket_idle_send()", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+                rws_socket_idle_send(s);
+            }
+
+            if (s->is_connected)
+            {
+                LOG_D("[T:%.8d, L:%.5d, %*.*s] call rws_socket_idle_recv()", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+                rws_socket_idle_recv(s);
+            }
+            break;
+
+        default:
+            LOG_D("[T:%.8d, L:%.5d, %*.*s] other command: %d", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__, s->command);
+            break;
+        }
+
+        rws_mutex_unlock(s->work_mutex);
+
+        switch (s->command)
+        {
+        case COMMAND_INFORM_CONNECTED:
+        {
+            LOG_D("[T:%.8d, L:%.5d, %*.*s] COMMAND_INFORM_CONNECTED", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+
+            s->command = COMMAND_IDLE;
+            if (s->on_connected)
+            {
+                LOG_D("[T:%.8d, L:%.5d, %*.*s] call on_connected function", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+                s->on_connected(s);
+                LOG_D("[T:%.8d, L:%.5d, %*.*s] call on_connected function end", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+            }
+        }
+        break;
+
+        /* 断开连接需要关掉线程吗? */
+        case COMMAND_INFORM_DISCONNECTED:
+        {
+            LOG_D("[T:%.8d, L:%.5d, %*.*s] COMMAND_INFORM_DISCONNECTED", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+
+            s->command = COMMAND_END;
+            rws_socket_send_disconnect(s);
+
+            if (s->on_disconnected)
+            {
+                LOG_D("[T:%.8d, L:%.5d, %*.*s] call on_disconnected function", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+                s->on_disconnected(s);
+                LOG_D("[T:%.8d, L:%.5d, %*.*s] call on_disconnected function end", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+            }
+        }
+        break;
+
+        case COMMAND_IDLE:
+            LOG_D("[T:%.8d, L:%.5d, %*.*s] COMMAND_IDLE", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+
+            if (s->recvd_frames)
+            {
+                LOG_D("[T:%.8d, L:%.5d, %*.*s] rws_socket_inform_recvd_frames", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+                rws_socket_inform_recvd_frames(s);
+            }
+            break;
+
+        default:
+            LOG_D("[T:%.8d, L:%.5d, %*.*s] other command: %d", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__, s->command);
+            break;
+        }
+
+        rws_thread_sleep(5);
+    }
+
+    LOG_D("[T:%.8d, L:%.5d, %*.*s] this websocket work ready to quit, close socket", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__);
+
+    rws_socket_close(s);
+    s->work_thread = NULL;
+    rws_socket_delete(s);
+
+    pthread_exit(NULL);
+}
+
+rws_bool rws_socket_create_start_work_thread(_rws_socket *s)
+{
+    rws_error_delete_clean(&s->error);
+    s->command = COMMAND_NONE;
+    s->work_thread = rws_thread_create(&rws_socket_work_th_func, s);
+    if (s->work_thread)
+    {
+        s->command = COMMAND_CONNECT_TO_HOST;
+        return rws_true;
+    }
+    return rws_false;
+}
+
+void rws_socket_resize_received(_rws_socket *s, const size_t size)
+{
+    void *res = NULL;
+    size_t min = 0;
+    if (size == s->received_size)
+    {
+        return;
+    }
+
+    res = rws_malloc(size);
+    assert(res && (size > 0));
+
+    min = (s->received_size < size) ? s->received_size : size;
+    if (min > 0 && s->received)
+    {
+        memcpy(res, s->received, min);
+    }
+    rws_free_clean(&s->received);
+    s->received = res;
+    s->received_size = size;
+}
+
+void rws_socket_close(_rws_socket *s)
+{
+    s->received_len = 0;
+    if (s->socket != RWS_INVALID_SOCKET)
+    {
+#ifdef LIBRWS_USING_MBED_TLS
+        if (s->scheme && strcmp(s->scheme, "wss") == 0)
+        {
+            rws_ssl_close(s);
+        }
+        else
+#endif /* LIBRWS_USING_MBED_TLS */
+        {
+            RWS_SOCK_CLOSE(s->socket);
+        }
+
+        s->socket = RWS_INVALID_SOCKET;
+#if defined(RWS_OS_WINDOWS)
+        WSACleanup();
+#endif
+    }
+    s->is_connected = rws_false;
+}
+
+void rws_socket_append_recvd_frames(_rws_socket *s, _rws_frame *frame)
+{
+    _rws_node_value frame_list_var;
+    frame_list_var.object = frame;
+    if (s->recvd_frames)
+    {
+        rws_list_append(s->recvd_frames, frame_list_var);
+    }
+    else
+    {
+        s->recvd_frames = rws_list_create();
+        s->recvd_frames->value = frame_list_var;
+    }
+}
+
+void rws_socket_append_send_frames(_rws_socket *s, _rws_frame *frame)
+{
+    _rws_node_value frame_list_var;
+    frame_list_var.object = frame;
+    if (s->send_frames)
+    {
+        rws_list_append(s->send_frames, frame_list_var);
+    }
+    else
+    {
+        s->send_frames = rws_list_create();
+        s->send_frames->value = frame_list_var;
+    }
+}
+
+rws_bool rws_socket_send_text_priv(_rws_socket *s, const char *text)
+{
+    size_t len = text ? strlen(text) : 0;
+    _rws_frame *frame = NULL;
+
+    if (len <= 0)
+    {
+        return rws_false;
+    }
+
+    frame = rws_frame_create();
+    frame->is_masked = rws_true;
+    frame->opcode = rws_opcode_text_frame;
+    rws_frame_fill_with_send_data(frame, text, len);
+    rws_socket_append_send_frames(s, frame);
+
+    return rws_true;
+}
+
+rws_bool rws_socket_send_bin_priv(_rws_socket *s, const char *data, size_t len, rws_opcode opcode, rws_bool is_fin)
+{
+    _rws_frame *frame = NULL;
+
+    if (len <= 0) len = 0;
+
+    frame = rws_frame_create();
+    frame->is_masked = rws_true;
+    frame->opcode = opcode;
+    rws_frame_fill_with_send_bin(frame, data, len, is_fin);
+    rws_socket_append_send_frames(s, frame);
+
+    return rws_true;
+}
+
+void rws_socket_delete_all_frames_in_list(_rws_list *list_with_frames)
+{
+    _rws_frame *frame = NULL;
+    _rws_node *cur = list_with_frames;
+    while (cur)
+    {
+        frame = (_rws_frame *)cur->value.object;
+        if (frame)
+        {
+            rws_frame_delete(frame);
+        }
+        cur->value.object = NULL;
+    }
+}
+
+void rws_socket_set_option(rws_socket_t s, int option, int value)
+{
+
+    setsockopt(s, SOL_SOCKET, option, (char *)&value, sizeof(int));
+}
+
+void rws_socket_check_write_error(_rws_socket *s, int error_num)
+{
+#if defined(RWS_OS_WINDOWS)
+    int socket_code = 0, code = 0;
+    unsigned int socket_code_size = sizeof(int);
+#else
+    int socket_code = 0, code = 0;
+    socklen_t socket_code_size = sizeof(socket_code);
+#endif
+
+    if (s->socket != RWS_INVALID_SOCKET)
+    {
+#if defined(RWS_OS_WINDOWS)
+        if (getsockopt(s->socket, SOL_SOCKET, SO_ERROR, (char *)&socket_code, (int *)&socket_code_size) != 0)
+        {
+            socket_code = 0;
+        }
+#else
+        if (getsockopt(s->socket, SOL_SOCKET, SO_ERROR, &socket_code, &socket_code_size) != 0)
+        {
+            socket_code = 0;
+        }
+#endif
+    }
+
+    code = (socket_code > 0) ? socket_code : error_num;
+    if (code <= 0)
+    {
+        return;
+    }
+
+    switch (code)
+    {
+    // send errors
+    case EACCES: //
+
+    //		case EAGAIN: // The socket is marked nonblocking and the requested operation would block
+    //		case EWOULDBLOCK: // The socket is marked nonblocking and the receive operation would block
+
+    case EBADF:        // An invalid descriptor was specified
+    case ECONNRESET:   // Connection reset by peer
+    case EDESTADDRREQ: // The socket is not connection-mode, and no peer address is set
+    case EFAULT:       // An invalid user space address was specified for an argument
+    // The receive buffer pointer(s) point outside the process's address space.
+    case EINTR:        // A signal occurred before any data was transmitted
+    // The receive was interrupted by delivery of a signal before any data were available
+    case EINVAL:       // Invalid argument passed
+    case EISCONN:      // The connection-mode socket was connected already but a recipient was specified
+    case EMSGSIZE:     // The socket type requires that message be sent atomically, and the size of the message to be sent made this impossible
+    case ENOBUFS:      // The output queue for a network interface was full
+    case ENOMEM:       // No memory available
+    case ENOTCONN:     // The socket is not connected, and no target has been given
+    // The socket is associated with a connection-oriented protocol and has not been connected
+    case ENOTSOCK:     // The argument sockfd is not a socket
+    // The argument sockfd does not refer to a socket
+    case EOPNOTSUPP:   // Some bit in the flags argument is inappropriate for the socket type.
+    case EPIPE:        // The local end has been shut down on a connection oriented socket
+    // recv errors
+    case ECONNREFUSED: // A remote host refused to allow the network connection (typically because it is not running the requested service).
+
+        s->error = rws_error_new_code_descr(rws_error_code_read_write_socket, rws_strerror(code));
+        break;
+
+    default:
+        break;
+    }
+}
+
+#ifdef LIBRWS_USING_MBED_TLS
+#if defined(MBEDTLS_DEBUG_C)
+#define DEBUG_LEVEL 1
+#endif
+
+void rws_debug(void *ctx, int level, const char *file, int line, const char *str)
+{
+    LOG_I("%s", str ? str : NULL);
+}
+
+// TODO: mbedtls_ssl_set_hostname() should be called.
+int rws_ssl_conn(_rws_socket *s)
+{
+    int authmode = MBEDTLS_SSL_VERIFY_NONE;
+    const char *pers = "https";
+    int value, ret = 0;
+    uint32_t flags;
+    _rws_ssl *ssl = NULL;
+    char portstr[16] = {0};
+
+    value = value;
+
+    s->ssl = rws_malloc_zero(sizeof(_rws_ssl));
+    if (!s->ssl)
+    {
+        LOG_I("Memory malloc error.");
+        ret = -1;
+        goto exit;
+    }
+    ssl = s->ssl;
+
+    if (s->server_cert)
+        authmode = MBEDTLS_SSL_VERIFY_OPTIONAL;
+
+    /*
+    * Initialize the RNG and the session data
+    */
+#if defined(MBEDTLS_DEBUG_C)
+    mbedtls_debug_set_threshold(DEBUG_LEVEL);
+#endif
+    mbedtls_net_init(&ssl->net_ctx);
+    mbedtls_ssl_init(&ssl->ssl_ctx);
+    mbedtls_ssl_config_init(&ssl->ssl_conf);
+    mbedtls_x509_crt_init(&ssl->cacert);
+    mbedtls_x509_crt_init(&ssl->clicert);
+    mbedtls_pk_init(&ssl->pkey);
+    mbedtls_ctr_drbg_init(&ssl->ctr_drbg);
+
+    /*
+     * 0. Initialize the RNG and the session data
+     */
+    mbedtls_entropy_init(&ssl->entropy);
+    if ((value = mbedtls_ctr_drbg_seed(&ssl->ctr_drbg,
+                                       mbedtls_entropy_func,
+                                       &ssl->entropy,
+                                       (const unsigned char *)pers,
+                                       strlen(pers))) != 0)
+    {
+        LOG_I("mbedtls_ctr_drbg_seed() failed, value:-0x%x.", -value);
+        ret = -1;
+        goto exit;
+    }
+
+    /*
+    * Load the Client certificate
+    */
+    if (s->client_cert && s->client_pk)
+    {
+        ret = mbedtls_x509_crt_parse(&ssl->clicert, (const unsigned char *)s->client_cert, s->client_cert_len);
+        if (ret < 0)
+        {
+            LOG_I("Loading cli_cert failed! mbedtls_x509_crt_parse returned -0x%x.", -ret);
+            goto exit;
+        }
+
+        ret = mbedtls_pk_parse_key(&ssl->pkey, (const unsigned char *)s->client_pk, s->client_pk_len, NULL, 0);
+        if (ret != 0)
+        {
+            LOG_I("failed! mbedtls_pk_parse_key returned -0x%x.", -ret);
+            goto exit;
+        }
+    }
+
+    /*
+    * Load the trusted CA
+    */
+    /* cert_len passed in is gotten from sizeof not strlen */
+    if (s->server_cert && ((value = mbedtls_x509_crt_parse(&ssl->cacert,
+                                    (const unsigned char *)s->server_cert,
+                                    s->server_cert_len)) < 0))
+    {
+        LOG_I("mbedtls_x509_crt_parse() failed, value:-0x%x.", -value);
+        ret = -1;
+        goto exit;
+    }
+
+    // rws_socket_set_option(ssl->net_ctx.fd, SO_ERROR, 1);     // When an error occurs on a socket, set error variable so_error and notify process
+    // rws_socket_set_option(ssl->net_ctx.fd, SO_KEEPALIVE, 1); // Periodically test if connection is alive
+
+    // {
+    //     struct timeval timeout;
+
+    //     timeout.tv_sec  = 1;
+    //     timeout.tv_usec = 0;
+    //     setsockopt(ssl->net_ctx.fd, SOL_SOCKET, SO_SNDTIMEO, (void *)&timeout, sizeof(timeout));
+    //     setsockopt(ssl->net_ctx.fd, SOL_SOCKET, SO_RCVTIMEO, (void *)&timeout, sizeof(timeout));
+    // }
+
+    /*
+     * Start the connection
+     */
+    rws_sprintf(portstr, 16, "%i", s->port);
+    if ((ret = mbedtls_net_connect(&ssl->net_ctx, s->host, portstr, MBEDTLS_NET_PROTO_TCP)) != 0)
+    {
+        LOG_I("failed! mbedtls_net_connect returned %d, port:%s.", ret, portstr);
+        goto exit;
+    }
+
+    s->received_len = 0;
+    s->socket = ssl->net_ctx.fd;
+
+    /*
+     * Setup stuff
+     */
+    if ((value = mbedtls_ssl_config_defaults(&ssl->ssl_conf,
+                 MBEDTLS_SSL_IS_CLIENT,
+                 MBEDTLS_SSL_TRANSPORT_STREAM,
+                 MBEDTLS_SSL_PRESET_DEFAULT)) != 0)
+    {
+        LOG_I("mbedtls_ssl_config_defaults() failed, value:-0x%x.", -value);
+        ret = -1;
+        goto exit;
+    }
+
+    // TODO: add customerization encryption algorithm
+    memcpy(&ssl->profile, ssl->ssl_conf.cert_profile, sizeof(mbedtls_x509_crt_profile));
+    ssl->profile.allowed_mds = ssl->profile.allowed_mds | MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_MD5);
+    mbedtls_ssl_conf_cert_profile(&ssl->ssl_conf, &ssl->profile);
+
+    mbedtls_ssl_conf_authmode(&ssl->ssl_conf, authmode);
+    mbedtls_ssl_conf_ca_chain(&ssl->ssl_conf, &ssl->cacert, NULL);
+    mbedtls_ssl_conf_max_frag_len(&ssl->ssl_conf, MBEDTLS_SSL_MAX_FRAG_LEN_4096);
+
+    if (s->client_cert && (ret = mbedtls_ssl_conf_own_cert(&ssl->ssl_conf, &ssl->clicert, &ssl->pkey)) != 0)
+    {
+        LOG_I(" failed! mbedtls_ssl_conf_own_cert returned %d.", ret);
+        goto exit;
+    }
+
+    mbedtls_ssl_conf_rng(&ssl->ssl_conf, mbedtls_ctr_drbg_random, &ssl->ctr_drbg);
+    mbedtls_ssl_conf_dbg(&ssl->ssl_conf, rws_debug, NULL);
+
+    if ((value = mbedtls_ssl_setup(&ssl->ssl_ctx, &ssl->ssl_conf)) != 0)
+    {
+        LOG_I("mbedtls_ssl_setup() failed, value:-0x%x.", -value);
+        ret = -1;
+        goto exit;
+    }
+
+    if ((ret = mbedtls_ssl_set_hostname(&ssl->ssl_ctx, s->host)) != 0)
+    {
+        LOG_I("failed\n! mbedtls_ssl_set_hostname returned %d\n", ret);
+        goto exit;
+    }
+
+    mbedtls_ssl_set_bio(&ssl->ssl_ctx, &ssl->net_ctx, mbedtls_net_send, mbedtls_net_recv, NULL);
+
+    /*
+    * Handshake
+    */
+    while ((ret = mbedtls_ssl_handshake(&ssl->ssl_ctx)) != 0)
+    {
+        if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE)
+        {
+            LOG_I("mbedtls_ssl_handshake() failed, ret:-0x%x.", -ret);
+            ret = -1;
+            goto exit;
+        }
+
+        LOG_I("mbedtls_ssl_handshake() while");
+    }
+
+    LOG_I("mbedtls_ssl_handshake() ok");
+
+    // Todo
+    // mbedtls_net_set_nonblock(&ssl->net_ctx);
+
+    {
+        struct timeval timeout;
+
+        timeout.tv_sec  = 3;
+        timeout.tv_usec = 0;
+        setsockopt(ssl->net_ctx.fd, SOL_SOCKET, SO_SNDTIMEO, (void *)&timeout, sizeof(timeout));
+
+        timeout.tv_sec  = 0;
+        timeout.tv_usec = 1000;
+        setsockopt(ssl->net_ctx.fd, SOL_SOCKET, SO_RCVTIMEO, (void *)&timeout, sizeof(timeout));
+    }
+
+    /*
+     * Verify the server certificate
+     */
+    /* In real life, we would have used MBEDTLS_SSL_VERIFY_REQUIRED so that the
+        * handshake would not succeed if the peer's cert is bad.  Even if we used
+        * MBEDTLS_SSL_VERIFY_OPTIONAL, we would bail out here if ret != 0 */
+    if ((flags = mbedtls_ssl_get_verify_result(&ssl->ssl_ctx)) != 0)
+    {
+        char vrfy_buf[512];
+        LOG_I("svr_cert varification failed. authmode:%d", authmode);
+        mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), "  ! ", flags);
+        LOG_I("%s", vrfy_buf);
+    }
+    else
+    {
+        LOG_I("svr_cert varification ok. authmode:%d", authmode);
+    }
+
+exit:
+    if (ret != 0)
+    {
+#ifdef MBEDTLS_ERROR_C
+        char error_buf[100];
+
+        extern void mbedtls_strerror(int ret, char *buf, size_t buflen);
+        mbedtls_strerror(ret, error_buf, 100);
+        LOG_I("Last error was: %d - %s", ret, error_buf);
+#endif
+        LOG_I("ret=%d.", ret);
+        s->error = rws_error_new_code_descr(rws_error_code_connect_to_host, "Failed connect to host");
+        LOG_I("%s: code:%d, error:%s", __FUNCTION__, s->error->code, s->error->description);
+        s->command = COMMAND_INFORM_DISCONNECTED;
+
+        if (s->ssl)
+        {
+            mbedtls_net_free(&s->ssl->net_ctx);
+            mbedtls_x509_crt_free(&s->ssl->cacert);
+            mbedtls_x509_crt_free(&s->ssl->clicert);
+            mbedtls_pk_free(&s->ssl->pkey);
+            mbedtls_ssl_free(&s->ssl->ssl_ctx);
+            mbedtls_ssl_config_free(&s->ssl->ssl_conf);
+            mbedtls_ctr_drbg_free(&s->ssl->ctr_drbg);
+            mbedtls_entropy_free(&s->ssl->entropy);
+
+            rws_free(s->ssl);
+            s->ssl = NULL;
+        }
+
+        s->socket == RWS_INVALID_SOCKET;
+    }
+    else
+    {
+        s->command = COMMAND_SEND_HANDSHAKE;
+    }
+    return ret;
+}
+
+int rws_ssl_close(_rws_socket *s)
+{
+    _rws_ssl *ssl = s->ssl;
+
+    if (!ssl)
+        return -1;
+
+    mbedtls_ssl_close_notify(&ssl->ssl_ctx);
+    mbedtls_net_free(&ssl->net_ctx);
+    mbedtls_x509_crt_free(&ssl->cacert);
+    mbedtls_x509_crt_free(&ssl->clicert);
+    mbedtls_pk_free(&ssl->pkey);
+    mbedtls_ssl_free(&ssl->ssl_ctx);
+    mbedtls_ssl_config_free(&ssl->ssl_conf);
+    mbedtls_ctr_drbg_free(&ssl->ctr_drbg);
+    mbedtls_entropy_free(&ssl->entropy);
+
+    rws_free(ssl);
+    s->ssl = NULL;
+
+    return 0;
+}
+#endif

+ 428 - 0
librws/src/rws_socketpub.c

@@ -0,0 +1,428 @@
+/*
+ *   Copyright (c) 2014 - 2017 Kulykov Oleh <info@resident.name>
+ *
+ *   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.
+ */
+
+#include "librws.h"
+#include "rws_socket.h"
+#include "rws_memory.h"
+#include "rws_string.h"
+#include <assert.h>
+
+#if !defined(RWS_OS_WINDOWS)
+#include <signal.h>
+#endif
+
+// public
+rws_bool rws_socket_connect(rws_socket socket)
+{
+    _rws_socket *s = (_rws_socket *)socket;
+    const char *params_error_msg = NULL;
+    if (!s)
+    {
+        return rws_false;
+    }
+
+    rws_error_delete_clean(&s->error);
+
+    if (s->port <= 0)
+    {
+        params_error_msg = "No URL port provided";
+    }
+    if (!s->scheme)
+    {
+        params_error_msg = "No URL scheme provided";
+    }
+    if (!s->host)
+    {
+        params_error_msg = "No URL host provided";
+    }
+    if (!s->path)
+    {
+        params_error_msg = "No URL path provided";
+    }
+    if (!s->on_disconnected)
+    {
+        params_error_msg = "No on_disconnected callback provided";
+    }
+    s->received_len = 0;
+    if (params_error_msg)
+    {
+        s->error = rws_error_new_code_descr(rws_error_code_missed_parameter, params_error_msg);
+        return rws_false;
+    }
+    return rws_socket_create_start_work_thread(s);
+}
+
+void rws_socket_disconnect_and_release(rws_socket socket)
+{
+    _rws_socket *s = (_rws_socket *)socket;
+    if (!s)
+    {
+        return;
+    }
+
+    rws_mutex_lock(s->work_mutex);
+
+    rws_socket_delete_all_frames_in_list(s->send_frames);
+    rws_list_delete_clean(&s->send_frames);
+
+    if (s->is_connected)
+    {
+        // connected in loop
+        s->command = COMMAND_DISCONNECT;
+        rws_mutex_unlock(s->work_mutex);
+    }
+    else if (s->work_thread)
+    {
+        // disconnected in loop
+        s->command = COMMAND_END;
+        rws_mutex_unlock(s->work_mutex);
+    }
+    else if (s->command != COMMAND_END)
+    {
+        // not in loop
+        rws_mutex_unlock(s->work_mutex);
+        rws_socket_delete(s);
+    }
+}
+
+rws_bool rws_socket_send_text(rws_socket socket, const char *text)
+{
+    _rws_socket *s = (_rws_socket *)socket;
+    rws_bool r = rws_false;
+    if (s)
+    {
+        rws_mutex_lock(s->send_mutex);
+        r = rws_socket_send_text_priv(s, text);
+        rws_mutex_unlock(s->send_mutex);
+    }
+    return r;
+}
+
+rws_bool rws_socket_send_bin(rws_socket socket, void *data, size_t len, int opcode, rws_bool is_fin)
+{
+    //DBG("%s,%d", __FUNCTION__,__LINE__);
+
+    _rws_socket *s = (_rws_socket *)socket;
+    rws_bool r = rws_false;
+    if (!s) return r;
+    rws_mutex_lock(s->send_mutex);
+    r = rws_socket_send_bin_priv(s, data, len, opcode, is_fin);
+    rws_mutex_unlock(s->send_mutex);
+
+    return r;
+}
+
+#if !defined(RWS_OS_WINDOWS)
+void rws_socket_handle_sigpipe(int signal_number)
+{
+    printf("\nlibrws handle sigpipe %i", signal_number);
+    (void)signal_number;
+    return;
+}
+#endif
+
+#define STRING_I(s) #s
+#define TO_STRING(s) STRING_I(s)
+
+void rws_socket_check_info(const char *info)
+{
+    assert(info);
+    (void)info;
+}
+
+rws_socket rws_socket_create(void)
+{
+    _rws_socket *s = (_rws_socket *)rws_malloc_zero(sizeof(_rws_socket));
+    if (!s)
+    {
+        return NULL;
+    }
+
+    s->header_buff  = rws_malloc(RWS_RECEIVE_HEADER_BUFF_SIZE);
+    s->payload_buff = rws_malloc(RWS_RECEIVE_PAYLOAD_BUFF_SIZE);
+
+#if !defined(RWS_OS_WINDOWS)
+    signal(SIGPIPE, rws_socket_handle_sigpipe);
+#endif
+
+    s->port = -1;
+    s->socket = RWS_INVALID_SOCKET;
+    s->command = COMMAND_NONE;
+
+    s->work_mutex = rws_mutex_create_recursive();
+    s->send_mutex = rws_mutex_create_recursive();
+
+    static const char *info = "librws ver: " TO_STRING(RWS_VERSION_MAJOR) "." TO_STRING(RWS_VERSION_MINOR) "." TO_STRING(RWS_VERSION_PATCH) "\n";
+    rws_socket_check_info(info);
+
+    return s;
+}
+
+void rws_socket_delete(_rws_socket *s)
+{
+    rws_socket_close(s);
+
+    rws_string_delete_clean(&s->sec_ws_accept);
+
+    rws_free_clean(&s->received);
+    s->received_size = 0;
+    s->received_len = 0;
+
+    rws_socket_delete_all_frames_in_list(s->send_frames);
+    rws_list_delete_clean(&s->send_frames);
+    rws_socket_delete_all_frames_in_list(s->recvd_frames);
+    rws_list_delete_clean(&s->recvd_frames);
+
+    rws_string_delete_clean(&s->scheme);
+    rws_string_delete_clean(&s->host);
+    rws_string_delete_clean(&s->path);
+
+    rws_string_delete_clean(&s->sec_ws_accept);
+
+    rws_error_delete_clean(&s->error);
+
+    rws_free_clean(&s->received);
+    rws_socket_delete_all_frames_in_list(s->send_frames);
+    rws_list_delete_clean(&s->send_frames);
+    rws_socket_delete_all_frames_in_list(s->recvd_frames);
+    rws_list_delete_clean(&s->recvd_frames);
+
+    rws_mutex_delete(s->work_mutex);
+    rws_mutex_delete(s->send_mutex);
+
+    rws_free(s->header_buff);
+    rws_free(s->payload_buff);
+
+    rws_free(s);
+}
+
+void rws_socket_set_url(rws_socket socket,
+                        const char *scheme,
+                        const char *host,
+                        const int port,
+                        const char *path)
+{
+    _rws_socket *s = (_rws_socket *)socket;
+    if (s)
+    {
+        rws_string_delete(s->scheme);
+        s->scheme = rws_string_copy(scheme);
+
+        rws_string_delete(s->host);
+        s->host = rws_string_copy(host);
+
+        rws_string_delete(s->path);
+        s->path = rws_string_copy(path);
+
+        s->port = port;
+    }
+}
+
+void rws_socket_set_scheme(rws_socket socket, const char *scheme)
+{
+    _rws_socket *s = (_rws_socket *)socket;
+    if (s)
+    {
+        rws_string_delete(s->scheme);
+        s->scheme = rws_string_copy(scheme);
+    }
+}
+
+const char *rws_socket_get_scheme(rws_socket socket)
+{
+    _rws_socket *s = (_rws_socket *)socket;
+    return s ? s->scheme : NULL;
+}
+
+void rws_socket_set_host(rws_socket socket, const char *host)
+{
+    _rws_socket *s = (_rws_socket *)socket;
+    if (s)
+    {
+        rws_string_delete(s->host);
+        s->host = rws_string_copy(host);
+    }
+}
+
+const char *rws_socket_get_host(rws_socket socket)
+{
+    _rws_socket *s = (_rws_socket *)socket;
+    return s ? s->host : NULL;
+}
+
+void rws_socket_set_path(rws_socket socket, const char *path)
+{
+    _rws_socket *s = (_rws_socket *)socket;
+    if (s)
+    {
+        rws_string_delete(s->path);
+        s->path = rws_string_copy(path);
+    }
+}
+
+const char *rws_socket_get_path(rws_socket socket)
+{
+    _rws_socket *s = (_rws_socket *)socket;
+    return s ? s->path : NULL;
+}
+
+void rws_socket_set_port(rws_socket socket, const int port)
+{
+    _rws_socket *s = (_rws_socket *)socket;
+    if (s)
+    {
+        s->port = port;
+    }
+}
+
+int rws_socket_get_port(rws_socket socket)
+{
+    _rws_socket *s = (_rws_socket *)socket;
+    return s ? s->port : -1;
+}
+
+/*
+unsigned int _rws_socket_get_receive_buffer_size(rws_socket_t socket) {
+    unsigned int size = 0;
+#if defined(RWS_OS_WINDOWS)
+    int len = sizeof(unsigned int);
+    if (getsockopt(socket, SOL_SOCKET, SO_RCVBUF, (char *)&size, &len) == -1) {
+        size = 0;
+    }
+#else
+    socklen_t len = sizeof(unsigned int);
+    if (getsockopt(socket, SOL_SOCKET, SO_RCVBUF, &size, &len) == -1) {
+        size = 0;
+    }
+#endif
+    return size;
+}
+
+unsigned int rws_socket_get_receive_buffer_size(rws_socket socket) {
+    _rws_socket * s = (_rws_socket *)socket;
+    if (!s) {
+        return 0;
+    }
+    if (s->socket == RWS_INVALID_SOCKET) {
+        return 0;
+    }
+    return _rws_socket_get_receive_buffer_size(s->socket);
+}
+*/
+
+rws_error rws_socket_get_error(rws_socket socket)
+{
+    _rws_socket *s = (_rws_socket *)socket;
+    return s ? s->error : NULL;
+}
+
+void rws_socket_set_user_object(rws_socket socket, void *user_object)
+{
+    _rws_socket *s = (_rws_socket *)socket;
+    if (s)
+    {
+        s->user_object = user_object;
+    }
+}
+
+void *rws_socket_get_user_object(rws_socket socket)
+{
+    _rws_socket *s = (_rws_socket *)socket;
+    return s ? s->user_object : NULL;
+}
+
+void rws_socket_set_on_connected(rws_socket socket, rws_on_socket callback)
+{
+    _rws_socket *s = (_rws_socket *)socket;
+    if (s)
+    {
+        s->on_connected = callback;
+    }
+}
+
+void rws_socket_set_on_disconnected(rws_socket socket, rws_on_socket callback)
+{
+    _rws_socket *s = (_rws_socket *)socket;
+    if (s)
+    {
+        s->on_disconnected = callback;
+    }
+}
+
+void rws_socket_set_on_received_text(rws_socket socket, rws_on_socket_recvd_text callback)
+{
+    _rws_socket *s = (_rws_socket *)socket;
+    if (s)
+    {
+        s->on_recvd_text = callback;
+    }
+}
+
+void rws_socket_set_on_received_bin(rws_socket socket, rws_on_socket_recvd_bin callback)
+{
+    _rws_socket *s = (_rws_socket *)socket;
+    if (s)
+    {
+        s->on_recvd_bin = callback;
+    }
+}
+
+rws_bool rws_socket_is_connected(rws_socket socket)
+{
+    _rws_socket *s = (_rws_socket *)socket;
+    rws_bool r = rws_false;
+    if (s)
+    {
+        rws_mutex_lock(s->send_mutex);
+        r = s->is_connected;
+        rws_mutex_unlock(s->send_mutex);
+    }
+    return r;
+}
+
+#ifdef LIBRWS_USING_MBED_TLS
+void rws_socket_set_server_cert(rws_socket socket, const char *server_cert, int server_cert_len)
+{
+    LOG_D("[T:%.8d, L:%.5d, %*.*s] cert:\n%s", rt_tick_get(), __LINE__, DBG_FUNCTION_NUM, DBG_FUNCTION_NUM, __FUNCTION__, server_cert_len, server_cert ? server_cert : "");
+
+    _rws_socket *s = (_rws_socket *)socket;
+    if (s)
+    {
+        s->server_cert = server_cert;
+        s->server_cert_len = server_cert_len;
+    }
+}
+#endif
+
+/* RT-Thread Team add */
+void rws_socket_set_custom_mode(rws_socket socket)
+{
+    LOG_I("[%s:%d, tick:%d] start.", __FUNCTION__, __LINE__, rt_tick_get());
+
+    _rws_socket *s = (_rws_socket *)socket;
+    if (s)
+    {
+        s->custom_mode = 0x1234;
+    }
+
+    LOG_I("[%s:%d, tick:%d] end.", __FUNCTION__, __LINE__, rt_tick_get());
+}

+ 24 - 20
src/rws_string.c → librws/src/rws_string.c

@@ -1,5 +1,5 @@
 /*
 /*
- *   Copyright (c) 2014 - 2019 Oleh Kulykov <info@resident.name>
+ *   Copyright (c) 2014 - 2017 Kulykov Oleh <info@resident.name>
  *
  *
  *   Permission is hereby granted, free of charge, to any person obtaining a copy
  *   Permission is hereby granted, free of charge, to any person obtaining a copy
  *   of this software and associated documentation files (the "Software"), to deal
  *   of this software and associated documentation files (the "Software"), to deal
@@ -20,32 +20,36 @@
  *   THE SOFTWARE.
  *   THE SOFTWARE.
  */
  */
 
 
-
 #include "rws_string.h"
 #include "rws_string.h"
 #include "rws_memory.h"
 #include "rws_memory.h"
 
 
-char * rws_string_copy(const char * str) {
-	return str ? rws_string_copy_len(str, strlen(str)) : NULL;
+char *rws_string_copy(const char *str)
+{
+    return str ? rws_string_copy_len(str, strlen(str)) : NULL;
 }
 }
 
 
-char * rws_string_copy_len(const char * str, const size_t len) {
-	char * s = (str && len > 0) ? (char *)rws_malloc(len + 1) : NULL;
-	if (s) {
-		memcpy(s, str, len);
-		s[len] = 0;
-		return s;
-	}
-	return NULL;
+char *rws_string_copy_len(const char *str, const size_t len)
+{
+    char *s = (str && len > 0) ? (char *)rws_malloc(len + 1) : NULL;
+    if (s)
+    {
+        memcpy(s, str, len);
+        s[len] = 0;
+        return s;
+    }
+    return NULL;
 }
 }
 
 
-void rws_string_delete(char * str) {
-	rws_free(str);
+void rws_string_delete(char *str)
+{
+    rws_free(str);
 }
 }
 
 
-void rws_string_delete_clean(char ** str) {
-	if (str) {
-		rws_free(*str);
-		*str = NULL;
-	}
+void rws_string_delete_clean(char **str)
+{
+    if (str)
+    {
+        rws_free(*str);
+        *str = NULL;
+    }
 }
 }
-

+ 242 - 0
librws/src/rws_thread.c

@@ -0,0 +1,242 @@
+/*
+ *   Copyright (c) 2014 - 2017 Kulykov Oleh <info@resident.name>
+ *
+ *   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.
+ */
+
+#include "librws.h"
+#include "rws_thread.h"
+#include "rws_memory.h"
+#include "rws_common.h"
+
+#include <assert.h>
+
+#if defined(RWS_OS_WINDOWS)
+#include <windows.h>
+#else
+#include <pthread.h>
+#include <unistd.h>
+#endif
+#include "rtthread.h"
+
+typedef struct _rws_thread_struct
+{
+    rws_thread_funct thread_function;
+    void *user_object;
+#if defined(RWS_OS_WINDOWS)
+    HANDLE thread;
+#else
+    pthread_t thread;
+#endif
+} _rws_thread;
+
+typedef struct _rws_threads_joiner_struct
+{
+    _rws_thread *thread;
+    rws_mutex mutex;
+} _rws_threads_joiner;
+
+static _rws_threads_joiner *_threads_joiner = NULL;
+
+static void rws_threads_joiner_clean(void)
+{
+    // private
+    _rws_thread *t = _threads_joiner->thread;
+
+#if defined(RWS_OS_WINDOWS)
+    DWORD dwExitCode = 0;
+#else
+    void *r = NULL;
+#endif
+
+    if (!t)
+    {
+        return;
+    }
+    _threads_joiner->thread = NULL;
+
+#if defined(RWS_OS_WINDOWS)
+    do
+    {
+        if (GetExitCodeThread(t->thread, &dwExitCode) == 0)
+        {
+            break; // fail
+        }
+    }
+    while (dwExitCode == STILL_ACTIVE);
+
+    if (dwExitCode == STILL_ACTIVE)
+    {
+        TerminateThread(t->thread, 0);
+    }
+
+    if (CloseHandle(t->thread))
+    {
+        t->thread = NULL;
+    }
+#else
+    pthread_join(t->thread, &r);
+    assert(r == NULL);
+#endif
+
+    rws_free(t);
+}
+
+static void rws_threads_joiner_add(_rws_thread *thread)
+{
+    // public
+    rws_mutex_lock(_threads_joiner->mutex);
+    rws_threads_joiner_clean();
+    _threads_joiner->thread = thread;
+    rws_mutex_unlock(_threads_joiner->mutex);
+}
+
+static void rws_threads_joiner_create_ifneed(void)
+{
+    if (_threads_joiner)
+    {
+        return;
+    }
+    _threads_joiner = (_rws_threads_joiner *)rws_malloc_zero(sizeof(_rws_threads_joiner));
+    _threads_joiner->mutex = rws_mutex_create_recursive();
+}
+
+#if defined(RWS_OS_WINDOWS)
+static DWORD WINAPI rws_thread_func_priv(LPVOID some_pointer)
+{
+#else
+static void *rws_thread_func_priv(void *some_pointer)
+{
+#endif
+    _rws_thread *t = (_rws_thread *)some_pointer;
+    t->thread_function(t->user_object);
+    rws_threads_joiner_add(t);
+
+#if defined(RWS_OS_WINDOWS)
+    return 0;
+#else
+    return NULL;
+#endif
+}
+
+rws_thread rws_thread_create(rws_thread_funct thread_function, void *user_object)
+{
+    _rws_thread *t = NULL;
+    int res = -1;
+#if !defined(RWS_OS_WINDOWS)
+    pthread_attr_t attr;
+#endif
+
+    if (!thread_function)
+    {
+        return NULL;
+    }
+    rws_threads_joiner_create_ifneed();
+    t = (_rws_thread *)rws_malloc_zero(sizeof(_rws_thread));
+    t->user_object = user_object;
+    t->thread_function = thread_function;
+#if defined(RWS_OS_WINDOWS)
+    t->thread = CreateThread(NULL, 0, &rws_thread_func_priv, (LPVOID)t, 0, NULL);
+    assert(t->thread);
+#else
+    if (pthread_attr_init(&attr) == 0)
+    {
+        if (pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM) == 0)
+        {
+            if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) == 0)
+            {
+                attr.stack_size = 1024 * 8;
+                res = pthread_create(&t->thread, &attr, &rws_thread_func_priv, (void *)t);
+            }
+        }
+        pthread_attr_destroy(&attr);
+    }
+    assert(res == 0);
+#endif
+    return t;
+}
+
+void rws_thread_sleep(const unsigned int millisec)
+{
+#if defined(RWS_OS_WINDOWS)
+    Sleep(millisec); // 1s = 1'000 millisec.
+#else
+    rt_thread_mdelay(millisec);
+#endif
+}
+
+rws_mutex rws_mutex_create_recursive(void)
+{
+#if defined(RWS_OS_WINDOWS)
+    CRITICAL_SECTION *mutex = (CRITICAL_SECTION *)rws_malloc_zero(sizeof(CRITICAL_SECTION));
+    InitializeCriticalSection((LPCRITICAL_SECTION)mutex);
+    return mutex;
+#else
+    pthread_mutex_t *mutex = (pthread_mutex_t *)rws_malloc_zero(sizeof(pthread_mutex_t));
+    int res = -1;
+    pthread_mutexattr_t attr;
+    if (pthread_mutexattr_init(&attr) == 0)
+    {
+        if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) == 0)
+        {
+            res = pthread_mutex_init(mutex, &attr);
+        }
+        pthread_mutexattr_destroy(&attr);
+    }
+    assert(res == 0);
+    return mutex;
+#endif
+}
+
+void rws_mutex_lock(rws_mutex mutex)
+{
+    if (mutex)
+    {
+#if defined(RWS_OS_WINDOWS)
+        EnterCriticalSection((LPCRITICAL_SECTION)mutex);
+#else
+        pthread_mutex_lock((pthread_mutex_t *)mutex);
+#endif
+    }
+}
+
+void rws_mutex_unlock(rws_mutex mutex)
+{
+    if (mutex)
+    {
+#if defined(RWS_OS_WINDOWS)
+        LeaveCriticalSection((LPCRITICAL_SECTION)mutex);
+#else
+        pthread_mutex_unlock((pthread_mutex_t *)mutex);
+#endif
+    }
+}
+
+void rws_mutex_delete(rws_mutex mutex)
+{
+    if (mutex)
+    {
+#if defined(RWS_OS_WINDOWS)
+        DeleteCriticalSection((LPCRITICAL_SECTION)mutex);
+#else
+        pthread_mutex_destroy((pthread_mutex_t *)mutex);
+#endif
+        rws_free(mutex);
+    }
+}

+ 0 - 68
src/rws_error.c

@@ -1,68 +0,0 @@
-/*
- *   Copyright (c) 2014 - 2019 Oleh Kulykov <info@resident.name>
- *
- *   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.
- */
-
-
-#include "../librws.h"
-#include "rws_error.h"
-#include "rws_string.h"
-#include "rws_memory.h"
-
-
-// private
-rws_error rws_error_create(void) {
-	return (rws_error)rws_malloc_zero(sizeof(struct rws_error_struct));
-}
-
-rws_error rws_error_new_code_descr(const int code, const char * description) {
-	rws_error e = (rws_error)rws_malloc_zero(sizeof(struct rws_error_struct));
-	e->code = code;
-	e->description = rws_string_copy(description);
-	return e;
-}
-
-void rws_error_delete(rws_error error) {
-	if (error) {
-		rws_string_delete(error->description);
-		rws_free(error);
-	}
-}
-
-void rws_error_delete_clean(rws_error * error) {
-	if (error) {
-		rws_error_delete(*error);
-		*error = NULL;
-	}
-}
-
-// public
-int rws_error_get_code(rws_error error) {
-	return error ? error->code : 0;
-}
-
-int rws_error_get_http_error(rws_error error) {
-	return error ? error->http_error : 0;
-}
-
-const char * rws_error_get_description(rws_error error) {
-	return error ? error->description : NULL;
-}
-

+ 0 - 266
src/rws_frame.c

@@ -1,266 +0,0 @@
-/*
- *   Copyright (c) 2014 - 2019 Oleh Kulykov <info@resident.name>
- *
- *   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.
- */
-
-
-#include "rws_frame.h"
-#include "rws_memory.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <time.h>
-
-_rws_frame * rws_frame_create_with_recv_data(const void * data, const size_t data_size) {
-	if (data && data_size >= 2) {
-		const unsigned char * udata = (const unsigned char *)data;
-		
-		const rws_opcode opcode = (rws_opcode)(udata[0] & 0x0f);
-		const unsigned int is_finshd = (udata[0] >> 7) & 0x01;
-		const unsigned int is_masked = (udata[1] >> 7) & 0x01;
-		const unsigned int payload = udata[1] & 0x7f;
-		unsigned int header_size = is_masked ? 6 : 2;
-		
-		unsigned int expected_size = 0, mask_pos = 0;
-		size_t index = 0;
-		_rws_frame * frame = NULL;
-		const unsigned char * actual_udata = NULL;
-		unsigned char * unmasked = NULL;
-		
-		switch (payload) {
-			case 126: header_size += 2; break;
-			case 127: header_size += 8; break;
-			default: break;
-		}
-		
-		if (data_size < header_size) {
-			return NULL;
-		}
-		
-		switch (payload) {
-			case 126:
-				expected_size |= ((unsigned int)udata[2]) << 8;
-				expected_size |= (unsigned int)udata[3];
-				mask_pos = 4;
-				break;
-				
-			case 127:
-				expected_size |= ((unsigned int)udata[6]) << 24;
-				expected_size |= ((unsigned int)udata[7]) << 16;
-				expected_size |= ((unsigned int)udata[8]) << 8;
-				expected_size |= (unsigned int)udata[9];
-				mask_pos = 10;
-				break;
-				
-			default:
-				if (payload <= 125) {
-					mask_pos = 2;
-					expected_size = payload;
-				}
-				break;
-		}
-		
-		frame = rws_frame_create();
-		
-		frame->opcode = opcode;
-		if (is_finshd) frame->is_finished = rws_true;
-		frame->header_size = (unsigned char)header_size;
-		
-		if (is_masked) {
-			frame->is_masked = rws_true;
-			memcpy(frame->mask, &udata[mask_pos], 4);
-		}
-		
-		if (opcode == rws_opcode_connection_close || opcode == rws_opcode_pong) {
-			return frame;
-		}
-		
-		if (!is_finshd) {
-			frame->is_finished = rws_false;
-		}
-		
-		if (expected_size > 0) {
-			frame->data = rws_malloc(expected_size);
-			frame->data_size = expected_size;
-			actual_udata = udata + header_size;
-			if (is_masked) {
-				unmasked = (unsigned char *)frame->data;
-				for (index = 0; index < expected_size; index++) {
-					*unmasked = *actual_udata ^ frame->mask[index & 0x3];
-					unmasked++; actual_udata++;
-				}
-			} else {
-				memcpy(frame->data, actual_udata, expected_size);
-			}
-		}
-		return frame;
-	}
-	return NULL;
-}
-
-void rws_frame_create_header(_rws_frame * f, unsigned char * header, const size_t data_size) {
-	const unsigned int size = (unsigned int)data_size;
-	
-	*header++ = 0x80 | f->opcode;
-	if (size < 126) {
-		*header++ = (size & 0xff) | (f->is_masked ? 0x80 : 0);
-		f->header_size = 2;
-	} else if (size < 65536) {
-		*header++ = 126 | (f->is_masked ? 0x80 : 0);
-		*header++ = (size >> 8) & 0xff;
-		*header++ = size & 0xff;
-		f->header_size = 4;
-	} else {
-		*header++ = 127 | (f->is_masked ? 0x80 : 0);
-		
-		*(unsigned int *)header = 0;
-		header += 4;
-		
-		*header++ = (size >> 24) & 0xff;
-		*header++ = (size >> 16) & 0xff;
-		*header++ = (size >> 8) & 0xff;
-		*header++ = size & 0xff;
-		f->header_size = 10;
-	}
-	
-	if (f->is_masked) {
-		memcpy(header, f->mask, 4);
-		f->header_size += 4;
-	}
-}
-
-void rws_frame_fill_with_send_data(_rws_frame * f, const void * data, const size_t data_size) {
-	unsigned char header[16];
-	unsigned char * frame = NULL;
-	unsigned char mask[4];
-	size_t index = 0;
-	
-	rws_frame_create_header(f, header, data_size);
-	f->data_size = data_size + f->header_size;
-	f->data = rws_malloc(f->data_size);
-	frame = (unsigned char *)f->data;
-	memcpy(frame, header, f->header_size);
-	
-	if (data) { // have data to send
-		frame += f->header_size;
-		memcpy(frame, data, data_size);
-		
-		if (f->is_masked) {
-			memcpy(mask, &f->mask, 4);
-			for (index = 0; index < data_size; index++) {
-				*frame = *frame ^ mask[index & 0x3];
-				frame++;
-			}
-		}
-	}
-	f->is_finished = rws_true;
-}
-
-void rws_frame_combine_datas(_rws_frame * to, _rws_frame * from) {
-	unsigned char * comb_data = (unsigned char *)rws_malloc(to->data_size + from->data_size);
-	if (comb_data) {
-		if (to->data && to->data_size) {
-			memcpy(comb_data, to->data, to->data_size);
-		}
-		comb_data += to->data_size;
-		if (from->data && from->data_size) {
-			memcpy(comb_data, from->data, from->data_size);
-		}
-	}
-	rws_free(to->data);
-	to->data = comb_data;
-	to->data_size += from->data_size;
-}
-
-_rws_frame * rws_frame_create(void) {
-	_rws_frame * f = (_rws_frame *)rws_malloc_zero(sizeof(_rws_frame));
-	union {
-		unsigned int ui;
-		unsigned char b[4];
-	} mask_union;
-	assert(sizeof(unsigned int) == 4);
-	//	mask_union.ui = 2018915346;
-	mask_union.ui = (rand() / (RAND_MAX / 2) + 1) * rand();
-	memcpy(f->mask, mask_union.b, 4);
-	return f;
-}
-
-void rws_frame_delete(_rws_frame * f) {
-	if (f) {
-		rws_free(f->data);
-		rws_free(f);
-	}
-}
-
-void rws_frame_delete_clean(_rws_frame ** f) {
-	if (f) {
-		rws_frame_delete(*f);
-		*f = NULL;
-	}
-}
-
-size_t rws_check_recv_frame_size(const void * data, const size_t data_size) {
-	if (data && data_size >= 2) {
-		const unsigned char * udata = (const unsigned char *)data;
-		//        const unsigned int is_finshd = (udata[0] >> 7) & 0x01;
-		const unsigned int is_masked = (udata[1] >> 7) & 0x01;
-		const unsigned int payload = udata[1] & 0x7f;
-		unsigned int header_size = is_masked ? 6 : 2;
-		
-		unsigned int expected_size = 0;
-		
-		switch (payload) {
-			case 126: header_size += 2; break;
-			case 127: header_size += 8; break;
-			default: break;
-		}
-		
-		if (data_size < header_size) {
-			return 0;
-		}
-		
-		switch (payload) {
-			case 126:
-				expected_size |= ((unsigned int)udata[2]) << 8;
-				expected_size |= (unsigned int)udata[3];
-				break;
-				
-			case 127:
-				expected_size |= ((unsigned int)udata[6]) << 24;
-				expected_size |= ((unsigned int)udata[7]) << 16;
-				expected_size |= ((unsigned int)udata[8]) << 8;
-				expected_size |= (unsigned int)udata[9];
-				break;
-				
-			default:
-				if (payload <= 125) {
-					expected_size = payload;
-				}
-				break;
-		}
-		
-		const unsigned int nPackSize = expected_size + header_size;
-		return (nPackSize <= data_size) ? nPackSize : 0;
-	}
-	return 0;
-}
-
-

+ 0 - 65
src/rws_frame.h

@@ -1,65 +0,0 @@
-/*
- *   Copyright (c) 2014 - 2019 Oleh Kulykov <info@resident.name>
- *
- *   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.
- */
-
-
-#ifndef __RWS_FRAME_H__
-#define __RWS_FRAME_H__ 1
-
-#include "../librws.h"
-#include "rws_common.h"
-
-typedef enum _rws_opcode {
-	rws_opcode_continuation = 0x0, // %x0 denotes a continuation frame
-	rws_opcode_text_frame = 0x1, // %x1 denotes a text frame
-	rws_opcode_binary_frame = 0x2, // %x2 denotes a binary frame
-	rws_opcode_connection_close = 0x8, // %x8 denotes a connection close
-	rws_opcode_ping = 0x9, // %x9 denotes a ping
-	rws_opcode_pong = 0xA // %xA denotes a pong
-} rws_opcode;
-
-typedef struct _rws_frame_struct {
-	void * data;
-	size_t data_size;
-	rws_opcode opcode;
-	unsigned char mask[4];
-	rws_bool is_masked;
-	rws_bool is_finished;
-	unsigned char header_size;
-} _rws_frame;
-
-size_t rws_check_recv_frame_size(const void * data, const size_t data_size);
-
-_rws_frame * rws_frame_create_with_recv_data(const void * data, const size_t data_size);
-
-// data - should be null, and setted by newly created. 'data' & 'data_size' can be null
-void rws_frame_fill_with_send_data(_rws_frame * f, const void * data, const size_t data_size);
-
-// combine datas of 2 frames. combined is 'to'
-void rws_frame_combine_datas(_rws_frame * to, _rws_frame * from);
-
-_rws_frame * rws_frame_create(void);
-
-void rws_frame_delete(_rws_frame * f);
-
-void rws_frame_delete_clean(_rws_frame ** f);
-
-#endif

+ 0 - 169
src/rws_socket.h

@@ -1,169 +0,0 @@
-/*
- *   Copyright (c) 2014 - 2019 Oleh Kulykov <info@resident.name>
- *
- *   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.
- */
-
-
-#ifndef __RWS_SOCKET_H__
-#define __RWS_SOCKET_H__ 1
-
-#include "rws_common.h"
-
-#if defined(RWS_OS_WINDOWS)
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#else
-#include <netdb.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <netinet/tcp.h>
-#include <fcntl.h>
-#include <unistd.h>
-#endif
-
-#include <assert.h>
-#include <errno.h>
-
-#include "rws_error.h"
-#include "rws_thread.h"
-#include "rws_frame.h"
-#include "rws_list.h"
-
-#if defined(RWS_OS_WINDOWS)
-typedef SOCKET rws_socket_t;
-#define RWS_INVALID_SOCKET INVALID_SOCKET
-#define RWS_SOCK_CLOSE(sock) closesocket(sock)
-#else
-typedef int rws_socket_t;
-#define RWS_INVALID_SOCKET -1
-#define RWS_SOCK_CLOSE(sock) close(sock)
-#endif
-
-static const char * k_rws_socket_min_http_ver = "1.1";
-static const char * k_rws_socket_sec_websocket_accept = "Sec-WebSocket-Accept";
-
-struct rws_socket_struct {
-	int port;
-	rws_socket_t socket;
-	char * scheme;
-	char * host;
-	char * path;
-
-	char * sec_ws_accept; // "Sec-WebSocket-Accept" field from handshake
-
-	rws_thread work_thread;
-
-	int command;
-
-	unsigned int next_message_id;
-
-	rws_bool is_connected; // sock connected + handshake done
-
-	void * user_object;
-	rws_on_socket on_connected;
-	rws_on_socket on_disconnected;
-	rws_on_socket_recvd_text on_recvd_text;
-	rws_on_socket_recvd_bin on_recvd_bin;
-
-	void * received;
-	size_t received_size; // size of 'received' memory
-	size_t received_len; // length of actualy readed message
-
-	_rws_list * send_frames;
-	_rws_list * recvd_frames;
-
-	rws_error error;
-
-	rws_mutex work_mutex;
-	rws_mutex send_mutex;
-};
-
-rws_bool rws_socket_process_handshake_responce(rws_socket s);
-
-// receive raw data from socket
-rws_bool rws_socket_recv(rws_socket s);
-
-// send raw data to socket
-rws_bool rws_socket_send(rws_socket s, const void * data, const size_t data_size);
-
-_rws_frame * rws_socket_last_unfin_recvd_frame_by_opcode(rws_socket s, const rws_opcode opcode);
-
-void rws_socket_process_bin_or_text_frame(rws_socket s, _rws_frame * frame);
-
-void rws_socket_process_ping_frame(rws_socket s, _rws_frame * frame);
-
-void rws_socket_process_conn_close_frame(rws_socket s, _rws_frame * frame);
-
-void rws_socket_process_received_frame(rws_socket s, _rws_frame * frame);
-
-void rws_socket_idle_recv(rws_socket s);
-
-void rws_socket_idle_send(rws_socket s);
-
-void rws_socket_wait_handshake_responce(rws_socket s);
-
-unsigned int rws_socket_get_next_message_id(rws_socket s);
-
-void rws_socket_send_ping(rws_socket s);
-
-void rws_socket_send_disconnect(rws_socket s);
-
-void rws_socket_send_handshake(rws_socket s);
-
-struct addrinfo * rws_socket_connect_getaddr_info(rws_socket s);
-
-void rws_socket_connect_to_host(rws_socket s);
-
-rws_bool rws_socket_create_start_work_thread(rws_socket s);
-
-void rws_socket_close(rws_socket s);
-
-void rws_socket_resize_received(rws_socket s, const size_t size);
-
-void rws_socket_append_recvd_frames(rws_socket s, _rws_frame * frame);
-
-void rws_socket_append_send_frames(rws_socket s, _rws_frame * frame);
-
-rws_bool rws_socket_send_text_priv(rws_socket s, const char * text);
-
-void rws_socket_inform_recvd_frames(rws_socket s);
-
-void rws_socket_set_option(rws_socket_t s, int option, int value);
-
-void rws_socket_delete_all_frames_in_list(_rws_list * list_with_frames);
-
-void rws_socket_check_write_error(rws_socket s, int error_num);
-
-void rws_socket_delete(rws_socket s);
-
-#define COMMAND_IDLE -1
-#define COMMAND_NONE 0
-#define COMMAND_CONNECT_TO_HOST 1
-#define COMMAND_SEND_HANDSHAKE 2
-#define COMMAND_WAIT_HANDSHAKE_RESPONCE 3
-#define COMMAND_INFORM_CONNECTED 4
-#define COMMAND_INFORM_DISCONNECTED 5
-#define COMMAND_DISCONNECT 6
-
-#define COMMAND_END 9999
-
-
-
-#endif

+ 0 - 725
src/rws_socketpriv.c

@@ -1,725 +0,0 @@
-/*
- *   Copyright (c) 2014 - 2019 Oleh Kulykov <info@resident.name>
- *
- *   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.
- */
-
-
-#include "../librws.h"
-#include "rws_socket.h"
-#include "rws_memory.h"
-#include "rws_string.h"
-
-#define RWS_CONNECT_RETRY_DELAY 200
-#define RWS_CONNECT_ATTEMPS 5
-
-#ifndef  RWS_OS_WINDOWS 
-#define	WSAEWOULDBLOCK  EAGAIN	
-#define	WSAEINPROGRESS     EINPROGRESS	
-#endif
-
-unsigned int rws_socket_get_next_message_id(rws_socket s) {
-	const unsigned int mess_id = ++s->next_message_id;
-	if (mess_id > 9999999) {
-		s->next_message_id = 0;
-	}
-	return mess_id;
-}
-
-void rws_socket_send_ping(rws_socket s) {
-	char buff[16];
-	size_t len = 0;
-	_rws_frame * frame = rws_frame_create();
-
-	len = rws_sprintf(buff, 16, "%u", rws_socket_get_next_message_id(s));
-
-	frame->is_masked = rws_true;
-	frame->opcode = rws_opcode_ping;
-	rws_frame_fill_with_send_data(frame, buff, len);
-	rws_socket_append_send_frames(s, frame);
-}
-
-void rws_socket_inform_recvd_frames(rws_socket s) {
-	rws_bool is_all_finished = rws_true;
-	_rws_frame * frame = NULL;
-	_rws_node * cur = s->recvd_frames;
-	while (cur) {
-		frame = (_rws_frame *)cur->value.object;
-		if (frame) {
-			if (frame->is_finished) {
-				switch (frame->opcode) {
-					case rws_opcode_text_frame:
-						if (s->on_recvd_text) {
-							s->on_recvd_text(s, (const char *)frame->data, (unsigned int)frame->data_size);
-						}
-						break;
-					case rws_opcode_binary_frame:
-						if (s->on_recvd_bin) {
-							s->on_recvd_bin(s, frame->data, (unsigned int)frame->data_size);
-						}
-						break;
-					default: break;
-				}
-				rws_frame_delete(frame);
-				cur->value.object = NULL;
-			} else {
-				is_all_finished = rws_false;
-			}
-		}
-		cur = cur->next;
-	}
-	if (is_all_finished) {
-		rws_list_delete_clean(&s->recvd_frames);
-	}
-}
-
-void rws_socket_read_handshake_responce_value(const char * str, char ** value) {
-	const char * s = NULL;
-	size_t len = 0;
-
-	while (*str == ':' || *str == ' ') {
-		str++;
-	}
-	s = str;
-	while (*s != '\r' && *s != '\n') {
-		s++;
-		len++;
-	}
-	if (len > 0) {
-		*value = rws_string_copy_len(str, len);
-	}
-}
-
-rws_bool rws_socket_process_handshake_responce(rws_socket s) {
-	const char * str = (const char *)s->received;
-	const char * sub = NULL;
-	float http_ver = -1;
-	int http_code = -1;
-
-	rws_error_delete_clean(&s->error);
-	sub = strstr(str, "HTTP/");
-	if (!sub) {
-		return rws_false;
-	}
-	
-	sub += 5;
-	if (rws_sscanf(sub, "%f %i", &http_ver, &http_code) != 2) {
-		http_ver = -1;
-		http_code = -1;
-	}
-
-	sub = strstr(str, k_rws_socket_sec_websocket_accept); // "Sec-WebSocket-Accept"
-	if (sub) {
-		sub += strlen(k_rws_socket_sec_websocket_accept);
-		rws_socket_read_handshake_responce_value(sub, &s->sec_ws_accept);
-	}
-
-	if (http_code != 101 || !s->sec_ws_accept) {
-		s->error = rws_error_new_code_descr(rws_error_code_parse_handshake,
-											(http_code != 101) ? "HTPP code not found or non 101" : "Accept key not found");
-		return rws_false;
-	}
-	return rws_true;
-}
-
-// need close socket on error
-rws_bool rws_socket_send(rws_socket s, const void * data, const size_t data_size) {
-	int sended = -1, error_number = -1;
-	rws_error_delete_clean(&s->error);
-
-	//errno = -1;
-#if defined(RWS_OS_WINDOWS)
-	sended = send(s->socket, (const char *)data, data_size, 0);
-    error_number = WSAGetLastError();
-#else
-	sended = (int)send(s->socket, data, (int)data_size, 0);
-    error_number = errno;
-#endif
-
-
-	if (sended > 0) {
-		return rws_true;
-	}
-
-	rws_socket_check_write_error(s, error_number);
-	if (s->error) {
-		rws_socket_close(s);
-		return rws_false;
-	}
-	return rws_true;
-}
-
-rws_bool rws_socket_recv(rws_socket s) {
-	int is_reading = 1, error_number = -1, len = -1;
-	char * received = NULL;
-	size_t total_len = 0;
-	char buff[8192];
-	rws_error_delete_clean(&s->error);
-	while (is_reading) {
-		len = (int)recv(s->socket, buff, 8192, 0);
-#if defined(RWS_OS_WINDOWS)
-		error_number = WSAGetLastError();
-#else
-		error_number = errno;
-#endif
-		if (len > 0) {
-			total_len += len;
-			if (s->received_size - s->received_len < len) {
-				rws_socket_resize_received(s, s->received_size + len);
-			}
-			received = (char *)s->received;
-			if (s->received_len) {
-				received += s->received_len;
-			}
-			memcpy(received, buff, len);
-			s->received_len += len;
-		} else {
-			is_reading = 0;
-		}
-	}
-	//if (error_number < 0) return rws_true;
-	if (error_number != WSAEWOULDBLOCK && error_number != WSAEINPROGRESS) {
-		s->error = rws_error_new_code_descr(rws_error_code_read_write_socket, "Failed read/write socket");
-		rws_socket_close(s);
-		return rws_false;
-	}
-	return rws_true;
-}
-
-_rws_frame * rws_socket_last_unfin_recvd_frame_by_opcode(rws_socket s, const rws_opcode opcode) {
-	_rws_frame * last = NULL;
-	_rws_frame * frame = NULL;
-	_rws_node * cur = s->recvd_frames;
-	while (cur) {
-		frame = (_rws_frame *)cur->value.object;
-		if (frame) {
-            //  [FIN=0,opcode !=0 ],[FIN=0,opcode ==0 ],....[FIN=1,opcode ==0 ]
-			if (!frame->is_finished /*&& frame->opcode == opcode*/) {
-				last = frame;
-			}
-		}
-		cur = cur->next;
-	}
-	return last;
-}
-
-void rws_socket_process_bin_or_text_frame(rws_socket s, _rws_frame * frame) {
-	_rws_frame * last_unfin = rws_socket_last_unfin_recvd_frame_by_opcode(s, frame->opcode);
-	if (last_unfin) {
-		rws_frame_combine_datas(last_unfin, frame);
-		last_unfin->is_finished = frame->is_finished;
-		rws_frame_delete(frame);
-	} else if (frame->data && frame->data_size) {
-		rws_socket_append_recvd_frames(s, frame);
-	} else {
-		rws_frame_delete(frame);
-	}
-}
-
-void rws_socket_process_ping_frame(rws_socket s, _rws_frame * frame) {
-	_rws_frame * pong_frame = rws_frame_create();
-	pong_frame->opcode = rws_opcode_pong;
-	pong_frame->is_masked = rws_true;
-	rws_frame_fill_with_send_data(pong_frame, frame->data, frame->data_size);
-	rws_frame_delete(frame);
-	rws_socket_append_send_frames(s, pong_frame);
-}
-
-void rws_socket_process_conn_close_frame(rws_socket s, _rws_frame * frame) {
-	s->command = COMMAND_INFORM_DISCONNECTED;
-	s->error = rws_error_new_code_descr(rws_error_code_connection_closed, "Connection was closed by endpoint");
-	//rws_socket_close(s);
-	rws_frame_delete(frame);
-}
-
-void rws_socket_process_received_frame(rws_socket s, _rws_frame * frame) {
-	switch (frame->opcode) {
-		case rws_opcode_ping: rws_socket_process_ping_frame(s, frame); break;
-		case rws_opcode_text_frame:
-		case rws_opcode_binary_frame:
-		case rws_opcode_continuation:
-			rws_socket_process_bin_or_text_frame(s, frame);
-			break;
-		case rws_opcode_connection_close: rws_socket_process_conn_close_frame(s, frame); break;
-		default:
-			// unprocessed => delete
-			rws_frame_delete(frame);
-			break;
-	}
-}
-
-void rws_socket_idle_recv(rws_socket s) {
-	_rws_frame * frame = NULL;
-
-	if (!rws_socket_recv(s)) {
-		// sock already closed
-		if (s->error) {
-			s->command = COMMAND_INFORM_DISCONNECTED;
-		}
-		return;
-	}
-
-   const size_t nframe_size = rws_check_recv_frame_size(s->received, s->received_len);
-   if (nframe_size) {
-       frame = rws_frame_create_with_recv_data(s->received, nframe_size);
-       if (frame)  {
-           rws_socket_process_received_frame(s, frame);
-       }
-	   
-       if (nframe_size == s->received_len) {
-           s->received_len = 0;
-       } else if (s->received_len > nframe_size) {
-           const size_t nLeftLen = s->received_len - nframe_size;
-           memmove((char*)s->received, (char*)s->received + nframe_size, nLeftLen);
-           s->received_len = nLeftLen;
-       }
-   }
-}
-
-void rws_socket_idle_send(rws_socket s) {
-	_rws_node * cur = NULL;
-	rws_bool sending = rws_true;
-	_rws_frame * frame = NULL;
-
-	rws_mutex_lock(s->send_mutex);
-	cur = s->send_frames;
-	if (cur) {
-		while (cur && s->is_connected && sending) {
-			frame = (_rws_frame *)cur->value.object;
-			cur->value.object = NULL;
-			if (frame) {
-				sending = rws_socket_send(s, frame->data, frame->data_size);
-			}
-			rws_frame_delete(frame);
-			cur = cur->next;
-		}
-		rws_list_delete_clean(&s->send_frames);
-		if (s->error) {
-			s->command = COMMAND_INFORM_DISCONNECTED;
-		}
-	}
-	rws_mutex_unlock(s->send_mutex);
-}
-
-void rws_socket_wait_handshake_responce(rws_socket s) {
-	if (!rws_socket_recv(s)) {
-		// sock already closed
-		if (s->error) {
-			s->command = COMMAND_INFORM_DISCONNECTED;
-		}
-		return;
-	}
-	
-	if (s->received_len == 0) {
-		return;
-	}
-
-	if (rws_socket_process_handshake_responce(s)) {
-        s->received_len = 0;
-		s->is_connected = rws_true;
-		s->command = COMMAND_INFORM_CONNECTED;
-	} else {
-		rws_socket_close(s);
-		s->command = COMMAND_INFORM_DISCONNECTED;
-	}
-}
-
-void rws_socket_send_disconnect(rws_socket s) {
-	char buff[16];
-	size_t len = 0;
-	_rws_frame * frame = rws_frame_create();
-
-	len = rws_sprintf(buff, 16, "%u", rws_socket_get_next_message_id(s));
-
-	frame->is_masked = rws_true;
-	frame->opcode = rws_opcode_connection_close;
-	rws_frame_fill_with_send_data(frame, buff, len);
-	rws_socket_send(s, frame->data, frame->data_size);
-	rws_frame_delete(frame);
-	s->command = COMMAND_END;
-	rws_thread_sleep(RWS_CONNECT_RETRY_DELAY); // little bit wait after send message
-}
-
-void rws_socket_send_handshake(rws_socket s) {
-	char buff[512];
-	char * ptr = buff;
-	size_t writed = 0;
-	writed = rws_sprintf(ptr, 512, "GET %s HTTP/%s\r\n", s->path, k_rws_socket_min_http_ver);
-
-	if (s->port == 80) {
-		writed += rws_sprintf(ptr + writed, 512 - writed, "Host: %s\r\n", s->host);
-	} else {
-		writed += rws_sprintf(ptr + writed, 512 - writed, "Host: %s:%i\r\n", s->host, s->port);
-	}
-
-	writed += rws_sprintf(ptr + writed, 512 - writed,
-						  "Upgrade: websocket\r\n"
-						  "Connection: Upgrade\r\n"
-						  "Origin: %s://%s\r\n",
-						  s->scheme, s->host);
-
-	writed += rws_sprintf(ptr + writed, 512 - writed,
-						  "Sec-WebSocket-Key: %s\r\n"
-						  "Sec-WebSocket-Protocol: chat, superchat\r\n"
-						  "Sec-WebSocket-Version: 13\r\n"
-						  "\r\n",
-						  "dGhlIHNhbXBsZSBub25jZQ==");
-
-	if (rws_socket_send(s, buff, writed)) {
-		s->command = COMMAND_WAIT_HANDSHAKE_RESPONCE;
-	} else {
-		if (s->error) {
-			s->error->code = rws_error_code_send_handshake;
-		} else {
-			s->error = rws_error_new_code_descr(rws_error_code_send_handshake, "Send handshake");
-		}
-		rws_socket_close(s);
-		s->command = COMMAND_INFORM_DISCONNECTED;
-	}
-}
-
-struct addrinfo * rws_socket_connect_getaddr_info(rws_socket s) {
-	struct addrinfo hints;
-	char portstr[16];
-	struct addrinfo * result = NULL;
-	int ret = 0, retry_number = 0, last_ret = 0;
-#if defined(RWS_OS_WINDOWS)
-	WSADATA wsa;
-#endif
-
-	rws_error_delete_clean(&s->error);
-
-#if defined(RWS_OS_WINDOWS)
-	memset(&wsa, 0, sizeof(WSADATA));
-	if (WSAStartup(MAKEWORD(2,2), &wsa) != 0) {
-		s->error = rws_error_new_code_descr(rws_error_code_connect_to_host, "Failed initialise winsock");
-		s->command = COMMAND_INFORM_DISCONNECTED;
-		return NULL;
-	}
-#endif
-
-	rws_sprintf(portstr, 16, "%i", s->port);
-	while (++retry_number < RWS_CONNECT_ATTEMPS) {
-		result = NULL;
-		memset(&hints, 0, sizeof(hints));
-		hints.ai_family = AF_UNSPEC;
-		hints.ai_socktype = SOCK_STREAM;
-
-		ret = getaddrinfo(s->host, portstr, &hints, &result);
-		if (ret == 0 && result) {
-			return result;
-		}
-
-		if (ret != 0) {
-			last_ret = ret;
-		}
-		
-		if (result) {
-			freeaddrinfo(result);
-		}
-		
-		rws_thread_sleep(RWS_CONNECT_RETRY_DELAY);
-	}
-
-#if defined(RWS_OS_WINDOWS)
-	WSACleanup();
-#endif
-
-	s->error = rws_error_new_code_descr(rws_error_code_connect_to_host,
-										(last_ret > 0) ? gai_strerror(last_ret) : "Failed connect to host");
-	s->command = COMMAND_INFORM_DISCONNECTED;
-	return NULL;
-}
-
-void rws_socket_connect_to_host(rws_socket s) {
-	struct addrinfo * result = NULL;
-	struct addrinfo * p = NULL;
-	rws_socket_t sock = RWS_INVALID_SOCKET;
-	int retry_number = 0;
-#if defined(RWS_OS_WINDOWS)
-	unsigned long iMode = 0;
-#endif
-
-	result = rws_socket_connect_getaddr_info(s);
-	if (!result) {
-		return;
-	}
-
-	while ((++retry_number < RWS_CONNECT_ATTEMPS) && (sock == RWS_INVALID_SOCKET)) {
-		for (p = result; p != NULL; p = p->ai_next) {
-			sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
-			if (sock != RWS_INVALID_SOCKET) {
-				rws_socket_set_option(sock, SO_ERROR, 1); // When an error occurs on a socket, set error variable so_error and notify process
-				rws_socket_set_option(sock, SO_KEEPALIVE, 1); // Periodically test if connection is alive
-
-				if (connect(sock, p->ai_addr, p->ai_addrlen) == 0) {
-                    s->received_len = 0;
-					s->socket = sock;
-#if defined(RWS_OS_WINDOWS)
-					// If iMode != 0, non-blocking mode is enabled.
-					iMode = 1;
-					ioctlsocket(s->socket, FIONBIO, &iMode);
-#else
-					fcntl(s->socket, F_SETFL, O_NONBLOCK);
-#endif
-					break;
-				}
-				RWS_SOCK_CLOSE(sock);
-			}
-		}
-		if (sock == RWS_INVALID_SOCKET) {
-			rws_thread_sleep(RWS_CONNECT_RETRY_DELAY);
-		}
-	}
-
-	freeaddrinfo(result);
-
-	if (s->socket == RWS_INVALID_SOCKET) {
-#if defined(RWS_OS_WINDOWS)
-		WSACleanup();
-#endif
-		s->error = rws_error_new_code_descr(rws_error_code_connect_to_host, "Failed connect to host");
-		s->command = COMMAND_INFORM_DISCONNECTED;
-	} else {
-		s->command = COMMAND_SEND_HANDSHAKE;
-	}
-}
-
-static void rws_socket_work_th_func(void * user_object) {
-	rws_socket s = (rws_socket)user_object;
-	size_t loop_number = 0;
-	while (s->command < COMMAND_END) {
-		loop_number++;
-		rws_mutex_lock(s->work_mutex);
-		switch (s->command) {
-			case COMMAND_CONNECT_TO_HOST: rws_socket_connect_to_host(s); break;
-			case COMMAND_SEND_HANDSHAKE: rws_socket_send_handshake(s); break;
-			case COMMAND_WAIT_HANDSHAKE_RESPONCE: rws_socket_wait_handshake_responce(s); break;
-			case COMMAND_DISCONNECT: rws_socket_send_disconnect(s); break;
-			case COMMAND_IDLE:
-				if (loop_number >= 400) {
-					loop_number = 0;
-					
-					if (s->is_connected) {
-						rws_socket_send_ping(s);
-					}
-				}
-				
-				if (s->is_connected) {
-					rws_socket_idle_send(s);
-				}
-				
-				if (s->is_connected) {
-					rws_socket_idle_recv(s);
-				}
-				break;
-			default: break;
-		}
-		
-		rws_mutex_unlock(s->work_mutex);
-		
-		switch (s->command) {
-			case COMMAND_INFORM_CONNECTED:
-				s->command = COMMAND_IDLE;
-				if (s->on_connected) {
-					s->on_connected(s);
-				}
-				break;
-			case COMMAND_INFORM_DISCONNECTED: {
-                    s->command = COMMAND_END;
-                    rws_socket_send_disconnect(s);
-                    if (s->on_disconnected)  {
-                        s->on_disconnected(s);
-                    }
-                }
-				break;
-			case COMMAND_IDLE:
-				if (s->recvd_frames) {
-					rws_socket_inform_recvd_frames(s);
-				}
-				break;
-			default: break;
-		}
-		rws_thread_sleep(5);
-	}
-
-	rws_socket_close(s);
-	s->work_thread = NULL;
-	rws_socket_delete(s);
-}
-
-rws_bool rws_socket_create_start_work_thread(rws_socket s) {
-	rws_error_delete_clean(&s->error);
-	s->command = COMMAND_NONE;
-	s->work_thread = rws_thread_create(&rws_socket_work_th_func, s);
-	if (s->work_thread) {
-		s->command = COMMAND_CONNECT_TO_HOST;
-		return rws_true;
-	}
-	return rws_false;
-}
-
-void rws_socket_resize_received(rws_socket s, const size_t size) {
-	void * res = NULL;
-	size_t min = 0;
-	if (size == s->received_size) {
-		return;
-	}
-
-	res = rws_malloc(size);
-	assert(res && (size > 0));
-
-	min = (s->received_size < size) ? s->received_size : size;
-	if (min > 0 && s->received) {
-		memcpy(res, s->received, min);
-	}
-	rws_free_clean(&s->received);
-	s->received = res;
-	s->received_size = size;
-}
-
-void rws_socket_close(rws_socket s) {
-    s->received_len = 0;
-	if (s->socket != RWS_INVALID_SOCKET) {
-		RWS_SOCK_CLOSE(s->socket);
-		s->socket = RWS_INVALID_SOCKET;
-#if defined(RWS_OS_WINDOWS)
-		WSACleanup();
-#endif
-	}
-	s->is_connected = rws_false;
-}
-
-void rws_socket_append_recvd_frames(rws_socket s, _rws_frame * frame) {
-	_rws_node_value frame_list_var;
-	frame_list_var.object = frame;
-	if (s->recvd_frames) {
-		rws_list_append(s->recvd_frames, frame_list_var);
-	} else {
-		s->recvd_frames = rws_list_create();
-		s->recvd_frames->value = frame_list_var;
-	}
-}
-
-void rws_socket_append_send_frames(rws_socket s, _rws_frame * frame) {
-	_rws_node_value frame_list_var;
-	frame_list_var.object = frame;
-	if (s->send_frames) {
-		rws_list_append(s->send_frames, frame_list_var);
-	} else {
-		s->send_frames = rws_list_create();
-		s->send_frames->value = frame_list_var;
-	}
-}
-
-rws_bool rws_socket_send_text_priv(rws_socket s, const char * text) {
-	size_t len = text ? strlen(text) : 0;
-	_rws_frame * frame = NULL;
-
-	if (len <= 0) {
-		return rws_false;
-	}
-
-	frame = rws_frame_create();
-	frame->is_masked = rws_true;
-	frame->opcode = rws_opcode_text_frame;
-	rws_frame_fill_with_send_data(frame, text, len);
-	rws_socket_append_send_frames(s, frame);
-
-	return rws_true;
-}
-
-void rws_socket_delete_all_frames_in_list(_rws_list * list_with_frames) {
-	_rws_frame * frame = NULL;
-	_rws_node * cur = list_with_frames;
-	while (cur) {
-		frame = (_rws_frame *)cur->value.object;
-		if (frame) {
-			rws_frame_delete(frame);
-		}
-		cur->value.object = NULL;
-	}
-}
-
-void rws_socket_set_option(rws_socket_t s, int option, int value) {
-	setsockopt(s, SOL_SOCKET, option, (char *)&value, sizeof(int));
-}
-
-void rws_socket_check_write_error(rws_socket s, int error_num) {
-#if defined(RWS_OS_WINDOWS)
-	int socket_code = 0, code = 0;
-	unsigned int socket_code_size = sizeof(int);
-#else
-	int socket_code = 0, code = 0;
-	socklen_t socket_code_size = sizeof(socket_code);
-#endif
-
-	if (s->socket != RWS_INVALID_SOCKET) {
-#if defined(RWS_OS_WINDOWS)
-		if (getsockopt(s->socket, SOL_SOCKET, SO_ERROR, (char *)&socket_code, (int*)&socket_code_size) != 0) {
-			socket_code = 0;
-		}
-#else
-		if (getsockopt(s->socket, SOL_SOCKET, SO_ERROR, &socket_code, &socket_code_size) != 0) {
-			socket_code = 0;
-		}
-#endif
-	}
-
-	code = (socket_code > 0) ? socket_code : error_num;
-	if (code <= 0) {
-		return;
-	}
-	
-	switch (code) {
-		// send errors
-		case EACCES: //
-
-//		case EAGAIN: // The socket is marked nonblocking and the requested operation would block
-//		case EWOULDBLOCK: // The socket is marked nonblocking and the receive operation would block
-
-		case EBADF: // An invalid descriptor was specified
-		case ECONNRESET: // Connection reset by peer
-		case EDESTADDRREQ: // The socket is not connection-mode, and no peer address is set
-		case EFAULT: // An invalid user space address was specified for an argument
-					// The receive buffer pointer(s) point outside the process's address space.
-		case EINTR: // A signal occurred before any data was transmitted
-					// The receive was interrupted by delivery of a signal before any data were available
-		case EINVAL: // Invalid argument passed
-		case EISCONN: // The connection-mode socket was connected already but a recipient was specified
-		case EMSGSIZE: // The socket type requires that message be sent atomically, and the size of the message to be sent made this impossible
-		case ENOBUFS: // The output queue for a network interface was full
-		case ENOMEM: // No memory available
-		case ENOTCONN: // The socket is not connected, and no target has been given
-						// The socket is associated with a connection-oriented protocol and has not been connected
-		case ENOTSOCK: // The argument sockfd is not a socket
-					// The argument sockfd does not refer to a socket
-		case EOPNOTSUPP: // Some bit in the flags argument is inappropriate for the socket type.
-		case EPIPE: // The local end has been shut down on a connection oriented socket
-		// recv errors
-		case ECONNREFUSED: // A remote host refused to allow the network connection (typically because it is not running the requested service).
-
-			s->error = rws_error_new_code_descr(rws_error_code_read_write_socket, rws_strerror(code));
-			break;
-
-		default:
-			break;
-	}
-}
-

+ 0 - 310
src/rws_socketpub.c

@@ -1,310 +0,0 @@
-/*
- *   Copyright (c) 2014 - 2019 Oleh Kulykov <info@resident.name>
- *
- *   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.
- */
-
-
-#include "../librws.h"
-#include "rws_socket.h"
-#include "rws_memory.h"
-#include "rws_string.h"
-#include <assert.h>
-
-#if !defined(RWS_OS_WINDOWS)
-#include <signal.h>
-#endif
-
-// public
-rws_bool rws_socket_connect(rws_socket socket) {
-	const char * params_error_msg = NULL;
-	if (!socket) {
-		return rws_false;
-	}
-
-	rws_error_delete_clean(&socket->error);
-
-	if (socket->port <= 0) {
-		params_error_msg = "No URL port provided";
-	}
-	if (!socket->scheme) {
-		params_error_msg = "No URL scheme provided";
-	}
-	if (!socket->host) {
-		params_error_msg = "No URL host provided";
-	}
-	if (!socket->path) {
-		params_error_msg = "No URL path provided";
-	}
-	if (!socket->on_disconnected) {
-		params_error_msg = "No on_disconnected callback provided";
-	}
-    socket->received_len = 0;
-	if (params_error_msg) {
-		socket->error = rws_error_new_code_descr(rws_error_code_missed_parameter, params_error_msg);
-		return rws_false;
-	}
-	return rws_socket_create_start_work_thread(socket);
-}
-
-void rws_socket_disconnect_and_release(rws_socket socket) {
-	if (!socket) {
-		return;
-	}
-	
-	rws_mutex_lock(socket->work_mutex);
-
-	rws_socket_delete_all_frames_in_list(socket->send_frames);
-	rws_list_delete_clean(&socket->send_frames);
-
-	if (socket->is_connected) { // connected in loop
-		socket->command = COMMAND_DISCONNECT;
-		rws_mutex_unlock(socket->work_mutex);
-	} else if (socket->work_thread) { // disconnected in loop
-		socket->command = COMMAND_END;
-		rws_mutex_unlock(socket->work_mutex);
-	} else if (socket->command != COMMAND_END) {
-		// not in loop
-		rws_mutex_unlock(socket->work_mutex);
-		rws_socket_delete(socket);
-	}
-}
-
-rws_bool rws_socket_send_text(rws_socket socket, const char * text) {
-	rws_bool r = rws_false;
-	if (socket) {
-		rws_mutex_lock(socket->send_mutex);
-		r = rws_socket_send_text_priv(socket, text);
-		rws_mutex_unlock(socket->send_mutex);
-	}
-	return r;
-}
-
-#if !defined(RWS_OS_WINDOWS)
-void rws_socket_handle_sigpipe(int signal_number) {
-	printf("\nlibrws handle sigpipe %i", signal_number);
-	(void)signal_number;
-	return;
-}
-#endif
-
-#define STRING_I(s) #s
-#define TO_STRING(s) STRING_I(s)
-
-void rws_socket_check_info(const char * info) {
-	assert(info);
-	(void)info;
-}
-
-rws_socket rws_socket_create(void) {
-	rws_socket s = (rws_socket)rws_malloc_zero(sizeof(struct rws_socket_struct));
-	if (!s) {
-		return NULL;
-	}
-
-#if !defined(RWS_OS_WINDOWS)
-	signal(SIGPIPE, rws_socket_handle_sigpipe);
-#endif
-
-	s->port = -1;
-	s->socket = RWS_INVALID_SOCKET;
-	s->command = COMMAND_NONE;
-
-	s->work_mutex = rws_mutex_create_recursive();
-	s->send_mutex = rws_mutex_create_recursive();
-
-	static const char * info = "librws ver: " TO_STRING(RWS_VERSION_MAJOR) "." TO_STRING(RWS_VERSION_MINOR) "." TO_STRING(RWS_VERSION_PATCH) "\n";
-	rws_socket_check_info(info);
-
-	return s;
-}
-
-void rws_socket_delete(rws_socket s) {
-	rws_socket_close(s);
-
-	rws_string_delete_clean(&s->sec_ws_accept);
-
-	rws_free_clean(&s->received);
-	s->received_size = 0;
-	s->received_len = 0;
-
-	rws_socket_delete_all_frames_in_list(s->send_frames);
-	rws_list_delete_clean(&s->send_frames);
-	rws_socket_delete_all_frames_in_list(s->recvd_frames);
-	rws_list_delete_clean(&s->recvd_frames);
-
-	rws_string_delete_clean(&s->scheme);
-	rws_string_delete_clean(&s->host);
-	rws_string_delete_clean(&s->path);
-
-	rws_string_delete_clean(&s->sec_ws_accept);
-
-	rws_error_delete_clean(&s->error);
-
-	rws_free_clean(&s->received);
-	rws_socket_delete_all_frames_in_list(s->send_frames);
-	rws_list_delete_clean(&s->send_frames);
-	rws_socket_delete_all_frames_in_list(s->recvd_frames);
-	rws_list_delete_clean(&s->recvd_frames);
-
-	rws_mutex_delete(s->work_mutex);
-	rws_mutex_delete(s->send_mutex);
-
-	rws_free(s);
-}
-
-void rws_socket_set_url(rws_socket socket,
-						const char * scheme,
-						const char * host,
-						const int port,
-						const char * path) {
-	if (socket) {
-		rws_string_delete(socket->scheme);
-		socket->scheme = rws_string_copy(scheme);
-		
-		rws_string_delete(socket->host);
-		socket->host = rws_string_copy(host);
-		
-		rws_string_delete(socket->path);
-		socket->path = rws_string_copy(path);
-		
-		socket->port = port;
-	}
-}
-
-void rws_socket_set_scheme(rws_socket socket, const char * scheme) {
-	if (socket) {
-		rws_string_delete(socket->scheme);
-		socket->scheme = rws_string_copy(scheme);
-	}
-}
-
-const char * rws_socket_get_scheme(rws_socket socket) {
-	return socket ? socket->scheme : NULL;
-}
-
-void rws_socket_set_host(rws_socket socket, const char * host) {
-	if (socket) {
-		rws_string_delete(socket->host);
-		socket->host = rws_string_copy(host);
-	}
-}
-
-const char * rws_socket_get_host(rws_socket socket) {
-	return socket ? socket->host : NULL;
-}
-
-void rws_socket_set_path(rws_socket socket, const char * path) {
-	if (socket) {
-		rws_string_delete(socket->path);
-		socket->path = rws_string_copy(path);
-	}
-}
-
-const char * rws_socket_get_path(rws_socket socket) {
-	return socket ? socket->path : NULL;
-}
-
-void rws_socket_set_port(rws_socket socket, const int port) {
-	if (socket) {
-		socket->port = port;
-	}
-}
-
-int rws_socket_get_port(rws_socket socket) {
-	return socket ? socket->port : -1;
-}
-
-/*
-unsigned int _rws_socket_get_receive_buffer_size(rws_socket_t socket) {
-	unsigned int size = 0;
-#if defined(RWS_OS_WINDOWS)
-	int len = sizeof(unsigned int);
-	if (getsockopt(socket, SOL_SOCKET, SO_RCVBUF, (char *)&size, &len) == -1) { 
-		size = 0;
-	}
-#else
-	socklen_t len = sizeof(unsigned int);
-	if (getsockopt(socket, SOL_SOCKET, SO_RCVBUF, &size, &len) == -1) { 
-		size = 0; 
-	}
-#endif
-	return size;
-}
-
-unsigned int rws_socket_get_receive_buffer_size(rws_socket socket) {
-	_rws_socket * s = (_rws_socket *)socket;
-	if (!s) { 
-		return 0; 
-	}
-	if (s->socket == RWS_INVALID_SOCKET) { 
-		return 0; 
-	}
-	return _rws_socket_get_receive_buffer_size(s->socket);
-}
-*/
-
-rws_error rws_socket_get_error(rws_socket socket) {
-	return socket ? socket->error : NULL;
-}
-
-void rws_socket_set_user_object(rws_socket socket, void * user_object) {
-	if (socket) {
-		socket->user_object = user_object;
-	}
-}
-
-void * rws_socket_get_user_object(rws_socket socket) {
-	return socket ? socket->user_object : NULL;
-}
-
-void rws_socket_set_on_connected(rws_socket socket, rws_on_socket callback) {
-	if (socket) {
-		socket->on_connected = callback;
-	}
-}
-
-void rws_socket_set_on_disconnected(rws_socket socket, rws_on_socket callback) {
-	if (socket) {
-		socket->on_disconnected = callback;
-	}
-}
-
-void rws_socket_set_on_received_text(rws_socket socket, rws_on_socket_recvd_text callback) {
-	if (socket) {
-		socket->on_recvd_text = callback;
-	}
-}
-
-void rws_socket_set_on_received_bin(rws_socket socket, rws_on_socket_recvd_bin callback) {
-	if (socket) {
-		socket->on_recvd_bin = callback;
-	}
-}
-
-rws_bool rws_socket_is_connected(rws_socket socket) {
-	rws_bool r = rws_false;
-	if (socket) {
-		rws_mutex_lock(socket->send_mutex);
-		r = socket->is_connected;
-		rws_mutex_unlock(socket->send_mutex);
-	}
-	return r;
-}
-

+ 0 - 206
src/rws_thread.c

@@ -1,206 +0,0 @@
-/*
- *   Copyright (c) 2014 - 2019 Oleh Kulykov <info@resident.name>
- *
- *   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.
- */
-
-
-#include "../librws.h"
-#include "rws_thread.h"
-#include "rws_memory.h"
-#include "rws_common.h"
-
-#include <assert.h>
-
-#if defined(RWS_OS_WINDOWS)
-#include <windows.h>
-#else
-#include <pthread.h>
-#include <unistd.h>
-#endif
-
-struct rws_thread_struct {
-	rws_thread_funct thread_function;
-	void * user_object;
-#if defined(RWS_OS_WINDOWS)
-	HANDLE thread;
-#else
-	pthread_t thread;
-#endif
-};
-
-typedef struct _rws_threads_joiner_struct {
-	rws_thread thread;
-	rws_mutex mutex;
-} _rws_threads_joiner;
-
-static _rws_threads_joiner * _threads_joiner = NULL;
-static void rws_threads_joiner_clean(void) { // private
-	rws_thread t = _threads_joiner->thread;
-#if defined(RWS_OS_WINDOWS)
-	DWORD dwExitCode = 0;
-#else
-	void * r = NULL;
-#endif
-
-	if (!t) {
-		return;
-	}
-	_threads_joiner->thread = NULL;
-
-#if defined(RWS_OS_WINDOWS)
-	do {
-		if (GetExitCodeThread(t->thread, &dwExitCode) == 0) {
-			break; // fail
-		}
-	} while (dwExitCode == STILL_ACTIVE);
-	if (dwExitCode == STILL_ACTIVE) {
-		TerminateThread(t->thread, 0);
-	}
-	if (CloseHandle(t->thread)) {
-		t->thread = NULL;
-	}
-#else
-	pthread_join(t->thread, &r);
-	assert(r == NULL);
-#endif
-	rws_free(t);
-}
-
-static void rws_threads_joiner_add(rws_thread thread) { // public
-	rws_mutex_lock(_threads_joiner->mutex);
-	rws_threads_joiner_clean();
-	_threads_joiner->thread = thread;
-	rws_mutex_unlock(_threads_joiner->mutex);
-}
-
-static void rws_threads_joiner_create_ifneed(void) {
-	if (_threads_joiner) {
-		return;
-	}
-	_threads_joiner = (_rws_threads_joiner *)rws_malloc_zero(sizeof(_rws_threads_joiner));
-	_threads_joiner->mutex = rws_mutex_create_recursive();
-}
-
-#if defined(RWS_OS_WINDOWS)
-static DWORD WINAPI rws_thread_func_priv(LPVOID some_pointer) {
-#else
-static void * rws_thread_func_priv(void * some_pointer) {
-#endif
-	rws_thread t = (rws_thread)some_pointer;
-	t->thread_function(t->user_object);
-	rws_threads_joiner_add(t);
-
-#if  defined(RWS_OS_WINDOWS)
-	return 0;
-#else
-	return NULL;
-#endif
-}
-
-rws_thread rws_thread_create(rws_thread_funct thread_function, void * user_object) {
-	rws_thread t = NULL;
-	int res = -1;
-#if !defined(RWS_OS_WINDOWS)
-	pthread_attr_t attr;
-#endif
-
-	if (!thread_function) {
-		return NULL;
-	}
-	rws_threads_joiner_create_ifneed();
-	t = (rws_thread)rws_malloc_zero(sizeof(struct rws_thread_struct));
-	t->user_object = user_object;
-	t->thread_function = thread_function;
-#if defined(RWS_OS_WINDOWS)
-	t->thread = CreateThread(NULL, 0, &rws_thread_func_priv, (LPVOID)t, 0, NULL);
-	assert(t->thread);
-#else
-	if (pthread_attr_init(&attr) == 0) {
-		if (pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM) == 0) {
-			if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) == 0) {
-				res = pthread_create(&t->thread, &attr, &rws_thread_func_priv, (void *)t);
-			}
-		}
-		pthread_attr_destroy(&attr);
-	}
-	assert(res == 0);
-#endif
-	return t;
-}
-
-void rws_thread_sleep(const unsigned int millisec) {
-#if defined(RWS_OS_WINDOWS)
-	Sleep(millisec); // 1s = 1'000 millisec.
-#else
-	usleep(millisec * 1000); // 1s = 1'000'000 microsec.
-#endif
-}
-
-rws_mutex rws_mutex_create_recursive(void) {
-#if defined(RWS_OS_WINDOWS)
-	CRITICAL_SECTION * mutex = (CRITICAL_SECTION *)rws_malloc_zero(sizeof(CRITICAL_SECTION));
-	InitializeCriticalSection((LPCRITICAL_SECTION)mutex);
-	return mutex;
-#else
-	pthread_mutex_t * mutex = (pthread_mutex_t *)rws_malloc_zero(sizeof(pthread_mutex_t));
-	int res = -1;
-	pthread_mutexattr_t attr;
-	if (pthread_mutexattr_init(&attr) == 0) {
-		if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) == 0) {
-			res = pthread_mutex_init(mutex, &attr);
-		}
-		pthread_mutexattr_destroy(&attr);
-	}
-	assert(res == 0);
-	return mutex;
-#endif
-}
-
-void rws_mutex_lock(rws_mutex mutex) {
-	if (mutex) {
-#if defined(RWS_OS_WINDOWS)
-		EnterCriticalSection((LPCRITICAL_SECTION)mutex);
-#else
-		pthread_mutex_lock((pthread_mutex_t *)mutex);
-#endif
-	}
-}
-
-void rws_mutex_unlock(rws_mutex mutex) {
-	if (mutex) {
-#if defined(RWS_OS_WINDOWS)
-		LeaveCriticalSection((LPCRITICAL_SECTION)mutex);
-#else
-		pthread_mutex_unlock((pthread_mutex_t *)mutex);
-#endif
-	}
-}
-
-void rws_mutex_delete(rws_mutex mutex) {
-	if (mutex) {
-#if defined(RWS_OS_WINDOWS)
-		DeleteCriticalSection((LPCRITICAL_SECTION)mutex);
-#else
-		pthread_mutex_destroy((pthread_mutex_t *)mutex);
-#endif
-		rws_free(mutex);
-	}
-}
-

+ 0 - 60
test/CMakeLists.txt

@@ -1,60 +0,0 @@
-#
-#   Copyright (c) 2014 - 2016 Kulykov Oleh <info@resident.name>
-#
-#   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.
-#
-
-include(CheckLibraryExists)
-
-include_directories(${PROJECT_BINARY_DIR})
-
-link_directories(${PROJECT_BINARY_DIR})
-
-remove_definitions(-DCMAKE_BUILD)
-
-if (RWS_OPT_APPVEYOR_CI)
-	add_definitions(-DRWS_APPVEYOR_CI)
-endif()
-
-add_executable(test_librws_creation test_librws_creation.c)
-#set_property(TARGET test_librws_creation APPEND PROPERTY COMPILE_FLAGS -DLIBRWS_STATIC)
-target_link_libraries(test_librws_creation rws)
-add_test(test_librws_creation test_librws_creation)
-
-
-add_executable(test_librws_socket_get_set test_librws_socket_get_set.c)
-#set_property(TARGET test_librws_socket_get_set APPEND PROPERTY COMPILE_FLAGS -DLIBRWS_STATIC)
-target_link_libraries(test_librws_socket_get_set rws)
-add_test(test_librws_socket_get_set test_librws_socket_get_set)
-
-
-if(RWS_HAVE_PTHREAD_H)
-	target_link_libraries(test_librws_creation pthread)
-	target_link_libraries(test_librws_socket_get_set pthread)
-endif(RWS_HAVE_PTHREAD_H)
-
-if(MINGW)
-	target_link_libraries(test_librws_creation ws2_32)
-	target_link_libraries(test_librws_socket_get_set ws2_32)
-endif(MINGW)
-
-
-install(TARGETS test_librws_creation DESTINATION bin)
-install(TARGETS test_librws_socket_get_set DESTINATION bin)
-

+ 0 - 548
test/librws_test.xcodeproj/project.pbxproj

@@ -1,548 +0,0 @@
-// !$*UTF8*$!
-{
-	archiveVersion = 1;
-	classes = {
-	};
-	objectVersion = 46;
-	objects = {
-
-/* Begin PBXBuildFile section */
-		3D1B9EEF1C5F03810021C58B /* RWSSocketObjc.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D1B9EEE1C5F03810021C58B /* RWSSocketObjc.m */; };
-		3D1B9EF01C5F03840021C58B /* RWSSocketObjc.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D1B9EEE1C5F03810021C58B /* RWSSocketObjc.m */; };
-		3D1B9EF21C5F04BA0021C58B /* ObjcContrib.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D1B9EF11C5F04BA0021C58B /* ObjcContrib.m */; };
-		3D8A11A51C4E9C130005F9B9 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D8A11A41C4E9C130005F9B9 /* main.m */; };
-		3D8A11A81C4E9C130005F9B9 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D8A11A71C4E9C130005F9B9 /* AppDelegate.m */; };
-		3D8A11AB1C4E9C130005F9B9 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D8A11AA1C4E9C130005F9B9 /* ViewController.m */; };
-		3D8A11AE1C4E9C130005F9B9 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3D8A11AC1C4E9C130005F9B9 /* Main.storyboard */; };
-		3D8A11B01C4E9C130005F9B9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3D8A11AF1C4E9C130005F9B9 /* Assets.xcassets */; };
-		3D8A11B31C4E9C130005F9B9 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3D8A11B11C4E9C130005F9B9 /* LaunchScreen.storyboard */; };
-		3D8A11CB1C4E9CAE0005F9B9 /* librws.c in Sources */ = {isa = PBXBuildFile; fileRef = 3D8A11C91C4E9CAE0005F9B9 /* librws.c */; };
-		3DD7B9431C8F6D43002AF61A /* rws_list.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DD7B9411C8F6D43002AF61A /* rws_list.c */; };
-		3DD7B9441C8F6D43002AF61A /* rws_list.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DD7B9411C8F6D43002AF61A /* rws_list.c */; };
-		3DD7B9471C8F6D4D002AF61A /* rws_thread.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DD7B9451C8F6D4D002AF61A /* rws_thread.c */; };
-		3DD7B9481C8F6D4D002AF61A /* rws_thread.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DD7B9451C8F6D4D002AF61A /* rws_thread.c */; };
-		3DD7B94B1C8F6D58002AF61A /* rws_error.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DD7B9491C8F6D58002AF61A /* rws_error.c */; };
-		3DD7B94C1C8F6D58002AF61A /* rws_error.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DD7B9491C8F6D58002AF61A /* rws_error.c */; };
-		3DD7B94F1C8F6D61002AF61A /* rws_memory.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DD7B94D1C8F6D61002AF61A /* rws_memory.c */; };
-		3DD7B9501C8F6D61002AF61A /* rws_memory.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DD7B94D1C8F6D61002AF61A /* rws_memory.c */; };
-		3DD7B9531C8F6D6C002AF61A /* rws_common.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DD7B9511C8F6D6C002AF61A /* rws_common.c */; };
-		3DD7B9541C8F6D6C002AF61A /* rws_common.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DD7B9511C8F6D6C002AF61A /* rws_common.c */; };
-		3DD7B9581C8F6D7D002AF61A /* rws_socketpriv.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DD7B9561C8F6D7D002AF61A /* rws_socketpriv.c */; };
-		3DD7B9591C8F6D7D002AF61A /* rws_socketpriv.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DD7B9561C8F6D7D002AF61A /* rws_socketpriv.c */; };
-		3DD7B95A1C8F6D7D002AF61A /* rws_socketpub.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DD7B9571C8F6D7D002AF61A /* rws_socketpub.c */; };
-		3DD7B95B1C8F6D7D002AF61A /* rws_socketpub.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DD7B9571C8F6D7D002AF61A /* rws_socketpub.c */; };
-		3DD7B95E1C8F6D85002AF61A /* rws_string.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DD7B95C1C8F6D85002AF61A /* rws_string.c */; };
-		3DD7B95F1C8F6D85002AF61A /* rws_string.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DD7B95C1C8F6D85002AF61A /* rws_string.c */; };
-		3DD7B9621C8F6D8C002AF61A /* rws_frame.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DD7B9601C8F6D8C002AF61A /* rws_frame.c */; };
-		3DD7B9631C8F6D8C002AF61A /* rws_frame.c in Sources */ = {isa = PBXBuildFile; fileRef = 3DD7B9601C8F6D8C002AF61A /* rws_frame.c */; };
-		3DE1B2721C58E67A00966F56 /* creation.m in Sources */ = {isa = PBXBuildFile; fileRef = 3DE1B2711C58E67A00966F56 /* creation.m */; };
-		3DE1B2731C58E6AD00966F56 /* librws.c in Sources */ = {isa = PBXBuildFile; fileRef = 3D8A11C91C4E9CAE0005F9B9 /* librws.c */; };
-		3DE1B27E1C58E85300966F56 /* getterAndSetters.m in Sources */ = {isa = PBXBuildFile; fileRef = 3DE1B27D1C58E85300966F56 /* getterAndSetters.m */; };
-		3DE1B2801C58ECCE00966F56 /* connection.m in Sources */ = {isa = PBXBuildFile; fileRef = 3DE1B27F1C58ECCE00966F56 /* connection.m */; };
-/* End PBXBuildFile section */
-
-/* Begin PBXContainerItemProxy section */
-		3D8A11BA1C4E9C140005F9B9 /* PBXContainerItemProxy */ = {
-			isa = PBXContainerItemProxy;
-			containerPortal = 3D8A11981C4E9C130005F9B9 /* Project object */;
-			proxyType = 1;
-			remoteGlobalIDString = 3D8A119F1C4E9C130005F9B9;
-			remoteInfo = librws_test;
-		};
-/* End PBXContainerItemProxy section */
-
-/* Begin PBXFileReference section */
-		3D1B9EED1C5F03810021C58B /* RWSSocketObjc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RWSSocketObjc.h; path = ../contrib/objc/RWSSocketObjc.h; sourceTree = "<group>"; };
-		3D1B9EEE1C5F03810021C58B /* RWSSocketObjc.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RWSSocketObjc.m; path = ../contrib/objc/RWSSocketObjc.m; sourceTree = "<group>"; };
-		3D1B9EF11C5F04BA0021C58B /* ObjcContrib.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjcContrib.m; sourceTree = "<group>"; };
-		3D8A11A01C4E9C130005F9B9 /* librws_test.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = librws_test.app; sourceTree = BUILT_PRODUCTS_DIR; };
-		3D8A11A41C4E9C130005F9B9 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
-		3D8A11A61C4E9C130005F9B9 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
-		3D8A11A71C4E9C130005F9B9 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
-		3D8A11A91C4E9C130005F9B9 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
-		3D8A11AA1C4E9C130005F9B9 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
-		3D8A11AD1C4E9C130005F9B9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
-		3D8A11AF1C4E9C130005F9B9 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
-		3D8A11B21C4E9C130005F9B9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
-		3D8A11B41C4E9C130005F9B9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
-		3D8A11B91C4E9C140005F9B9 /* librws_testTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = librws_testTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
-		3D8A11BF1C4E9C140005F9B9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
-		3D8A11C91C4E9CAE0005F9B9 /* librws.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = librws.c; path = ../src/librws.c; sourceTree = "<group>"; };
-		3D8A11CC1C4E9CC40005F9B9 /* librws.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = librws.h; path = ../librws.h; sourceTree = "<group>"; };
-		3DB6A4EE1C4EEB2600DDBEAF /* test_librws_creation.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = test_librws_creation.c; sourceTree = SOURCE_ROOT; };
-		3DB6A4F31C4EF8E400DDBEAF /* test_librws_socket_get_set.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = test_librws_socket_get_set.c; sourceTree = SOURCE_ROOT; };
-		3DD7B9411C8F6D43002AF61A /* rws_list.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = rws_list.c; path = ../src/rws_list.c; sourceTree = "<group>"; };
-		3DD7B9421C8F6D43002AF61A /* rws_list.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = rws_list.h; path = ../src/rws_list.h; sourceTree = "<group>"; };
-		3DD7B9451C8F6D4D002AF61A /* rws_thread.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = rws_thread.c; path = ../src/rws_thread.c; sourceTree = "<group>"; };
-		3DD7B9461C8F6D4D002AF61A /* rws_thread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = rws_thread.h; path = ../src/rws_thread.h; sourceTree = "<group>"; };
-		3DD7B9491C8F6D58002AF61A /* rws_error.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = rws_error.c; path = ../src/rws_error.c; sourceTree = "<group>"; };
-		3DD7B94A1C8F6D58002AF61A /* rws_error.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = rws_error.h; path = ../src/rws_error.h; sourceTree = "<group>"; };
-		3DD7B94D1C8F6D61002AF61A /* rws_memory.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = rws_memory.c; path = ../src/rws_memory.c; sourceTree = "<group>"; };
-		3DD7B94E1C8F6D61002AF61A /* rws_memory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = rws_memory.h; path = ../src/rws_memory.h; sourceTree = "<group>"; };
-		3DD7B9511C8F6D6C002AF61A /* rws_common.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = rws_common.c; path = ../src/rws_common.c; sourceTree = "<group>"; };
-		3DD7B9521C8F6D6C002AF61A /* rws_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = rws_common.h; path = ../src/rws_common.h; sourceTree = "<group>"; };
-		3DD7B9551C8F6D74002AF61A /* rws_socket.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = rws_socket.h; path = ../src/rws_socket.h; sourceTree = "<group>"; };
-		3DD7B9561C8F6D7D002AF61A /* rws_socketpriv.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = rws_socketpriv.c; path = ../src/rws_socketpriv.c; sourceTree = "<group>"; };
-		3DD7B9571C8F6D7D002AF61A /* rws_socketpub.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = rws_socketpub.c; path = ../src/rws_socketpub.c; sourceTree = "<group>"; };
-		3DD7B95C1C8F6D85002AF61A /* rws_string.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = rws_string.c; path = ../src/rws_string.c; sourceTree = "<group>"; };
-		3DD7B95D1C8F6D85002AF61A /* rws_string.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = rws_string.h; path = ../src/rws_string.h; sourceTree = "<group>"; };
-		3DD7B9601C8F6D8C002AF61A /* rws_frame.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = rws_frame.c; path = ../src/rws_frame.c; sourceTree = "<group>"; };
-		3DD7B9611C8F6D8C002AF61A /* rws_frame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = rws_frame.h; path = ../src/rws_frame.h; sourceTree = "<group>"; };
-		3DE1B2711C58E67A00966F56 /* creation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = creation.m; sourceTree = "<group>"; };
-		3DE1B27D1C58E85300966F56 /* getterAndSetters.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = getterAndSetters.m; sourceTree = "<group>"; };
-		3DE1B27F1C58ECCE00966F56 /* connection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = connection.m; sourceTree = "<group>"; };
-/* End PBXFileReference section */
-
-/* Begin PBXFrameworksBuildPhase section */
-		3D8A119D1C4E9C130005F9B9 /* Frameworks */ = {
-			isa = PBXFrameworksBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-		};
-		3D8A11B61C4E9C140005F9B9 /* Frameworks */ = {
-			isa = PBXFrameworksBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-		};
-/* End PBXFrameworksBuildPhase section */
-
-/* Begin PBXGroup section */
-		3D1B9EEC1C5F034D0021C58B /* contrib */ = {
-			isa = PBXGroup;
-			children = (
-				3D1B9EED1C5F03810021C58B /* RWSSocketObjc.h */,
-				3D1B9EEE1C5F03810021C58B /* RWSSocketObjc.m */,
-			);
-			name = contrib;
-			sourceTree = "<group>";
-		};
-		3D8A11971C4E9C130005F9B9 = {
-			isa = PBXGroup;
-			children = (
-				3D8A11C81C4E9C980005F9B9 /* librws */,
-				3D8A11A21C4E9C130005F9B9 /* librws_test */,
-				3D8A11BC1C4E9C140005F9B9 /* librws_testTests */,
-				3D8A11A11C4E9C130005F9B9 /* Products */,
-			);
-			sourceTree = "<group>";
-		};
-		3D8A11A11C4E9C130005F9B9 /* Products */ = {
-			isa = PBXGroup;
-			children = (
-				3D8A11A01C4E9C130005F9B9 /* librws_test.app */,
-				3D8A11B91C4E9C140005F9B9 /* librws_testTests.xctest */,
-			);
-			name = Products;
-			sourceTree = "<group>";
-		};
-		3D8A11A21C4E9C130005F9B9 /* librws_test */ = {
-			isa = PBXGroup;
-			children = (
-				3D8A11A61C4E9C130005F9B9 /* AppDelegate.h */,
-				3D8A11A71C4E9C130005F9B9 /* AppDelegate.m */,
-				3D8A11A91C4E9C130005F9B9 /* ViewController.h */,
-				3D8A11AA1C4E9C130005F9B9 /* ViewController.m */,
-				3D8A11AC1C4E9C130005F9B9 /* Main.storyboard */,
-				3D8A11AF1C4E9C130005F9B9 /* Assets.xcassets */,
-				3D8A11B11C4E9C130005F9B9 /* LaunchScreen.storyboard */,
-				3D8A11B41C4E9C130005F9B9 /* Info.plist */,
-				3D8A11A31C4E9C130005F9B9 /* Supporting Files */,
-			);
-			path = librws_test;
-			sourceTree = "<group>";
-		};
-		3D8A11A31C4E9C130005F9B9 /* Supporting Files */ = {
-			isa = PBXGroup;
-			children = (
-				3D8A11A41C4E9C130005F9B9 /* main.m */,
-			);
-			name = "Supporting Files";
-			sourceTree = "<group>";
-		};
-		3D8A11BC1C4E9C140005F9B9 /* librws_testTests */ = {
-			isa = PBXGroup;
-			children = (
-				3DB6A4F31C4EF8E400DDBEAF /* test_librws_socket_get_set.c */,
-				3DB6A4EE1C4EEB2600DDBEAF /* test_librws_creation.c */,
-				3D8A11BF1C4E9C140005F9B9 /* Info.plist */,
-				3DE1B2711C58E67A00966F56 /* creation.m */,
-				3DE1B27D1C58E85300966F56 /* getterAndSetters.m */,
-				3DE1B27F1C58ECCE00966F56 /* connection.m */,
-				3D1B9EF11C5F04BA0021C58B /* ObjcContrib.m */,
-			);
-			path = librws_testTests;
-			sourceTree = "<group>";
-		};
-		3D8A11C81C4E9C980005F9B9 /* librws */ = {
-			isa = PBXGroup;
-			children = (
-				3D1B9EEC1C5F034D0021C58B /* contrib */,
-				3D8A11CD1C4E9E090005F9B9 /* src */,
-				3D8A11CC1C4E9CC40005F9B9 /* librws.h */,
-			);
-			name = librws;
-			sourceTree = "<group>";
-		};
-		3D8A11CD1C4E9E090005F9B9 /* src */ = {
-			isa = PBXGroup;
-			children = (
-				3DD7B9421C8F6D43002AF61A /* rws_list.h */,
-				3DD7B9411C8F6D43002AF61A /* rws_list.c */,
-				3DD7B9461C8F6D4D002AF61A /* rws_thread.h */,
-				3DD7B9451C8F6D4D002AF61A /* rws_thread.c */,
-				3DD7B94A1C8F6D58002AF61A /* rws_error.h */,
-				3DD7B9491C8F6D58002AF61A /* rws_error.c */,
-				3DD7B94E1C8F6D61002AF61A /* rws_memory.h */,
-				3DD7B94D1C8F6D61002AF61A /* rws_memory.c */,
-				3DD7B9521C8F6D6C002AF61A /* rws_common.h */,
-				3DD7B9511C8F6D6C002AF61A /* rws_common.c */,
-				3DD7B9551C8F6D74002AF61A /* rws_socket.h */,
-				3DD7B9561C8F6D7D002AF61A /* rws_socketpriv.c */,
-				3DD7B9571C8F6D7D002AF61A /* rws_socketpub.c */,
-				3D8A11C91C4E9CAE0005F9B9 /* librws.c */,
-				3DD7B95D1C8F6D85002AF61A /* rws_string.h */,
-				3DD7B95C1C8F6D85002AF61A /* rws_string.c */,
-				3DD7B9611C8F6D8C002AF61A /* rws_frame.h */,
-				3DD7B9601C8F6D8C002AF61A /* rws_frame.c */,
-			);
-			name = src;
-			sourceTree = "<group>";
-		};
-/* End PBXGroup section */
-
-/* Begin PBXNativeTarget section */
-		3D8A119F1C4E9C130005F9B9 /* librws_test */ = {
-			isa = PBXNativeTarget;
-			buildConfigurationList = 3D8A11C21C4E9C140005F9B9 /* Build configuration list for PBXNativeTarget "librws_test" */;
-			buildPhases = (
-				3D8A119C1C4E9C130005F9B9 /* Sources */,
-				3D8A119D1C4E9C130005F9B9 /* Frameworks */,
-				3D8A119E1C4E9C130005F9B9 /* Resources */,
-			);
-			buildRules = (
-			);
-			dependencies = (
-			);
-			name = librws_test;
-			productName = librws_test;
-			productReference = 3D8A11A01C4E9C130005F9B9 /* librws_test.app */;
-			productType = "com.apple.product-type.application";
-		};
-		3D8A11B81C4E9C140005F9B9 /* librws_testTests */ = {
-			isa = PBXNativeTarget;
-			buildConfigurationList = 3D8A11C51C4E9C140005F9B9 /* Build configuration list for PBXNativeTarget "librws_testTests" */;
-			buildPhases = (
-				3D8A11B51C4E9C140005F9B9 /* Sources */,
-				3D8A11B61C4E9C140005F9B9 /* Frameworks */,
-				3D8A11B71C4E9C140005F9B9 /* Resources */,
-			);
-			buildRules = (
-			);
-			dependencies = (
-				3D8A11BB1C4E9C140005F9B9 /* PBXTargetDependency */,
-			);
-			name = librws_testTests;
-			productName = librws_testTests;
-			productReference = 3D8A11B91C4E9C140005F9B9 /* librws_testTests.xctest */;
-			productType = "com.apple.product-type.bundle.unit-test";
-		};
-/* End PBXNativeTarget section */
-
-/* Begin PBXProject section */
-		3D8A11981C4E9C130005F9B9 /* Project object */ = {
-			isa = PBXProject;
-			attributes = {
-				LastUpgradeCheck = 0720;
-				ORGANIZATIONNAME = none;
-				TargetAttributes = {
-					3D8A119F1C4E9C130005F9B9 = {
-						CreatedOnToolsVersion = 7.2;
-					};
-					3D8A11B81C4E9C140005F9B9 = {
-						CreatedOnToolsVersion = 7.2;
-						TestTargetID = 3D8A119F1C4E9C130005F9B9;
-					};
-				};
-			};
-			buildConfigurationList = 3D8A119B1C4E9C130005F9B9 /* Build configuration list for PBXProject "librws_test" */;
-			compatibilityVersion = "Xcode 3.2";
-			developmentRegion = English;
-			hasScannedForEncodings = 0;
-			knownRegions = (
-				en,
-				Base,
-			);
-			mainGroup = 3D8A11971C4E9C130005F9B9;
-			productRefGroup = 3D8A11A11C4E9C130005F9B9 /* Products */;
-			projectDirPath = "";
-			projectRoot = "";
-			targets = (
-				3D8A119F1C4E9C130005F9B9 /* librws_test */,
-				3D8A11B81C4E9C140005F9B9 /* librws_testTests */,
-			);
-		};
-/* End PBXProject section */
-
-/* Begin PBXResourcesBuildPhase section */
-		3D8A119E1C4E9C130005F9B9 /* Resources */ = {
-			isa = PBXResourcesBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-				3D8A11B31C4E9C130005F9B9 /* LaunchScreen.storyboard in Resources */,
-				3D8A11B01C4E9C130005F9B9 /* Assets.xcassets in Resources */,
-				3D8A11AE1C4E9C130005F9B9 /* Main.storyboard in Resources */,
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-		};
-		3D8A11B71C4E9C140005F9B9 /* Resources */ = {
-			isa = PBXResourcesBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-		};
-/* End PBXResourcesBuildPhase section */
-
-/* Begin PBXSourcesBuildPhase section */
-		3D8A119C1C4E9C130005F9B9 /* Sources */ = {
-			isa = PBXSourcesBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-				3DD7B94F1C8F6D61002AF61A /* rws_memory.c in Sources */,
-				3DD7B9581C8F6D7D002AF61A /* rws_socketpriv.c in Sources */,
-				3DD7B9621C8F6D8C002AF61A /* rws_frame.c in Sources */,
-				3D8A11CB1C4E9CAE0005F9B9 /* librws.c in Sources */,
-				3DD7B9471C8F6D4D002AF61A /* rws_thread.c in Sources */,
-				3D8A11AB1C4E9C130005F9B9 /* ViewController.m in Sources */,
-				3DD7B9531C8F6D6C002AF61A /* rws_common.c in Sources */,
-				3D1B9EEF1C5F03810021C58B /* RWSSocketObjc.m in Sources */,
-				3D8A11A81C4E9C130005F9B9 /* AppDelegate.m in Sources */,
-				3DD7B9431C8F6D43002AF61A /* rws_list.c in Sources */,
-				3DD7B94B1C8F6D58002AF61A /* rws_error.c in Sources */,
-				3DD7B95A1C8F6D7D002AF61A /* rws_socketpub.c in Sources */,
-				3D8A11A51C4E9C130005F9B9 /* main.m in Sources */,
-				3DD7B95E1C8F6D85002AF61A /* rws_string.c in Sources */,
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-		};
-		3D8A11B51C4E9C140005F9B9 /* Sources */ = {
-			isa = PBXSourcesBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-				3DD7B9541C8F6D6C002AF61A /* rws_common.c in Sources */,
-				3DD7B94C1C8F6D58002AF61A /* rws_error.c in Sources */,
-				3DD7B9481C8F6D4D002AF61A /* rws_thread.c in Sources */,
-				3DD7B95B1C8F6D7D002AF61A /* rws_socketpub.c in Sources */,
-				3DD7B95F1C8F6D85002AF61A /* rws_string.c in Sources */,
-				3DD7B9501C8F6D61002AF61A /* rws_memory.c in Sources */,
-				3DE1B27E1C58E85300966F56 /* getterAndSetters.m in Sources */,
-				3DE1B2731C58E6AD00966F56 /* librws.c in Sources */,
-				3D1B9EF21C5F04BA0021C58B /* ObjcContrib.m in Sources */,
-				3D1B9EF01C5F03840021C58B /* RWSSocketObjc.m in Sources */,
-				3DD7B9591C8F6D7D002AF61A /* rws_socketpriv.c in Sources */,
-				3DE1B2801C58ECCE00966F56 /* connection.m in Sources */,
-				3DD7B9631C8F6D8C002AF61A /* rws_frame.c in Sources */,
-				3DE1B2721C58E67A00966F56 /* creation.m in Sources */,
-				3DD7B9441C8F6D43002AF61A /* rws_list.c in Sources */,
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-		};
-/* End PBXSourcesBuildPhase section */
-
-/* Begin PBXTargetDependency section */
-		3D8A11BB1C4E9C140005F9B9 /* PBXTargetDependency */ = {
-			isa = PBXTargetDependency;
-			target = 3D8A119F1C4E9C130005F9B9 /* librws_test */;
-			targetProxy = 3D8A11BA1C4E9C140005F9B9 /* PBXContainerItemProxy */;
-		};
-/* End PBXTargetDependency section */
-
-/* Begin PBXVariantGroup section */
-		3D8A11AC1C4E9C130005F9B9 /* Main.storyboard */ = {
-			isa = PBXVariantGroup;
-			children = (
-				3D8A11AD1C4E9C130005F9B9 /* Base */,
-			);
-			name = Main.storyboard;
-			sourceTree = "<group>";
-		};
-		3D8A11B11C4E9C130005F9B9 /* LaunchScreen.storyboard */ = {
-			isa = PBXVariantGroup;
-			children = (
-				3D8A11B21C4E9C130005F9B9 /* Base */,
-			);
-			name = LaunchScreen.storyboard;
-			sourceTree = "<group>";
-		};
-/* End PBXVariantGroup section */
-
-/* Begin XCBuildConfiguration section */
-		3D8A11C01C4E9C140005F9B9 /* Debug */ = {
-			isa = XCBuildConfiguration;
-			buildSettings = {
-				ALWAYS_SEARCH_USER_PATHS = NO;
-				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
-				CLANG_CXX_LIBRARY = "libc++";
-				CLANG_ENABLE_MODULES = YES;
-				CLANG_ENABLE_OBJC_ARC = YES;
-				CLANG_WARN_BOOL_CONVERSION = YES;
-				CLANG_WARN_CONSTANT_CONVERSION = YES;
-				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
-				CLANG_WARN_EMPTY_BODY = YES;
-				CLANG_WARN_ENUM_CONVERSION = YES;
-				CLANG_WARN_INT_CONVERSION = YES;
-				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
-				CLANG_WARN_UNREACHABLE_CODE = YES;
-				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
-				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
-				COPY_PHASE_STRIP = NO;
-				DEBUG_INFORMATION_FORMAT = dwarf;
-				ENABLE_STRICT_OBJC_MSGSEND = YES;
-				ENABLE_TESTABILITY = YES;
-				GCC_DYNAMIC_NO_PIC = NO;
-				GCC_NO_COMMON_BLOCKS = YES;
-				GCC_OPTIMIZATION_LEVEL = 0;
-				GCC_PREPROCESSOR_DEFINITIONS = (
-					"DEBUG=1",
-					"$(inherited)",
-				);
-				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
-				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
-				GCC_WARN_UNDECLARED_SELECTOR = YES;
-				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
-				GCC_WARN_UNUSED_FUNCTION = YES;
-				GCC_WARN_UNUSED_VARIABLE = YES;
-				IPHONEOS_DEPLOYMENT_TARGET = 8.1;
-				MTL_ENABLE_DEBUG_INFO = YES;
-				ONLY_ACTIVE_ARCH = YES;
-				SDKROOT = iphoneos;
-			};
-			name = Debug;
-		};
-		3D8A11C11C4E9C140005F9B9 /* Release */ = {
-			isa = XCBuildConfiguration;
-			buildSettings = {
-				ALWAYS_SEARCH_USER_PATHS = NO;
-				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
-				CLANG_CXX_LIBRARY = "libc++";
-				CLANG_ENABLE_MODULES = YES;
-				CLANG_ENABLE_OBJC_ARC = YES;
-				CLANG_WARN_BOOL_CONVERSION = YES;
-				CLANG_WARN_CONSTANT_CONVERSION = YES;
-				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
-				CLANG_WARN_EMPTY_BODY = YES;
-				CLANG_WARN_ENUM_CONVERSION = YES;
-				CLANG_WARN_INT_CONVERSION = YES;
-				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
-				CLANG_WARN_UNREACHABLE_CODE = YES;
-				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
-				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
-				COPY_PHASE_STRIP = NO;
-				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-				ENABLE_NS_ASSERTIONS = NO;
-				ENABLE_STRICT_OBJC_MSGSEND = YES;
-				GCC_NO_COMMON_BLOCKS = YES;
-				GCC_PREPROCESSOR_DEFINITIONS = "";
-				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
-				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
-				GCC_WARN_UNDECLARED_SELECTOR = YES;
-				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
-				GCC_WARN_UNUSED_FUNCTION = YES;
-				GCC_WARN_UNUSED_VARIABLE = YES;
-				IPHONEOS_DEPLOYMENT_TARGET = 8.1;
-				MTL_ENABLE_DEBUG_INFO = NO;
-				SDKROOT = iphoneos;
-				VALIDATE_PRODUCT = YES;
-			};
-			name = Release;
-		};
-		3D8A11C31C4E9C140005F9B9 /* Debug */ = {
-			isa = XCBuildConfiguration;
-			buildSettings = {
-				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
-				INFOPLIST_FILE = librws_test/Info.plist;
-				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
-				PRODUCT_BUNDLE_IDENTIFIER = "re.librws-test";
-				PRODUCT_NAME = "$(TARGET_NAME)";
-			};
-			name = Debug;
-		};
-		3D8A11C41C4E9C140005F9B9 /* Release */ = {
-			isa = XCBuildConfiguration;
-			buildSettings = {
-				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
-				INFOPLIST_FILE = librws_test/Info.plist;
-				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
-				PRODUCT_BUNDLE_IDENTIFIER = "re.librws-test";
-				PRODUCT_NAME = "$(TARGET_NAME)";
-			};
-			name = Release;
-		};
-		3D8A11C61C4E9C140005F9B9 /* Debug */ = {
-			isa = XCBuildConfiguration;
-			buildSettings = {
-				BUNDLE_LOADER = "$(TEST_HOST)";
-				GCC_PREPROCESSOR_DEFINITIONS = (
-					"DEBUG=1",
-					"$(inherited)",
-					"XCODE=1",
-				);
-				INFOPLIST_FILE = librws_testTests/Info.plist;
-				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-				PRODUCT_BUNDLE_IDENTIFIER = "re.librws-testTests";
-				PRODUCT_NAME = "$(TARGET_NAME)";
-				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/librws_test.app/librws_test";
-			};
-			name = Debug;
-		};
-		3D8A11C71C4E9C140005F9B9 /* Release */ = {
-			isa = XCBuildConfiguration;
-			buildSettings = {
-				BUNDLE_LOADER = "$(TEST_HOST)";
-				GCC_PREPROCESSOR_DEFINITIONS = "XCODE=1";
-				INFOPLIST_FILE = librws_testTests/Info.plist;
-				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-				PRODUCT_BUNDLE_IDENTIFIER = "re.librws-testTests";
-				PRODUCT_NAME = "$(TARGET_NAME)";
-				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/librws_test.app/librws_test";
-			};
-			name = Release;
-		};
-/* End XCBuildConfiguration section */
-
-/* Begin XCConfigurationList section */
-		3D8A119B1C4E9C130005F9B9 /* Build configuration list for PBXProject "librws_test" */ = {
-			isa = XCConfigurationList;
-			buildConfigurations = (
-				3D8A11C01C4E9C140005F9B9 /* Debug */,
-				3D8A11C11C4E9C140005F9B9 /* Release */,
-			);
-			defaultConfigurationIsVisible = 0;
-			defaultConfigurationName = Release;
-		};
-		3D8A11C21C4E9C140005F9B9 /* Build configuration list for PBXNativeTarget "librws_test" */ = {
-			isa = XCConfigurationList;
-			buildConfigurations = (
-				3D8A11C31C4E9C140005F9B9 /* Debug */,
-				3D8A11C41C4E9C140005F9B9 /* Release */,
-			);
-			defaultConfigurationIsVisible = 0;
-			defaultConfigurationName = Release;
-		};
-		3D8A11C51C4E9C140005F9B9 /* Build configuration list for PBXNativeTarget "librws_testTests" */ = {
-			isa = XCConfigurationList;
-			buildConfigurations = (
-				3D8A11C61C4E9C140005F9B9 /* Debug */,
-				3D8A11C71C4E9C140005F9B9 /* Release */,
-			);
-			defaultConfigurationIsVisible = 0;
-			defaultConfigurationName = Release;
-		};
-/* End XCConfigurationList section */
-	};
-	rootObject = 3D8A11981C4E9C130005F9B9 /* Project object */;
-}

+ 0 - 7
test/librws_test.xcodeproj/project.xcworkspace/contents.xcworkspacedata

@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Workspace
-   version = "1.0">
-   <FileRef
-      location = "self:librws_test.xcodeproj">
-   </FileRef>
-</Workspace>

BIN
test/librws_test.xcodeproj/project.xcworkspace/xcuserdata/olehkulykov.xcuserdatad/UserInterfaceState.xcuserstate


BIN
test/librws_test.xcodeproj/project.xcworkspace/xcuserdata/residentevil.xcuserdatad/UserInterfaceState.xcuserstate


+ 0 - 5
test/librws_test.xcodeproj/xcuserdata/olehkulykov.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist

@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Bucket
-   type = "1"
-   version = "2.0">
-</Bucket>

+ 0 - 101
test/librws_test.xcodeproj/xcuserdata/olehkulykov.xcuserdatad/xcschemes/librws_test.xcscheme

@@ -1,101 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
-   LastUpgradeVersion = "0730"
-   version = "1.3">
-   <BuildAction
-      parallelizeBuildables = "YES"
-      buildImplicitDependencies = "YES">
-      <BuildActionEntries>
-         <BuildActionEntry
-            buildForTesting = "YES"
-            buildForRunning = "YES"
-            buildForProfiling = "YES"
-            buildForArchiving = "YES"
-            buildForAnalyzing = "YES">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "3D8A119F1C4E9C130005F9B9"
-               BuildableName = "librws_test.app"
-               BlueprintName = "librws_test"
-               ReferencedContainer = "container:librws_test.xcodeproj">
-            </BuildableReference>
-         </BuildActionEntry>
-      </BuildActionEntries>
-   </BuildAction>
-   <TestAction
-      buildConfiguration = "Debug"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      shouldUseLaunchSchemeArgsEnv = "YES">
-      <Testables>
-         <TestableReference
-            skipped = "NO">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "3D8A11B81C4E9C140005F9B9"
-               BuildableName = "librws_testTests.xctest"
-               BlueprintName = "librws_testTests"
-               ReferencedContainer = "container:librws_test.xcodeproj">
-            </BuildableReference>
-         </TestableReference>
-      </Testables>
-      <MacroExpansion>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "3D8A119F1C4E9C130005F9B9"
-            BuildableName = "librws_test.app"
-            BlueprintName = "librws_test"
-            ReferencedContainer = "container:librws_test.xcodeproj">
-         </BuildableReference>
-      </MacroExpansion>
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </TestAction>
-   <LaunchAction
-      buildConfiguration = "Debug"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      launchStyle = "0"
-      useCustomWorkingDirectory = "NO"
-      ignoresPersistentStateOnLaunch = "NO"
-      debugDocumentVersioning = "YES"
-      debugServiceExtension = "internal"
-      allowLocationSimulation = "YES">
-      <BuildableProductRunnable
-         runnableDebuggingMode = "0">
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "3D8A119F1C4E9C130005F9B9"
-            BuildableName = "librws_test.app"
-            BlueprintName = "librws_test"
-            ReferencedContainer = "container:librws_test.xcodeproj">
-         </BuildableReference>
-      </BuildableProductRunnable>
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </LaunchAction>
-   <ProfileAction
-      buildConfiguration = "Release"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      savedToolIdentifier = ""
-      useCustomWorkingDirectory = "NO"
-      debugDocumentVersioning = "YES">
-      <BuildableProductRunnable
-         runnableDebuggingMode = "0">
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "3D8A119F1C4E9C130005F9B9"
-            BuildableName = "librws_test.app"
-            BlueprintName = "librws_test"
-            ReferencedContainer = "container:librws_test.xcodeproj">
-         </BuildableReference>
-      </BuildableProductRunnable>
-   </ProfileAction>
-   <AnalyzeAction
-      buildConfiguration = "Debug">
-   </AnalyzeAction>
-   <ArchiveAction
-      buildConfiguration = "Release"
-      revealArchiveInOrganizer = "YES">
-   </ArchiveAction>
-</Scheme>

+ 0 - 27
test/librws_test.xcodeproj/xcuserdata/olehkulykov.xcuserdatad/xcschemes/xcschememanagement.plist

@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-	<key>SchemeUserState</key>
-	<dict>
-		<key>librws_test.xcscheme</key>
-		<dict>
-			<key>orderHint</key>
-			<integer>0</integer>
-		</dict>
-	</dict>
-	<key>SuppressBuildableAutocreation</key>
-	<dict>
-		<key>3D8A119F1C4E9C130005F9B9</key>
-		<dict>
-			<key>primary</key>
-			<true/>
-		</dict>
-		<key>3D8A11B81C4E9C140005F9B9</key>
-		<dict>
-			<key>primary</key>
-			<true/>
-		</dict>
-	</dict>
-</dict>
-</plist>

+ 0 - 23
test/librws_test.xcodeproj/xcuserdata/residentevil.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist

@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Bucket
-   type = "1"
-   version = "2.0">
-   <Breakpoints>
-      <BreakpointProxy
-         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
-         <BreakpointContent
-            shouldBeEnabled = "Yes"
-            ignoreCount = "0"
-            continueAfterRunningActions = "No"
-            filePath = "../src/rws_socketpriv.c"
-            timestampString = "479166769.510243"
-            startingColumnNumber = "9223372036854775807"
-            endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "111"
-            endingLineNumber = "111"
-            landmarkName = "rws_socket_process_handshake_responce()"
-            landmarkType = "7">
-         </BreakpointContent>
-      </BreakpointProxy>
-   </Breakpoints>
-</Bucket>

+ 0 - 101
test/librws_test.xcodeproj/xcuserdata/residentevil.xcuserdatad/xcschemes/librws_test.xcscheme

@@ -1,101 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
-   LastUpgradeVersion = "0720"
-   version = "1.3">
-   <BuildAction
-      parallelizeBuildables = "YES"
-      buildImplicitDependencies = "YES">
-      <BuildActionEntries>
-         <BuildActionEntry
-            buildForTesting = "YES"
-            buildForRunning = "YES"
-            buildForProfiling = "YES"
-            buildForArchiving = "YES"
-            buildForAnalyzing = "YES">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "3D8A119F1C4E9C130005F9B9"
-               BuildableName = "librws_test.app"
-               BlueprintName = "librws_test"
-               ReferencedContainer = "container:librws_test.xcodeproj">
-            </BuildableReference>
-         </BuildActionEntry>
-      </BuildActionEntries>
-   </BuildAction>
-   <TestAction
-      buildConfiguration = "Debug"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      shouldUseLaunchSchemeArgsEnv = "YES">
-      <Testables>
-         <TestableReference
-            skipped = "NO">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "3D8A11B81C4E9C140005F9B9"
-               BuildableName = "librws_testTests.xctest"
-               BlueprintName = "librws_testTests"
-               ReferencedContainer = "container:librws_test.xcodeproj">
-            </BuildableReference>
-         </TestableReference>
-      </Testables>
-      <MacroExpansion>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "3D8A119F1C4E9C130005F9B9"
-            BuildableName = "librws_test.app"
-            BlueprintName = "librws_test"
-            ReferencedContainer = "container:librws_test.xcodeproj">
-         </BuildableReference>
-      </MacroExpansion>
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </TestAction>
-   <LaunchAction
-      buildConfiguration = "Debug"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      launchStyle = "0"
-      useCustomWorkingDirectory = "NO"
-      ignoresPersistentStateOnLaunch = "NO"
-      debugDocumentVersioning = "YES"
-      debugServiceExtension = "internal"
-      allowLocationSimulation = "YES">
-      <BuildableProductRunnable
-         runnableDebuggingMode = "0">
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "3D8A119F1C4E9C130005F9B9"
-            BuildableName = "librws_test.app"
-            BlueprintName = "librws_test"
-            ReferencedContainer = "container:librws_test.xcodeproj">
-         </BuildableReference>
-      </BuildableProductRunnable>
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </LaunchAction>
-   <ProfileAction
-      buildConfiguration = "Release"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      savedToolIdentifier = ""
-      useCustomWorkingDirectory = "NO"
-      debugDocumentVersioning = "YES">
-      <BuildableProductRunnable
-         runnableDebuggingMode = "0">
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "3D8A119F1C4E9C130005F9B9"
-            BuildableName = "librws_test.app"
-            BlueprintName = "librws_test"
-            ReferencedContainer = "container:librws_test.xcodeproj">
-         </BuildableReference>
-      </BuildableProductRunnable>
-   </ProfileAction>
-   <AnalyzeAction
-      buildConfiguration = "Debug">
-   </AnalyzeAction>
-   <ArchiveAction
-      buildConfiguration = "Release"
-      revealArchiveInOrganizer = "YES">
-   </ArchiveAction>
-</Scheme>

+ 0 - 27
test/librws_test.xcodeproj/xcuserdata/residentevil.xcuserdatad/xcschemes/xcschememanagement.plist

@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-	<key>SchemeUserState</key>
-	<dict>
-		<key>librws_test.xcscheme</key>
-		<dict>
-			<key>orderHint</key>
-			<integer>0</integer>
-		</dict>
-	</dict>
-	<key>SuppressBuildableAutocreation</key>
-	<dict>
-		<key>3D8A119F1C4E9C130005F9B9</key>
-		<dict>
-			<key>primary</key>
-			<true/>
-		</dict>
-		<key>3D8A11B81C4E9C140005F9B9</key>
-		<dict>
-			<key>primary</key>
-			<true/>
-		</dict>
-	</dict>
-</dict>
-</plist>

+ 0 - 11
test/librws_test/AppDelegate.h

@@ -1,11 +0,0 @@
-
-
-#import <UIKit/UIKit.h>
-
-@interface AppDelegate : UIResponder <UIApplicationDelegate>
-
-@property (strong, nonatomic) UIWindow *window;
-
-
-@end
-

+ 0 - 39
test/librws_test/AppDelegate.m

@@ -1,39 +0,0 @@
-
-
-#import "AppDelegate.h"
-
-@interface AppDelegate ()
-
-@end
-
-@implementation AppDelegate
-
-
-- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
-	// Override point for customization after application launch.
-	return YES;
-}
-
-- (void)applicationWillResignActive:(UIApplication *)application {
-	// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
-	// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
-}
-
-- (void)applicationDidEnterBackground:(UIApplication *)application {
-	// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
-	// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
-}
-
-- (void)applicationWillEnterForeground:(UIApplication *)application {
-	// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
-}
-
-- (void)applicationDidBecomeActive:(UIApplication *)application {
-	// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
-}
-
-- (void)applicationWillTerminate:(UIApplication *)application {
-	// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
-}
-
-@end

+ 0 - 38
test/librws_test/Assets.xcassets/AppIcon.appiconset/Contents.json

@@ -1,38 +0,0 @@
-{
-  "images" : [
-    {
-      "idiom" : "iphone",
-      "size" : "29x29",
-      "scale" : "2x"
-    },
-    {
-      "idiom" : "iphone",
-      "size" : "29x29",
-      "scale" : "3x"
-    },
-    {
-      "idiom" : "iphone",
-      "size" : "40x40",
-      "scale" : "2x"
-    },
-    {
-      "idiom" : "iphone",
-      "size" : "40x40",
-      "scale" : "3x"
-    },
-    {
-      "idiom" : "iphone",
-      "size" : "60x60",
-      "scale" : "2x"
-    },
-    {
-      "idiom" : "iphone",
-      "size" : "60x60",
-      "scale" : "3x"
-    }
-  ],
-  "info" : {
-    "version" : 1,
-    "author" : "xcode"
-  }
-}

+ 0 - 27
test/librws_test/Base.lproj/LaunchScreen.storyboard

@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="8150" systemVersion="15A204g" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" initialViewController="01J-lp-oVM">
-    <dependencies>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="8122"/>
-    </dependencies>
-    <scenes>
-        <!--View Controller-->
-        <scene sceneID="EHf-IW-A2E">
-            <objects>
-                <viewController id="01J-lp-oVM" sceneMemberID="viewController">
-                    <layoutGuides>
-                        <viewControllerLayoutGuide type="top" id="Llm-lL-Icb"/>
-                        <viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/>
-                    </layoutGuides>
-                    <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
-                        <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
-                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
-                        <animations/>
-                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
-                    </view>
-                </viewController>
-                <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
-            </objects>
-            <point key="canvasLocation" x="53" y="375"/>
-        </scene>
-    </scenes>
-</document>

+ 0 - 27
test/librws_test/Base.lproj/Main.storyboard

@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="9531" systemVersion="15D21" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
-    <dependencies>
-        <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9529"/>
-    </dependencies>
-    <scenes>
-        <!--View Controller-->
-        <scene sceneID="tne-QT-ifu">
-            <objects>
-                <viewController id="BYZ-38-t0r" customClass="ViewController" sceneMemberID="viewController">
-                    <layoutGuides>
-                        <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
-                        <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
-                    </layoutGuides>
-                    <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
-                        <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
-                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
-                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
-                    </view>
-                </viewController>
-                <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
-            </objects>
-            <point key="canvasLocation" x="235" y="417"/>
-        </scene>
-    </scenes>
-</document>

+ 0 - 40
test/librws_test/Info.plist

@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-	<key>CFBundleDevelopmentRegion</key>
-	<string>en</string>
-	<key>CFBundleExecutable</key>
-	<string>$(EXECUTABLE_NAME)</string>
-	<key>CFBundleIdentifier</key>
-	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
-	<key>CFBundleInfoDictionaryVersion</key>
-	<string>6.0</string>
-	<key>CFBundleName</key>
-	<string>$(PRODUCT_NAME)</string>
-	<key>CFBundlePackageType</key>
-	<string>APPL</string>
-	<key>CFBundleShortVersionString</key>
-	<string>1.0</string>
-	<key>CFBundleSignature</key>
-	<string>????</string>
-	<key>CFBundleVersion</key>
-	<string>1</string>
-	<key>LSRequiresIPhoneOS</key>
-	<true/>
-	<key>UILaunchStoryboardName</key>
-	<string>LaunchScreen</string>
-	<key>UIMainStoryboardFile</key>
-	<string>Main</string>
-	<key>UIRequiredDeviceCapabilities</key>
-	<array>
-		<string>armv7</string>
-	</array>
-	<key>UISupportedInterfaceOrientations</key>
-	<array>
-		<string>UIInterfaceOrientationPortrait</string>
-		<string>UIInterfaceOrientationLandscapeLeft</string>
-		<string>UIInterfaceOrientationLandscapeRight</string>
-	</array>
-</dict>
-</plist>

+ 0 - 8
test/librws_test/ViewController.h

@@ -1,8 +0,0 @@
-
-
-#import <UIKit/UIKit.h>
-
-@interface ViewController : UIViewController
-
-@end
-

+ 0 - 20
test/librws_test/ViewController.m

@@ -1,20 +0,0 @@
-
-#import "ViewController.h"
-
-@interface ViewController ()
-
-@end
-
-@implementation ViewController
-
-- (void)viewDidLoad {
-	[super viewDidLoad];
-	// Do any additional setup after loading the view, typically from a nib.
-}
-
-- (void)didReceiveMemoryWarning {
-	[super didReceiveMemoryWarning];
-	// Dispose of any resources that can be recreated.
-}
-
-@end

+ 0 - 10
test/librws_test/main.m

@@ -1,10 +0,0 @@
-
-
-#import <UIKit/UIKit.h>
-#import "AppDelegate.h"
-
-int main(int argc, char * argv[]) {
-	@autoreleasepool {
-	    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
-	}
-}

+ 0 - 24
test/librws_testTests/Info.plist

@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-	<key>CFBundleDevelopmentRegion</key>
-	<string>en</string>
-	<key>CFBundleExecutable</key>
-	<string>$(EXECUTABLE_NAME)</string>
-	<key>CFBundleIdentifier</key>
-	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
-	<key>CFBundleInfoDictionaryVersion</key>
-	<string>6.0</string>
-	<key>CFBundleName</key>
-	<string>$(PRODUCT_NAME)</string>
-	<key>CFBundlePackageType</key>
-	<string>BNDL</string>
-	<key>CFBundleShortVersionString</key>
-	<string>1.0</string>
-	<key>CFBundleSignature</key>
-	<string>????</string>
-	<key>CFBundleVersion</key>
-	<string>1</string>
-</dict>
-</plist>

+ 0 - 68
test/librws_testTests/ObjcContrib.m

@@ -1,68 +0,0 @@
-/*
- *   Copyright (c) 2014 - 2019 Oleh Kulykov <info@resident.name>
- *
- *   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.
- */
-
-
-#import <XCTest/XCTest.h>
-#import "RWSSocketObjc.h"
-
-@interface ObjcContrib : XCTestCase
-
-@property (nonatomic) RWSSocketObjc * socket;
-
-@end
-
-@implementation ObjcContrib
-
-- (void)setUp {
-    [super setUp];
-    // Put setup code here. This method is called before the invocation of each test method in the class.
-
-	self.socket = [[RWSSocketObjc alloc] init];
-	XCTAssertNil(self.socket);
-
-	self.socket = [[RWSSocketObjc alloc] initWithURL:[NSURL URLWithString:@"ws://echo.websocket.org:80"]];
-	XCTAssertNotNil(self.socket);
-}
-
-- (void)tearDown {
-    // Put teardown code here. This method is called after the invocation of each test method in the class.
-    [super tearDown];
-}
-
-- (void)testConnect {
-    // This is an example of a functional test case.
-    // Use XCTAssert and related functions to verify your tests produce the correct results.
-	[self.socket connect];
-	
-	while (![self.socket isConnected]) {
-		[NSThread sleepForTimeInterval:0.1];
-	}
-}
-
-- (void)testPerformanceExample {
-    // This is an example of a performance test case.
-    [self measureBlock:^{
-        // Put the code you want to measure the time of here.
-    }];
-}
-
-@end

+ 0 - 119
test/librws_testTests/connection.m

@@ -1,119 +0,0 @@
-/*
- *   Copyright (c) 2014 - 2019 Oleh Kulykov <info@resident.name>
- *
- *   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.
- */
-
-
-#import <XCTest/XCTest.h>
-#import "librws.h"
-
-@interface connection : XCTestCase {
-@private
-	rws_socket _socket;
-}
-
-@property (nonatomic) BOOL isWorking;
-@property (nonatomic) BOOL isError;
-@property (nonatomic) BOOL isFinished;
-@property (nonatomic, strong) NSString * errorMessage;
-
-@end
-
-@implementation connection
-
-static const char * _testSendText = "{\"version\":\"1.0\",\"supportedConnectionTypes\":[\"websocket\"],\"minimumVersion\":\"1.0\",\"channel\":\"/meta/handshake\"}";
-
-static void on_socket_received_text(rws_socket socket, const char * text, const unsigned int length) {
-	connection * con = (__bridge connection *)rws_socket_get_user_object(socket);
-
-	if (strncmp(text, _testSendText, length) != 0) {
-		con.isError = YES;
-		con.errorMessage = @"send and echo test/len not equal";
-	}
-	con.isWorking = NO;
-	con.isFinished = YES;
-}
-
-static void on_socket_connected(rws_socket socket) {
-	NSLog(@"Socket connected");
-
-	rws_socket_send_text(socket, _testSendText);
-}
-
-static void on_socket_disconnected(rws_socket socket) {
-	rws_error error = rws_socket_get_error(socket);
-	if (error) {
-		NSLog(@"Socket disconnect with code, error: %i, %s",
-			  rws_error_get_code(error),
-			  rws_error_get_description(error));
-	}
-	connection * con = (__bridge connection *)rws_socket_get_user_object(socket);
-	con.errorMessage = @"can't connect to host";
-	con.isError = YES;
-	con.isWorking = NO;
-	con.isFinished = YES;
-}
-
-- (void)setUp {
-    [super setUp];
-    // Put setup code here. This method is called before the invocation of each test method in the class.
-
-	_socket = rws_socket_create();
-}
-
-- (void)tearDown {
-    // Put teardown code here. This method is called after the invocation of each test method in the class.
-    [super tearDown];
-
-	rws_socket_disconnect_and_release(_socket);
-	_socket = NULL;
-}
-
-- (void) testConnection {
-    // This is an example of a functional test case.
-    // Use XCTAssert and related functions to verify your tests produce the correct results.
-
-	rws_socket_set_url(_socket, "ws", "echo.websocket.org", 80, "/");
-	rws_socket_set_user_object(_socket, (__bridge void *)self);
-
-	rws_socket_set_on_disconnected(_socket, &on_socket_disconnected);
-	rws_socket_set_on_connected(_socket, &on_socket_connected);
-	rws_socket_set_on_received_text(_socket, &on_socket_received_text);
-
-	self.isWorking = YES;
-	self.isError = NO;
-	self.isFinished = NO;
-	rws_socket_connect(_socket);
-
-	while (self.isWorking) {
-		rws_thread_sleep(100);
-	}
-	XCTAssertFalse(self.isError, @"error during connection");
-	XCTAssertTrue(self.isFinished, @"connection test not finished");
-}
-
-- (void)testPerformanceExample {
-    // This is an example of a performance test case.
-    [self measureBlock:^{
-        // Put the code you want to measure the time of here.
-    }];
-}
-
-@end

+ 0 - 67
test/librws_testTests/creation.m

@@ -1,67 +0,0 @@
-/*
- *   Copyright (c) 2014 - 2019 Oleh Kulykov <info@resident.name>
- *
- *   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.
- */
-
-
-#import <XCTest/XCTest.h>
-#import "librws.h"
-
-@interface creation : XCTestCase
-
-@end
-
-@implementation creation
-
-- (void)setUp {
-    [super setUp];
-    // Put setup code here. This method is called before the invocation of each test method in the class.
-}
-
-- (void)tearDown {
-    // Put teardown code here. This method is called after the invocation of each test method in the class.
-    [super tearDown];
-}
-
-- (void) testCreate
-{
-    // This is an example of a functional test case.
-    // Use XCTAssert and related functions to verify your tests produce the correct results.
-	rws_socket socket = rws_socket_create();
-	XCTAssert(socket != NULL, @"Not created");
-	rws_socket_disconnect_and_release(socket);
-
-	const rws_bool expressionTrue = rws_true;
-	XCTAssertTrue(expressionTrue, @"rws_true is not true");
-	XCTAssertTrue(rws_true, @"rws_true is not true");
-
-	const rws_bool expressionFalse = rws_false;
-	XCTAssertFalse(expressionFalse, @"rws_false is not false");
-	XCTAssertFalse(rws_false, @"rws_false is not false");
-}
-
-- (void)testPerformanceExample {
-    // This is an example of a performance test case.
-    [self measureBlock:^{
-        // Put the code you want to measure the time of here.
-    }];
-}
-
-@end

+ 0 - 117
test/librws_testTests/getterAndSetters.m

@@ -1,117 +0,0 @@
-/*
- *   Copyright (c) 2014 - 2019 Oleh Kulykov <info@resident.name>
- *
- *   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.
- */
-
-
-#import <XCTest/XCTest.h>
-#import "librws.h"
-
-@interface getterAndSetters : XCTestCase {
-@private
-	rws_socket _socket;
-}
-@end
-
-@implementation getterAndSetters
-
-- (void) setUp {
-    [super setUp];
-    // Put setup code here. This method is called before the invocation of each test method in the class.
-	_socket = rws_socket_create();
-}
-
-- (void) tearDown {
-    // Put teardown code here. This method is called after the invocation of each test method in the class.
-    [super tearDown];
-	rws_socket_disconnect_and_release(_socket);
-	_socket = NULL;
-}
-
-- (void) testSetURL {
-    // This is an example of a functional test case.
-    // Use XCTAssert and related functions to verify your tests produce the correct results.
-
-	rws_socket_set_url(_socket, "ws", "host", 80, "/");
-
-	XCTAssert(strcmp(rws_socket_get_scheme(_socket), "ws") == 0, @"set get scheme");
-	XCTAssert(strcmp(rws_socket_get_host(_socket), "host") == 0, @"set get host");
-	XCTAssert(strcmp(rws_socket_get_path(_socket), "/") == 0, @"set get path");
-	XCTAssert(rws_socket_get_port(_socket) == 80, @"set get port");
-
-	rws_socket_set_url(_socket, NULL, NULL, -2, NULL);
-	XCTAssert(rws_socket_get_scheme(_socket) == NULL, @"set get scheme");
-	XCTAssert(rws_socket_get_host(_socket) == NULL, @"set get host");
-	XCTAssert(rws_socket_get_path(_socket) == NULL, @"set get path");
-	XCTAssert(rws_socket_get_port(_socket) == -2, @"set get port");
-
-	XCTAssert(rws_socket_get_scheme(NULL) == NULL, @"set get scheme");
-	XCTAssert(rws_socket_get_host(NULL) == NULL, @"set get host");
-	XCTAssert(rws_socket_get_path(NULL) == NULL, @"set get path");
-	XCTAssert(rws_socket_get_port(NULL) < 0, @"set get port");
-
-	rws_socket_set_scheme(_socket, "ws1");
-	rws_socket_set_scheme(NULL, "ws2");
-	rws_socket_set_scheme(NULL, NULL);
-	XCTAssert(strcmp(rws_socket_get_scheme(_socket), "ws1") == 0, @"set get scheme");
-	rws_socket_set_scheme(_socket, NULL);
-	XCTAssert(rws_socket_get_scheme(_socket) == NULL, @"set get scheme");
-
-	rws_socket_set_host(_socket, "host1");
-	rws_socket_set_host(NULL, "host1");
-	rws_socket_set_host(NULL, NULL);
-	XCTAssert(strcmp(rws_socket_get_host(_socket), "host1") == 0, @"set get host");
-	rws_socket_set_host(_socket, NULL);
-	XCTAssert(rws_socket_get_host(_socket) == NULL, @"set get host");
-
-	rws_socket_set_path(_socket, "/path1");
-	rws_socket_set_path(NULL, "/path1");
-	rws_socket_set_path(NULL, NULL);
-	XCTAssert(strcmp(rws_socket_get_path(_socket), "/path1") == 0, @"set get path");
-	rws_socket_set_path(_socket, NULL);
-	XCTAssert(rws_socket_get_path(_socket) == NULL, @"set get path");
-
-
-	XCTAssert(rws_socket_get_error(_socket) == NULL, @"set get error");
-	XCTAssert(rws_socket_get_error(NULL) == NULL, @"set get error");
-
-
-	XCTAssertFalse(rws_socket_is_connected(_socket), "check is connected without connect");
-	XCTAssertFalse(rws_socket_is_connected(NULL), "check is connected without connect");
-
-
-	rws_socket_set_user_object(_socket, (__bridge void *)self);
-	rws_socket_set_user_object(NULL, NULL);
-	id thisTestClass = (__bridge id)(rws_socket_get_user_object(_socket));
-	XCTAssertEqualObjects(self, thisTestClass, @"user object incorrect");
-	XCTAssert(rws_socket_get_user_object(NULL) == NULL, @"user object incorrect");
-
-	rws_socket_set_user_object(_socket, NULL);
-	XCTAssert(rws_socket_get_user_object(_socket) == NULL, @"user object incorrect");
-}
-
-- (void)testPerformanceExample {
-    // This is an example of a performance test case.
-    [self measureBlock:^{
-        // Put the code you want to measure the time of here.
-    }];
-}
-
-@end

+ 0 - 103
test/test_librws_creation.c

@@ -1,103 +0,0 @@
-/*
- *   Copyright (c) 2014 - 2019 Oleh Kulykov <info@resident.name>
- *
- *   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.
- */
-
-
-#include <stdlib.h>
-#include <assert.h>
-#include <string.h>
-
-#if defined(CMAKE_BUILD)
-#undef CMAKE_BUILD
-#endif
-
-
-#if defined(XCODE)
-#include "librws.h"
-#else
-#include <librws.h>
-#endif
-
-
-#if defined(CMAKE_BUILD)
-#undef CMAKE_BUILD
-#endif
-
-static rws_socket _socket = NULL;
-
-static void on_socket_received_text(rws_socket socket, const char * text, const unsigned int length) {
-	char buff[8*1024];
-	memcpy(buff, text, length);
-	buff[length] = 0;
-
-	printf("\nSocket text: %s", text);
-}
-
-static void on_socket_received_bin(rws_socket socket, const void * data, const unsigned int length) {
-	char buff[8*1024];
-	memcpy(buff, data, length);
-	buff[length] = 0;
-
-	printf("\nSocket bin: <%s>", buff);
-}
-
-static void on_socket_connected(rws_socket socket) {
-	const char * test_send_text =
-	"{\"version\":\"1.0\",\"supportedConnectionTypes\":[\"websocket\"],\"minimumVersion\":\"1.0\",\"channel\":\"/meta/handshake\"}";
-
-	printf("\nSocket connected");
-
-	rws_socket_send_text(socket, test_send_text);
-}
-
-static void on_socket_disconnected(rws_socket socket) {
-	rws_error error = rws_socket_get_error(socket);
-	if (error) {
-		printf("\nSocket disconnect with code, error: %i, %s",
-			  rws_error_get_code(error),
-			  rws_error_get_description(error));
-	}
-}
-
-int main(int argc, char* argv[]) {
-	_socket = rws_socket_create(); // create and store socket handle
-	assert(_socket);
-
-	rws_socket_set_scheme(_socket, "ws");
-	rws_socket_set_host(_socket, "echo.websocket.org");
-	rws_socket_set_path(_socket, "/");
-	rws_socket_set_port(_socket, 80);
-
-	rws_socket_set_on_disconnected(_socket, &on_socket_disconnected);
-	rws_socket_set_on_connected(_socket, &on_socket_connected);
-	rws_socket_set_on_received_text(_socket, &on_socket_received_text);
-	rws_socket_set_on_received_bin(_socket, &on_socket_received_bin);
-
-#if !defined(RWS_APPVEYOR_CI)
-	// connection denied for client applications
-	rws_socket_connect(_socket);
-#endif
-
-	// main loop here
-
-	return 0;
-}
-

+ 0 - 83
test/test_librws_socket_get_set.c

@@ -1,83 +0,0 @@
-/*
- *   Copyright (c) 2014 - 2019 Oleh Kulykov <info@resident.name>
- *
- *   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.
- */
-
-
-#include <stdlib.h>
-#include <assert.h>
-#include <string.h>
-
-
-#if defined(CMAKE_BUILD)
-#undef CMAKE_BUILD
-#endif
-
-#if defined(XCODE)
-#include "librws.h"
-#else
-#include <librws.h>
-#endif
-
-#if defined(CMAKE_BUILD)
-#undef CMAKE_BUILD
-#endif
-
-int main(int argc, char* argv[]) {
-	const char * scheme = "ws";
-	const char * host = "echo.websocket.org";
-	const char * path = "/";
-	
-	rws_socket socket = rws_socket_create();
-	assert(socket);
-
-
-	rws_socket_set_scheme(socket, scheme);								printf("%i\n", (int)__LINE__);
-	assert(strcmp(rws_socket_get_scheme(socket), scheme) == 0);			printf("%i\n", (int)__LINE__);
-
-	rws_socket_set_host(socket, host);									printf("%i\n", (int)__LINE__);
-	assert(strcmp(rws_socket_get_host(socket), host) == 0);				printf("%i\n", (int)__LINE__);
-
-	rws_socket_set_path(socket, path);									printf("%i\n", (int)__LINE__);
-	assert(strcmp(rws_socket_get_path(socket), path) == 0);				printf("%i\n", (int)__LINE__);
-
-	rws_socket_set_port(socket, 80);									printf("%i\n", (int)__LINE__);
-	assert(rws_socket_get_port(socket) == 80);							printf("%i\n", (int)__LINE__);
-
-	rws_socket_set_port(socket, 443);									printf("%i\n", (int)__LINE__);
-	assert(rws_socket_get_port(socket) == 443);							printf("%i\n", (int)__LINE__);
-
-
-
-	rws_socket_set_scheme(socket, NULL);								printf("%i\n", (int)__LINE__);
-	assert(rws_socket_get_scheme(socket) == NULL);						printf("%i\n", (int)__LINE__);
-
-	rws_socket_set_host(socket, NULL);									printf("%i\n", (int)__LINE__);
-	assert(rws_socket_get_host(socket) == NULL);						printf("%i\n", (int)__LINE__);
-
-	rws_socket_set_path(socket, NULL);									printf("%i\n", (int)__LINE__);
-	assert(rws_socket_get_path(socket) == NULL);						printf("%i\n", (int)__LINE__);
-
-
-	rws_socket_disconnect_and_release(socket);
-
-	return 0;
-}
-