From 05a88c89dc552f56a2d896964d94dd3551f01465 Mon Sep 17 00:00:00 2001 From: James Chen Date: Fri, 31 May 2013 23:13:03 +0800 Subject: [PATCH 1/8] fixed #1647: Adding WebSocket support for Cpp and JSB. --- cocos2dx/platform/win32/CCStdC.cpp | 4 + cocos2dx/platform/win32/CCStdC.h | 3 + extensions/Android.mk | 3 + extensions/network/WebSocket.cpp | 658 ++++++++++++ extensions/network/WebSocket.h | 154 +++ extensions/proj.win32/libExtensions.vcxproj | 6 +- .../proj.win32/libExtensions.vcxproj.filters | 20 +- external/libwebsockets/android/Android.mk | 10 + .../android/include/libwebsockets.h | 993 ++++++++++++++++++ .../libwebsockets/ios/include/libwebsockets.h | 993 ++++++++++++++++++ .../ios/lib/libwebsockets.a.REMOVED.git-id | 1 + .../win32/include/libwebsockets.h | 993 ++++++++++++++++++ .../win32/include/win32helpers/gettimeofday.h | 28 + .../win32/include/win32helpers/websock-w32.h | 62 ++ licenses/LICENSE_libwebsockets.txt | 526 ++++++++++ samples/Cpp/TestCpp/Android.mk | 1 + .../Classes/ExtensionsTest/ExtensionsTest.cpp | 17 + .../NetworkTest/WebSocketTest.cpp | 241 +++++ .../NetworkTest/WebSocketTest.h | 50 + .../project.pbxproj.REMOVED.git-id | 2 +- .../Cpp/TestCpp/proj.win32/TestCpp.vcxproj | 10 +- .../proj.win32/TestCpp.vcxproj.filters | 6 + .../TestJavascript/Classes/AppDelegate.cpp | 3 + .../project.pbxproj.REMOVED.git-id | 2 +- scripting/javascript/bindings/Android.mk | 3 +- .../bindings/proj.win32/libJSBinding.vcxproj | 6 +- .../proj.win32/libJSBinding.vcxproj.filters | 6 + 27 files changed, 4783 insertions(+), 18 deletions(-) create mode 100644 extensions/network/WebSocket.cpp create mode 100644 extensions/network/WebSocket.h create mode 100644 external/libwebsockets/android/Android.mk create mode 100644 external/libwebsockets/android/include/libwebsockets.h create mode 100644 external/libwebsockets/ios/include/libwebsockets.h create mode 100644 external/libwebsockets/ios/lib/libwebsockets.a.REMOVED.git-id create mode 100644 external/libwebsockets/win32/include/libwebsockets.h create mode 100644 external/libwebsockets/win32/include/win32helpers/gettimeofday.h create mode 100644 external/libwebsockets/win32/include/win32helpers/websock-w32.h create mode 100644 licenses/LICENSE_libwebsockets.txt create mode 100644 samples/Cpp/TestCpp/Classes/ExtensionsTest/NetworkTest/WebSocketTest.cpp create mode 100644 samples/Cpp/TestCpp/Classes/ExtensionsTest/NetworkTest/WebSocketTest.h diff --git a/cocos2dx/platform/win32/CCStdC.cpp b/cocos2dx/platform/win32/CCStdC.cpp index 426234c3ca..8368194f76 100644 --- a/cocos2dx/platform/win32/CCStdC.cpp +++ b/cocos2dx/platform/win32/CCStdC.cpp @@ -26,6 +26,8 @@ THE SOFTWARE. #ifndef __MINGW32__ +NS_CC_BEGIN + int gettimeofday(struct timeval * val, struct timezone *) { if (val) @@ -39,4 +41,6 @@ int gettimeofday(struct timeval * val, struct timezone *) return 0; } +NS_CC_END + #endif // __MINGW32__ diff --git a/cocos2dx/platform/win32/CCStdC.h b/cocos2dx/platform/win32/CCStdC.h index 5b90c0824b..28e574a98e 100644 --- a/cocos2dx/platform/win32/CCStdC.h +++ b/cocos2dx/platform/win32/CCStdC.h @@ -87,6 +87,7 @@ THE SOFTWARE. #include +NS_CC_BEGIN struct timezone { @@ -96,6 +97,8 @@ struct timezone int CC_DLL gettimeofday(struct timeval *, struct timezone *); +NS_CC_END + #else #include diff --git a/extensions/Android.mk b/extensions/Android.mk index c410362b97..800c0e4364 100644 --- a/extensions/Android.mk +++ b/extensions/Android.mk @@ -48,6 +48,7 @@ GUI/CCScrollView/CCSorting.cpp \ GUI/CCEditBox/CCEditBox.cpp \ GUI/CCEditBox/CCEditBoxImplAndroid.cpp \ network/HttpClient.cpp \ +network/WebSocket.cpp \ physics_nodes/CCPhysicsDebugNode.cpp \ physics_nodes/CCPhysicsSprite.cpp \ LocalStorage/LocalStorageAndroid.cpp \ @@ -76,6 +77,7 @@ LOCAL_WHOLE_STATIC_LIBRARIES += cocosdenshion_static LOCAL_WHOLE_STATIC_LIBRARIES += cocos_curl_static LOCAL_WHOLE_STATIC_LIBRARIES += box2d_static LOCAL_WHOLE_STATIC_LIBRARIES += chipmunk_static +LOCAL_WHOLE_STATIC_LIBRARIES += libwebsockets_static LOCAL_CFLAGS += -DCC_ENABLE_CHIPMUNK_INTEGRATION=1 LOCAL_EXPORT_CFLAGS += -DCC_ENABLE_CHIPMUNK_INTEGRATION=1 @@ -94,3 +96,4 @@ $(call import-module,CocosDenshion/android) $(call import-module,cocos2dx/platform/third_party/android/prebuilt/libcurl) $(call import-module,external/Box2D) $(call import-module,external/chipmunk) +$(call import-module,external/libwebsockets/android) diff --git a/extensions/network/WebSocket.cpp b/extensions/network/WebSocket.cpp new file mode 100644 index 0000000000..844fd9ed99 --- /dev/null +++ b/extensions/network/WebSocket.cpp @@ -0,0 +1,658 @@ +/**************************************************************************** + Copyright (c) 2010-2013 cocos2d-x.org + Copyright (c) 2013 James Chen + + http://www.cocos2d-x.org + + 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 "WebSocket.h" +#include +#include +#include + +NS_CC_EXT_BEGIN + +class WsMessage +{ +public: + WsMessage() : what(0), obj(NULL){} + unsigned int what; // message type + void* obj; +}; + +/** + * @brief Websocket thread helper, it's used for sending message between UI thread and websocket thread. + */ +class WsThreadHelper : public cocos2d::CCObject +{ +public: + WsThreadHelper(); + ~WsThreadHelper(); + + // Creates a new thread + bool createThread(const WebSocket& ws); + // Quits sub-thread (websocket thread). + void quitSubThread(); + + // Schedule callback function + virtual void update(float dt); + + // Sends message to UI thread. It's needed to be invoked in sub-thread. + void sendMessageToUIThread(WsMessage *msg); + + // Sends message to sub-thread(websocket thread). It's needs to be invoked in UI thread. + void sendMessageToSubThread(WsMessage *msg); + + // Waits the sub-thread (websocket thread) to exit, + void joinSubThread(); + + +protected: + friend class WsThreadEntry; + void* wsThreadEntryFunc(void* arg); + +private: + std::list* _UIWsMessageQueue; + std::list* _subThreadWsMessageQueue; + pthread_mutex_t _UIWsMessageQueueMutex; + pthread_mutex_t _subThreadWsMessageQueueMutex; + pthread_t _subThreadInstance; + WebSocket* _ws; + bool _needQuit; + friend class WebSocket; +}; + +// Wrapper for converting websocket callback from static function to member function of WebSocket class. +class WebSocketCallbackWrapper { +public: + + static int onSocketCallback(struct libwebsocket_context *ctx, + struct libwebsocket *wsi, + enum libwebsocket_callback_reasons reason, + void *user, void *in, size_t len) + { + // Gets the user data from context. We know that it's a 'WebSocket' instance. + WebSocket* wsInstance = (WebSocket*)libwebsocket_context_user(ctx); + if (wsInstance) + { + return wsInstance->onSocketCallback(ctx, wsi, reason, user, in, len); + } + return 0; + } +}; + +// Implementation of WsThreadHelper +WsThreadHelper::WsThreadHelper() +: _ws(NULL) +, _needQuit(false) +{ + _UIWsMessageQueue = new std::list(); + pthread_mutex_init(&_UIWsMessageQueueMutex, NULL); + _subThreadWsMessageQueue = new std::list(); + pthread_mutex_init(&_subThreadWsMessageQueueMutex, NULL); + + CCDirector::sharedDirector()->getScheduler()->scheduleUpdateForTarget(this, 0, false); +} + +WsThreadHelper::~WsThreadHelper() +{ + CCDirector::sharedDirector()->getScheduler()->unscheduleAllForTarget(this); + pthread_mutex_destroy(&_UIWsMessageQueueMutex); + pthread_mutex_destroy(&_subThreadWsMessageQueueMutex); + delete _UIWsMessageQueue; + delete _subThreadWsMessageQueue; +} + +// For converting static function to member function +class WsThreadEntry +{ +public: + static void* entry(void* arg) + { + WsThreadHelper* self = static_cast(arg); + return self->wsThreadEntryFunc(arg); + } +}; + +bool WsThreadHelper::createThread(const WebSocket& ws) +{ + _ws = const_cast(&ws); + pthread_attr_t attr; + pthread_attr_init (&attr); +// pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); + + // Creates websocket thread + if (0 == pthread_create(&_subThreadInstance, &attr, WsThreadEntry::entry, this)) + { + return true; + } + return false; +} + +void WsThreadHelper::quitSubThread() +{ + _needQuit = true; +} + +void* WsThreadHelper::wsThreadEntryFunc(void* arg) +{ + _ws->onSubThreadStarted(); + + while (!_needQuit) + { + if (_ws->onSubThreadLoop()) + { + break; + } + } + + _ws->onSubThreadEnded(); + + return (void*)0; +} + +void WsThreadHelper::sendMessageToUIThread(WsMessage *msg) +{ + pthread_mutex_lock(&_UIWsMessageQueueMutex); + _UIWsMessageQueue->push_back(msg); + pthread_mutex_unlock(&_UIWsMessageQueueMutex); +} + +void WsThreadHelper::sendMessageToSubThread(WsMessage *msg) +{ + pthread_mutex_lock(&_subThreadWsMessageQueueMutex); + _subThreadWsMessageQueue->push_back(msg); + pthread_mutex_unlock(&_subThreadWsMessageQueueMutex); +} + +void WsThreadHelper::joinSubThread() +{ + void* ret = NULL; + pthread_join(_subThreadInstance, &ret); +} + +void WsThreadHelper::update(float dt) +{ + WsMessage *msg = NULL; + + // Returns quickly if no message + pthread_mutex_lock(&_UIWsMessageQueueMutex); + if (0 == _UIWsMessageQueue->size()) + { + pthread_mutex_unlock(&_UIWsMessageQueueMutex); + return; + } + + // Gets message + msg = *(_UIWsMessageQueue->begin()); + _UIWsMessageQueue->pop_front(); + pthread_mutex_unlock(&_UIWsMessageQueueMutex); + + if (_ws) + { + _ws->onUIThreadReceiveMessage(msg); + } + + CC_SAFE_DELETE(msg); +} + +enum WS_MSG { + WS_MSG_TO_SUBTRHEAD_SENDING_STRING = 0, + WS_MSG_TO_SUBTRHEAD_SENDING_BINARY, + WS_MSG_TO_SUBTRHEAD_CLOSING, + WS_MSG_TO_UITHREAD_OPEN, + WS_MSG_TO_UITHREAD_MESSAGE, + WS_MSG_TO_UITHREAD_ERROR, + WS_MSG_TO_UITHREAD_CLOSE +}; + +WebSocket::WebSocket() +: _readyState(WS_STATE_CONNECTING) +, _port(80) +, _wsHelper(NULL) +, _wsInstance(NULL) +, _wsContext(NULL) +, _delegate(NULL) +, _SSLConnection(0) +, _wsProtocols(NULL) +{ +} + +WebSocket::~WebSocket() +{ + close(); + CC_SAFE_RELEASE_NULL(_wsHelper); + + for (int i = 0; _wsProtocols[i].callback != NULL; ++i) { + CC_SAFE_DELETE_ARRAY(_wsProtocols[i].name); + } + CC_SAFE_DELETE_ARRAY(_wsProtocols); +} + +bool WebSocket::init(const Delegate& delegate, + const std::string& url, + const std::vector* protocols/* = NULL*/) +{ + bool ret = false; + bool useSSL = false; + std::string host = url; + int pos = 0; + int port = 80; + + _delegate = const_cast(&delegate); + + //ws:// + pos = host.find("ws://"); + if (pos == 0){ + host.erase(0,5); + } + + pos = host.find("wss://"); + if (pos == 0) + { + host.erase(0,6); + useSSL = true; + } + + pos = host.find(":"); + if(pos >= 0){ + port = atoi(host.substr(pos+1, host.size()).c_str()); + } + + pos = host.find("/", pos); + std::string path = "/"; + if(pos >= 0){ + path += host.substr(pos + 1, host.size()); + } + + pos = host.find(":"); + if(pos >= 0){ + host.erase(pos, host.size()); + } + + + _host = host; + _port = port; + _path = path; + _SSLConnection = useSSL ? 1 : 0; + + int protocolCount = 0; + if (protocols && protocols->size() > 0) + { + protocolCount = protocols->size(); + } + else + { + protocolCount = 1; + } + + _wsProtocols = new libwebsocket_protocols[protocolCount+1]; + memset(_wsProtocols, 0, sizeof(libwebsocket_protocols)*(protocolCount+1)); + + if (protocols) + { + int i = 0; + for (std::vector::const_iterator iter = protocols->begin(); iter != protocols->end(); ++iter, ++i) { + char* name = new char[(*iter).length()+1]; + strcpy(name, (*iter).c_str()); + _wsProtocols[i].name = name; + _wsProtocols[i].callback = WebSocketCallbackWrapper::onSocketCallback; + } + } + else + { + char* name = new char[20]; + strcpy(name, "default-protocol"); + _wsProtocols[0].name = name; + _wsProtocols[0].callback = WebSocketCallbackWrapper::onSocketCallback; + } + + + // WebSocket thread needs to be invoked at the end of this method. + _wsHelper = new WsThreadHelper(); + ret = _wsHelper->createThread(*this); + + return ret; +} + +void WebSocket::send(const std::string& message) +{ + if (_readyState == WS_STATE_OPEN) + { + // In main thread + WsMessage* msg = new WsMessage(); + msg->what = WS_MSG_TO_SUBTRHEAD_SENDING_STRING; + Data* data = new Data(); + data->bytes = new char[message.length()+1]; + strcpy(data->bytes, message.c_str()); + data->len = message.length(); + msg->obj = data; + _wsHelper->sendMessageToSubThread(msg); + } +} + +void WebSocket::send(const unsigned char* binaryMsg, unsigned int len) +{ + CCAssert(binaryMsg != NULL && len > 0, "parameter invalid."); + + if (_readyState == WS_STATE_OPEN) + { + // In main thread + WsMessage* msg = new WsMessage(); + msg->what = WS_MSG_TO_SUBTRHEAD_SENDING_BINARY; + Data* data = new Data(); + data->bytes = new char[len]; + memcpy((void*)data->bytes, (void*)binaryMsg, len); + data->len = len; + msg->obj = data; + _wsHelper->sendMessageToSubThread(msg); + } +} + +void WebSocket::close() +{ + CCDirector::sharedDirector()->getScheduler()->unscheduleAllForTarget(_wsHelper); + + if (_readyState == WS_STATE_CLOSING || _readyState == WS_STATE_CLOSED) + return; + + CCLOG("websocket (%p) connection closed by client", this); + _readyState = WS_STATE_CLOSED; + + WsMessage* msg = new WsMessage(); + msg->what = WS_MSG_TO_SUBTRHEAD_CLOSING; + + _wsHelper->sendMessageToSubThread(msg); + _wsHelper->joinSubThread(); + + // onClose callback needs to be invoked at the end of this method + // since websocket instance may be deleted in 'onClose'. + _delegate->onClose(this); +} + +WebSocket::WS_STATE WebSocket::getReadyState() +{ + return _readyState; +} + +int WebSocket::onSubThreadLoop() +{ + if (_readyState == WS_STATE_CLOSED || _readyState == WS_STATE_CLOSING) + { + libwebsocket_context_destroy(_wsContext); + // return 1 to exit the loop. + return 1; + } + + if (_wsContext && _readyState != WS_STATE_CLOSED && _readyState != WS_STATE_CLOSING) + { + libwebsocket_service(_wsContext, 0); + } + + // Sleep 50 ms +#ifdef WIN32 + Sleep(50); +#else + usleep(50000); +#endif + // return 0 to continue the loop. + return 0; +} + +void WebSocket::onSubThreadStarted() +{ + struct lws_context_creation_info info; + memset(&info, 0, sizeof info); + + /* + * create the websocket context. This tracks open connections and + * knows how to route any traffic and which protocol version to use, + * and if each connection is client or server side. + * + * For this client-only demo, we tell it to not listen on any port. + */ + + info.port = CONTEXT_PORT_NO_LISTEN; + info.protocols = _wsProtocols; +#ifndef LWS_NO_EXTENSIONS + info.extensions = libwebsocket_get_internal_extensions(); +#endif + info.gid = -1; + info.uid = -1; + info.user = (void*)this; + + _wsContext = libwebsocket_create_context(&info); + + if(NULL != _wsContext){ + _readyState = WS_STATE_CONNECTING; + std::string name; + for (int i = 0; _wsProtocols[i].callback != NULL; ++i) { + name += (_wsProtocols[i].name); + if (_wsProtocols[i+1].callback != NULL) + { + name += ", "; + } + } + _wsInstance = libwebsocket_client_connect(_wsContext, _host.c_str(), _port, _SSLConnection, + _path.c_str(), _host.c_str(), _host.c_str(), + name.c_str(), -1); + } +} + +void WebSocket::onSubThreadEnded() +{ + +} + + +int WebSocket::onSocketCallback(struct libwebsocket_context *ctx, + struct libwebsocket *wsi, + enum libwebsocket_callback_reasons reason, + void *user, void *in, size_t len) +{ + //CCLOG("socket callback for %d reason", reason); + CCAssert(_wsContext == NULL || ctx == _wsContext, "Invalid context."); + CCAssert(_wsInstance == NULL || wsi == NULL || wsi == _wsInstance, "Invaild websocket instance."); + + switch (reason) + { + case LWS_CALLBACK_DEL_POLL_FD: + case LWS_CALLBACK_PROTOCOL_DESTROY: + case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: + { + WsMessage* msg = new WsMessage(); + if (reason == LWS_CALLBACK_CLIENT_CONNECTION_ERROR + || (reason == LWS_CALLBACK_PROTOCOL_DESTROY && _readyState == WS_STATE_CONNECTING) + || (reason == LWS_CALLBACK_DEL_POLL_FD && _readyState == WS_STATE_CONNECTING) + ) + { + msg->what = WS_MSG_TO_UITHREAD_ERROR; + _readyState = WS_STATE_CLOSING; + } + else if (reason == LWS_CALLBACK_PROTOCOL_DESTROY && _readyState == WS_STATE_CLOSING) + { + msg->what = WS_MSG_TO_UITHREAD_CLOSE; + } + _wsHelper->sendMessageToUIThread(msg); + } + break; + case LWS_CALLBACK_CLIENT_ESTABLISHED: + { + WsMessage* msg = new WsMessage(); + msg->what = WS_MSG_TO_UITHREAD_OPEN; + _readyState = WS_STATE_OPEN; + /* + * start the ball rolling, + * LWS_CALLBACK_CLIENT_WRITEABLE will come next service + */ + libwebsocket_callback_on_writable(ctx, wsi); + _wsHelper->sendMessageToUIThread(msg); + } + break; + + case LWS_CALLBACK_CLIENT_WRITEABLE: + { + pthread_mutex_lock(&_wsHelper->_subThreadWsMessageQueueMutex); + std::list::iterator iter = _wsHelper->_subThreadWsMessageQueue->begin(); + + int bytesWrite = 0; + for (; iter != _wsHelper->_subThreadWsMessageQueue->end(); ++iter) { + + WsMessage* subThreadMsg = *iter; + + if ( WS_MSG_TO_SUBTRHEAD_SENDING_STRING == subThreadMsg->what + || WS_MSG_TO_SUBTRHEAD_SENDING_BINARY == subThreadMsg->what) + { + Data* data = (Data*)subThreadMsg->obj; + + unsigned char* buf = new unsigned char[LWS_SEND_BUFFER_PRE_PADDING + + data->len + LWS_SEND_BUFFER_POST_PADDING]; + + memset(&buf[LWS_SEND_BUFFER_PRE_PADDING], 0, data->len); + memcpy((char*)&buf[LWS_SEND_BUFFER_PRE_PADDING], data->bytes, data->len); + + enum libwebsocket_write_protocol writeProtocol; + + if (WS_MSG_TO_SUBTRHEAD_SENDING_STRING == subThreadMsg->what) + { + writeProtocol = LWS_WRITE_TEXT; + } + else + { + writeProtocol = LWS_WRITE_BINARY; + } + + bytesWrite = libwebsocket_write(wsi, &buf[LWS_SEND_BUFFER_PRE_PADDING], data->len, writeProtocol); + + if (bytesWrite < 0) { + CCLOGERROR("%s", "libwebsocket_write error..."); + } + if (bytesWrite < data->len) { + CCLOGERROR("Partial write LWS_CALLBACK_CLIENT_WRITEABLE\n"); + } + + CC_SAFE_DELETE_ARRAY(data->bytes); + CC_SAFE_DELETE(data); + CC_SAFE_DELETE_ARRAY(buf); + } + } + + _wsHelper->_subThreadWsMessageQueue->clear(); + + pthread_mutex_unlock(&_wsHelper->_subThreadWsMessageQueueMutex); + + /* get notified as soon as we can write again */ + + libwebsocket_callback_on_writable(ctx, wsi); + } + break; + + case LWS_CALLBACK_CLOSED: + { + + CCLOG("%s", "connection closing.."); + + _wsHelper->quitSubThread(); + + if (_readyState != WS_STATE_CLOSED) + { + WsMessage* msg = new WsMessage(); + _readyState = WS_STATE_CLOSED; + msg->what = WS_MSG_TO_UITHREAD_CLOSE; + _wsHelper->sendMessageToUIThread(msg); + } + } + break; + + case LWS_CALLBACK_CLIENT_RECEIVE: + { + if (in && len > 0) + { + WsMessage* msg = new WsMessage(); + msg->what = WS_MSG_TO_UITHREAD_MESSAGE; + + char* bytes = NULL; + Data* data = new Data(); + + if (lws_frame_is_binary(wsi)) + { + + bytes = new char[len]; + data->isBinary = true; + } + else + { + bytes = new char[len+1]; + bytes[len] = '\0'; + data->isBinary = false; + } + + memcpy(bytes, in, len); + + data->bytes = bytes; + data->len = len; + msg->obj = (void*)data; + + _wsHelper->sendMessageToUIThread(msg); + } + } + break; + default: + break; + + } + + return 0; +} + +void WebSocket::onUIThreadReceiveMessage(WsMessage* msg) +{ + switch (msg->what) { + case WS_MSG_TO_UITHREAD_OPEN: + { + _delegate->onOpen(this); + } + break; + case WS_MSG_TO_UITHREAD_MESSAGE: + { + Data* data = (Data*)msg->obj; + _delegate->onMessage(this, *data); + CC_SAFE_DELETE_ARRAY(data->bytes); + CC_SAFE_DELETE(data); + } + break; + case WS_MSG_TO_UITHREAD_CLOSE: + { + _delegate->onClose(this); + } + break; + case WS_MSG_TO_UITHREAD_ERROR: + { + WebSocket::WS_ERROR err = WS_ERROR_CONNECTION_FAILS; + _delegate->onError(this, err); + } + break; + default: + break; + } +} + +NS_CC_EXT_END diff --git a/extensions/network/WebSocket.h b/extensions/network/WebSocket.h new file mode 100644 index 0000000000..021e4e4395 --- /dev/null +++ b/extensions/network/WebSocket.h @@ -0,0 +1,154 @@ +/**************************************************************************** + Copyright (c) 2010-2013 cocos2d-x.org + Copyright (c) 2013 James Chen + + http://www.cocos2d-x.org + + 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 __CC_WEBSOCKET_H__ +#define __CC_WEBSOCKET_H__ + +#include "ExtensionMacros.h" +#include +#include "cocos2d.h" +#include "libwebsockets.h" +#include + +NS_CC_EXT_BEGIN + +class WsThreadHelper; +class WsMessage; + +class WebSocket +{ +public: + WebSocket(); + virtual ~WebSocket(); + + /** + * @brief Data structure for message + */ + struct Data + { + Data():bytes(NULL), len(0), isBinary(false){} + char* bytes; + int len; + bool isBinary; + }; + + /** + * @brief Errors in websocket + */ + enum WS_ERROR + { + WS_ERROR_TIMEOUT=0, + WS_ERROR_CONNECTION_FAILS, + WS_ERROR_UNKNOWN + }; + + /** + * @brief The delegate class to process websocket events. + */ + class Delegate + { + public: + virtual ~Delegate() {} + virtual void onOpen(WebSocket* ws) = 0; + virtual void onMessage(WebSocket* ws, const Data& data) = 0; + virtual void onClose(WebSocket* ws) = 0; + virtual void onError(WebSocket* ws, const WS_ERROR& error) = 0; + }; + + + /** + * @brief The initialized method for websocket. + * It needs to be invoked right after websocket instance is allocated. + * @param delegate The delegate which want to receive event from websocket. + * @param url The URL of websocket server. + * @return true: Success, false: Failure + */ + bool init(const Delegate& delegate, + const std::string& url, + const std::vector* protocols = NULL); + + /** + * @brief Sends string data to websocket server. + */ + void send(const std::string& message); + + /** + * @brief Sends binary data to websocket server. + */ + void send(const unsigned char* binaryMsg, unsigned int len); + + /** + * @brief Closes the connection to server. + */ + void close(); + + /** + * Websocket state + */ + enum WS_STATE + { + WS_STATE_CONNECTING = 0, + WS_STATE_OPEN, + WS_STATE_CLOSING, + WS_STATE_CLOSED + }; + + /** + * @brief Gets current state of connection. + */ + WS_STATE getReadyState(); + +private: + virtual void onSubThreadStarted(); + virtual int onSubThreadLoop(); + virtual void onSubThreadEnded(); + virtual void onUIThreadReceiveMessage(WsMessage* msg); + + + friend class WebSocketCallbackWrapper; + int onSocketCallback(struct libwebsocket_context *ctx, + struct libwebsocket *wsi, + enum libwebsocket_callback_reasons reason, + void *user, void *in, size_t len); + +private: + WS_STATE _readyState; + std::string _host; + unsigned int _port; + std::string _path; + + friend class WsThreadHelper; + WsThreadHelper* _wsHelper; + + struct libwebsocket* _wsInstance; + struct libwebsocket_context* _wsContext; + Delegate* _delegate; + int _SSLConnection; + libwebsocket_protocols* _wsProtocols; +}; + +NS_CC_EXT_END + +#endif /* defined(__CC_JSB_WEBSOCKET_H__) */ diff --git a/extensions/proj.win32/libExtensions.vcxproj b/extensions/proj.win32/libExtensions.vcxproj index 53b27bb577..a7a318899f 100644 --- a/extensions/proj.win32/libExtensions.vcxproj +++ b/extensions/proj.win32/libExtensions.vcxproj @@ -63,7 +63,7 @@ Disabled - $(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A\include;$(ProjectDir)..\..\external\chipmunk\include\chipmunk;$(ProjectDir)..\..\external\sqlite3\include;$(ProjectDir)..\..\external;$(ProjectDir)..\..\cocos2dx;$(ProjectDir)..\..\cocos2dx\include;$(ProjectDir)..\..\cocos2dx\kazmath\include;$(ProjectDir)..\..\cocos2dx\platform\win32;$(ProjectDir)..\..\cocos2dx\platform\third_party\win32;$(ProjectDir)..\..\cocos2dx\platform\third_party\win32\pthread;$(ProjectDir)..\..\cocos2dx\platform\third_party\win32\OGLES;$(ProjectDir)..\..\cocos2dx\platform\third_party\win32\zlib;$(ProjectDir)..\..\CocosDenshion\include;..\;%(AdditionalIncludeDirectories) + $(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A\include;$(ProjectDir)..\..\external\chipmunk\include\chipmunk;$(ProjectDir)..\..\external\sqlite3\include;$(ProjectDir)..\..\external;$(ProjectDir)..\..\external\libwebsockets\win32\include;$(ProjectDir)..\..\cocos2dx;$(ProjectDir)..\..\cocos2dx\include;$(ProjectDir)..\..\cocos2dx\kazmath\include;$(ProjectDir)..\..\cocos2dx\platform\win32;$(ProjectDir)..\..\cocos2dx\platform\third_party\win32;$(ProjectDir)..\..\cocos2dx\platform\third_party\win32\pthread;$(ProjectDir)..\..\cocos2dx\platform\third_party\win32\OGLES;$(ProjectDir)..\..\cocos2dx\platform\third_party\win32\zlib;$(ProjectDir)..\..\CocosDenshion\include;..\;%(AdditionalIncludeDirectories) WIN32;_WINDOWS;_DEBUG;_LIB;COCOS2D_DEBUG=1;CC_ENABLE_CHIPMUNK_INTEGRATION=1;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true EnableFastChecks @@ -79,7 +79,7 @@ MaxSpeed true - $(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A\include;$(ProjectDir)..\..\external\chipmunk\include\chipmunk;$(ProjectDir)..\..\external\sqlite3\include;$(ProjectDir)..\..\external;$(ProjectDir)..\..\cocos2dx;$(ProjectDir)..\..\cocos2dx\include;$(ProjectDir)..\..\cocos2dx\kazmath\include;$(ProjectDir)..\..\cocos2dx\platform\win32;$(ProjectDir)..\..\cocos2dx\platform\third_party\win32;$(ProjectDir)..\..\cocos2dx\platform\third_party\win32\pthread;$(ProjectDir)..\..\cocos2dx\platform\third_party\win32\OGLES;$(ProjectDir)..\..\cocos2dx\platform\third_party\win32\zlib;$(ProjectDir)..\..\CocosDenshion\include;..\;%(AdditionalIncludeDirectories) + $(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A\include;$(ProjectDir)..\..\external\chipmunk\include\chipmunk;$(ProjectDir)..\..\external\sqlite3\include;$(ProjectDir)..\..\external;$(ProjectDir)..\..\external\libwebsockets\win32\include;$(ProjectDir)..\..\cocos2dx;$(ProjectDir)..\..\cocos2dx\include;$(ProjectDir)..\..\cocos2dx\kazmath\include;$(ProjectDir)..\..\cocos2dx\platform\win32;$(ProjectDir)..\..\cocos2dx\platform\third_party\win32;$(ProjectDir)..\..\cocos2dx\platform\third_party\win32\pthread;$(ProjectDir)..\..\cocos2dx\platform\third_party\win32\OGLES;$(ProjectDir)..\..\cocos2dx\platform\third_party\win32\zlib;$(ProjectDir)..\..\CocosDenshion\include;..\;%(AdditionalIncludeDirectories) WIN32;_WINDOWS;NDEBUG;_LIB;CC_ENABLE_CHIPMUNK_INTEGRATION=1;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) MultiThreadedDLL true @@ -135,6 +135,7 @@ + @@ -213,6 +214,7 @@ + diff --git a/extensions/proj.win32/libExtensions.vcxproj.filters b/extensions/proj.win32/libExtensions.vcxproj.filters index 864b0a888c..a256f1481d 100644 --- a/extensions/proj.win32/libExtensions.vcxproj.filters +++ b/extensions/proj.win32/libExtensions.vcxproj.filters @@ -13,9 +13,6 @@ {46797895-f71d-4ddb-b381-d0884e678d39} - - {2a7741ff-87a5-41c8-8e51-d7a1cf0c8e4d} - {d5806151-7ae1-4fef-af5a-2fa1d1c7377b} @@ -31,13 +28,16 @@ {ff4b5934-99d4-4ea7-9f50-a774192d9ca9} + + {2a7741ff-87a5-41c8-8e51-d7a1cf0c8e4d} + GUI\CCScrollView - GUI\network + network GUI\CCScrollView @@ -231,6 +231,9 @@ spine + + network + @@ -239,13 +242,13 @@ - GUI\network + network - GUI\network + network - GUI\network + network GUI\CCScrollView @@ -460,5 +463,8 @@ spine + + network + \ No newline at end of file diff --git a/external/libwebsockets/android/Android.mk b/external/libwebsockets/android/Android.mk new file mode 100644 index 0000000000..158211b64c --- /dev/null +++ b/external/libwebsockets/android/Android.mk @@ -0,0 +1,10 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := libwebsockets_static +LOCAL_MODULE_FILENAME := libwebsockets_static +LOCAL_SRC_FILES := ./lib/$(TARGET_ARCH_ABI)/libwebsockets.a +LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include +LOCAL_CPPFLAGS := -D__STDC_LIMIT_MACROS=1 +LOCAL_EXPORT_CPPFLAGS := -D__STDC_LIMIT_MACROS=1 +include $(PREBUILT_STATIC_LIBRARY) diff --git a/external/libwebsockets/android/include/libwebsockets.h b/external/libwebsockets/android/include/libwebsockets.h new file mode 100644 index 0000000000..65bae14534 --- /dev/null +++ b/external/libwebsockets/android/include/libwebsockets.h @@ -0,0 +1,993 @@ +/* + * libwebsockets - small server side websockets and web server implementation + * + * Copyright (C) 2010-2013 Andy Green + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifndef __LIBWEBSOCKET_H__ +#define __LIBWEBSOCKET_H__ + +#ifdef __cplusplus +extern "C" { +#include +#endif + +#ifdef WIN32 + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#include +#include +#include "../win32port/win32helpers/websock-w32.h" + +#include "../win32port/win32helpers/gettimeofday.h" + +#define strcasecmp stricmp +#define getdtablesize() 30000 + +typedef int ssize_t; + +#define LWS_VISIBLE + +#ifdef LWS_DLL +#ifdef LWS_INTERNAL +#define LWS_EXTERN extern __declspec(dllexport) +#else +#define LWS_EXTERN extern __declspec(dllimport) +#endif +#else +#define LWS_EXTERN +#endif + +#else // NOT WIN32 +#include +#include + +#if defined(__GNUC__) +#define LWS_VISIBLE __attribute__((visibility("default"))) +#else +#define LWS_VISIBLE +#endif + +#endif + +#include + +#ifndef LWS_EXTERN +#define LWS_EXTERN extern +#endif + +#define CONTEXT_PORT_NO_LISTEN 0 +#define MAX_MUX_RECURSION 2 + +enum lws_log_levels { + LLL_ERR = 1 << 0, + LLL_WARN = 1 << 1, + LLL_NOTICE = 1 << 2, + LLL_INFO = 1 << 3, + LLL_DEBUG = 1 << 4, + LLL_PARSER = 1 << 5, + LLL_HEADER = 1 << 6, + LLL_EXT = 1 << 7, + LLL_CLIENT = 1 << 8, + LLL_LATENCY = 1 << 9, + + LLL_COUNT = 10 /* set to count of valid flags */ +}; + +LWS_VISIBLE LWS_EXTERN void _lws_log(int filter, const char *format, ...); + +/* notice, warn and log are always compiled in */ +#define lwsl_notice(...) _lws_log(LLL_NOTICE, __VA_ARGS__) +#define lwsl_warn(...) _lws_log(LLL_WARN, __VA_ARGS__) +#define lwsl_err(...) _lws_log(LLL_ERR, __VA_ARGS__) +/* + * weaker logging can be deselected at configure time using --disable-debug + * that gets rid of the overhead of checking while keeping _warn and _err + * active + */ +#ifdef _DEBUG + +#define lwsl_info(...) _lws_log(LLL_INFO, __VA_ARGS__) +#define lwsl_debug(...) _lws_log(LLL_DEBUG, __VA_ARGS__) +#define lwsl_parser(...) _lws_log(LLL_PARSER, __VA_ARGS__) +#define lwsl_header(...) _lws_log(LLL_HEADER, __VA_ARGS__) +#define lwsl_ext(...) _lws_log(LLL_EXT, __VA_ARGS__) +#define lwsl_client(...) _lws_log(LLL_CLIENT, __VA_ARGS__) +#define lwsl_latency(...) _lws_log(LLL_LATENCY, __VA_ARGS__) +LWS_VISIBLE LWS_EXTERN void lwsl_hexdump(void *buf, size_t len); + +#else /* no debug */ + +#define lwsl_info(...) +#define lwsl_debug(...) +#define lwsl_parser(...) +#define lwsl_header(...) +#define lwsl_ext(...) +#define lwsl_client(...) +#define lwsl_latency(...) +#define lwsl_hexdump(a, b) + +#endif + +enum libwebsocket_context_options { + LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT = 2, + LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME = 4, +}; + +enum libwebsocket_callback_reasons { + LWS_CALLBACK_ESTABLISHED, + LWS_CALLBACK_CLIENT_CONNECTION_ERROR, + LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH, + LWS_CALLBACK_CLIENT_ESTABLISHED, + LWS_CALLBACK_CLOSED, + LWS_CALLBACK_RECEIVE, + LWS_CALLBACK_CLIENT_RECEIVE, + LWS_CALLBACK_CLIENT_RECEIVE_PONG, + LWS_CALLBACK_CLIENT_WRITEABLE, + LWS_CALLBACK_SERVER_WRITEABLE, + LWS_CALLBACK_HTTP, + LWS_CALLBACK_HTTP_FILE_COMPLETION, + LWS_CALLBACK_HTTP_WRITEABLE, + LWS_CALLBACK_FILTER_NETWORK_CONNECTION, + LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION, + LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS, + LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS, + LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION, + LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER, + LWS_CALLBACK_CONFIRM_EXTENSION_OKAY, + LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED, + LWS_CALLBACK_PROTOCOL_INIT, + LWS_CALLBACK_PROTOCOL_DESTROY, + /* external poll() management support */ + LWS_CALLBACK_ADD_POLL_FD, + LWS_CALLBACK_DEL_POLL_FD, + LWS_CALLBACK_SET_MODE_POLL_FD, + LWS_CALLBACK_CLEAR_MODE_POLL_FD, +}; + +#ifndef LWS_NO_EXTENSIONS +enum libwebsocket_extension_callback_reasons { + LWS_EXT_CALLBACK_SERVER_CONTEXT_CONSTRUCT, + LWS_EXT_CALLBACK_CLIENT_CONTEXT_CONSTRUCT, + LWS_EXT_CALLBACK_SERVER_CONTEXT_DESTRUCT, + LWS_EXT_CALLBACK_CLIENT_CONTEXT_DESTRUCT, + LWS_EXT_CALLBACK_CONSTRUCT, + LWS_EXT_CALLBACK_CLIENT_CONSTRUCT, + LWS_EXT_CALLBACK_CHECK_OK_TO_REALLY_CLOSE, + LWS_EXT_CALLBACK_CHECK_OK_TO_PROPOSE_EXTENSION, + LWS_EXT_CALLBACK_DESTROY, + LWS_EXT_CALLBACK_DESTROY_ANY_WSI_CLOSING, + LWS_EXT_CALLBACK_ANY_WSI_ESTABLISHED, + LWS_EXT_CALLBACK_PACKET_RX_PREPARSE, + LWS_EXT_CALLBACK_PACKET_TX_PRESEND, + LWS_EXT_CALLBACK_PACKET_TX_DO_SEND, + LWS_EXT_CALLBACK_HANDSHAKE_REPLY_TX, + LWS_EXT_CALLBACK_FLUSH_PENDING_TX, + LWS_EXT_CALLBACK_EXTENDED_PAYLOAD_RX, + LWS_EXT_CALLBACK_CAN_PROXY_CLIENT_CONNECTION, + LWS_EXT_CALLBACK_1HZ, + LWS_EXT_CALLBACK_REQUEST_ON_WRITEABLE, + LWS_EXT_CALLBACK_IS_WRITEABLE, + LWS_EXT_CALLBACK_PAYLOAD_TX, + LWS_EXT_CALLBACK_PAYLOAD_RX, +}; +#endif + +enum libwebsocket_write_protocol { + LWS_WRITE_TEXT, + LWS_WRITE_BINARY, + LWS_WRITE_CONTINUATION, + LWS_WRITE_HTTP, + + /* special 04+ opcodes */ + + LWS_WRITE_CLOSE, + LWS_WRITE_PING, + LWS_WRITE_PONG, + + /* flags */ + + LWS_WRITE_NO_FIN = 0x40, + /* + * client packet payload goes out on wire unmunged + * only useful for security tests since normal servers cannot + * decode the content if used + */ + LWS_WRITE_CLIENT_IGNORE_XOR_MASK = 0x80 +}; + +/* + * you need these to look at headers that have been parsed if using the + * LWS_CALLBACK_FILTER_CONNECTION callback. If a header from the enum + * list below is absent, .token = NULL and token_len = 0. Otherwise .token + * points to .token_len chars containing that header content. + */ + +struct lws_tokens { + char *token; + int token_len; +}; + +enum lws_token_indexes { + WSI_TOKEN_GET_URI, + WSI_TOKEN_HOST, + WSI_TOKEN_CONNECTION, + WSI_TOKEN_KEY1, + WSI_TOKEN_KEY2, + WSI_TOKEN_PROTOCOL, + WSI_TOKEN_UPGRADE, + WSI_TOKEN_ORIGIN, + WSI_TOKEN_DRAFT, + WSI_TOKEN_CHALLENGE, + + /* new for 04 */ + WSI_TOKEN_KEY, + WSI_TOKEN_VERSION, + WSI_TOKEN_SWORIGIN, + + /* new for 05 */ + WSI_TOKEN_EXTENSIONS, + + /* client receives these */ + WSI_TOKEN_ACCEPT, + WSI_TOKEN_NONCE, + WSI_TOKEN_HTTP, + WSI_TOKEN_MUXURL, + + /* use token storage to stash these */ + + _WSI_TOKEN_CLIENT_SENT_PROTOCOLS, + _WSI_TOKEN_CLIENT_PEER_ADDRESS, + _WSI_TOKEN_CLIENT_URI, + _WSI_TOKEN_CLIENT_HOST, + _WSI_TOKEN_CLIENT_ORIGIN, + + /* always last real token index*/ + WSI_TOKEN_COUNT, + /* parser state additions */ + WSI_TOKEN_NAME_PART, + WSI_TOKEN_SKIPPING, + WSI_TOKEN_SKIPPING_SAW_CR, + WSI_PARSING_COMPLETE, + WSI_INIT_TOKEN_MUXURL, +}; + +/* + * From RFC 6455 + 1000 + + 1000 indicates a normal closure, meaning that the purpose for + which the connection was established has been fulfilled. + + 1001 + + 1001 indicates that an endpoint is "going away", such as a server + going down or a browser having navigated away from a page. + + 1002 + + 1002 indicates that an endpoint is terminating the connection due + to a protocol error. + + 1003 + + 1003 indicates that an endpoint is terminating the connection + because it has received a type of data it cannot accept (e.g., an + endpoint that understands only text data MAY send this if it + receives a binary message). + + 1004 + + Reserved. The specific meaning might be defined in the future. + + 1005 + + 1005 is a reserved value and MUST NOT be set as a status code in a + Close control frame by an endpoint. It is designated for use in + applications expecting a status code to indicate that no status + code was actually present. + + 1006 + + 1006 is a reserved value and MUST NOT be set as a status code in a + Close control frame by an endpoint. It is designated for use in + applications expecting a status code to indicate that the + connection was closed abnormally, e.g., without sending or + receiving a Close control frame. + + 1007 + + 1007 indicates that an endpoint is terminating the connection + because it has received data within a message that was not + consistent with the type of the message (e.g., non-UTF-8 [RFC3629] + data within a text message). + + 1008 + + 1008 indicates that an endpoint is terminating the connection + because it has received a message that violates its policy. This + is a generic status code that can be returned when there is no + other more suitable status code (e.g., 1003 or 1009) or if there + is a need to hide specific details about the policy. + + 1009 + + 1009 indicates that an endpoint is terminating the connection + because it has received a message that is too big for it to + process. + + 1010 + + 1010 indicates that an endpoint (client) is terminating the + connection because it has expected the server to negotiate one or + more extension, but the server didn't return them in the response + message of the WebSocket handshake. The list of extensions that + are needed SHOULD appear in the /reason/ part of the Close frame. + Note that this status code is not used by the server, because it + can fail the WebSocket handshake instead. + + 1011 + + 1011 indicates that a server is terminating the connection because + it encountered an unexpected condition that prevented it from + fulfilling the request. + + 1015 + + 1015 is a reserved value and MUST NOT be set as a status code in a + Close control frame by an endpoint. It is designated for use in + applications expecting a status code to indicate that the + connection was closed due to a failure to perform a TLS handshake + (e.g., the server certificate can't be verified). +*/ + +enum lws_close_status { + LWS_CLOSE_STATUS_NOSTATUS = 0, + LWS_CLOSE_STATUS_NORMAL = 1000, + LWS_CLOSE_STATUS_GOINGAWAY = 1001, + LWS_CLOSE_STATUS_PROTOCOL_ERR = 1002, + LWS_CLOSE_STATUS_UNACCEPTABLE_OPCODE = 1003, + LWS_CLOSE_STATUS_RESERVED = 1004, + LWS_CLOSE_STATUS_NO_STATUS = 1005, + LWS_CLOSE_STATUS_ABNORMAL_CLOSE = 1006, + LWS_CLOSE_STATUS_INVALID_PAYLOAD = 1007, + LWS_CLOSE_STATUS_POLICY_VIOLATION = 1008, + LWS_CLOSE_STATUS_MESSAGE_TOO_LARGE = 1009, + LWS_CLOSE_STATUS_EXTENSION_REQUIRED = 1010, + LWS_CLOSE_STATUS_UNEXPECTED_CONDITION = 1011, + LWS_CLOSE_STATUS_TLS_FAILURE = 1015, +}; + +struct libwebsocket; +struct libwebsocket_context; +/* needed even with extensions disabled for create context */ +struct libwebsocket_extension; + +/** + * callback_function() - User server actions + * @context: Websockets context + * @wsi: Opaque websocket instance pointer + * @reason: The reason for the call + * @user: Pointer to per-session user data allocated by library + * @in: Pointer used for some callback reasons + * @len: Length set for some callback reasons + * + * This callback is the way the user controls what is served. All the + * protocol detail is hidden and handled by the library. + * + * For each connection / session there is user data allocated that is + * pointed to by "user". You set the size of this user data area when + * the library is initialized with libwebsocket_create_server. + * + * You get an opportunity to initialize user data when called back with + * LWS_CALLBACK_ESTABLISHED reason. + * + * LWS_CALLBACK_ESTABLISHED: after the server completes a handshake with + * an incoming client + * + * LWS_CALLBACK_CLIENT_CONNECTION_ERROR: the request client connection has + * been unable to complete a handshake with the remote server + * + * LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH: this is the last chance for the + * client user code to examine the http headers + * and decide to reject the connection. If the + * content in the headers is interesting to the + * client (url, etc) it needs to copy it out at + * this point since it will be destroyed before + * the CLIENT_ESTABLISHED call + * + * LWS_CALLBACK_CLIENT_ESTABLISHED: after your client connection completed + * a handshake with the remote server + * + * LWS_CALLBACK_CLOSED: when the websocket session ends + * + * LWS_CALLBACK_RECEIVE: data has appeared for this server endpoint from a + * remote client, it can be found at *in and is + * len bytes long + * + * LWS_CALLBACK_CLIENT_RECEIVE_PONG: if you elected to see PONG packets, + * they appear with this callback reason. PONG + * packets only exist in 04+ protocol + * + * LWS_CALLBACK_CLIENT_RECEIVE: data has appeared from the server for the + * client connection, it can be found at *in and + * is len bytes long + * + * LWS_CALLBACK_HTTP: an http request has come from a client that is not + * asking to upgrade the connection to a websocket + * one. This is a chance to serve http content, + * for example, to send a script to the client + * which will then open the websockets connection. + * @in points to the URI path requested and + * libwebsockets_serve_http_file() makes it very + * simple to send back a file to the client. + * Normally after sending the file you are done + * with the http connection, since the rest of the + * activity will come by websockets from the script + * that was delivered by http, so you will want to + * return 1; to close and free up the connection. + * That's important because it uses a slot in the + * total number of client connections allowed set + * by MAX_CLIENTS. + * + * LWS_CALLBACK_HTTP_WRITEABLE: you can write more down the http protocol + * link now. + * + * LWS_CALLBACK_HTTP_FILE_COMPLETION: a file requested to be send down + * http link has completed. + * + * LWS_CALLBACK_CLIENT_WRITEABLE: + * LWS_CALLBACK_SERVER_WRITEABLE: If you call + * libwebsocket_callback_on_writable() on a connection, you will + * get one of these callbacks coming when the connection socket + * is able to accept another write packet without blocking. + * If it already was able to take another packet without blocking, + * you'll get this callback at the next call to the service loop + * function. Notice that CLIENTs get LWS_CALLBACK_CLIENT_WRITEABLE + * and servers get LWS_CALLBACK_SERVER_WRITEABLE. + * + * LWS_CALLBACK_FILTER_NETWORK_CONNECTION: called when a client connects to + * the server at network level; the connection is accepted but then + * passed to this callback to decide whether to hang up immediately + * or not, based on the client IP. @in contains the connection + * socket's descriptor. Return non-zero to terminate + * the connection before sending or receiving anything. + * Because this happens immediately after the network connection + * from the client, there's no websocket protocol selected yet so + * this callback is issued only to protocol 0. + * + * LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION: called when the handshake has + * been received and parsed from the client, but the response is + * not sent yet. Return non-zero to disallow the connection. + * @user is a pointer to an array of struct lws_tokens, you can + * use the header enums lws_token_indexes from libwebsockets.h + * to check for and read the supported header presence and + * content before deciding to allow the handshake to proceed or + * to kill the connection. + * + * LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS: if configured for + * including OpenSSL support, this callback allows your user code + * to perform extra SSL_CTX_load_verify_locations() or similar + * calls to direct OpenSSL where to find certificates the client + * can use to confirm the remote server identity. @user is the + * OpenSSL SSL_CTX* + * + * LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS: if configured for + * including OpenSSL support, this callback allows your user code + * to load extra certifcates into the server which allow it to + * verify the validity of certificates returned by clients. @user + * is the server's OpenSSL SSL_CTX* + * + * LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION: if the + * libwebsockets context was created with the option + * LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT, then this + * callback is generated during OpenSSL verification of the cert + * sent from the client. It is sent to protocol[0] callback as + * no protocol has been negotiated on the connection yet. + * Notice that the libwebsockets context and wsi are both NULL + * during this callback. See + * http://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html + * to understand more detail about the OpenSSL callback that + * generates this libwebsockets callback and the meanings of the + * arguments passed. In this callback, @user is the x509_ctx, + * @in is the ssl pointer and @len is preverify_ok + * Notice that this callback maintains libwebsocket return + * conventions, return 0 to mean the cert is OK or 1 to fail it. + * This also means that if you don't handle this callback then + * the default callback action of returning 0 allows the client + * certificates. + * + * LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER: this callback happens + * when a client handshake is being compiled. @user is NULL, + * @in is a char **, it's pointing to a char * which holds the + * next location in the header buffer where you can add + * headers, and @len is the remaining space in the header buffer, + * which is typically some hundreds of bytes. So, to add a canned + * cookie, your handler code might look similar to: + * + * char **p = (char **)in; + * + * if (len < 100) + * return 1; + * + * *p += sprintf(*p, "Cookie: a=b\x0d\x0a"); + * + * return 0; + * + * Notice if you add anything, you just have to take care about + * the CRLF on the line you added. Obviously this callback is + * optional, if you don't handle it everything is fine. + * + * Notice the callback is coming to protocols[0] all the time, + * because there is no specific protocol handshook yet. + * + * LWS_CALLBACK_CONFIRM_EXTENSION_OKAY: When the server handshake code + * sees that it does support a requested extension, before + * accepting the extension by additing to the list sent back to + * the client it gives this callback just to check that it's okay + * to use that extension. It calls back to the requested protocol + * and with @in being the extension name, @len is 0 and @user is + * valid. Note though at this time the ESTABLISHED callback hasn't + * happened yet so if you initialize @user content there, @user + * content during this callback might not be useful for anything. + * Notice this callback comes to protocols[0]. + * + * LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED: When a client + * connection is being prepared to start a handshake to a server, + * each supported extension is checked with protocols[0] callback + * with this reason, giving the user code a chance to suppress the + * claim to support that extension by returning non-zero. If + * unhandled, by default 0 will be returned and the extension + * support included in the header to the server. Notice this + * callback comes to protocols[0]. + * + * LWS_CALLBACK_PROTOCOL_INIT: One-time call per protocol so it can + * do initial setup / allocations etc + * + * LWS_CALLBACK_PROTOCOL_DESTROY: One-time call per protocol indicating + * this protocol won't get used at all after this callback, the + * context is getting destroyed. Take the opportunity to + * deallocate everything that was allocated by the protocol. + * + * The next four reasons are optional and only need taking care of if you + * will be integrating libwebsockets sockets into an external polling + * array. + * + * LWS_CALLBACK_ADD_POLL_FD: libwebsocket deals with its poll() loop + * internally, but in the case you are integrating with another + * server you will need to have libwebsocket sockets share a + * polling array with the other server. This and the other + * POLL_FD related callbacks let you put your specialized + * poll array interface code in the callback for protocol 0, the + * first protocol you support, usually the HTTP protocol in the + * serving case. This callback happens when a socket needs to be + * added to the polling loop: @in contains the fd, and + * @len is the events bitmap (like, POLLIN). If you are using the + * internal polling loop (the "service" callback), you can just + * ignore these callbacks. + * + * LWS_CALLBACK_DEL_POLL_FD: This callback happens when a socket descriptor + * needs to be removed from an external polling array. @in is + * the socket desricptor. If you are using the internal polling + * loop, you can just ignore it. + * + * LWS_CALLBACK_SET_MODE_POLL_FD: This callback happens when libwebsockets + * wants to modify the events for the socket descriptor in @in. + * The handler should OR @len on to the events member of the pollfd + * struct for this socket descriptor. If you are using the + * internal polling loop, you can just ignore it. + * + * LWS_CALLBACK_CLEAR_MODE_POLL_FD: This callback occurs when libwebsockets + * wants to modify the events for the socket descriptor in @in. + * The handler should AND ~@len on to the events member of the + * pollfd struct for this socket descriptor. If you are using the + * internal polling loop, you can just ignore it. + */ +LWS_VISIBLE LWS_EXTERN int callback(struct libwebsocket_context *context, + struct libwebsocket *wsi, + enum libwebsocket_callback_reasons reason, void *user, + void *in, size_t len); + +typedef int (callback_function)(struct libwebsocket_context *context, + struct libwebsocket *wsi, + enum libwebsocket_callback_reasons reason, void *user, + void *in, size_t len); + +#ifndef LWS_NO_EXTENSIONS +/** + * extension_callback_function() - Hooks to allow extensions to operate + * @context: Websockets context + * @ext: This extension + * @wsi: Opaque websocket instance pointer + * @reason: The reason for the call + * @user: Pointer to per-session user data allocated by library + * @in: Pointer used for some callback reasons + * @len: Length set for some callback reasons + * + * Each extension that is active on a particular connection receives + * callbacks during the connection lifetime to allow the extension to + * operate on websocket data and manage itself. + * + * Libwebsockets takes care of allocating and freeing "user" memory for + * each active extension on each connection. That is what is pointed to + * by the @user parameter. + * + * LWS_EXT_CALLBACK_CONSTRUCT: called when the server has decided to + * select this extension from the list provided by the client, + * just before the server will send back the handshake accepting + * the connection with this extension active. This gives the + * extension a chance to initialize its connection context found + * in @user. + * + * LWS_EXT_CALLBACK_CLIENT_CONSTRUCT: same as LWS_EXT_CALLBACK_CONSTRUCT + * but called when client is instantiating this extension. Some + * extensions will work the same on client and server side and then + * you can just merge handlers for both CONSTRUCTS. + * + * LWS_EXT_CALLBACK_DESTROY: called when the connection the extension was + * being used on is about to be closed and deallocated. It's the + * last chance for the extension to deallocate anything it has + * allocated in the user data (pointed to by @user) before the + * user data is deleted. This same callback is used whether you + * are in client or server instantiation context. + * + * LWS_EXT_CALLBACK_PACKET_RX_PREPARSE: when this extension was active on + * a connection, and a packet of data arrived at the connection, + * it is passed to this callback to give the extension a chance to + * change the data, eg, decompress it. @user is pointing to the + * extension's private connection context data, @in is pointing + * to an lws_tokens struct, it consists of a char * pointer called + * token, and an int called token_len. At entry, these are + * set to point to the received buffer and set to the content + * length. If the extension will grow the content, it should use + * a new buffer allocated in its private user context data and + * set the pointed-to lws_tokens members to point to its buffer. + * + * LWS_EXT_CALLBACK_PACKET_TX_PRESEND: this works the same way as + * LWS_EXT_CALLBACK_PACKET_RX_PREPARSE above, except it gives the + * extension a chance to change websocket data just before it will + * be sent out. Using the same lws_token pointer scheme in @in, + * the extension can change the buffer and the length to be + * transmitted how it likes. Again if it wants to grow the + * buffer safely, it should copy the data into its own buffer and + * set the lws_tokens token pointer to it. + */ +LWS_VISIBLE LWS_EXTERN int extension_callback(struct libwebsocket_context *context, + struct libwebsocket_extension *ext, + struct libwebsocket *wsi, + enum libwebsocket_extension_callback_reasons reason, + void *user, void *in, size_t len); + +typedef int (extension_callback_function)(struct libwebsocket_context *context, + struct libwebsocket_extension *ext, + struct libwebsocket *wsi, + enum libwebsocket_extension_callback_reasons reason, + void *user, void *in, size_t len); +#endif + +/** + * struct libwebsocket_protocols - List of protocols and handlers server + * supports. + * @name: Protocol name that must match the one given in the client + * Javascript new WebSocket(url, 'protocol') name + * @callback: The service callback used for this protocol. It allows the + * service action for an entire protocol to be encapsulated in + * the protocol-specific callback + * @per_session_data_size: Each new connection using this protocol gets + * this much memory allocated on connection establishment and + * freed on connection takedown. A pointer to this per-connection + * allocation is passed into the callback in the 'user' parameter + * @rx_buffer_size: if you want atomic frames delivered to the callback, you + * should set this to the size of the biggest legal frame that + * you support. If the frame size is exceeded, there is no + * error, but the buffer will spill to the user callback when + * full, which you can detect by using + * libwebsockets_remaining_packet_payload(). Notice that you + * just talk about frame size here, the LWS_SEND_BUFFER_PRE_PADDING + * and post-padding are automatically also allocated on top. + * @owning_server: the server init call fills in this opaque pointer when + * registering this protocol with the server. + * @protocol_index: which protocol we are starting from zero + * + * This structure represents one protocol supported by the server. An + * array of these structures is passed to libwebsocket_create_server() + * allows as many protocols as you like to be handled by one server. + */ + +struct libwebsocket_protocols { + const char *name; + callback_function *callback; + size_t per_session_data_size; + size_t rx_buffer_size; + + /* + * below are filled in on server init and can be left uninitialized, + * no need for user to use them directly either + */ + + struct libwebsocket_context *owning_server; + int protocol_index; +}; + +#ifndef LWS_NO_EXTENSIONS +/** + * struct libwebsocket_extension - An extension we know how to cope with + * + * @name: Formal extension name, eg, "deflate-stream" + * @callback: Service callback + * @per_session_data_size: Libwebsockets will auto-malloc this much + * memory for the use of the extension, a pointer + * to it comes in the @user callback parameter + * @per_context_private_data: Optional storage for this extension that + * is per-context, so it can track stuff across + * all sessions, etc, if it wants + */ + +struct libwebsocket_extension { + const char *name; + extension_callback_function *callback; + size_t per_session_data_size; + void *per_context_private_data; +}; +#endif + +/** + * struct lws_context_creation_info: parameters to create context with + * + * @port: Port to listen on... you can use 0 to suppress listening on + * any port, that's what you want if you are not running a + * websocket server at all but just using it as a client + * @iface: NULL to bind the listen socket to all interfaces, or the + * interface name, eg, "eth2" + * @protocols: Array of structures listing supported protocols and a protocol- + * specific callback for each one. The list is ended with an + * entry that has a NULL callback pointer. + * It's not const because we write the owning_server member + * @extensions: NULL or array of libwebsocket_extension structs listing the + * extensions this context supports. If you configured with + * --without-extensions, you should give NULL here. + * @ssl_cert_filepath: If libwebsockets was compiled to use ssl, and you want + * to listen using SSL, set to the filepath to fetch the + * server cert from, otherwise NULL for unencrypted + * @ssl_private_key_filepath: filepath to private key if wanting SSL mode, + * else ignored + * @ssl_ca_filepath: CA certificate filepath or NULL + * @ssl_cipher_list: List of valid ciphers to use (eg, + * "RC4-MD5:RC4-SHA:AES128-SHA:AES256-SHA:HIGH:!DSS:!aNULL" + * or you can leave it as NULL to get "DEFAULT" + * @gid: group id to change to after setting listen socket, or -1. + * @uid: user id to change to after setting listen socket, or -1. + * @options: 0, or LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK + * @user: optional user pointer that can be recovered via the context + * pointer using libwebsocket_context_user + * @ka_time: 0 for no keepalive, otherwise apply this keepalive timeout to + * all libwebsocket sockets, client or server + * @ka_probes: if ka_time was nonzero, after the timeout expires how many + * times to try to get a response from the peer before giving up + * and killing the connection + * @ka_interval: if ka_time was nonzero, how long to wait before each ka_probes + * attempt + */ + +struct lws_context_creation_info { + int port; + const char *iface; + struct libwebsocket_protocols *protocols; + struct libwebsocket_extension *extensions; + const char *ssl_cert_filepath; + const char *ssl_private_key_filepath; + const char *ssl_ca_filepath; + const char *ssl_cipher_list; + int gid; + int uid; + unsigned int options; + void *user; + int ka_time; + int ka_probes; + int ka_interval; + +}; + +LWS_VISIBLE LWS_EXTERN +void lws_set_log_level(int level, + void (*log_emit_function)(int level, const char *line)); + +LWS_VISIBLE LWS_EXTERN void +lwsl_emit_syslog(int level, const char *line); + +LWS_VISIBLE LWS_EXTERN struct libwebsocket_context * +libwebsocket_create_context(struct lws_context_creation_info *info); + +LWS_VISIBLE LWS_EXTERN void +libwebsocket_context_destroy(struct libwebsocket_context *context); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_service(struct libwebsocket_context *context, int timeout_ms); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_service_fd(struct libwebsocket_context *context, + struct pollfd *pollfd); + +LWS_VISIBLE LWS_EXTERN void * +libwebsocket_context_user(struct libwebsocket_context *context); + +/* + * IMPORTANT NOTICE! + * + * When sending with websocket protocol (LWS_WRITE_TEXT or LWS_WRITE_BINARY) + * the send buffer has to have LWS_SEND_BUFFER_PRE_PADDING bytes valid BEFORE + * buf, and LWS_SEND_BUFFER_POST_PADDING bytes valid AFTER (buf + len). + * + * This allows us to add protocol info before and after the data, and send as + * one packet on the network without payload copying, for maximum efficiency. + * + * So for example you need this kind of code to use libwebsocket_write with a + * 128-byte payload + * + * char buf[LWS_SEND_BUFFER_PRE_PADDING + 128 + LWS_SEND_BUFFER_POST_PADDING]; + * + * // fill your part of the buffer... for example here it's all zeros + * memset(&buf[LWS_SEND_BUFFER_PRE_PADDING], 0, 128); + * + * libwebsocket_write(wsi, &buf[LWS_SEND_BUFFER_PRE_PADDING], 128, + * LWS_WRITE_TEXT); + * + * When sending LWS_WRITE_HTTP, there is no protocol addition and you can just + * use the whole buffer without taking care of the above. + */ + +/* + * this is the frame nonce plus two header plus 8 length + * there's an additional two for mux extension per mux nesting level + * 2 byte prepend on close will already fit because control frames cannot use + * the big length style + */ + +#define LWS_SEND_BUFFER_PRE_PADDING (4 + 10 + (2 * MAX_MUX_RECURSION)) +#define LWS_SEND_BUFFER_POST_PADDING 4 + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_write(struct libwebsocket *wsi, unsigned char *buf, size_t len, + enum libwebsocket_write_protocol protocol); + +LWS_VISIBLE LWS_EXTERN int +libwebsockets_serve_http_file(struct libwebsocket_context *context, + struct libwebsocket *wsi, const char *file, + const char *content_type); +LWS_VISIBLE LWS_EXTERN int +libwebsockets_serve_http_file_fragment(struct libwebsocket_context *context, + struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN const struct libwebsocket_protocols * +libwebsockets_get_protocol(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_callback_on_writable(struct libwebsocket_context *context, + struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_callback_on_writable_all_protocol( + const struct libwebsocket_protocols *protocol); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_get_socket_fd(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_is_final_fragment(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN unsigned char +libwebsocket_get_reserved_bits(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_rx_flow_control(struct libwebsocket *wsi, int enable); + +LWS_VISIBLE LWS_EXTERN void +libwebsocket_rx_flow_allow_all_protocol( + const struct libwebsocket_protocols *protocol); + +LWS_VISIBLE LWS_EXTERN size_t +libwebsockets_remaining_packet_payload(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN struct libwebsocket * +libwebsocket_client_connect(struct libwebsocket_context *clients, + const char *address, + int port, + int ssl_connection, + const char *path, + const char *host, + const char *origin, + const char *protocol, + int ietf_version_or_minus_one); + +LWS_VISIBLE LWS_EXTERN struct libwebsocket * +libwebsocket_client_connect_extended(struct libwebsocket_context *clients, + const char *address, + int port, + int ssl_connection, + const char *path, + const char *host, + const char *origin, + const char *protocol, + int ietf_version_or_minus_one, + void *userdata); + +LWS_VISIBLE LWS_EXTERN const char * +libwebsocket_canonical_hostname(struct libwebsocket_context *context); + + +LWS_VISIBLE LWS_EXTERN void +libwebsockets_get_peer_addresses(struct libwebsocket_context *context, + struct libwebsocket *wsi, int fd, char *name, int name_len, + char *rip, int rip_len); + +LWS_VISIBLE LWS_EXTERN int +libwebsockets_get_random(struct libwebsocket_context *context, + void *buf, int len); + +LWS_VISIBLE LWS_EXTERN int +lws_daemonize(const char *_lock_path); + +LWS_VISIBLE LWS_EXTERN int +lws_send_pipe_choked(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int +lws_frame_is_binary(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN unsigned char * +libwebsockets_SHA1(const unsigned char *d, size_t n, unsigned char *md); + +LWS_VISIBLE LWS_EXTERN int +lws_b64_encode_string(const char *in, int in_len, char *out, int out_size); + +LWS_VISIBLE LWS_EXTERN int +lws_b64_decode_string(const char *in, char *out, int out_size); + +LWS_VISIBLE LWS_EXTERN const char * +lws_get_library_version(void); + +/* access to headers... only valid while headers valid */ + +LWS_VISIBLE LWS_EXTERN int +lws_hdr_total_length(struct libwebsocket *wsi, enum lws_token_indexes h); + +LWS_VISIBLE LWS_EXTERN int +lws_hdr_copy(struct libwebsocket *wsi, char *dest, int len, + enum lws_token_indexes h); + +/* + * Note: this is not normally needed as a user api. It's provided in case it is + * useful when integrating with other app poll loop service code. + */ + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_read(struct libwebsocket_context *context, + struct libwebsocket *wsi, + unsigned char *buf, size_t len); + +#ifndef LWS_NO_EXTENSIONS +LWS_VISIBLE LWS_EXTERN struct libwebsocket_extension *libwebsocket_get_internal_extensions(); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/external/libwebsockets/ios/include/libwebsockets.h b/external/libwebsockets/ios/include/libwebsockets.h new file mode 100644 index 0000000000..65bae14534 --- /dev/null +++ b/external/libwebsockets/ios/include/libwebsockets.h @@ -0,0 +1,993 @@ +/* + * libwebsockets - small server side websockets and web server implementation + * + * Copyright (C) 2010-2013 Andy Green + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifndef __LIBWEBSOCKET_H__ +#define __LIBWEBSOCKET_H__ + +#ifdef __cplusplus +extern "C" { +#include +#endif + +#ifdef WIN32 + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#include +#include +#include "../win32port/win32helpers/websock-w32.h" + +#include "../win32port/win32helpers/gettimeofday.h" + +#define strcasecmp stricmp +#define getdtablesize() 30000 + +typedef int ssize_t; + +#define LWS_VISIBLE + +#ifdef LWS_DLL +#ifdef LWS_INTERNAL +#define LWS_EXTERN extern __declspec(dllexport) +#else +#define LWS_EXTERN extern __declspec(dllimport) +#endif +#else +#define LWS_EXTERN +#endif + +#else // NOT WIN32 +#include +#include + +#if defined(__GNUC__) +#define LWS_VISIBLE __attribute__((visibility("default"))) +#else +#define LWS_VISIBLE +#endif + +#endif + +#include + +#ifndef LWS_EXTERN +#define LWS_EXTERN extern +#endif + +#define CONTEXT_PORT_NO_LISTEN 0 +#define MAX_MUX_RECURSION 2 + +enum lws_log_levels { + LLL_ERR = 1 << 0, + LLL_WARN = 1 << 1, + LLL_NOTICE = 1 << 2, + LLL_INFO = 1 << 3, + LLL_DEBUG = 1 << 4, + LLL_PARSER = 1 << 5, + LLL_HEADER = 1 << 6, + LLL_EXT = 1 << 7, + LLL_CLIENT = 1 << 8, + LLL_LATENCY = 1 << 9, + + LLL_COUNT = 10 /* set to count of valid flags */ +}; + +LWS_VISIBLE LWS_EXTERN void _lws_log(int filter, const char *format, ...); + +/* notice, warn and log are always compiled in */ +#define lwsl_notice(...) _lws_log(LLL_NOTICE, __VA_ARGS__) +#define lwsl_warn(...) _lws_log(LLL_WARN, __VA_ARGS__) +#define lwsl_err(...) _lws_log(LLL_ERR, __VA_ARGS__) +/* + * weaker logging can be deselected at configure time using --disable-debug + * that gets rid of the overhead of checking while keeping _warn and _err + * active + */ +#ifdef _DEBUG + +#define lwsl_info(...) _lws_log(LLL_INFO, __VA_ARGS__) +#define lwsl_debug(...) _lws_log(LLL_DEBUG, __VA_ARGS__) +#define lwsl_parser(...) _lws_log(LLL_PARSER, __VA_ARGS__) +#define lwsl_header(...) _lws_log(LLL_HEADER, __VA_ARGS__) +#define lwsl_ext(...) _lws_log(LLL_EXT, __VA_ARGS__) +#define lwsl_client(...) _lws_log(LLL_CLIENT, __VA_ARGS__) +#define lwsl_latency(...) _lws_log(LLL_LATENCY, __VA_ARGS__) +LWS_VISIBLE LWS_EXTERN void lwsl_hexdump(void *buf, size_t len); + +#else /* no debug */ + +#define lwsl_info(...) +#define lwsl_debug(...) +#define lwsl_parser(...) +#define lwsl_header(...) +#define lwsl_ext(...) +#define lwsl_client(...) +#define lwsl_latency(...) +#define lwsl_hexdump(a, b) + +#endif + +enum libwebsocket_context_options { + LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT = 2, + LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME = 4, +}; + +enum libwebsocket_callback_reasons { + LWS_CALLBACK_ESTABLISHED, + LWS_CALLBACK_CLIENT_CONNECTION_ERROR, + LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH, + LWS_CALLBACK_CLIENT_ESTABLISHED, + LWS_CALLBACK_CLOSED, + LWS_CALLBACK_RECEIVE, + LWS_CALLBACK_CLIENT_RECEIVE, + LWS_CALLBACK_CLIENT_RECEIVE_PONG, + LWS_CALLBACK_CLIENT_WRITEABLE, + LWS_CALLBACK_SERVER_WRITEABLE, + LWS_CALLBACK_HTTP, + LWS_CALLBACK_HTTP_FILE_COMPLETION, + LWS_CALLBACK_HTTP_WRITEABLE, + LWS_CALLBACK_FILTER_NETWORK_CONNECTION, + LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION, + LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS, + LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS, + LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION, + LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER, + LWS_CALLBACK_CONFIRM_EXTENSION_OKAY, + LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED, + LWS_CALLBACK_PROTOCOL_INIT, + LWS_CALLBACK_PROTOCOL_DESTROY, + /* external poll() management support */ + LWS_CALLBACK_ADD_POLL_FD, + LWS_CALLBACK_DEL_POLL_FD, + LWS_CALLBACK_SET_MODE_POLL_FD, + LWS_CALLBACK_CLEAR_MODE_POLL_FD, +}; + +#ifndef LWS_NO_EXTENSIONS +enum libwebsocket_extension_callback_reasons { + LWS_EXT_CALLBACK_SERVER_CONTEXT_CONSTRUCT, + LWS_EXT_CALLBACK_CLIENT_CONTEXT_CONSTRUCT, + LWS_EXT_CALLBACK_SERVER_CONTEXT_DESTRUCT, + LWS_EXT_CALLBACK_CLIENT_CONTEXT_DESTRUCT, + LWS_EXT_CALLBACK_CONSTRUCT, + LWS_EXT_CALLBACK_CLIENT_CONSTRUCT, + LWS_EXT_CALLBACK_CHECK_OK_TO_REALLY_CLOSE, + LWS_EXT_CALLBACK_CHECK_OK_TO_PROPOSE_EXTENSION, + LWS_EXT_CALLBACK_DESTROY, + LWS_EXT_CALLBACK_DESTROY_ANY_WSI_CLOSING, + LWS_EXT_CALLBACK_ANY_WSI_ESTABLISHED, + LWS_EXT_CALLBACK_PACKET_RX_PREPARSE, + LWS_EXT_CALLBACK_PACKET_TX_PRESEND, + LWS_EXT_CALLBACK_PACKET_TX_DO_SEND, + LWS_EXT_CALLBACK_HANDSHAKE_REPLY_TX, + LWS_EXT_CALLBACK_FLUSH_PENDING_TX, + LWS_EXT_CALLBACK_EXTENDED_PAYLOAD_RX, + LWS_EXT_CALLBACK_CAN_PROXY_CLIENT_CONNECTION, + LWS_EXT_CALLBACK_1HZ, + LWS_EXT_CALLBACK_REQUEST_ON_WRITEABLE, + LWS_EXT_CALLBACK_IS_WRITEABLE, + LWS_EXT_CALLBACK_PAYLOAD_TX, + LWS_EXT_CALLBACK_PAYLOAD_RX, +}; +#endif + +enum libwebsocket_write_protocol { + LWS_WRITE_TEXT, + LWS_WRITE_BINARY, + LWS_WRITE_CONTINUATION, + LWS_WRITE_HTTP, + + /* special 04+ opcodes */ + + LWS_WRITE_CLOSE, + LWS_WRITE_PING, + LWS_WRITE_PONG, + + /* flags */ + + LWS_WRITE_NO_FIN = 0x40, + /* + * client packet payload goes out on wire unmunged + * only useful for security tests since normal servers cannot + * decode the content if used + */ + LWS_WRITE_CLIENT_IGNORE_XOR_MASK = 0x80 +}; + +/* + * you need these to look at headers that have been parsed if using the + * LWS_CALLBACK_FILTER_CONNECTION callback. If a header from the enum + * list below is absent, .token = NULL and token_len = 0. Otherwise .token + * points to .token_len chars containing that header content. + */ + +struct lws_tokens { + char *token; + int token_len; +}; + +enum lws_token_indexes { + WSI_TOKEN_GET_URI, + WSI_TOKEN_HOST, + WSI_TOKEN_CONNECTION, + WSI_TOKEN_KEY1, + WSI_TOKEN_KEY2, + WSI_TOKEN_PROTOCOL, + WSI_TOKEN_UPGRADE, + WSI_TOKEN_ORIGIN, + WSI_TOKEN_DRAFT, + WSI_TOKEN_CHALLENGE, + + /* new for 04 */ + WSI_TOKEN_KEY, + WSI_TOKEN_VERSION, + WSI_TOKEN_SWORIGIN, + + /* new for 05 */ + WSI_TOKEN_EXTENSIONS, + + /* client receives these */ + WSI_TOKEN_ACCEPT, + WSI_TOKEN_NONCE, + WSI_TOKEN_HTTP, + WSI_TOKEN_MUXURL, + + /* use token storage to stash these */ + + _WSI_TOKEN_CLIENT_SENT_PROTOCOLS, + _WSI_TOKEN_CLIENT_PEER_ADDRESS, + _WSI_TOKEN_CLIENT_URI, + _WSI_TOKEN_CLIENT_HOST, + _WSI_TOKEN_CLIENT_ORIGIN, + + /* always last real token index*/ + WSI_TOKEN_COUNT, + /* parser state additions */ + WSI_TOKEN_NAME_PART, + WSI_TOKEN_SKIPPING, + WSI_TOKEN_SKIPPING_SAW_CR, + WSI_PARSING_COMPLETE, + WSI_INIT_TOKEN_MUXURL, +}; + +/* + * From RFC 6455 + 1000 + + 1000 indicates a normal closure, meaning that the purpose for + which the connection was established has been fulfilled. + + 1001 + + 1001 indicates that an endpoint is "going away", such as a server + going down or a browser having navigated away from a page. + + 1002 + + 1002 indicates that an endpoint is terminating the connection due + to a protocol error. + + 1003 + + 1003 indicates that an endpoint is terminating the connection + because it has received a type of data it cannot accept (e.g., an + endpoint that understands only text data MAY send this if it + receives a binary message). + + 1004 + + Reserved. The specific meaning might be defined in the future. + + 1005 + + 1005 is a reserved value and MUST NOT be set as a status code in a + Close control frame by an endpoint. It is designated for use in + applications expecting a status code to indicate that no status + code was actually present. + + 1006 + + 1006 is a reserved value and MUST NOT be set as a status code in a + Close control frame by an endpoint. It is designated for use in + applications expecting a status code to indicate that the + connection was closed abnormally, e.g., without sending or + receiving a Close control frame. + + 1007 + + 1007 indicates that an endpoint is terminating the connection + because it has received data within a message that was not + consistent with the type of the message (e.g., non-UTF-8 [RFC3629] + data within a text message). + + 1008 + + 1008 indicates that an endpoint is terminating the connection + because it has received a message that violates its policy. This + is a generic status code that can be returned when there is no + other more suitable status code (e.g., 1003 or 1009) or if there + is a need to hide specific details about the policy. + + 1009 + + 1009 indicates that an endpoint is terminating the connection + because it has received a message that is too big for it to + process. + + 1010 + + 1010 indicates that an endpoint (client) is terminating the + connection because it has expected the server to negotiate one or + more extension, but the server didn't return them in the response + message of the WebSocket handshake. The list of extensions that + are needed SHOULD appear in the /reason/ part of the Close frame. + Note that this status code is not used by the server, because it + can fail the WebSocket handshake instead. + + 1011 + + 1011 indicates that a server is terminating the connection because + it encountered an unexpected condition that prevented it from + fulfilling the request. + + 1015 + + 1015 is a reserved value and MUST NOT be set as a status code in a + Close control frame by an endpoint. It is designated for use in + applications expecting a status code to indicate that the + connection was closed due to a failure to perform a TLS handshake + (e.g., the server certificate can't be verified). +*/ + +enum lws_close_status { + LWS_CLOSE_STATUS_NOSTATUS = 0, + LWS_CLOSE_STATUS_NORMAL = 1000, + LWS_CLOSE_STATUS_GOINGAWAY = 1001, + LWS_CLOSE_STATUS_PROTOCOL_ERR = 1002, + LWS_CLOSE_STATUS_UNACCEPTABLE_OPCODE = 1003, + LWS_CLOSE_STATUS_RESERVED = 1004, + LWS_CLOSE_STATUS_NO_STATUS = 1005, + LWS_CLOSE_STATUS_ABNORMAL_CLOSE = 1006, + LWS_CLOSE_STATUS_INVALID_PAYLOAD = 1007, + LWS_CLOSE_STATUS_POLICY_VIOLATION = 1008, + LWS_CLOSE_STATUS_MESSAGE_TOO_LARGE = 1009, + LWS_CLOSE_STATUS_EXTENSION_REQUIRED = 1010, + LWS_CLOSE_STATUS_UNEXPECTED_CONDITION = 1011, + LWS_CLOSE_STATUS_TLS_FAILURE = 1015, +}; + +struct libwebsocket; +struct libwebsocket_context; +/* needed even with extensions disabled for create context */ +struct libwebsocket_extension; + +/** + * callback_function() - User server actions + * @context: Websockets context + * @wsi: Opaque websocket instance pointer + * @reason: The reason for the call + * @user: Pointer to per-session user data allocated by library + * @in: Pointer used for some callback reasons + * @len: Length set for some callback reasons + * + * This callback is the way the user controls what is served. All the + * protocol detail is hidden and handled by the library. + * + * For each connection / session there is user data allocated that is + * pointed to by "user". You set the size of this user data area when + * the library is initialized with libwebsocket_create_server. + * + * You get an opportunity to initialize user data when called back with + * LWS_CALLBACK_ESTABLISHED reason. + * + * LWS_CALLBACK_ESTABLISHED: after the server completes a handshake with + * an incoming client + * + * LWS_CALLBACK_CLIENT_CONNECTION_ERROR: the request client connection has + * been unable to complete a handshake with the remote server + * + * LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH: this is the last chance for the + * client user code to examine the http headers + * and decide to reject the connection. If the + * content in the headers is interesting to the + * client (url, etc) it needs to copy it out at + * this point since it will be destroyed before + * the CLIENT_ESTABLISHED call + * + * LWS_CALLBACK_CLIENT_ESTABLISHED: after your client connection completed + * a handshake with the remote server + * + * LWS_CALLBACK_CLOSED: when the websocket session ends + * + * LWS_CALLBACK_RECEIVE: data has appeared for this server endpoint from a + * remote client, it can be found at *in and is + * len bytes long + * + * LWS_CALLBACK_CLIENT_RECEIVE_PONG: if you elected to see PONG packets, + * they appear with this callback reason. PONG + * packets only exist in 04+ protocol + * + * LWS_CALLBACK_CLIENT_RECEIVE: data has appeared from the server for the + * client connection, it can be found at *in and + * is len bytes long + * + * LWS_CALLBACK_HTTP: an http request has come from a client that is not + * asking to upgrade the connection to a websocket + * one. This is a chance to serve http content, + * for example, to send a script to the client + * which will then open the websockets connection. + * @in points to the URI path requested and + * libwebsockets_serve_http_file() makes it very + * simple to send back a file to the client. + * Normally after sending the file you are done + * with the http connection, since the rest of the + * activity will come by websockets from the script + * that was delivered by http, so you will want to + * return 1; to close and free up the connection. + * That's important because it uses a slot in the + * total number of client connections allowed set + * by MAX_CLIENTS. + * + * LWS_CALLBACK_HTTP_WRITEABLE: you can write more down the http protocol + * link now. + * + * LWS_CALLBACK_HTTP_FILE_COMPLETION: a file requested to be send down + * http link has completed. + * + * LWS_CALLBACK_CLIENT_WRITEABLE: + * LWS_CALLBACK_SERVER_WRITEABLE: If you call + * libwebsocket_callback_on_writable() on a connection, you will + * get one of these callbacks coming when the connection socket + * is able to accept another write packet without blocking. + * If it already was able to take another packet without blocking, + * you'll get this callback at the next call to the service loop + * function. Notice that CLIENTs get LWS_CALLBACK_CLIENT_WRITEABLE + * and servers get LWS_CALLBACK_SERVER_WRITEABLE. + * + * LWS_CALLBACK_FILTER_NETWORK_CONNECTION: called when a client connects to + * the server at network level; the connection is accepted but then + * passed to this callback to decide whether to hang up immediately + * or not, based on the client IP. @in contains the connection + * socket's descriptor. Return non-zero to terminate + * the connection before sending or receiving anything. + * Because this happens immediately after the network connection + * from the client, there's no websocket protocol selected yet so + * this callback is issued only to protocol 0. + * + * LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION: called when the handshake has + * been received and parsed from the client, but the response is + * not sent yet. Return non-zero to disallow the connection. + * @user is a pointer to an array of struct lws_tokens, you can + * use the header enums lws_token_indexes from libwebsockets.h + * to check for and read the supported header presence and + * content before deciding to allow the handshake to proceed or + * to kill the connection. + * + * LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS: if configured for + * including OpenSSL support, this callback allows your user code + * to perform extra SSL_CTX_load_verify_locations() or similar + * calls to direct OpenSSL where to find certificates the client + * can use to confirm the remote server identity. @user is the + * OpenSSL SSL_CTX* + * + * LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS: if configured for + * including OpenSSL support, this callback allows your user code + * to load extra certifcates into the server which allow it to + * verify the validity of certificates returned by clients. @user + * is the server's OpenSSL SSL_CTX* + * + * LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION: if the + * libwebsockets context was created with the option + * LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT, then this + * callback is generated during OpenSSL verification of the cert + * sent from the client. It is sent to protocol[0] callback as + * no protocol has been negotiated on the connection yet. + * Notice that the libwebsockets context and wsi are both NULL + * during this callback. See + * http://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html + * to understand more detail about the OpenSSL callback that + * generates this libwebsockets callback and the meanings of the + * arguments passed. In this callback, @user is the x509_ctx, + * @in is the ssl pointer and @len is preverify_ok + * Notice that this callback maintains libwebsocket return + * conventions, return 0 to mean the cert is OK or 1 to fail it. + * This also means that if you don't handle this callback then + * the default callback action of returning 0 allows the client + * certificates. + * + * LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER: this callback happens + * when a client handshake is being compiled. @user is NULL, + * @in is a char **, it's pointing to a char * which holds the + * next location in the header buffer where you can add + * headers, and @len is the remaining space in the header buffer, + * which is typically some hundreds of bytes. So, to add a canned + * cookie, your handler code might look similar to: + * + * char **p = (char **)in; + * + * if (len < 100) + * return 1; + * + * *p += sprintf(*p, "Cookie: a=b\x0d\x0a"); + * + * return 0; + * + * Notice if you add anything, you just have to take care about + * the CRLF on the line you added. Obviously this callback is + * optional, if you don't handle it everything is fine. + * + * Notice the callback is coming to protocols[0] all the time, + * because there is no specific protocol handshook yet. + * + * LWS_CALLBACK_CONFIRM_EXTENSION_OKAY: When the server handshake code + * sees that it does support a requested extension, before + * accepting the extension by additing to the list sent back to + * the client it gives this callback just to check that it's okay + * to use that extension. It calls back to the requested protocol + * and with @in being the extension name, @len is 0 and @user is + * valid. Note though at this time the ESTABLISHED callback hasn't + * happened yet so if you initialize @user content there, @user + * content during this callback might not be useful for anything. + * Notice this callback comes to protocols[0]. + * + * LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED: When a client + * connection is being prepared to start a handshake to a server, + * each supported extension is checked with protocols[0] callback + * with this reason, giving the user code a chance to suppress the + * claim to support that extension by returning non-zero. If + * unhandled, by default 0 will be returned and the extension + * support included in the header to the server. Notice this + * callback comes to protocols[0]. + * + * LWS_CALLBACK_PROTOCOL_INIT: One-time call per protocol so it can + * do initial setup / allocations etc + * + * LWS_CALLBACK_PROTOCOL_DESTROY: One-time call per protocol indicating + * this protocol won't get used at all after this callback, the + * context is getting destroyed. Take the opportunity to + * deallocate everything that was allocated by the protocol. + * + * The next four reasons are optional and only need taking care of if you + * will be integrating libwebsockets sockets into an external polling + * array. + * + * LWS_CALLBACK_ADD_POLL_FD: libwebsocket deals with its poll() loop + * internally, but in the case you are integrating with another + * server you will need to have libwebsocket sockets share a + * polling array with the other server. This and the other + * POLL_FD related callbacks let you put your specialized + * poll array interface code in the callback for protocol 0, the + * first protocol you support, usually the HTTP protocol in the + * serving case. This callback happens when a socket needs to be + * added to the polling loop: @in contains the fd, and + * @len is the events bitmap (like, POLLIN). If you are using the + * internal polling loop (the "service" callback), you can just + * ignore these callbacks. + * + * LWS_CALLBACK_DEL_POLL_FD: This callback happens when a socket descriptor + * needs to be removed from an external polling array. @in is + * the socket desricptor. If you are using the internal polling + * loop, you can just ignore it. + * + * LWS_CALLBACK_SET_MODE_POLL_FD: This callback happens when libwebsockets + * wants to modify the events for the socket descriptor in @in. + * The handler should OR @len on to the events member of the pollfd + * struct for this socket descriptor. If you are using the + * internal polling loop, you can just ignore it. + * + * LWS_CALLBACK_CLEAR_MODE_POLL_FD: This callback occurs when libwebsockets + * wants to modify the events for the socket descriptor in @in. + * The handler should AND ~@len on to the events member of the + * pollfd struct for this socket descriptor. If you are using the + * internal polling loop, you can just ignore it. + */ +LWS_VISIBLE LWS_EXTERN int callback(struct libwebsocket_context *context, + struct libwebsocket *wsi, + enum libwebsocket_callback_reasons reason, void *user, + void *in, size_t len); + +typedef int (callback_function)(struct libwebsocket_context *context, + struct libwebsocket *wsi, + enum libwebsocket_callback_reasons reason, void *user, + void *in, size_t len); + +#ifndef LWS_NO_EXTENSIONS +/** + * extension_callback_function() - Hooks to allow extensions to operate + * @context: Websockets context + * @ext: This extension + * @wsi: Opaque websocket instance pointer + * @reason: The reason for the call + * @user: Pointer to per-session user data allocated by library + * @in: Pointer used for some callback reasons + * @len: Length set for some callback reasons + * + * Each extension that is active on a particular connection receives + * callbacks during the connection lifetime to allow the extension to + * operate on websocket data and manage itself. + * + * Libwebsockets takes care of allocating and freeing "user" memory for + * each active extension on each connection. That is what is pointed to + * by the @user parameter. + * + * LWS_EXT_CALLBACK_CONSTRUCT: called when the server has decided to + * select this extension from the list provided by the client, + * just before the server will send back the handshake accepting + * the connection with this extension active. This gives the + * extension a chance to initialize its connection context found + * in @user. + * + * LWS_EXT_CALLBACK_CLIENT_CONSTRUCT: same as LWS_EXT_CALLBACK_CONSTRUCT + * but called when client is instantiating this extension. Some + * extensions will work the same on client and server side and then + * you can just merge handlers for both CONSTRUCTS. + * + * LWS_EXT_CALLBACK_DESTROY: called when the connection the extension was + * being used on is about to be closed and deallocated. It's the + * last chance for the extension to deallocate anything it has + * allocated in the user data (pointed to by @user) before the + * user data is deleted. This same callback is used whether you + * are in client or server instantiation context. + * + * LWS_EXT_CALLBACK_PACKET_RX_PREPARSE: when this extension was active on + * a connection, and a packet of data arrived at the connection, + * it is passed to this callback to give the extension a chance to + * change the data, eg, decompress it. @user is pointing to the + * extension's private connection context data, @in is pointing + * to an lws_tokens struct, it consists of a char * pointer called + * token, and an int called token_len. At entry, these are + * set to point to the received buffer and set to the content + * length. If the extension will grow the content, it should use + * a new buffer allocated in its private user context data and + * set the pointed-to lws_tokens members to point to its buffer. + * + * LWS_EXT_CALLBACK_PACKET_TX_PRESEND: this works the same way as + * LWS_EXT_CALLBACK_PACKET_RX_PREPARSE above, except it gives the + * extension a chance to change websocket data just before it will + * be sent out. Using the same lws_token pointer scheme in @in, + * the extension can change the buffer and the length to be + * transmitted how it likes. Again if it wants to grow the + * buffer safely, it should copy the data into its own buffer and + * set the lws_tokens token pointer to it. + */ +LWS_VISIBLE LWS_EXTERN int extension_callback(struct libwebsocket_context *context, + struct libwebsocket_extension *ext, + struct libwebsocket *wsi, + enum libwebsocket_extension_callback_reasons reason, + void *user, void *in, size_t len); + +typedef int (extension_callback_function)(struct libwebsocket_context *context, + struct libwebsocket_extension *ext, + struct libwebsocket *wsi, + enum libwebsocket_extension_callback_reasons reason, + void *user, void *in, size_t len); +#endif + +/** + * struct libwebsocket_protocols - List of protocols and handlers server + * supports. + * @name: Protocol name that must match the one given in the client + * Javascript new WebSocket(url, 'protocol') name + * @callback: The service callback used for this protocol. It allows the + * service action for an entire protocol to be encapsulated in + * the protocol-specific callback + * @per_session_data_size: Each new connection using this protocol gets + * this much memory allocated on connection establishment and + * freed on connection takedown. A pointer to this per-connection + * allocation is passed into the callback in the 'user' parameter + * @rx_buffer_size: if you want atomic frames delivered to the callback, you + * should set this to the size of the biggest legal frame that + * you support. If the frame size is exceeded, there is no + * error, but the buffer will spill to the user callback when + * full, which you can detect by using + * libwebsockets_remaining_packet_payload(). Notice that you + * just talk about frame size here, the LWS_SEND_BUFFER_PRE_PADDING + * and post-padding are automatically also allocated on top. + * @owning_server: the server init call fills in this opaque pointer when + * registering this protocol with the server. + * @protocol_index: which protocol we are starting from zero + * + * This structure represents one protocol supported by the server. An + * array of these structures is passed to libwebsocket_create_server() + * allows as many protocols as you like to be handled by one server. + */ + +struct libwebsocket_protocols { + const char *name; + callback_function *callback; + size_t per_session_data_size; + size_t rx_buffer_size; + + /* + * below are filled in on server init and can be left uninitialized, + * no need for user to use them directly either + */ + + struct libwebsocket_context *owning_server; + int protocol_index; +}; + +#ifndef LWS_NO_EXTENSIONS +/** + * struct libwebsocket_extension - An extension we know how to cope with + * + * @name: Formal extension name, eg, "deflate-stream" + * @callback: Service callback + * @per_session_data_size: Libwebsockets will auto-malloc this much + * memory for the use of the extension, a pointer + * to it comes in the @user callback parameter + * @per_context_private_data: Optional storage for this extension that + * is per-context, so it can track stuff across + * all sessions, etc, if it wants + */ + +struct libwebsocket_extension { + const char *name; + extension_callback_function *callback; + size_t per_session_data_size; + void *per_context_private_data; +}; +#endif + +/** + * struct lws_context_creation_info: parameters to create context with + * + * @port: Port to listen on... you can use 0 to suppress listening on + * any port, that's what you want if you are not running a + * websocket server at all but just using it as a client + * @iface: NULL to bind the listen socket to all interfaces, or the + * interface name, eg, "eth2" + * @protocols: Array of structures listing supported protocols and a protocol- + * specific callback for each one. The list is ended with an + * entry that has a NULL callback pointer. + * It's not const because we write the owning_server member + * @extensions: NULL or array of libwebsocket_extension structs listing the + * extensions this context supports. If you configured with + * --without-extensions, you should give NULL here. + * @ssl_cert_filepath: If libwebsockets was compiled to use ssl, and you want + * to listen using SSL, set to the filepath to fetch the + * server cert from, otherwise NULL for unencrypted + * @ssl_private_key_filepath: filepath to private key if wanting SSL mode, + * else ignored + * @ssl_ca_filepath: CA certificate filepath or NULL + * @ssl_cipher_list: List of valid ciphers to use (eg, + * "RC4-MD5:RC4-SHA:AES128-SHA:AES256-SHA:HIGH:!DSS:!aNULL" + * or you can leave it as NULL to get "DEFAULT" + * @gid: group id to change to after setting listen socket, or -1. + * @uid: user id to change to after setting listen socket, or -1. + * @options: 0, or LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK + * @user: optional user pointer that can be recovered via the context + * pointer using libwebsocket_context_user + * @ka_time: 0 for no keepalive, otherwise apply this keepalive timeout to + * all libwebsocket sockets, client or server + * @ka_probes: if ka_time was nonzero, after the timeout expires how many + * times to try to get a response from the peer before giving up + * and killing the connection + * @ka_interval: if ka_time was nonzero, how long to wait before each ka_probes + * attempt + */ + +struct lws_context_creation_info { + int port; + const char *iface; + struct libwebsocket_protocols *protocols; + struct libwebsocket_extension *extensions; + const char *ssl_cert_filepath; + const char *ssl_private_key_filepath; + const char *ssl_ca_filepath; + const char *ssl_cipher_list; + int gid; + int uid; + unsigned int options; + void *user; + int ka_time; + int ka_probes; + int ka_interval; + +}; + +LWS_VISIBLE LWS_EXTERN +void lws_set_log_level(int level, + void (*log_emit_function)(int level, const char *line)); + +LWS_VISIBLE LWS_EXTERN void +lwsl_emit_syslog(int level, const char *line); + +LWS_VISIBLE LWS_EXTERN struct libwebsocket_context * +libwebsocket_create_context(struct lws_context_creation_info *info); + +LWS_VISIBLE LWS_EXTERN void +libwebsocket_context_destroy(struct libwebsocket_context *context); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_service(struct libwebsocket_context *context, int timeout_ms); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_service_fd(struct libwebsocket_context *context, + struct pollfd *pollfd); + +LWS_VISIBLE LWS_EXTERN void * +libwebsocket_context_user(struct libwebsocket_context *context); + +/* + * IMPORTANT NOTICE! + * + * When sending with websocket protocol (LWS_WRITE_TEXT or LWS_WRITE_BINARY) + * the send buffer has to have LWS_SEND_BUFFER_PRE_PADDING bytes valid BEFORE + * buf, and LWS_SEND_BUFFER_POST_PADDING bytes valid AFTER (buf + len). + * + * This allows us to add protocol info before and after the data, and send as + * one packet on the network without payload copying, for maximum efficiency. + * + * So for example you need this kind of code to use libwebsocket_write with a + * 128-byte payload + * + * char buf[LWS_SEND_BUFFER_PRE_PADDING + 128 + LWS_SEND_BUFFER_POST_PADDING]; + * + * // fill your part of the buffer... for example here it's all zeros + * memset(&buf[LWS_SEND_BUFFER_PRE_PADDING], 0, 128); + * + * libwebsocket_write(wsi, &buf[LWS_SEND_BUFFER_PRE_PADDING], 128, + * LWS_WRITE_TEXT); + * + * When sending LWS_WRITE_HTTP, there is no protocol addition and you can just + * use the whole buffer without taking care of the above. + */ + +/* + * this is the frame nonce plus two header plus 8 length + * there's an additional two for mux extension per mux nesting level + * 2 byte prepend on close will already fit because control frames cannot use + * the big length style + */ + +#define LWS_SEND_BUFFER_PRE_PADDING (4 + 10 + (2 * MAX_MUX_RECURSION)) +#define LWS_SEND_BUFFER_POST_PADDING 4 + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_write(struct libwebsocket *wsi, unsigned char *buf, size_t len, + enum libwebsocket_write_protocol protocol); + +LWS_VISIBLE LWS_EXTERN int +libwebsockets_serve_http_file(struct libwebsocket_context *context, + struct libwebsocket *wsi, const char *file, + const char *content_type); +LWS_VISIBLE LWS_EXTERN int +libwebsockets_serve_http_file_fragment(struct libwebsocket_context *context, + struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN const struct libwebsocket_protocols * +libwebsockets_get_protocol(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_callback_on_writable(struct libwebsocket_context *context, + struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_callback_on_writable_all_protocol( + const struct libwebsocket_protocols *protocol); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_get_socket_fd(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_is_final_fragment(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN unsigned char +libwebsocket_get_reserved_bits(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_rx_flow_control(struct libwebsocket *wsi, int enable); + +LWS_VISIBLE LWS_EXTERN void +libwebsocket_rx_flow_allow_all_protocol( + const struct libwebsocket_protocols *protocol); + +LWS_VISIBLE LWS_EXTERN size_t +libwebsockets_remaining_packet_payload(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN struct libwebsocket * +libwebsocket_client_connect(struct libwebsocket_context *clients, + const char *address, + int port, + int ssl_connection, + const char *path, + const char *host, + const char *origin, + const char *protocol, + int ietf_version_or_minus_one); + +LWS_VISIBLE LWS_EXTERN struct libwebsocket * +libwebsocket_client_connect_extended(struct libwebsocket_context *clients, + const char *address, + int port, + int ssl_connection, + const char *path, + const char *host, + const char *origin, + const char *protocol, + int ietf_version_or_minus_one, + void *userdata); + +LWS_VISIBLE LWS_EXTERN const char * +libwebsocket_canonical_hostname(struct libwebsocket_context *context); + + +LWS_VISIBLE LWS_EXTERN void +libwebsockets_get_peer_addresses(struct libwebsocket_context *context, + struct libwebsocket *wsi, int fd, char *name, int name_len, + char *rip, int rip_len); + +LWS_VISIBLE LWS_EXTERN int +libwebsockets_get_random(struct libwebsocket_context *context, + void *buf, int len); + +LWS_VISIBLE LWS_EXTERN int +lws_daemonize(const char *_lock_path); + +LWS_VISIBLE LWS_EXTERN int +lws_send_pipe_choked(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int +lws_frame_is_binary(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN unsigned char * +libwebsockets_SHA1(const unsigned char *d, size_t n, unsigned char *md); + +LWS_VISIBLE LWS_EXTERN int +lws_b64_encode_string(const char *in, int in_len, char *out, int out_size); + +LWS_VISIBLE LWS_EXTERN int +lws_b64_decode_string(const char *in, char *out, int out_size); + +LWS_VISIBLE LWS_EXTERN const char * +lws_get_library_version(void); + +/* access to headers... only valid while headers valid */ + +LWS_VISIBLE LWS_EXTERN int +lws_hdr_total_length(struct libwebsocket *wsi, enum lws_token_indexes h); + +LWS_VISIBLE LWS_EXTERN int +lws_hdr_copy(struct libwebsocket *wsi, char *dest, int len, + enum lws_token_indexes h); + +/* + * Note: this is not normally needed as a user api. It's provided in case it is + * useful when integrating with other app poll loop service code. + */ + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_read(struct libwebsocket_context *context, + struct libwebsocket *wsi, + unsigned char *buf, size_t len); + +#ifndef LWS_NO_EXTENSIONS +LWS_VISIBLE LWS_EXTERN struct libwebsocket_extension *libwebsocket_get_internal_extensions(); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/external/libwebsockets/ios/lib/libwebsockets.a.REMOVED.git-id b/external/libwebsockets/ios/lib/libwebsockets.a.REMOVED.git-id new file mode 100644 index 0000000000..08dc34e960 --- /dev/null +++ b/external/libwebsockets/ios/lib/libwebsockets.a.REMOVED.git-id @@ -0,0 +1 @@ +ee4ee6cc26274f6d3138d08d429d6ba49b629f53 \ No newline at end of file diff --git a/external/libwebsockets/win32/include/libwebsockets.h b/external/libwebsockets/win32/include/libwebsockets.h new file mode 100644 index 0000000000..2203f53b4c --- /dev/null +++ b/external/libwebsockets/win32/include/libwebsockets.h @@ -0,0 +1,993 @@ +/* + * libwebsockets - small server side websockets and web server implementation + * + * Copyright (C) 2010-2013 Andy Green + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifndef __LIBWEBSOCKET_H__ +#define __LIBWEBSOCKET_H__ + +#ifdef __cplusplus +extern "C" { +#include +#endif + +#ifdef WIN32 + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#include +#include +#include "win32helpers/websock-w32.h" + +//#include "win32helpers/gettimeofday.h" + +#define strcasecmp stricmp +#define getdtablesize() 30000 + +typedef int ssize_t; + +#define LWS_VISIBLE + +#ifdef LWS_DLL +#ifdef LWS_INTERNAL +#define LWS_EXTERN extern __declspec(dllexport) +#else +#define LWS_EXTERN extern __declspec(dllimport) +#endif +#else +#define LWS_EXTERN +#endif + +#else // NOT WIN32 +#include +#include + +#if defined(__GNUC__) +#define LWS_VISIBLE __attribute__((visibility("default"))) +#else +#define LWS_VISIBLE +#endif + +#endif + +#include + +#ifndef LWS_EXTERN +#define LWS_EXTERN extern +#endif + +#define CONTEXT_PORT_NO_LISTEN 0 +#define MAX_MUX_RECURSION 2 + +enum lws_log_levels { + LLL_ERR = 1 << 0, + LLL_WARN = 1 << 1, + LLL_NOTICE = 1 << 2, + LLL_INFO = 1 << 3, + LLL_DEBUG = 1 << 4, + LLL_PARSER = 1 << 5, + LLL_HEADER = 1 << 6, + LLL_EXT = 1 << 7, + LLL_CLIENT = 1 << 8, + LLL_LATENCY = 1 << 9, + + LLL_COUNT = 10 /* set to count of valid flags */ +}; + +LWS_VISIBLE LWS_EXTERN void _lws_log(int filter, const char *format, ...); + +/* notice, warn and log are always compiled in */ +#define lwsl_notice(...) _lws_log(LLL_NOTICE, __VA_ARGS__) +#define lwsl_warn(...) _lws_log(LLL_WARN, __VA_ARGS__) +#define lwsl_err(...) _lws_log(LLL_ERR, __VA_ARGS__) +/* + * weaker logging can be deselected at configure time using --disable-debug + * that gets rid of the overhead of checking while keeping _warn and _err + * active + */ +#ifdef _DEBUG + +#define lwsl_info(...) _lws_log(LLL_INFO, __VA_ARGS__) +#define lwsl_debug(...) _lws_log(LLL_DEBUG, __VA_ARGS__) +#define lwsl_parser(...) _lws_log(LLL_PARSER, __VA_ARGS__) +#define lwsl_header(...) _lws_log(LLL_HEADER, __VA_ARGS__) +#define lwsl_ext(...) _lws_log(LLL_EXT, __VA_ARGS__) +#define lwsl_client(...) _lws_log(LLL_CLIENT, __VA_ARGS__) +#define lwsl_latency(...) _lws_log(LLL_LATENCY, __VA_ARGS__) +LWS_VISIBLE LWS_EXTERN void lwsl_hexdump(void *buf, size_t len); + +#else /* no debug */ + +#define lwsl_info(...) +#define lwsl_debug(...) +#define lwsl_parser(...) +#define lwsl_header(...) +#define lwsl_ext(...) +#define lwsl_client(...) +#define lwsl_latency(...) +#define lwsl_hexdump(a, b) + +#endif + +enum libwebsocket_context_options { + LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT = 2, + LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME = 4, +}; + +enum libwebsocket_callback_reasons { + LWS_CALLBACK_ESTABLISHED, + LWS_CALLBACK_CLIENT_CONNECTION_ERROR, + LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH, + LWS_CALLBACK_CLIENT_ESTABLISHED, + LWS_CALLBACK_CLOSED, + LWS_CALLBACK_RECEIVE, + LWS_CALLBACK_CLIENT_RECEIVE, + LWS_CALLBACK_CLIENT_RECEIVE_PONG, + LWS_CALLBACK_CLIENT_WRITEABLE, + LWS_CALLBACK_SERVER_WRITEABLE, + LWS_CALLBACK_HTTP, + LWS_CALLBACK_HTTP_FILE_COMPLETION, + LWS_CALLBACK_HTTP_WRITEABLE, + LWS_CALLBACK_FILTER_NETWORK_CONNECTION, + LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION, + LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS, + LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS, + LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION, + LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER, + LWS_CALLBACK_CONFIRM_EXTENSION_OKAY, + LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED, + LWS_CALLBACK_PROTOCOL_INIT, + LWS_CALLBACK_PROTOCOL_DESTROY, + /* external poll() management support */ + LWS_CALLBACK_ADD_POLL_FD, + LWS_CALLBACK_DEL_POLL_FD, + LWS_CALLBACK_SET_MODE_POLL_FD, + LWS_CALLBACK_CLEAR_MODE_POLL_FD, +}; + +#ifndef LWS_NO_EXTENSIONS +enum libwebsocket_extension_callback_reasons { + LWS_EXT_CALLBACK_SERVER_CONTEXT_CONSTRUCT, + LWS_EXT_CALLBACK_CLIENT_CONTEXT_CONSTRUCT, + LWS_EXT_CALLBACK_SERVER_CONTEXT_DESTRUCT, + LWS_EXT_CALLBACK_CLIENT_CONTEXT_DESTRUCT, + LWS_EXT_CALLBACK_CONSTRUCT, + LWS_EXT_CALLBACK_CLIENT_CONSTRUCT, + LWS_EXT_CALLBACK_CHECK_OK_TO_REALLY_CLOSE, + LWS_EXT_CALLBACK_CHECK_OK_TO_PROPOSE_EXTENSION, + LWS_EXT_CALLBACK_DESTROY, + LWS_EXT_CALLBACK_DESTROY_ANY_WSI_CLOSING, + LWS_EXT_CALLBACK_ANY_WSI_ESTABLISHED, + LWS_EXT_CALLBACK_PACKET_RX_PREPARSE, + LWS_EXT_CALLBACK_PACKET_TX_PRESEND, + LWS_EXT_CALLBACK_PACKET_TX_DO_SEND, + LWS_EXT_CALLBACK_HANDSHAKE_REPLY_TX, + LWS_EXT_CALLBACK_FLUSH_PENDING_TX, + LWS_EXT_CALLBACK_EXTENDED_PAYLOAD_RX, + LWS_EXT_CALLBACK_CAN_PROXY_CLIENT_CONNECTION, + LWS_EXT_CALLBACK_1HZ, + LWS_EXT_CALLBACK_REQUEST_ON_WRITEABLE, + LWS_EXT_CALLBACK_IS_WRITEABLE, + LWS_EXT_CALLBACK_PAYLOAD_TX, + LWS_EXT_CALLBACK_PAYLOAD_RX, +}; +#endif + +enum libwebsocket_write_protocol { + LWS_WRITE_TEXT, + LWS_WRITE_BINARY, + LWS_WRITE_CONTINUATION, + LWS_WRITE_HTTP, + + /* special 04+ opcodes */ + + LWS_WRITE_CLOSE, + LWS_WRITE_PING, + LWS_WRITE_PONG, + + /* flags */ + + LWS_WRITE_NO_FIN = 0x40, + /* + * client packet payload goes out on wire unmunged + * only useful for security tests since normal servers cannot + * decode the content if used + */ + LWS_WRITE_CLIENT_IGNORE_XOR_MASK = 0x80 +}; + +/* + * you need these to look at headers that have been parsed if using the + * LWS_CALLBACK_FILTER_CONNECTION callback. If a header from the enum + * list below is absent, .token = NULL and token_len = 0. Otherwise .token + * points to .token_len chars containing that header content. + */ + +struct lws_tokens { + char *token; + int token_len; +}; + +enum lws_token_indexes { + WSI_TOKEN_GET_URI, + WSI_TOKEN_HOST, + WSI_TOKEN_CONNECTION, + WSI_TOKEN_KEY1, + WSI_TOKEN_KEY2, + WSI_TOKEN_PROTOCOL, + WSI_TOKEN_UPGRADE, + WSI_TOKEN_ORIGIN, + WSI_TOKEN_DRAFT, + WSI_TOKEN_CHALLENGE, + + /* new for 04 */ + WSI_TOKEN_KEY, + WSI_TOKEN_VERSION, + WSI_TOKEN_SWORIGIN, + + /* new for 05 */ + WSI_TOKEN_EXTENSIONS, + + /* client receives these */ + WSI_TOKEN_ACCEPT, + WSI_TOKEN_NONCE, + WSI_TOKEN_HTTP, + WSI_TOKEN_MUXURL, + + /* use token storage to stash these */ + + _WSI_TOKEN_CLIENT_SENT_PROTOCOLS, + _WSI_TOKEN_CLIENT_PEER_ADDRESS, + _WSI_TOKEN_CLIENT_URI, + _WSI_TOKEN_CLIENT_HOST, + _WSI_TOKEN_CLIENT_ORIGIN, + + /* always last real token index*/ + WSI_TOKEN_COUNT, + /* parser state additions */ + WSI_TOKEN_NAME_PART, + WSI_TOKEN_SKIPPING, + WSI_TOKEN_SKIPPING_SAW_CR, + WSI_PARSING_COMPLETE, + WSI_INIT_TOKEN_MUXURL, +}; + +/* + * From RFC 6455 + 1000 + + 1000 indicates a normal closure, meaning that the purpose for + which the connection was established has been fulfilled. + + 1001 + + 1001 indicates that an endpoint is "going away", such as a server + going down or a browser having navigated away from a page. + + 1002 + + 1002 indicates that an endpoint is terminating the connection due + to a protocol error. + + 1003 + + 1003 indicates that an endpoint is terminating the connection + because it has received a type of data it cannot accept (e.g., an + endpoint that understands only text data MAY send this if it + receives a binary message). + + 1004 + + Reserved. The specific meaning might be defined in the future. + + 1005 + + 1005 is a reserved value and MUST NOT be set as a status code in a + Close control frame by an endpoint. It is designated for use in + applications expecting a status code to indicate that no status + code was actually present. + + 1006 + + 1006 is a reserved value and MUST NOT be set as a status code in a + Close control frame by an endpoint. It is designated for use in + applications expecting a status code to indicate that the + connection was closed abnormally, e.g., without sending or + receiving a Close control frame. + + 1007 + + 1007 indicates that an endpoint is terminating the connection + because it has received data within a message that was not + consistent with the type of the message (e.g., non-UTF-8 [RFC3629] + data within a text message). + + 1008 + + 1008 indicates that an endpoint is terminating the connection + because it has received a message that violates its policy. This + is a generic status code that can be returned when there is no + other more suitable status code (e.g., 1003 or 1009) or if there + is a need to hide specific details about the policy. + + 1009 + + 1009 indicates that an endpoint is terminating the connection + because it has received a message that is too big for it to + process. + + 1010 + + 1010 indicates that an endpoint (client) is terminating the + connection because it has expected the server to negotiate one or + more extension, but the server didn't return them in the response + message of the WebSocket handshake. The list of extensions that + are needed SHOULD appear in the /reason/ part of the Close frame. + Note that this status code is not used by the server, because it + can fail the WebSocket handshake instead. + + 1011 + + 1011 indicates that a server is terminating the connection because + it encountered an unexpected condition that prevented it from + fulfilling the request. + + 1015 + + 1015 is a reserved value and MUST NOT be set as a status code in a + Close control frame by an endpoint. It is designated for use in + applications expecting a status code to indicate that the + connection was closed due to a failure to perform a TLS handshake + (e.g., the server certificate can't be verified). +*/ + +enum lws_close_status { + LWS_CLOSE_STATUS_NOSTATUS = 0, + LWS_CLOSE_STATUS_NORMAL = 1000, + LWS_CLOSE_STATUS_GOINGAWAY = 1001, + LWS_CLOSE_STATUS_PROTOCOL_ERR = 1002, + LWS_CLOSE_STATUS_UNACCEPTABLE_OPCODE = 1003, + LWS_CLOSE_STATUS_RESERVED = 1004, + LWS_CLOSE_STATUS_NO_STATUS = 1005, + LWS_CLOSE_STATUS_ABNORMAL_CLOSE = 1006, + LWS_CLOSE_STATUS_INVALID_PAYLOAD = 1007, + LWS_CLOSE_STATUS_POLICY_VIOLATION = 1008, + LWS_CLOSE_STATUS_MESSAGE_TOO_LARGE = 1009, + LWS_CLOSE_STATUS_EXTENSION_REQUIRED = 1010, + LWS_CLOSE_STATUS_UNEXPECTED_CONDITION = 1011, + LWS_CLOSE_STATUS_TLS_FAILURE = 1015, +}; + +struct libwebsocket; +struct libwebsocket_context; +/* needed even with extensions disabled for create context */ +struct libwebsocket_extension; + +/** + * callback_function() - User server actions + * @context: Websockets context + * @wsi: Opaque websocket instance pointer + * @reason: The reason for the call + * @user: Pointer to per-session user data allocated by library + * @in: Pointer used for some callback reasons + * @len: Length set for some callback reasons + * + * This callback is the way the user controls what is served. All the + * protocol detail is hidden and handled by the library. + * + * For each connection / session there is user data allocated that is + * pointed to by "user". You set the size of this user data area when + * the library is initialized with libwebsocket_create_server. + * + * You get an opportunity to initialize user data when called back with + * LWS_CALLBACK_ESTABLISHED reason. + * + * LWS_CALLBACK_ESTABLISHED: after the server completes a handshake with + * an incoming client + * + * LWS_CALLBACK_CLIENT_CONNECTION_ERROR: the request client connection has + * been unable to complete a handshake with the remote server + * + * LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH: this is the last chance for the + * client user code to examine the http headers + * and decide to reject the connection. If the + * content in the headers is interesting to the + * client (url, etc) it needs to copy it out at + * this point since it will be destroyed before + * the CLIENT_ESTABLISHED call + * + * LWS_CALLBACK_CLIENT_ESTABLISHED: after your client connection completed + * a handshake with the remote server + * + * LWS_CALLBACK_CLOSED: when the websocket session ends + * + * LWS_CALLBACK_RECEIVE: data has appeared for this server endpoint from a + * remote client, it can be found at *in and is + * len bytes long + * + * LWS_CALLBACK_CLIENT_RECEIVE_PONG: if you elected to see PONG packets, + * they appear with this callback reason. PONG + * packets only exist in 04+ protocol + * + * LWS_CALLBACK_CLIENT_RECEIVE: data has appeared from the server for the + * client connection, it can be found at *in and + * is len bytes long + * + * LWS_CALLBACK_HTTP: an http request has come from a client that is not + * asking to upgrade the connection to a websocket + * one. This is a chance to serve http content, + * for example, to send a script to the client + * which will then open the websockets connection. + * @in points to the URI path requested and + * libwebsockets_serve_http_file() makes it very + * simple to send back a file to the client. + * Normally after sending the file you are done + * with the http connection, since the rest of the + * activity will come by websockets from the script + * that was delivered by http, so you will want to + * return 1; to close and free up the connection. + * That's important because it uses a slot in the + * total number of client connections allowed set + * by MAX_CLIENTS. + * + * LWS_CALLBACK_HTTP_WRITEABLE: you can write more down the http protocol + * link now. + * + * LWS_CALLBACK_HTTP_FILE_COMPLETION: a file requested to be send down + * http link has completed. + * + * LWS_CALLBACK_CLIENT_WRITEABLE: + * LWS_CALLBACK_SERVER_WRITEABLE: If you call + * libwebsocket_callback_on_writable() on a connection, you will + * get one of these callbacks coming when the connection socket + * is able to accept another write packet without blocking. + * If it already was able to take another packet without blocking, + * you'll get this callback at the next call to the service loop + * function. Notice that CLIENTs get LWS_CALLBACK_CLIENT_WRITEABLE + * and servers get LWS_CALLBACK_SERVER_WRITEABLE. + * + * LWS_CALLBACK_FILTER_NETWORK_CONNECTION: called when a client connects to + * the server at network level; the connection is accepted but then + * passed to this callback to decide whether to hang up immediately + * or not, based on the client IP. @in contains the connection + * socket's descriptor. Return non-zero to terminate + * the connection before sending or receiving anything. + * Because this happens immediately after the network connection + * from the client, there's no websocket protocol selected yet so + * this callback is issued only to protocol 0. + * + * LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION: called when the handshake has + * been received and parsed from the client, but the response is + * not sent yet. Return non-zero to disallow the connection. + * @user is a pointer to an array of struct lws_tokens, you can + * use the header enums lws_token_indexes from libwebsockets.h + * to check for and read the supported header presence and + * content before deciding to allow the handshake to proceed or + * to kill the connection. + * + * LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS: if configured for + * including OpenSSL support, this callback allows your user code + * to perform extra SSL_CTX_load_verify_locations() or similar + * calls to direct OpenSSL where to find certificates the client + * can use to confirm the remote server identity. @user is the + * OpenSSL SSL_CTX* + * + * LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS: if configured for + * including OpenSSL support, this callback allows your user code + * to load extra certifcates into the server which allow it to + * verify the validity of certificates returned by clients. @user + * is the server's OpenSSL SSL_CTX* + * + * LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION: if the + * libwebsockets context was created with the option + * LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT, then this + * callback is generated during OpenSSL verification of the cert + * sent from the client. It is sent to protocol[0] callback as + * no protocol has been negotiated on the connection yet. + * Notice that the libwebsockets context and wsi are both NULL + * during this callback. See + * http://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html + * to understand more detail about the OpenSSL callback that + * generates this libwebsockets callback and the meanings of the + * arguments passed. In this callback, @user is the x509_ctx, + * @in is the ssl pointer and @len is preverify_ok + * Notice that this callback maintains libwebsocket return + * conventions, return 0 to mean the cert is OK or 1 to fail it. + * This also means that if you don't handle this callback then + * the default callback action of returning 0 allows the client + * certificates. + * + * LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER: this callback happens + * when a client handshake is being compiled. @user is NULL, + * @in is a char **, it's pointing to a char * which holds the + * next location in the header buffer where you can add + * headers, and @len is the remaining space in the header buffer, + * which is typically some hundreds of bytes. So, to add a canned + * cookie, your handler code might look similar to: + * + * char **p = (char **)in; + * + * if (len < 100) + * return 1; + * + * *p += sprintf(*p, "Cookie: a=b\x0d\x0a"); + * + * return 0; + * + * Notice if you add anything, you just have to take care about + * the CRLF on the line you added. Obviously this callback is + * optional, if you don't handle it everything is fine. + * + * Notice the callback is coming to protocols[0] all the time, + * because there is no specific protocol handshook yet. + * + * LWS_CALLBACK_CONFIRM_EXTENSION_OKAY: When the server handshake code + * sees that it does support a requested extension, before + * accepting the extension by additing to the list sent back to + * the client it gives this callback just to check that it's okay + * to use that extension. It calls back to the requested protocol + * and with @in being the extension name, @len is 0 and @user is + * valid. Note though at this time the ESTABLISHED callback hasn't + * happened yet so if you initialize @user content there, @user + * content during this callback might not be useful for anything. + * Notice this callback comes to protocols[0]. + * + * LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED: When a client + * connection is being prepared to start a handshake to a server, + * each supported extension is checked with protocols[0] callback + * with this reason, giving the user code a chance to suppress the + * claim to support that extension by returning non-zero. If + * unhandled, by default 0 will be returned and the extension + * support included in the header to the server. Notice this + * callback comes to protocols[0]. + * + * LWS_CALLBACK_PROTOCOL_INIT: One-time call per protocol so it can + * do initial setup / allocations etc + * + * LWS_CALLBACK_PROTOCOL_DESTROY: One-time call per protocol indicating + * this protocol won't get used at all after this callback, the + * context is getting destroyed. Take the opportunity to + * deallocate everything that was allocated by the protocol. + * + * The next four reasons are optional and only need taking care of if you + * will be integrating libwebsockets sockets into an external polling + * array. + * + * LWS_CALLBACK_ADD_POLL_FD: libwebsocket deals with its poll() loop + * internally, but in the case you are integrating with another + * server you will need to have libwebsocket sockets share a + * polling array with the other server. This and the other + * POLL_FD related callbacks let you put your specialized + * poll array interface code in the callback for protocol 0, the + * first protocol you support, usually the HTTP protocol in the + * serving case. This callback happens when a socket needs to be + * added to the polling loop: @in contains the fd, and + * @len is the events bitmap (like, POLLIN). If you are using the + * internal polling loop (the "service" callback), you can just + * ignore these callbacks. + * + * LWS_CALLBACK_DEL_POLL_FD: This callback happens when a socket descriptor + * needs to be removed from an external polling array. @in is + * the socket desricptor. If you are using the internal polling + * loop, you can just ignore it. + * + * LWS_CALLBACK_SET_MODE_POLL_FD: This callback happens when libwebsockets + * wants to modify the events for the socket descriptor in @in. + * The handler should OR @len on to the events member of the pollfd + * struct for this socket descriptor. If you are using the + * internal polling loop, you can just ignore it. + * + * LWS_CALLBACK_CLEAR_MODE_POLL_FD: This callback occurs when libwebsockets + * wants to modify the events for the socket descriptor in @in. + * The handler should AND ~@len on to the events member of the + * pollfd struct for this socket descriptor. If you are using the + * internal polling loop, you can just ignore it. + */ +LWS_VISIBLE LWS_EXTERN int callback(struct libwebsocket_context *context, + struct libwebsocket *wsi, + enum libwebsocket_callback_reasons reason, void *user, + void *in, size_t len); + +typedef int (callback_function)(struct libwebsocket_context *context, + struct libwebsocket *wsi, + enum libwebsocket_callback_reasons reason, void *user, + void *in, size_t len); + +#ifndef LWS_NO_EXTENSIONS +/** + * extension_callback_function() - Hooks to allow extensions to operate + * @context: Websockets context + * @ext: This extension + * @wsi: Opaque websocket instance pointer + * @reason: The reason for the call + * @user: Pointer to per-session user data allocated by library + * @in: Pointer used for some callback reasons + * @len: Length set for some callback reasons + * + * Each extension that is active on a particular connection receives + * callbacks during the connection lifetime to allow the extension to + * operate on websocket data and manage itself. + * + * Libwebsockets takes care of allocating and freeing "user" memory for + * each active extension on each connection. That is what is pointed to + * by the @user parameter. + * + * LWS_EXT_CALLBACK_CONSTRUCT: called when the server has decided to + * select this extension from the list provided by the client, + * just before the server will send back the handshake accepting + * the connection with this extension active. This gives the + * extension a chance to initialize its connection context found + * in @user. + * + * LWS_EXT_CALLBACK_CLIENT_CONSTRUCT: same as LWS_EXT_CALLBACK_CONSTRUCT + * but called when client is instantiating this extension. Some + * extensions will work the same on client and server side and then + * you can just merge handlers for both CONSTRUCTS. + * + * LWS_EXT_CALLBACK_DESTROY: called when the connection the extension was + * being used on is about to be closed and deallocated. It's the + * last chance for the extension to deallocate anything it has + * allocated in the user data (pointed to by @user) before the + * user data is deleted. This same callback is used whether you + * are in client or server instantiation context. + * + * LWS_EXT_CALLBACK_PACKET_RX_PREPARSE: when this extension was active on + * a connection, and a packet of data arrived at the connection, + * it is passed to this callback to give the extension a chance to + * change the data, eg, decompress it. @user is pointing to the + * extension's private connection context data, @in is pointing + * to an lws_tokens struct, it consists of a char * pointer called + * token, and an int called token_len. At entry, these are + * set to point to the received buffer and set to the content + * length. If the extension will grow the content, it should use + * a new buffer allocated in its private user context data and + * set the pointed-to lws_tokens members to point to its buffer. + * + * LWS_EXT_CALLBACK_PACKET_TX_PRESEND: this works the same way as + * LWS_EXT_CALLBACK_PACKET_RX_PREPARSE above, except it gives the + * extension a chance to change websocket data just before it will + * be sent out. Using the same lws_token pointer scheme in @in, + * the extension can change the buffer and the length to be + * transmitted how it likes. Again if it wants to grow the + * buffer safely, it should copy the data into its own buffer and + * set the lws_tokens token pointer to it. + */ +LWS_VISIBLE LWS_EXTERN int extension_callback(struct libwebsocket_context *context, + struct libwebsocket_extension *ext, + struct libwebsocket *wsi, + enum libwebsocket_extension_callback_reasons reason, + void *user, void *in, size_t len); + +typedef int (extension_callback_function)(struct libwebsocket_context *context, + struct libwebsocket_extension *ext, + struct libwebsocket *wsi, + enum libwebsocket_extension_callback_reasons reason, + void *user, void *in, size_t len); +#endif + +/** + * struct libwebsocket_protocols - List of protocols and handlers server + * supports. + * @name: Protocol name that must match the one given in the client + * Javascript new WebSocket(url, 'protocol') name + * @callback: The service callback used for this protocol. It allows the + * service action for an entire protocol to be encapsulated in + * the protocol-specific callback + * @per_session_data_size: Each new connection using this protocol gets + * this much memory allocated on connection establishment and + * freed on connection takedown. A pointer to this per-connection + * allocation is passed into the callback in the 'user' parameter + * @rx_buffer_size: if you want atomic frames delivered to the callback, you + * should set this to the size of the biggest legal frame that + * you support. If the frame size is exceeded, there is no + * error, but the buffer will spill to the user callback when + * full, which you can detect by using + * libwebsockets_remaining_packet_payload(). Notice that you + * just talk about frame size here, the LWS_SEND_BUFFER_PRE_PADDING + * and post-padding are automatically also allocated on top. + * @owning_server: the server init call fills in this opaque pointer when + * registering this protocol with the server. + * @protocol_index: which protocol we are starting from zero + * + * This structure represents one protocol supported by the server. An + * array of these structures is passed to libwebsocket_create_server() + * allows as many protocols as you like to be handled by one server. + */ + +struct libwebsocket_protocols { + const char *name; + callback_function *callback; + size_t per_session_data_size; + size_t rx_buffer_size; + + /* + * below are filled in on server init and can be left uninitialized, + * no need for user to use them directly either + */ + + struct libwebsocket_context *owning_server; + int protocol_index; +}; + +#ifndef LWS_NO_EXTENSIONS +/** + * struct libwebsocket_extension - An extension we know how to cope with + * + * @name: Formal extension name, eg, "deflate-stream" + * @callback: Service callback + * @per_session_data_size: Libwebsockets will auto-malloc this much + * memory for the use of the extension, a pointer + * to it comes in the @user callback parameter + * @per_context_private_data: Optional storage for this extension that + * is per-context, so it can track stuff across + * all sessions, etc, if it wants + */ + +struct libwebsocket_extension { + const char *name; + extension_callback_function *callback; + size_t per_session_data_size; + void *per_context_private_data; +}; +#endif + +/** + * struct lws_context_creation_info: parameters to create context with + * + * @port: Port to listen on... you can use 0 to suppress listening on + * any port, that's what you want if you are not running a + * websocket server at all but just using it as a client + * @iface: NULL to bind the listen socket to all interfaces, or the + * interface name, eg, "eth2" + * @protocols: Array of structures listing supported protocols and a protocol- + * specific callback for each one. The list is ended with an + * entry that has a NULL callback pointer. + * It's not const because we write the owning_server member + * @extensions: NULL or array of libwebsocket_extension structs listing the + * extensions this context supports. If you configured with + * --without-extensions, you should give NULL here. + * @ssl_cert_filepath: If libwebsockets was compiled to use ssl, and you want + * to listen using SSL, set to the filepath to fetch the + * server cert from, otherwise NULL for unencrypted + * @ssl_private_key_filepath: filepath to private key if wanting SSL mode, + * else ignored + * @ssl_ca_filepath: CA certificate filepath or NULL + * @ssl_cipher_list: List of valid ciphers to use (eg, + * "RC4-MD5:RC4-SHA:AES128-SHA:AES256-SHA:HIGH:!DSS:!aNULL" + * or you can leave it as NULL to get "DEFAULT" + * @gid: group id to change to after setting listen socket, or -1. + * @uid: user id to change to after setting listen socket, or -1. + * @options: 0, or LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK + * @user: optional user pointer that can be recovered via the context + * pointer using libwebsocket_context_user + * @ka_time: 0 for no keepalive, otherwise apply this keepalive timeout to + * all libwebsocket sockets, client or server + * @ka_probes: if ka_time was nonzero, after the timeout expires how many + * times to try to get a response from the peer before giving up + * and killing the connection + * @ka_interval: if ka_time was nonzero, how long to wait before each ka_probes + * attempt + */ + +struct lws_context_creation_info { + int port; + const char *iface; + struct libwebsocket_protocols *protocols; + struct libwebsocket_extension *extensions; + const char *ssl_cert_filepath; + const char *ssl_private_key_filepath; + const char *ssl_ca_filepath; + const char *ssl_cipher_list; + int gid; + int uid; + unsigned int options; + void *user; + int ka_time; + int ka_probes; + int ka_interval; + +}; + +LWS_VISIBLE LWS_EXTERN +void lws_set_log_level(int level, + void (*log_emit_function)(int level, const char *line)); + +LWS_VISIBLE LWS_EXTERN void +lwsl_emit_syslog(int level, const char *line); + +LWS_VISIBLE LWS_EXTERN struct libwebsocket_context * +libwebsocket_create_context(struct lws_context_creation_info *info); + +LWS_VISIBLE LWS_EXTERN void +libwebsocket_context_destroy(struct libwebsocket_context *context); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_service(struct libwebsocket_context *context, int timeout_ms); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_service_fd(struct libwebsocket_context *context, + struct pollfd *pollfd); + +LWS_VISIBLE LWS_EXTERN void * +libwebsocket_context_user(struct libwebsocket_context *context); + +/* + * IMPORTANT NOTICE! + * + * When sending with websocket protocol (LWS_WRITE_TEXT or LWS_WRITE_BINARY) + * the send buffer has to have LWS_SEND_BUFFER_PRE_PADDING bytes valid BEFORE + * buf, and LWS_SEND_BUFFER_POST_PADDING bytes valid AFTER (buf + len). + * + * This allows us to add protocol info before and after the data, and send as + * one packet on the network without payload copying, for maximum efficiency. + * + * So for example you need this kind of code to use libwebsocket_write with a + * 128-byte payload + * + * char buf[LWS_SEND_BUFFER_PRE_PADDING + 128 + LWS_SEND_BUFFER_POST_PADDING]; + * + * // fill your part of the buffer... for example here it's all zeros + * memset(&buf[LWS_SEND_BUFFER_PRE_PADDING], 0, 128); + * + * libwebsocket_write(wsi, &buf[LWS_SEND_BUFFER_PRE_PADDING], 128, + * LWS_WRITE_TEXT); + * + * When sending LWS_WRITE_HTTP, there is no protocol addition and you can just + * use the whole buffer without taking care of the above. + */ + +/* + * this is the frame nonce plus two header plus 8 length + * there's an additional two for mux extension per mux nesting level + * 2 byte prepend on close will already fit because control frames cannot use + * the big length style + */ + +#define LWS_SEND_BUFFER_PRE_PADDING (4 + 10 + (2 * MAX_MUX_RECURSION)) +#define LWS_SEND_BUFFER_POST_PADDING 4 + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_write(struct libwebsocket *wsi, unsigned char *buf, size_t len, + enum libwebsocket_write_protocol protocol); + +LWS_VISIBLE LWS_EXTERN int +libwebsockets_serve_http_file(struct libwebsocket_context *context, + struct libwebsocket *wsi, const char *file, + const char *content_type); +LWS_VISIBLE LWS_EXTERN int +libwebsockets_serve_http_file_fragment(struct libwebsocket_context *context, + struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN const struct libwebsocket_protocols * +libwebsockets_get_protocol(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_callback_on_writable(struct libwebsocket_context *context, + struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_callback_on_writable_all_protocol( + const struct libwebsocket_protocols *protocol); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_get_socket_fd(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_is_final_fragment(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN unsigned char +libwebsocket_get_reserved_bits(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_rx_flow_control(struct libwebsocket *wsi, int enable); + +LWS_VISIBLE LWS_EXTERN void +libwebsocket_rx_flow_allow_all_protocol( + const struct libwebsocket_protocols *protocol); + +LWS_VISIBLE LWS_EXTERN size_t +libwebsockets_remaining_packet_payload(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN struct libwebsocket * +libwebsocket_client_connect(struct libwebsocket_context *clients, + const char *address, + int port, + int ssl_connection, + const char *path, + const char *host, + const char *origin, + const char *protocol, + int ietf_version_or_minus_one); + +LWS_VISIBLE LWS_EXTERN struct libwebsocket * +libwebsocket_client_connect_extended(struct libwebsocket_context *clients, + const char *address, + int port, + int ssl_connection, + const char *path, + const char *host, + const char *origin, + const char *protocol, + int ietf_version_or_minus_one, + void *userdata); + +LWS_VISIBLE LWS_EXTERN const char * +libwebsocket_canonical_hostname(struct libwebsocket_context *context); + + +LWS_VISIBLE LWS_EXTERN void +libwebsockets_get_peer_addresses(struct libwebsocket_context *context, + struct libwebsocket *wsi, int fd, char *name, int name_len, + char *rip, int rip_len); + +LWS_VISIBLE LWS_EXTERN int +libwebsockets_get_random(struct libwebsocket_context *context, + void *buf, int len); + +LWS_VISIBLE LWS_EXTERN int +lws_daemonize(const char *_lock_path); + +LWS_VISIBLE LWS_EXTERN int +lws_send_pipe_choked(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int +lws_frame_is_binary(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN unsigned char * +libwebsockets_SHA1(const unsigned char *d, size_t n, unsigned char *md); + +LWS_VISIBLE LWS_EXTERN int +lws_b64_encode_string(const char *in, int in_len, char *out, int out_size); + +LWS_VISIBLE LWS_EXTERN int +lws_b64_decode_string(const char *in, char *out, int out_size); + +LWS_VISIBLE LWS_EXTERN const char * +lws_get_library_version(void); + +/* access to headers... only valid while headers valid */ + +LWS_VISIBLE LWS_EXTERN int +lws_hdr_total_length(struct libwebsocket *wsi, enum lws_token_indexes h); + +LWS_VISIBLE LWS_EXTERN int +lws_hdr_copy(struct libwebsocket *wsi, char *dest, int len, + enum lws_token_indexes h); + +/* + * Note: this is not normally needed as a user api. It's provided in case it is + * useful when integrating with other app poll loop service code. + */ + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_read(struct libwebsocket_context *context, + struct libwebsocket *wsi, + unsigned char *buf, size_t len); + +#ifndef LWS_NO_EXTENSIONS +LWS_VISIBLE LWS_EXTERN struct libwebsocket_extension *libwebsocket_get_internal_extensions(); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/external/libwebsockets/win32/include/win32helpers/gettimeofday.h b/external/libwebsockets/win32/include/win32helpers/gettimeofday.h new file mode 100644 index 0000000000..223ceeed8b --- /dev/null +++ b/external/libwebsockets/win32/include/win32helpers/gettimeofday.h @@ -0,0 +1,28 @@ +#ifndef _GET_TIME_OF_DAY_H +#define _GET_TIME_OF_DAY_H + +#ifdef __MINGW64__ +#else +#ifdef __MINGW32__ +#else +#include < time.h > +#endif +#endif + +#include //I've ommited context line. +#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS) + #define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64 +#else + #define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL +#endif + +struct timezone +{ + int tz_minuteswest; /* minutes W of Greenwich */ + int tz_dsttime; /* type of dst correction */ +}; + +int gettimeofday(struct timeval *tv, struct timezone *tz); + + +#endif diff --git a/external/libwebsockets/win32/include/win32helpers/websock-w32.h b/external/libwebsockets/win32/include/win32helpers/websock-w32.h new file mode 100644 index 0000000000..72a4f5c6b6 --- /dev/null +++ b/external/libwebsockets/win32/include/win32helpers/websock-w32.h @@ -0,0 +1,62 @@ +#ifndef __WEB_SOCK_W32_H__ +#define __WEB_SOCK_W32_H__ + +// Windows uses _DEBUG and NDEBUG +#ifdef _DEBUG +#undef DEBUG +#define DEBUG 1 +#endif + +#pragma warning(disable : 4996) + +#define bzero(b,len) (memset((b), '\0', (len)), (void) 0) + +#define MSG_NOSIGNAL 0 +#define SHUT_RDWR SD_BOTH + +#define SOL_TCP IPPROTO_TCP + +#define random rand +#define usleep _sleep + +#ifdef __MINGW64__ +#define DEF_POLL_STUFF +#endif +#ifdef __MINGW32__ +#define DEF_POLL_STUFF +#endif + +#ifdef DEF_POLL_STUFF + +#include + +typedef struct pollfd { + SOCKET fd; + short events; + short revents; +} WSAPOLLFD, *PWSAPOLLFD, *LPWSAPOLLFD; + +#define POLLIN 0x0001 /* any readable data available */ +#define POLLOUT 0x0004 /* file descriptor is writeable */ +#define POLLERR 0x0008 /* some poll error occurred */ +#define POLLHUP 0x0010 /* file descriptor was "hung up" */ +#define POLLNVAL 0x0020 /* requested events "invalid" */ + +#endif + +typedef INT (WSAAPI *PFNWSAPOLL)(LPWSAPOLLFD fdarray, ULONG nfds, INT timeout); +extern PFNWSAPOLL poll; + +extern INT WSAAPI emulated_poll(LPWSAPOLLFD fdarray, ULONG nfds, INT timeout); + +/* override configure because we are not using Makefiles */ + +#define LWS_NO_FORK + +/* windows can't cope with this idea, needs assets in cwd */ + +#ifndef INSTALL_DATADIR +#define INSTALL_DATADIR "." +#endif + +#endif diff --git a/licenses/LICENSE_libwebsockets.txt b/licenses/LICENSE_libwebsockets.txt new file mode 100644 index 0000000000..7c8986558c --- /dev/null +++ b/licenses/LICENSE_libwebsockets.txt @@ -0,0 +1,526 @@ +Libwebsockets and included programs are provided under the terms of the GNU +Library General Public License (LGPL) 2.1, with the following exceptions: + +1) Static linking of programs with the libwebsockets library does not +constitute a derivative work and does not require the author to provide +source code for the program, use the shared libwebsockets libraries, or +link their program against a user-supplied version of libwebsockets. + +If you link the program to a modified version of libwebsockets, then the +changes to libwebsockets must be provided under the terms of the LGPL in +sections 1, 2, and 4. + +2) You do not have to provide a copy of the libwebsockets license with +programs that are linked to the libwebsockets library, nor do you have to +identify the libwebsockets license in your program or documentation as +required by section 6 of the LGPL. + +However, programs must still identify their use of libwebsockets. The +following example statement can be included in user documentation to +satisfy this requirement: + +"[program] is based in part on the work of the libwebsockets project +(http://libwebsockets.org)" + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/samples/Cpp/TestCpp/Android.mk b/samples/Cpp/TestCpp/Android.mk index eb24e345da..8a64ef5a18 100644 --- a/samples/Cpp/TestCpp/Android.mk +++ b/samples/Cpp/TestCpp/Android.mk @@ -55,6 +55,7 @@ Classes/ExtensionsTest/CocosBuilderTest/MenuTest/MenuTestLayer.cpp \ Classes/ExtensionsTest/CocosBuilderTest/AnimationsTest/AnimationsTestLayer.cpp \ Classes/ExtensionsTest/CocosBuilderTest/TimelineCallbackTest/TimelineCallbackTestLayer.cpp \ Classes/ExtensionsTest/NetworkTest/HttpClientTest.cpp \ +Classes/ExtensionsTest/NetworkTest/WebSocketTest.cpp \ Classes/ExtensionsTest/EditBoxTest/EditBoxTest.cpp \ Classes/ExtensionsTest/TableViewTest/TableViewTestScene.cpp \ Classes/ExtensionsTest/TableViewTest/CustomTableViewCell.cpp \ diff --git a/samples/Cpp/TestCpp/Classes/ExtensionsTest/ExtensionsTest.cpp b/samples/Cpp/TestCpp/Classes/ExtensionsTest/ExtensionsTest.cpp index cefd147aaf..f1c3003bf3 100644 --- a/samples/Cpp/TestCpp/Classes/ExtensionsTest/ExtensionsTest.cpp +++ b/samples/Cpp/TestCpp/Classes/ExtensionsTest/ExtensionsTest.cpp @@ -8,6 +8,10 @@ #endif #include "TableViewTest/TableViewTestScene.h" +#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) || (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) || (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) +#include "NetworkTest/WebSocketTest.h" +#endif + #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) || (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) || (CC_TARGET_PLATFORM == CC_PLATFORM_MAC) || (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) || (CC_TARGET_PLATFORM == CC_PLATFORM_TIZEN) #include "EditBoxTest/EditBoxTest.h" #endif @@ -24,6 +28,9 @@ enum TEST_CCCONTROLBUTTON, TEST_COCOSBUILDER, TEST_HTTPCLIENT, +#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) || (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) || (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) + TEST_WEBSOCKET, +#endif #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) || (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) || (CC_TARGET_PLATFORM == CC_PLATFORM_MAC) || (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) || (CC_TARGET_PLATFORM == CC_PLATFORM_TIZEN) TEST_EDITBOX, #endif @@ -39,6 +46,9 @@ static const std::string testsName[TEST_MAX_COUNT] = #if (CC_TARGET_PLATFORM != CC_PLATFORM_EMSCRIPTEN) "HttpClientTest", #endif +#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) || (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) || (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) + "WebSocketTest", +#endif #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) || (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) || (CC_TARGET_PLATFORM == CC_PLATFORM_MAC) || (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) || (CC_TARGET_PLATFORM == CC_PLATFORM_TIZEN) "EditBoxTest", #endif @@ -109,6 +119,13 @@ void ExtensionsMainLayer::menuCallback(CCObject* pSender) } break; #endif +#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) || (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) || (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) + case TEST_WEBSOCKET: + { + runWebSocketTest(); + } + break; +#endif #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) || (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) || (CC_TARGET_PLATFORM == CC_PLATFORM_MAC) || (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) || (CC_TARGET_PLATFORM == CC_PLATFORM_TIZEN) case TEST_EDITBOX: { diff --git a/samples/Cpp/TestCpp/Classes/ExtensionsTest/NetworkTest/WebSocketTest.cpp b/samples/Cpp/TestCpp/Classes/ExtensionsTest/NetworkTest/WebSocketTest.cpp new file mode 100644 index 0000000000..a06681e71a --- /dev/null +++ b/samples/Cpp/TestCpp/Classes/ExtensionsTest/NetworkTest/WebSocketTest.cpp @@ -0,0 +1,241 @@ +// +// WebSocketTest.cpp +// TestCpp +// +// Created by James Chen on 5/31/13. +// +// + +#include "WebSocketTest.h" +#include "../ExtensionsTest.h" + +USING_NS_CC; +USING_NS_CC_EXT; + +WebSocketTestLayer::WebSocketTestLayer() +: _wsiSendText(NULL) +, _wsiSendBinary(NULL) +, _wsiError(NULL) +, _sendTextStatus(NULL) +, _sendBinaryStatus(NULL) +, _errorStatus(NULL) +, _sendTextTimes(0) +, _sendBinaryTimes(0) +{ + CCSize winSize = CCDirector::sharedDirector()->getWinSize(); + + const int MARGIN = 40; + const int SPACE = 35; + + CCLabelTTF *label = CCLabelTTF::create("WebSocket Test", "Arial", 28); + label->setPosition(ccp(winSize.width / 2, winSize.height - MARGIN)); + addChild(label, 0); + + CCMenu *menuRequest = CCMenu::create(); + menuRequest->setPosition(CCPointZero); + addChild(menuRequest); + + // Send Text + CCLabelTTF *labelSendText = CCLabelTTF::create("Send Text", "Arial", 22); + CCMenuItemLabel *itemSendText = CCMenuItemLabel::create(labelSendText, this, menu_selector(WebSocketTestLayer::onMenuSendTextClicked)); + itemSendText->setPosition(ccp(winSize.width / 2, winSize.height - MARGIN - SPACE)); + menuRequest->addChild(itemSendText); + + // Send Binary + CCLabelTTF *labelSendBinary = CCLabelTTF::create("Send Binary", "Arial", 22); + CCMenuItemLabel *itemSendBinary = CCMenuItemLabel::create(labelSendBinary, this, menu_selector(WebSocketTestLayer::onMenuSendBinaryClicked)); + itemSendBinary->setPosition(ccp(winSize.width / 2, winSize.height - MARGIN - 2 * SPACE)); + menuRequest->addChild(itemSendBinary); + + + // Send Text Status Label + _sendTextStatus = CCLabelTTF::create("Send Text WS is waiting...", "Arial", 14, CCSizeMake(160, 100), kCCTextAlignmentCenter, kCCVerticalTextAlignmentTop); + _sendTextStatus->setAnchorPoint(ccp(0, 0)); + _sendTextStatus->setPosition(ccp(VisibleRect::left().x, VisibleRect::rightBottom().y + 25)); + this->addChild(_sendTextStatus); + + // Send Binary Status Label + _sendBinaryStatus = CCLabelTTF::create("Send Binary WS is waiting...", "Arial", 14, CCSizeMake(160, 100), kCCTextAlignmentCenter, kCCVerticalTextAlignmentTop); + _sendBinaryStatus->setAnchorPoint(ccp(0, 0)); + _sendBinaryStatus->setPosition(ccp(VisibleRect::left().x + 160, VisibleRect::rightBottom().y + 25)); + this->addChild(_sendBinaryStatus); + + // Error Label + _errorStatus = CCLabelTTF::create("Error WS is waiting...", "Arial", 14, CCSizeMake(160, 100), kCCTextAlignmentCenter, kCCVerticalTextAlignmentTop); + _errorStatus->setAnchorPoint(ccp(0, 0)); + _errorStatus->setPosition(ccp(VisibleRect::left().x + 320, VisibleRect::rightBottom().y + 25)); + this->addChild(_errorStatus); + + // Back Menu + CCMenuItemFont *itemBack = CCMenuItemFont::create("Back", this, menu_selector(WebSocketTestLayer::toExtensionsMainLayer)); + itemBack->setPosition(ccp(VisibleRect::rightBottom().x - 50, VisibleRect::rightBottom().y + 25)); + CCMenu *menuBack = CCMenu::create(itemBack, NULL); + menuBack->setPosition(CCPointZero); + addChild(menuBack); + + _wsiSendText = new WebSocket(); + _wsiSendBinary = new WebSocket(); + _wsiError = new WebSocket(); + + if (!_wsiSendText->init(*this, "ws://echo.websocket.org")) + { + CC_SAFE_DELETE(_wsiSendText); + } + + if (!_wsiSendBinary->init(*this, "ws://echo.websocket.org")) + { + CC_SAFE_DELETE(_wsiSendBinary); + } + + if (!_wsiError->init(*this, "ws://invalid.url.com")) + { + CC_SAFE_DELETE(_wsiError); + } +} + + +WebSocketTestLayer::~WebSocketTestLayer() +{ + if (_wsiSendText) + _wsiSendText->close(); + + if (_wsiSendBinary) + _wsiSendBinary->close(); + + if (_wsiError) + _wsiError->close(); +} + +// Delegate methods +void WebSocketTestLayer::onOpen(cocos2d::extension::WebSocket* ws) +{ + CCLog("Websocket (%p) opened", ws); + if (ws == _wsiSendText) + { + _sendTextStatus->setString("Send Text WS was opened."); + } + else if (ws == _wsiSendBinary) + { + _sendBinaryStatus->setString("Send Binary WS was opened."); + } + else if (ws == _wsiError) + { + CCAssert(0, "error test will never go here."); + } +} + +void WebSocketTestLayer::onMessage(cocos2d::extension::WebSocket* ws, const cocos2d::extension::WebSocket::Data& data) +{ + if (!data.isBinary) + { + _sendTextTimes++; + char times[100] = {0}; + sprintf(times, "%d", _sendTextTimes); + std::string textStr = std::string("response text msg: ")+data.bytes+", "+times; + CCLog("%s", textStr.c_str()); + + _sendTextStatus->setString(textStr.c_str()); + } + else + { + _sendBinaryTimes++; + char times[100] = {0}; + sprintf(times, "%d", _sendBinaryTimes); + + std::string binaryStr = "response bin msg: "; + + for (int i = 0; i < data.len; ++i) { + if (data.bytes[i] != '\0') + { + binaryStr += data.bytes[i]; + } + else + { + binaryStr += "\'\\0\'"; + } + } + + binaryStr += std::string(", ")+times; + CCLog("%s", binaryStr.c_str()); + _sendBinaryStatus->setString(binaryStr.c_str()); + } +} + +void WebSocketTestLayer::onClose(cocos2d::extension::WebSocket* ws) +{ + CCLog("websocket instance (%p) closed.", ws); + if (ws == _wsiSendText) + { + _wsiSendText = NULL; + } + else if (ws == _wsiSendBinary) + { + _wsiSendBinary = NULL; + } + else if (ws == _wsiError) + { + _wsiError = NULL; + } + // Delete websocket instance. + CC_SAFE_DELETE(ws); +} + +void WebSocketTestLayer::onError(cocos2d::extension::WebSocket* ws, const cocos2d::extension::WebSocket::WS_ERROR& error) +{ + CCLog("Error was fired, error code: %d", error); + if (ws == _wsiError) + { + char buf[100] = {0}; + sprintf(buf, "an error was fired, code: %d", error); + _errorStatus->setString(buf); + } +} + +void WebSocketTestLayer::toExtensionsMainLayer(cocos2d::CCObject *sender) +{ + ExtensionsTestScene *pScene = new ExtensionsTestScene(); + pScene->runThisTest(); + pScene->release(); +} + +// Menu Callbacks +void WebSocketTestLayer::onMenuSendTextClicked(cocos2d::CCObject *sender) +{ + if (_wsiSendText->getReadyState() == WebSocket::WS_STATE_OPEN) + { + _sendTextStatus->setString("Send Text WS is waiting..."); + _wsiSendText->send("Hello WebSocket, I'm a text message."); + } + else + { + std::string warningStr = "send text websocket instance wasn't ready..."; + CCLog("%s", warningStr.c_str()); + _sendTextStatus->setString(warningStr.c_str()); + } +} + +void WebSocketTestLayer::onMenuSendBinaryClicked(cocos2d::CCObject *sender) +{ + if (_wsiSendBinary->getReadyState() == WebSocket::WS_STATE_OPEN) + { + _sendBinaryStatus->setString("Send Binary WS is waiting..."); + char buf[] = "Hello WebSocket,\0 I'm\0 a\0 binary\0 message\0."; + _wsiSendBinary->send((unsigned char*)buf, sizeof(buf)); + } + else + { + std::string warningStr = "send binary websocket instance wasn't ready..."; + CCLog("%s", warningStr.c_str()); + _sendBinaryStatus->setString(warningStr.c_str()); + } +} + +void runWebSocketTest() +{ + CCScene *pScene = CCScene::create(); + WebSocketTestLayer *pLayer = new WebSocketTestLayer(); + pScene->addChild(pLayer); + + CCDirector::sharedDirector()->replaceScene(pScene); + pLayer->release(); +} diff --git a/samples/Cpp/TestCpp/Classes/ExtensionsTest/NetworkTest/WebSocketTest.h b/samples/Cpp/TestCpp/Classes/ExtensionsTest/NetworkTest/WebSocketTest.h new file mode 100644 index 0000000000..1070ce750a --- /dev/null +++ b/samples/Cpp/TestCpp/Classes/ExtensionsTest/NetworkTest/WebSocketTest.h @@ -0,0 +1,50 @@ +// +// WebSocketTest.h +// TestCpp +// +// Created by James Chen on 5/31/13. +// +// + +#ifndef __TestCpp__WebSocketTest__ +#define __TestCpp__WebSocketTest__ + +#include "cocos2d.h" +#include "cocos-ext.h" +#include "WebSocket.h" + +class WebSocketTestLayer +: public cocos2d::CCLayer +, public cocos2d::extension::WebSocket::Delegate +{ +public: + WebSocketTestLayer(); + virtual ~WebSocketTestLayer(); + + virtual void onOpen(cocos2d::extension::WebSocket* ws); + virtual void onMessage(cocos2d::extension::WebSocket* ws, const cocos2d::extension::WebSocket::Data& data); + virtual void onClose(cocos2d::extension::WebSocket* ws); + virtual void onError(cocos2d::extension::WebSocket* ws, const cocos2d::extension::WebSocket::WS_ERROR& error); + + void toExtensionsMainLayer(cocos2d::CCObject *sender); + + // Menu Callbacks + void onMenuSendTextClicked(cocos2d::CCObject *sender); + void onMenuSendBinaryClicked(cocos2d::CCObject *sender); + +private: + cocos2d::extension::WebSocket* _wsiSendText; + cocos2d::extension::WebSocket* _wsiSendBinary; + cocos2d::extension::WebSocket* _wsiError; + + cocos2d::CCLabelTTF* _sendTextStatus; + cocos2d::CCLabelTTF* _sendBinaryStatus; + cocos2d::CCLabelTTF* _errorStatus; + + int _sendTextTimes; + int _sendBinaryTimes; +}; + +void runWebSocketTest(); + +#endif /* defined(__TestCpp__WebSocketTest__) */ diff --git a/samples/Cpp/TestCpp/proj.ios/TestCpp.xcodeproj/project.pbxproj.REMOVED.git-id b/samples/Cpp/TestCpp/proj.ios/TestCpp.xcodeproj/project.pbxproj.REMOVED.git-id index a2a52c9d4c..4d413cf14c 100644 --- a/samples/Cpp/TestCpp/proj.ios/TestCpp.xcodeproj/project.pbxproj.REMOVED.git-id +++ b/samples/Cpp/TestCpp/proj.ios/TestCpp.xcodeproj/project.pbxproj.REMOVED.git-id @@ -1 +1 @@ -c263309fadbcba0104099bb226f0dc701522c6d1 \ No newline at end of file +c12820b10f5bb33955c15eaf4cae17a4628455f8 \ No newline at end of file diff --git a/samples/Cpp/TestCpp/proj.win32/TestCpp.vcxproj b/samples/Cpp/TestCpp/proj.win32/TestCpp.vcxproj index 11594b910a..e080de91cb 100644 --- a/samples/Cpp/TestCpp/proj.win32/TestCpp.vcxproj +++ b/samples/Cpp/TestCpp/proj.win32/TestCpp.vcxproj @@ -65,7 +65,7 @@ Disabled - $(ProjectDir)..\..\..\..\cocos2dx;$(ProjectDir)..\..\..\..\cocos2dx\include;$(ProjectDir)..\..\..\..\cocos2dx\kazmath\include;$(ProjectDir)..\..\..\..\cocos2dx\platform\win32;$(ProjectDir)..\..\..\..\cocos2dx\platform\third_party\win32;$(ProjectDir)..\..\..\..\cocos2dx\platform\third_party\win32\OGLES;$(ProjectDir)..\..\..\..\external;$(ProjectDir)..\..\..\..\external\chipmunk\include\chipmunk;$(ProjectDir)..\..\..\..\CocosDenshion\include;$(ProjectDir)..\..\..\..\extensions;..\Classes;..;%(AdditionalIncludeDirectories) + $(ProjectDir)..\..\..\..\cocos2dx;$(ProjectDir)..\..\..\..\cocos2dx\include;$(ProjectDir)..\..\..\..\cocos2dx\kazmath\include;$(ProjectDir)..\..\..\..\cocos2dx\platform\win32;$(ProjectDir)..\..\..\..\cocos2dx\platform\third_party\win32;$(ProjectDir)..\..\..\..\cocos2dx\platform\third_party\win32\OGLES;$(ProjectDir)..\..\..\..\cocos2dx\platform\third_party\win32\pthread;$(ProjectDir)..\..\..\..\external;$(ProjectDir)..\..\..\..\external\chipmunk\include\chipmunk;$(ProjectDir)..\..\..\..\external\libwebsockets\win32\include;$(ProjectDir)..\..\..\..\CocosDenshion\include;$(ProjectDir)..\..\..\..\extensions;$(ProjectDir)..\..\..\..\extensions\network;..\Classes;..;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_USE_MATH_DEFINES;GL_GLEXT_PROTOTYPES;CC_ENABLE_CHIPMUNK_INTEGRATION=1;COCOS2D_DEBUG=1;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true EnableFastChecks @@ -77,7 +77,7 @@ 4267;4251;4244;%(DisableSpecificWarnings) - libExtensions.lib;libcocos2d.lib;libCocosDenshion.lib;opengl32.lib;glew32.lib;libBox2d.lib;libchipmunk.lib;libcurl_imp.lib;pthreadVCE2.lib;%(AdditionalDependencies) + libExtensions.lib;libcocos2d.lib;libCocosDenshion.lib;opengl32.lib;glew32.lib;libBox2d.lib;libchipmunk.lib;libcurl_imp.lib;websockets.lib;pthreadVCE2.lib;%(AdditionalDependencies) $(OutDir)$(ProjectName).exe $(OutDir);%(AdditionalLibraryDirectories) true @@ -93,7 +93,7 @@ MaxSpeed true - $(ProjectDir)..\..\..\..\cocos2dx;$(ProjectDir)..\..\..\..\cocos2dx\include;$(ProjectDir)..\..\..\..\cocos2dx\kazmath\include;$(ProjectDir)..\..\..\..\cocos2dx\platform\win32;$(ProjectDir)..\..\..\..\cocos2dx\platform\third_party\win32;$(ProjectDir)..\..\..\..\cocos2dx\platform\third_party\win32\OGLES;$(ProjectDir)..\..\..\..\external;$(ProjectDir)..\..\..\..\external\chipmunk\include\chipmunk;$(ProjectDir)..\..\..\..\CocosDenshion\include;$(ProjectDir)..\..\..\..\extensions;..\Classes;..;%(AdditionalIncludeDirectories) + $(ProjectDir)..\..\..\..\cocos2dx;$(ProjectDir)..\..\..\..\cocos2dx\include;$(ProjectDir)..\..\..\..\cocos2dx\kazmath\include;$(ProjectDir)..\..\..\..\cocos2dx\platform\win32;$(ProjectDir)..\..\..\..\cocos2dx\platform\third_party\win32;$(ProjectDir)..\..\..\..\cocos2dx\platform\third_party\win32\OGLES;$(ProjectDir)..\..\..\..\cocos2dx\platform\third_party\win32\pthread;$(ProjectDir)..\..\..\..\external;$(ProjectDir)..\..\..\..\external\chipmunk\include\chipmunk;$(ProjectDir)..\..\..\..\external\libwebsockets\win32\include;$(ProjectDir)..\..\..\..\CocosDenshion\include;$(ProjectDir)..\..\..\..\extensions;$(ProjectDir)..\..\..\..\extensions\network;..\Classes;..;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USE_MATH_DEFINES;GL_GLEXT_PROTOTYPES;CC_ENABLE_CHIPMUNK_INTEGRATION=1;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) MultiThreadedDLL true @@ -104,7 +104,7 @@ 4267;4251;4244;%(DisableSpecificWarnings) - libcocos2d.lib;libCocosDenshion.lib;opengl32.lib;glew32.lib;libBox2d.lib;libchipmunk.lib;libcurl_imp.lib;libExtensions.lib;pthreadVCE2.lib;%(AdditionalDependencies) + libExtensions.lib;libcocos2d.lib;libCocosDenshion.lib;opengl32.lib;glew32.lib;libBox2d.lib;libchipmunk.lib;libcurl_imp.lib;websockets.lib;pthreadVCE2.lib;%(AdditionalDependencies) $(OutDir)$(ProjectName).exe $(OutDir);%(AdditionalLibraryDirectories) true @@ -129,6 +129,7 @@ + @@ -227,6 +228,7 @@ + diff --git a/samples/Cpp/TestCpp/proj.win32/TestCpp.vcxproj.filters b/samples/Cpp/TestCpp/proj.win32/TestCpp.vcxproj.filters index 5af8f8f44f..68a799d585 100644 --- a/samples/Cpp/TestCpp/proj.win32/TestCpp.vcxproj.filters +++ b/samples/Cpp/TestCpp/proj.win32/TestCpp.vcxproj.filters @@ -510,6 +510,9 @@ Classes\ConfigurationTest + + Classes\ExtensionsTest\NetworkTest + @@ -974,5 +977,8 @@ Classes\ConfigurationTest + + Classes\ExtensionsTest\NetworkTest + \ No newline at end of file diff --git a/samples/Javascript/TestJavascript/Classes/AppDelegate.cpp b/samples/Javascript/TestJavascript/Classes/AppDelegate.cpp index fb3c8521e7..1724dadf42 100644 --- a/samples/Javascript/TestJavascript/Classes/AppDelegate.cpp +++ b/samples/Javascript/TestJavascript/Classes/AppDelegate.cpp @@ -11,8 +11,10 @@ #include "js_bindings_system_registration.h" #include "jsb_opengl_registration.h" #include "XMLHTTPRequest.h" +#include "jsb_websocket.h" USING_NS_CC; +USING_NS_CC_EXT; using namespace CocosDenshion; AppDelegate::AppDelegate() @@ -45,6 +47,7 @@ bool AppDelegate::applicationDidFinishLaunching() sc->addRegisterCallback(JSB_register_opengl); sc->addRegisterCallback(jsb_register_system); sc->addRegisterCallback(MinXmlHttpRequest::_js_register); + sc->addRegisterCallback(register_jsb_websocket); sc->start(); diff --git a/samples/Javascript/TestJavascript/proj.ios/TestJavascript.xcodeproj/project.pbxproj.REMOVED.git-id b/samples/Javascript/TestJavascript/proj.ios/TestJavascript.xcodeproj/project.pbxproj.REMOVED.git-id index 0ae2a66e36..ef36824f9c 100644 --- a/samples/Javascript/TestJavascript/proj.ios/TestJavascript.xcodeproj/project.pbxproj.REMOVED.git-id +++ b/samples/Javascript/TestJavascript/proj.ios/TestJavascript.xcodeproj/project.pbxproj.REMOVED.git-id @@ -1 +1 @@ -58bdb54b5e8ea28b2382bd97ecc4bbd3fd60bba1 \ No newline at end of file +ccb7f062be010df9d1b6be60ac35b8f01f742ced \ No newline at end of file diff --git a/scripting/javascript/bindings/Android.mk b/scripting/javascript/bindings/Android.mk index 08ebbdfd1a..cff6760a99 100644 --- a/scripting/javascript/bindings/Android.mk +++ b/scripting/javascript/bindings/Android.mk @@ -25,7 +25,8 @@ LOCAL_SRC_FILES := ScriptingCore.cpp \ jsb_opengl_registration.cpp \ generated/jsb_cocos2dx_auto.cpp \ generated/jsb_cocos2dx_extension_auto.cpp \ - XMLHTTPRequest.cpp + XMLHTTPRequest.cpp \ + jsb_websocket.cpp LOCAL_CFLAGS := -DCOCOS2D_JAVASCRIPT diff --git a/scripting/javascript/bindings/proj.win32/libJSBinding.vcxproj b/scripting/javascript/bindings/proj.win32/libJSBinding.vcxproj index 99dcca009e..59164d2b19 100644 --- a/scripting/javascript/bindings/proj.win32/libJSBinding.vcxproj +++ b/scripting/javascript/bindings/proj.win32/libJSBinding.vcxproj @@ -19,6 +19,7 @@ + @@ -41,6 +42,7 @@ + @@ -125,7 +127,7 @@ Level3 Disabled WIN32;_WINDOWS;_DEBUG;_LIB;DEBUG;COCOS2D_DEBUG=1;XP_WIN;JS_HAVE___INTN;JS_INTPTR_TYPE=int;COCOS2D_JAVASCRIPT=1;CC_ENABLE_CHIPMUNK_INTEGRATION=1;%(PreprocessorDefinitions) - $(ProjectDir)..\..\..\..\cocos2dx;$(ProjectDir)..\..\..\..\cocos2dx\include;$(ProjectDir)..\..\..\..\cocos2dx\kazmath\include;$(ProjectDir)..\..\..\..\cocos2dx\platform\win32;$(ProjectDir)..\..\..\..\cocos2dx\platform\third_party\win32;$(ProjectDir)..\..\..\..\cocos2dx\platform\third_party\win32\pthread;$(ProjectDir)..\..\..\..\cocos2dx\platform\third_party\win32\OGLES;$(ProjectDir)..\..\..\..\CocosDenshion\include;$(ProjectDir)..;$(ProjectDir)..\..\spidermonkey-win32\include;$(ProjectDir)..\..\..\..\external\chipmunk\include\chipmunk;$(ProjectDir)..\..\..\..\extensions;$(ProjectDir)..\..\..\..\extensions\LocalStorage;%(AdditionalIncludeDirectories) + $(ProjectDir)..\..\..\..\cocos2dx;$(ProjectDir)..\..\..\..\cocos2dx\include;$(ProjectDir)..\..\..\..\cocos2dx\kazmath\include;$(ProjectDir)..\..\..\..\cocos2dx\platform\win32;$(ProjectDir)..\..\..\..\cocos2dx\platform\third_party\win32;$(ProjectDir)..\..\..\..\cocos2dx\platform\third_party\win32\pthread;$(ProjectDir)..\..\..\..\cocos2dx\platform\third_party\win32\OGLES;$(ProjectDir)..\..\..\..\CocosDenshion\include;$(ProjectDir)..;$(ProjectDir)..\..\spidermonkey-win32\include;$(ProjectDir)..\..\..\..\external\chipmunk\include\chipmunk;$(ProjectDir)..\..\..\..\external\libwebsockets\win32\include;$(ProjectDir)..\..\..\..\extensions;$(ProjectDir)..\..\..\..\extensions\LocalStorage;$(ProjectDir)..\..\..\..\extensions\network;%(AdditionalIncludeDirectories) 4068;4101;4800;4251;4996;4244;%(DisableSpecificWarnings) @@ -146,7 +148,7 @@ xcopy /Y /Q "$(ProjectDir)..\..\..\..\external\sqlite3\libraries\win32\*.*" "$(O true true WIN32;_WINDOWS;NDEBUG;_LIB;XP_WIN;JS_HAVE___INTN;JS_INTPTR_TYPE=int;COCOS2D_JAVASCRIPT=1;CC_ENABLE_CHIPMUNK_INTEGRATION=1;%(PreprocessorDefinitions) - $(ProjectDir)..\..\..\..\cocos2dx;$(ProjectDir)..\..\..\..\cocos2dx\include;$(ProjectDir)..\..\..\..\cocos2dx\kazmath\include;$(ProjectDir)..\..\..\..\cocos2dx\platform\win32;$(ProjectDir)..\..\..\..\cocos2dx\platform\third_party\win32;$(ProjectDir)..\..\..\..\cocos2dx\platform\third_party\win32\pthread;$(ProjectDir)..\..\..\..\cocos2dx\platform\third_party\win32\OGLES;$(ProjectDir)..\..\..\..\CocosDenshion\include;$(ProjectDir)..;$(ProjectDir)..\..\spidermonkey-win32\include;$(ProjectDir)..\..\..\..\external\chipmunk\include\chipmunk;$(ProjectDir)..\..\..\..\extensions;$(ProjectDir)..\..\..\..\extensions\LocalStorage;%(AdditionalIncludeDirectories) + $(ProjectDir)..\..\..\..\cocos2dx;$(ProjectDir)..\..\..\..\cocos2dx\include;$(ProjectDir)..\..\..\..\cocos2dx\kazmath\include;$(ProjectDir)..\..\..\..\cocos2dx\platform\win32;$(ProjectDir)..\..\..\..\cocos2dx\platform\third_party\win32;$(ProjectDir)..\..\..\..\cocos2dx\platform\third_party\win32\pthread;$(ProjectDir)..\..\..\..\cocos2dx\platform\third_party\win32\OGLES;$(ProjectDir)..\..\..\..\CocosDenshion\include;$(ProjectDir)..;$(ProjectDir)..\..\spidermonkey-win32\include;$(ProjectDir)..\..\..\..\external\chipmunk\include\chipmunk;$(ProjectDir)..\..\..\..\external\libwebsockets\win32\include;$(ProjectDir)..\..\..\..\extensions;$(ProjectDir)..\..\..\..\extensions\LocalStorage;$(ProjectDir)..\..\..\..\extensions\network;%(AdditionalIncludeDirectories) 4068;4101;4800;4251;4996;4244;%(DisableSpecificWarnings) diff --git a/scripting/javascript/bindings/proj.win32/libJSBinding.vcxproj.filters b/scripting/javascript/bindings/proj.win32/libJSBinding.vcxproj.filters index 43a979dcc4..f49e00a20f 100644 --- a/scripting/javascript/bindings/proj.win32/libJSBinding.vcxproj.filters +++ b/scripting/javascript/bindings/proj.win32/libJSBinding.vcxproj.filters @@ -74,6 +74,9 @@ manual + + manual + @@ -154,6 +157,9 @@ manual + + manual + From 669066b95476a103324ba7ac126c0d193818998d Mon Sep 17 00:00:00 2001 From: James Chen Date: Fri, 31 May 2013 23:25:01 +0800 Subject: [PATCH 2/8] fixed #1647: Adding missing files. --- .../javascript/bindings/XMLHTTPRequest.h | 2 +- .../{XMLHTTPHelper.h => jsb_helper.h} | 0 .../javascript/bindings/jsb_websocket.cpp | 388 ++++++++++++++++++ scripting/javascript/bindings/jsb_websocket.h | 34 ++ 4 files changed, 423 insertions(+), 1 deletion(-) rename scripting/javascript/bindings/{XMLHTTPHelper.h => jsb_helper.h} (100%) create mode 100644 scripting/javascript/bindings/jsb_websocket.cpp create mode 100644 scripting/javascript/bindings/jsb_websocket.h diff --git a/scripting/javascript/bindings/XMLHTTPRequest.h b/scripting/javascript/bindings/XMLHTTPRequest.h index b70331866b..8994da9cdb 100644 --- a/scripting/javascript/bindings/XMLHTTPRequest.h +++ b/scripting/javascript/bindings/XMLHTTPRequest.h @@ -35,7 +35,7 @@ #include "jstypes.h" #include "jsapi.h" #include "jsfriendapi.h" -#include "XMLHTTPHelper.h" +#include "jsb_helper.h" enum MinXmlHttpRequestResponseType { kRequestResponseTypeString, diff --git a/scripting/javascript/bindings/XMLHTTPHelper.h b/scripting/javascript/bindings/jsb_helper.h similarity index 100% rename from scripting/javascript/bindings/XMLHTTPHelper.h rename to scripting/javascript/bindings/jsb_helper.h diff --git a/scripting/javascript/bindings/jsb_websocket.cpp b/scripting/javascript/bindings/jsb_websocket.cpp new file mode 100644 index 0000000000..e346bba5cb --- /dev/null +++ b/scripting/javascript/bindings/jsb_websocket.cpp @@ -0,0 +1,388 @@ +/**************************************************************************** +Copyright (c) 2013 cocos2d-x.org +Copyright (c) 2013 James Chen + +http://www.cocos2d-x.org + +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 "jsb_websocket.h" +#include "cocos2d.h" +#include "Websocket.h" +#include "spidermonkey_specifics.h" +#include "ScriptingCore.h" +#include "cocos2d_specifics.hpp" + +USING_NS_CC_EXT; + +/* + [Constructor(in DOMString url, in optional DOMString protocols)] + [Constructor(in DOMString url, in optional DOMString[] protocols)] + interface WebSocket { + readonly attribute DOMString url; + + // ready state + const unsigned short CONNECTING = 0; + const unsigned short OPEN = 1; + const unsigned short CLOSING = 2; + const unsigned short CLOSED = 3; + readonly attribute unsigned short readyState; + readonly attribute unsigned long bufferedAmount; + + // networking + attribute Function onopen; + attribute Function onmessage; + attribute Function onerror; + attribute Function onclose; + readonly attribute DOMString protocol; + void send(in DOMString data); + void close(); + }; + WebSocket implements EventTarget; + */ + +class JSB_WebSocketDelegate : public WebSocket::Delegate +{ +public: + + virtual void onOpen(WebSocket* ws) + { + js_proxy_t * p; + JS_GET_PROXY(p, ws); + if (!p) return; + + JSContext* cx = ScriptingCore::getInstance()->getGlobalContext(); + JSObject* jsobj = JS_NewObject(cx, NULL, NULL, NULL); + jsval vp = c_string_to_jsval(cx, "open"); + JS_SetProperty(cx, jsobj, "type", &vp); + + jsval args = OBJECT_TO_JSVAL(jsobj); + + ScriptingCore::getInstance()->executeFunctionWithOwner(OBJECT_TO_JSVAL(m_pJSDelegate), "onopen", 1, &args); + } + + virtual void onMessage(WebSocket* ws, const WebSocket::Data& data) + { + js_proxy_t * p; + JS_GET_PROXY(p, ws); + if (!p) return; + + JSContext* cx = ScriptingCore::getInstance()->getGlobalContext(); + JSObject* jsobj = JS_NewObject(cx, NULL, NULL, NULL); + jsval vp = c_string_to_jsval(cx, "message"); + JS_SetProperty(cx, jsobj, "type", &vp); + + jsval args = OBJECT_TO_JSVAL(jsobj); + + if (data.isBinary) + {// data is binary + JSObject* buffer = JS_NewArrayBuffer(cx, data.len); + uint8_t* bufdata = JS_GetArrayBufferData(buffer); + memcpy((void*)bufdata, (void*)data.bytes, data.len); + jsval dataVal = OBJECT_TO_JSVAL(buffer); + JS_SetProperty(cx, jsobj, "data", &dataVal); + } + else + {// data is string + jsval dataVal = c_string_to_jsval(cx, data.bytes); + JS_SetProperty(cx, jsobj, "data", &dataVal); + } + + ScriptingCore::getInstance()->executeFunctionWithOwner(OBJECT_TO_JSVAL(m_pJSDelegate), "onmessage", 1, &args); + } + + virtual void onClose(WebSocket* ws) + { + js_proxy_t * p; + JS_GET_PROXY(p, ws); + if (!p) return; + + JSContext* cx = ScriptingCore::getInstance()->getGlobalContext(); + JSObject* jsobj = JS_NewObject(cx, NULL, NULL, NULL); + jsval vp = c_string_to_jsval(cx, "close"); + JS_SetProperty(cx, jsobj, "type", &vp); + + jsval args = OBJECT_TO_JSVAL(jsobj); + ScriptingCore::getInstance()->executeFunctionWithOwner(OBJECT_TO_JSVAL(m_pJSDelegate), "onclose", 1, &args); + + js_proxy_t* jsproxy; + JS_GET_NATIVE_PROXY(jsproxy, p->obj); + JS_RemoveObjectRoot(cx, &jsproxy->obj); + JS_REMOVE_PROXY(p, jsproxy); + CC_SAFE_DELETE(ws); + } + + virtual void onError(WebSocket* ws, const WebSocket::WS_ERROR& error) + { + js_proxy_t * p; + JS_GET_PROXY(p, ws); + if (!p) return; + + JSContext* cx = ScriptingCore::getInstance()->getGlobalContext(); + JSObject* jsobj = JS_NewObject(cx, NULL, NULL, NULL); + jsval vp = c_string_to_jsval(cx, "error"); + JS_SetProperty(cx, jsobj, "type", &vp); + + jsval args = OBJECT_TO_JSVAL(jsobj); + + ScriptingCore::getInstance()->executeFunctionWithOwner(OBJECT_TO_JSVAL(m_pJSDelegate), "onerror", 1, &args); + } + + void setJSDelegate(JSObject* pJSDelegate) + { + m_pJSDelegate = pJSDelegate; + } +private: + JSObject* m_pJSDelegate; +}; + +JSClass *js_cocos2dx_websocket_class; +JSObject *js_cocos2dx_websocket_prototype; + +void js_cocos2dx_WebSocket_finalize(JSFreeOp *fop, JSObject *obj) { + CCLOG("jsbindings: finalizing JS object %p (WebSocket)", obj); +} + +JSBool js_cocos2dx_extension_WebSocket_send(JSContext *cx, uint32_t argc, jsval *vp) +{ + jsval *argv = JS_ARGV(cx, vp); + JSObject *obj = JS_THIS_OBJECT(cx, vp); + js_proxy_t *proxy; JS_GET_NATIVE_PROXY(proxy, obj); + WebSocket* cobj = (WebSocket *)(proxy ? proxy->ptr : NULL); + JSB_PRECONDITION2( cobj, cx, JS_FALSE, "Invalid Native Object"); + + if(argc == 1){ + do + { + if (JSVAL_IS_STRING(argv[0])) + { + std::string data; + jsval_to_std_string(cx, argv[0], &data); + cobj->send(data); + break; + } + + if (argv[0].isObject()) + { + uint8_t *bufdata = NULL; + uint32_t len = 0; + + JSObject* jsobj = JSVAL_TO_OBJECT(argv[0]); + if (JS_IsArrayBufferObject(jsobj)) + { + bufdata = JS_GetArrayBufferData(jsobj); + len = JS_GetArrayBufferByteLength(jsobj); + } + else if (JS_IsArrayBufferViewObject(jsobj)) + { + bufdata = (uint8_t*)JS_GetArrayBufferViewData(jsobj); + len = JS_GetArrayBufferViewByteLength(jsobj); + } + + if (bufdata && len > 0) + { + cobj->send(bufdata, len); + break; + } + } + + JS_ReportError(cx, "data type to be sent is unsupported."); + + } while (0); + + JS_SET_RVAL(cx, vp, JSVAL_VOID); + + return JS_TRUE; + } + JS_ReportError(cx, "wrong number of arguments: %d, was expecting %d", argc, 0); + return JS_TRUE; +} + +JSBool js_cocos2dx_extension_WebSocket_close(JSContext *cx, uint32_t argc, jsval *vp){ + JSObject *obj = JS_THIS_OBJECT(cx, vp); + js_proxy_t *proxy; JS_GET_NATIVE_PROXY(proxy, obj); + WebSocket* cobj = (WebSocket *)(proxy ? proxy->ptr : NULL); + JSB_PRECONDITION2( cobj, cx, JS_FALSE, "Invalid Native Object"); + + if(argc == 0){ + cobj->close(); + JS_SET_RVAL(cx, vp, JSVAL_VOID); + return JS_TRUE; + } + JS_ReportError(cx, "wrong number of arguments: %d, was expecting %d", argc, 0); + return JS_FALSE; +} + +JSBool js_cocos2dx_extension_WebSocket_constructor(JSContext *cx, uint32_t argc, jsval *vp) +{ + jsval *argv = JS_ARGV(cx, vp); + + if (argc == 1 || argc == 2) + { + + std::string url; + + do { + JSBool ok = jsval_to_std_string(cx, argv[0], &url); + JSB_PRECONDITION2( ok, cx, JS_FALSE, "Error processing arguments"); + } while (0); + + JSObject *obj = JS_NewObject(cx, js_cocos2dx_websocket_class, js_cocos2dx_websocket_prototype, NULL); + + + cocos2d::extension::WebSocket* cobj = new cocos2d::extension::WebSocket(); + JSB_WebSocketDelegate* delegate = new JSB_WebSocketDelegate(); + delegate->setJSDelegate(obj); + + if (argc == 2) + { + std::vector protocols; + + if (JSVAL_IS_STRING(argv[1])) + { + std::string protocol; + do { + JSBool ok = jsval_to_std_string(cx, argv[1], &protocol); + JSB_PRECONDITION2( ok, cx, JS_FALSE, "Error processing arguments"); + } while (0); + protocols.push_back(protocol); + } + else if (argv[1].isObject()) + { + JSBool ok = JS_TRUE; + JSObject* arg2 = JSVAL_TO_OBJECT(argv[1]); + JSB_PRECONDITION(JS_IsArrayObject( cx, arg2 ), "Object must be an array"); + + uint32_t len = 0; + JS_GetArrayLength(cx, arg2, &len); + + for( uint32_t i=0; i< len;i++ ) + { + jsval valarg; + JS_GetElement(cx, arg2, i, &valarg); + std::string protocol; + do { + ok = jsval_to_std_string(cx, valarg, &protocol); + JSB_PRECONDITION2( ok, cx, JS_FALSE, "Error processing arguments"); + } while (0); + + protocols.push_back(protocol); + } + } + cobj->init(*delegate, url, &protocols); + } + else + { + cobj->init(*delegate, url); + } + + + JS_DefineProperty(cx, obj, "URL", argv[0] + , NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY); + + //protocol not support yet (always return "") + JS_DefineProperty(cx, obj, "protocol", c_string_to_jsval(cx, "") + , NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY); + + // link the native object with the javascript object + js_proxy_t *p; + JS_NEW_PROXY(p, cobj, obj); + JS_AddNamedObjectRoot(cx, &p->obj, "WebSocket"); + + JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj)); + return JS_TRUE; + } + + JS_ReportError(cx, "wrong number of arguments: %d, was expecting %d", argc, 0); + return JS_FALSE; +} + +static JSBool js_cocos2dx_extension_WebSocket_get_readyState(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHandleValue vp) +{ + JSObject* jsobj = obj.get(); + js_proxy_t *proxy; JS_GET_NATIVE_PROXY(proxy, jsobj); + WebSocket* cobj = (WebSocket *)(proxy ? proxy->ptr : NULL); + JSB_PRECONDITION2( cobj, cx, JS_FALSE, "Invalid Native Object"); + + if (cobj) { + vp.set(INT_TO_JSVAL((int)cobj->getReadyState())); + return JS_TRUE; + } else { + JS_ReportError(cx, "Error: WebSocket instance is invalid."); + return JS_FALSE; + } +} + +void register_jsb_websocket(JSContext *cx, JSObject *global) { + + js_cocos2dx_websocket_class = (JSClass *)calloc(1, sizeof(JSClass)); + js_cocos2dx_websocket_class->name = "WebSocket"; + js_cocos2dx_websocket_class->addProperty = JS_PropertyStub; + js_cocos2dx_websocket_class->delProperty = JS_PropertyStub; + js_cocos2dx_websocket_class->getProperty = JS_PropertyStub; + js_cocos2dx_websocket_class->setProperty = JS_StrictPropertyStub; + js_cocos2dx_websocket_class->enumerate = JS_EnumerateStub; + js_cocos2dx_websocket_class->resolve = JS_ResolveStub; + js_cocos2dx_websocket_class->convert = JS_ConvertStub; + js_cocos2dx_websocket_class->finalize = js_cocos2dx_WebSocket_finalize; + js_cocos2dx_websocket_class->flags = JSCLASS_HAS_RESERVED_SLOTS(2); + + static JSPropertySpec properties[] = { + {"readyState", 0, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, JSOP_WRAPPER(js_cocos2dx_extension_WebSocket_get_readyState), NULL}, + {0, 0, 0, 0, 0} + }; + + static JSFunctionSpec funcs[] = { + JS_FN("send",js_cocos2dx_extension_WebSocket_send, 1, JSPROP_PERMANENT | JSPROP_ENUMERATE), + JS_FN("close",js_cocos2dx_extension_WebSocket_close, 0, JSPROP_PERMANENT | JSPROP_ENUMERATE), + JS_FS_END + }; + + static JSFunctionSpec st_funcs[] = { + JS_FS_END + }; + + js_cocos2dx_websocket_prototype = JS_InitClass( + cx, global, + NULL, + js_cocos2dx_websocket_class, + js_cocos2dx_extension_WebSocket_constructor, 0, // constructor + properties, + funcs, + NULL, // no static properties + st_funcs); + + JSObject* jsclassObj = JSVAL_TO_OBJECT(anonEvaluate(cx, global, "(function () { return WebSocket; })()")); + + JS_DefineProperty(cx, jsclassObj, "CONNECTING", INT_TO_JSVAL((int)WebSocket::WS_STATE_CONNECTING) + , NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY); + JS_DefineProperty(cx, jsclassObj, "OPEN", INT_TO_JSVAL((int)WebSocket::WS_STATE_OPEN) + , NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY); + JS_DefineProperty(cx, jsclassObj, "CLOSING", INT_TO_JSVAL((int)WebSocket::WS_STATE_CLOSING) + , NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY); + JS_DefineProperty(cx, jsclassObj, "CLOSED", INT_TO_JSVAL((int)WebSocket::WS_STATE_CLOSED) + , NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY); + + // make the class enumerable in the registered namespace + JSBool found; + JS_SetPropertyAttributes(cx, global, "WebSocket", JSPROP_ENUMERATE | JSPROP_READONLY, &found); +} + + diff --git a/scripting/javascript/bindings/jsb_websocket.h b/scripting/javascript/bindings/jsb_websocket.h new file mode 100644 index 0000000000..cde0f40b2e --- /dev/null +++ b/scripting/javascript/bindings/jsb_websocket.h @@ -0,0 +1,34 @@ +/**************************************************************************** +Copyright (c) 2013 cocos2d-x.org +Copyright (c) 2013 James Chen + +http://www.cocos2d-x.org + +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 __jsb_websocket__ +#define __jsb_websocket__ + +#include "jsapi.h" +#include "jsfriendapi.h" + +void register_jsb_websocket(JSContext* cx, JSObject* global); + +#endif /* defined(__jsb_websocket__) */ From ad053632658bff8aa289f66e0d36d1fe32790856 Mon Sep 17 00:00:00 2001 From: James Chen Date: Fri, 31 May 2013 23:27:59 +0800 Subject: [PATCH 3/8] fixed #1647: Updating JS-test. --- samples/Javascript/Shared | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/Javascript/Shared b/samples/Javascript/Shared index 91d853f5c7..3e05297014 160000 --- a/samples/Javascript/Shared +++ b/samples/Javascript/Shared @@ -1 +1 @@ -Subproject commit 91d853f5c72df3137e2f3eb68229b426a3252e5d +Subproject commit 3e05297014a89a01218e15ad18d5ebdf75b0b7b4 From d5f45466a9b81de0c4c87e649910c4b055f98bbe Mon Sep 17 00:00:00 2001 From: James Chen Date: Sat, 1 Jun 2013 07:58:23 +0800 Subject: [PATCH 4/8] issue # 1647: Fix include, 'Websocket.h' -> 'WebSocket.h' since linux is case sensitive. --- scripting/javascript/bindings/jsb_websocket.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripting/javascript/bindings/jsb_websocket.cpp b/scripting/javascript/bindings/jsb_websocket.cpp index e346bba5cb..5768be58eb 100644 --- a/scripting/javascript/bindings/jsb_websocket.cpp +++ b/scripting/javascript/bindings/jsb_websocket.cpp @@ -25,7 +25,7 @@ THE SOFTWARE. #include "jsb_websocket.h" #include "cocos2d.h" -#include "Websocket.h" +#include "WebSocket.h" #include "spidermonkey_specifics.h" #include "ScriptingCore.h" #include "cocos2d_specifics.hpp" From 8e15cdf5fd5b5b2d17fca3bdf958d4103beea4c1 Mon Sep 17 00:00:00 2001 From: James Chen Date: Sat, 1 Jun 2013 19:51:10 +0800 Subject: [PATCH 5/8] WS_ERROR -> ERROR, WS_STATE -> STATE. --- extensions/network/WebSocket.cpp | 34 +++++++++---------- extensions/network/WebSocket.h | 24 ++++++------- .../NetworkTest/WebSocketTest.cpp | 6 ++-- .../NetworkTest/WebSocketTest.h | 2 +- .../javascript/bindings/jsb_websocket.cpp | 10 +++--- 5 files changed, 38 insertions(+), 38 deletions(-) diff --git a/extensions/network/WebSocket.cpp b/extensions/network/WebSocket.cpp index 844fd9ed99..a2a2516620 100644 --- a/extensions/network/WebSocket.cpp +++ b/extensions/network/WebSocket.cpp @@ -225,7 +225,7 @@ enum WS_MSG { }; WebSocket::WebSocket() -: _readyState(WS_STATE_CONNECTING) +: _readyState(STATE_CONNECTING) , _port(80) , _wsHelper(NULL) , _wsInstance(NULL) @@ -335,7 +335,7 @@ bool WebSocket::init(const Delegate& delegate, void WebSocket::send(const std::string& message) { - if (_readyState == WS_STATE_OPEN) + if (_readyState == STATE_OPEN) { // In main thread WsMessage* msg = new WsMessage(); @@ -353,7 +353,7 @@ void WebSocket::send(const unsigned char* binaryMsg, unsigned int len) { CCAssert(binaryMsg != NULL && len > 0, "parameter invalid."); - if (_readyState == WS_STATE_OPEN) + if (_readyState == STATE_OPEN) { // In main thread WsMessage* msg = new WsMessage(); @@ -371,11 +371,11 @@ void WebSocket::close() { CCDirector::sharedDirector()->getScheduler()->unscheduleAllForTarget(_wsHelper); - if (_readyState == WS_STATE_CLOSING || _readyState == WS_STATE_CLOSED) + if (_readyState == STATE_CLOSING || _readyState == STATE_CLOSED) return; CCLOG("websocket (%p) connection closed by client", this); - _readyState = WS_STATE_CLOSED; + _readyState = STATE_CLOSED; WsMessage* msg = new WsMessage(); msg->what = WS_MSG_TO_SUBTRHEAD_CLOSING; @@ -388,21 +388,21 @@ void WebSocket::close() _delegate->onClose(this); } -WebSocket::WS_STATE WebSocket::getReadyState() +WebSocket::STATE WebSocket::getReadyState() { return _readyState; } int WebSocket::onSubThreadLoop() { - if (_readyState == WS_STATE_CLOSED || _readyState == WS_STATE_CLOSING) + if (_readyState == STATE_CLOSED || _readyState == STATE_CLOSING) { libwebsocket_context_destroy(_wsContext); // return 1 to exit the loop. return 1; } - if (_wsContext && _readyState != WS_STATE_CLOSED && _readyState != WS_STATE_CLOSING) + if (_wsContext && _readyState != STATE_CLOSED && _readyState != STATE_CLOSING) { libwebsocket_service(_wsContext, 0); } @@ -442,7 +442,7 @@ void WebSocket::onSubThreadStarted() _wsContext = libwebsocket_create_context(&info); if(NULL != _wsContext){ - _readyState = WS_STATE_CONNECTING; + _readyState = STATE_CONNECTING; std::string name; for (int i = 0; _wsProtocols[i].callback != NULL; ++i) { name += (_wsProtocols[i].name); @@ -480,14 +480,14 @@ int WebSocket::onSocketCallback(struct libwebsocket_context *ctx, { WsMessage* msg = new WsMessage(); if (reason == LWS_CALLBACK_CLIENT_CONNECTION_ERROR - || (reason == LWS_CALLBACK_PROTOCOL_DESTROY && _readyState == WS_STATE_CONNECTING) - || (reason == LWS_CALLBACK_DEL_POLL_FD && _readyState == WS_STATE_CONNECTING) + || (reason == LWS_CALLBACK_PROTOCOL_DESTROY && _readyState == STATE_CONNECTING) + || (reason == LWS_CALLBACK_DEL_POLL_FD && _readyState == STATE_CONNECTING) ) { msg->what = WS_MSG_TO_UITHREAD_ERROR; - _readyState = WS_STATE_CLOSING; + _readyState = STATE_CLOSING; } - else if (reason == LWS_CALLBACK_PROTOCOL_DESTROY && _readyState == WS_STATE_CLOSING) + else if (reason == LWS_CALLBACK_PROTOCOL_DESTROY && _readyState == STATE_CLOSING) { msg->what = WS_MSG_TO_UITHREAD_CLOSE; } @@ -498,7 +498,7 @@ int WebSocket::onSocketCallback(struct libwebsocket_context *ctx, { WsMessage* msg = new WsMessage(); msg->what = WS_MSG_TO_UITHREAD_OPEN; - _readyState = WS_STATE_OPEN; + _readyState = STATE_OPEN; /* * start the ball rolling, * LWS_CALLBACK_CLIENT_WRITEABLE will come next service @@ -572,10 +572,10 @@ int WebSocket::onSocketCallback(struct libwebsocket_context *ctx, _wsHelper->quitSubThread(); - if (_readyState != WS_STATE_CLOSED) + if (_readyState != STATE_CLOSED) { WsMessage* msg = new WsMessage(); - _readyState = WS_STATE_CLOSED; + _readyState = STATE_CLOSED; msg->what = WS_MSG_TO_UITHREAD_CLOSE; _wsHelper->sendMessageToUIThread(msg); } @@ -646,7 +646,7 @@ void WebSocket::onUIThreadReceiveMessage(WsMessage* msg) break; case WS_MSG_TO_UITHREAD_ERROR: { - WebSocket::WS_ERROR err = WS_ERROR_CONNECTION_FAILS; + WebSocket::ERROR err = ERROR_CONNECTION_FAILS; _delegate->onError(this, err); } break; diff --git a/extensions/network/WebSocket.h b/extensions/network/WebSocket.h index 021e4e4395..f7698fff60 100644 --- a/extensions/network/WebSocket.h +++ b/extensions/network/WebSocket.h @@ -57,11 +57,11 @@ public: /** * @brief Errors in websocket */ - enum WS_ERROR + enum ERROR { - WS_ERROR_TIMEOUT=0, - WS_ERROR_CONNECTION_FAILS, - WS_ERROR_UNKNOWN + ERROR_TIMEOUT = 0, + ERROR_CONNECTION_FAILS, + ERROR_UNKNOWN }; /** @@ -74,7 +74,7 @@ public: virtual void onOpen(WebSocket* ws) = 0; virtual void onMessage(WebSocket* ws, const Data& data) = 0; virtual void onClose(WebSocket* ws) = 0; - virtual void onError(WebSocket* ws, const WS_ERROR& error) = 0; + virtual void onError(WebSocket* ws, const ERROR& error) = 0; }; @@ -107,18 +107,18 @@ public: /** * Websocket state */ - enum WS_STATE + enum STATE { - WS_STATE_CONNECTING = 0, - WS_STATE_OPEN, - WS_STATE_CLOSING, - WS_STATE_CLOSED + STATE_CONNECTING = 0, + STATE_OPEN, + STATE_CLOSING, + STATE_CLOSED }; /** * @brief Gets current state of connection. */ - WS_STATE getReadyState(); + STATE getReadyState(); private: virtual void onSubThreadStarted(); @@ -134,7 +134,7 @@ private: void *user, void *in, size_t len); private: - WS_STATE _readyState; + STATE _readyState; std::string _host; unsigned int _port; std::string _path; diff --git a/samples/Cpp/TestCpp/Classes/ExtensionsTest/NetworkTest/WebSocketTest.cpp b/samples/Cpp/TestCpp/Classes/ExtensionsTest/NetworkTest/WebSocketTest.cpp index a06681e71a..e80a0a8dae 100644 --- a/samples/Cpp/TestCpp/Classes/ExtensionsTest/NetworkTest/WebSocketTest.cpp +++ b/samples/Cpp/TestCpp/Classes/ExtensionsTest/NetworkTest/WebSocketTest.cpp @@ -180,7 +180,7 @@ void WebSocketTestLayer::onClose(cocos2d::extension::WebSocket* ws) CC_SAFE_DELETE(ws); } -void WebSocketTestLayer::onError(cocos2d::extension::WebSocket* ws, const cocos2d::extension::WebSocket::WS_ERROR& error) +void WebSocketTestLayer::onError(cocos2d::extension::WebSocket* ws, const cocos2d::extension::WebSocket::ERROR& error) { CCLog("Error was fired, error code: %d", error); if (ws == _wsiError) @@ -201,7 +201,7 @@ void WebSocketTestLayer::toExtensionsMainLayer(cocos2d::CCObject *sender) // Menu Callbacks void WebSocketTestLayer::onMenuSendTextClicked(cocos2d::CCObject *sender) { - if (_wsiSendText->getReadyState() == WebSocket::WS_STATE_OPEN) + if (_wsiSendText->getReadyState() == WebSocket::STATE_OPEN) { _sendTextStatus->setString("Send Text WS is waiting..."); _wsiSendText->send("Hello WebSocket, I'm a text message."); @@ -216,7 +216,7 @@ void WebSocketTestLayer::onMenuSendTextClicked(cocos2d::CCObject *sender) void WebSocketTestLayer::onMenuSendBinaryClicked(cocos2d::CCObject *sender) { - if (_wsiSendBinary->getReadyState() == WebSocket::WS_STATE_OPEN) + if (_wsiSendBinary->getReadyState() == WebSocket::STATE_OPEN) { _sendBinaryStatus->setString("Send Binary WS is waiting..."); char buf[] = "Hello WebSocket,\0 I'm\0 a\0 binary\0 message\0."; diff --git a/samples/Cpp/TestCpp/Classes/ExtensionsTest/NetworkTest/WebSocketTest.h b/samples/Cpp/TestCpp/Classes/ExtensionsTest/NetworkTest/WebSocketTest.h index 1070ce750a..dd4d1991cd 100644 --- a/samples/Cpp/TestCpp/Classes/ExtensionsTest/NetworkTest/WebSocketTest.h +++ b/samples/Cpp/TestCpp/Classes/ExtensionsTest/NetworkTest/WebSocketTest.h @@ -24,7 +24,7 @@ public: virtual void onOpen(cocos2d::extension::WebSocket* ws); virtual void onMessage(cocos2d::extension::WebSocket* ws, const cocos2d::extension::WebSocket::Data& data); virtual void onClose(cocos2d::extension::WebSocket* ws); - virtual void onError(cocos2d::extension::WebSocket* ws, const cocos2d::extension::WebSocket::WS_ERROR& error); + virtual void onError(cocos2d::extension::WebSocket* ws, const cocos2d::extension::WebSocket::ERROR& error); void toExtensionsMainLayer(cocos2d::CCObject *sender); diff --git a/scripting/javascript/bindings/jsb_websocket.cpp b/scripting/javascript/bindings/jsb_websocket.cpp index 5768be58eb..eea1ad41ff 100644 --- a/scripting/javascript/bindings/jsb_websocket.cpp +++ b/scripting/javascript/bindings/jsb_websocket.cpp @@ -129,7 +129,7 @@ public: CC_SAFE_DELETE(ws); } - virtual void onError(WebSocket* ws, const WebSocket::WS_ERROR& error) + virtual void onError(WebSocket* ws, const WebSocket::ERROR& error) { js_proxy_t * p; JS_GET_PROXY(p, ws); @@ -371,13 +371,13 @@ void register_jsb_websocket(JSContext *cx, JSObject *global) { JSObject* jsclassObj = JSVAL_TO_OBJECT(anonEvaluate(cx, global, "(function () { return WebSocket; })()")); - JS_DefineProperty(cx, jsclassObj, "CONNECTING", INT_TO_JSVAL((int)WebSocket::WS_STATE_CONNECTING) + JS_DefineProperty(cx, jsclassObj, "CONNECTING", INT_TO_JSVAL((int)WebSocket::STATE_CONNECTING) , NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY); - JS_DefineProperty(cx, jsclassObj, "OPEN", INT_TO_JSVAL((int)WebSocket::WS_STATE_OPEN) + JS_DefineProperty(cx, jsclassObj, "OPEN", INT_TO_JSVAL((int)WebSocket::STATE_OPEN) , NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY); - JS_DefineProperty(cx, jsclassObj, "CLOSING", INT_TO_JSVAL((int)WebSocket::WS_STATE_CLOSING) + JS_DefineProperty(cx, jsclassObj, "CLOSING", INT_TO_JSVAL((int)WebSocket::STATE_CLOSING) , NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY); - JS_DefineProperty(cx, jsclassObj, "CLOSED", INT_TO_JSVAL((int)WebSocket::WS_STATE_CLOSED) + JS_DefineProperty(cx, jsclassObj, "CLOSED", INT_TO_JSVAL((int)WebSocket::STATE_CLOSED) , NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY); // make the class enumerable in the registered namespace From 62f4e40e4aa977631d468937c7fc6e012a7b9d87 Mon Sep 17 00:00:00 2001 From: James Chen Date: Sat, 1 Jun 2013 19:51:59 +0800 Subject: [PATCH 6/8] Updating JS-Test. --- samples/Javascript/Shared | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/Javascript/Shared b/samples/Javascript/Shared index 3e05297014..568f0addf9 160000 --- a/samples/Javascript/Shared +++ b/samples/Javascript/Shared @@ -1 +1 @@ -Subproject commit 3e05297014a89a01218e15ad18d5ebdf75b0b7b4 +Subproject commit 568f0addf94b132938892a33eb83dc5e7149110b From 0ca86db0ffc23a41dcb21bd4ee49a53bb7bfd01b Mon Sep 17 00:00:00 2001 From: James Chen Date: Mon, 3 Jun 2013 09:55:43 +0800 Subject: [PATCH 7/8] fixed #1647: Renaming enumerations to Cocos2d-x style. ERROR and ERROR_TIMEOUT is defined as macros on Windows, fuck it. --- extensions/network/WebSocket.cpp | 35 ++++++++++--------- extensions/network/WebSocket.h | 26 +++++++------- .../NetworkTest/WebSocketTest.cpp | 6 ++-- .../NetworkTest/WebSocketTest.h | 2 +- .../javascript/bindings/jsb_websocket.cpp | 10 +++--- 5 files changed, 40 insertions(+), 39 deletions(-) diff --git a/extensions/network/WebSocket.cpp b/extensions/network/WebSocket.cpp index a2a2516620..93ecea4157 100644 --- a/extensions/network/WebSocket.cpp +++ b/extensions/network/WebSocket.cpp @@ -225,7 +225,7 @@ enum WS_MSG { }; WebSocket::WebSocket() -: _readyState(STATE_CONNECTING) +: _readyState(kStateConnecting) , _port(80) , _wsHelper(NULL) , _wsInstance(NULL) @@ -335,7 +335,7 @@ bool WebSocket::init(const Delegate& delegate, void WebSocket::send(const std::string& message) { - if (_readyState == STATE_OPEN) + if (_readyState == kStateOpen) { // In main thread WsMessage* msg = new WsMessage(); @@ -353,7 +353,7 @@ void WebSocket::send(const unsigned char* binaryMsg, unsigned int len) { CCAssert(binaryMsg != NULL && len > 0, "parameter invalid."); - if (_readyState == STATE_OPEN) + if (_readyState == kStateOpen) { // In main thread WsMessage* msg = new WsMessage(); @@ -371,11 +371,11 @@ void WebSocket::close() { CCDirector::sharedDirector()->getScheduler()->unscheduleAllForTarget(_wsHelper); - if (_readyState == STATE_CLOSING || _readyState == STATE_CLOSED) + if (_readyState == kStateClosing || _readyState == kStateClosed) return; CCLOG("websocket (%p) connection closed by client", this); - _readyState = STATE_CLOSED; + _readyState = kStateClosed; WsMessage* msg = new WsMessage(); msg->what = WS_MSG_TO_SUBTRHEAD_CLOSING; @@ -388,21 +388,21 @@ void WebSocket::close() _delegate->onClose(this); } -WebSocket::STATE WebSocket::getReadyState() +WebSocket::State WebSocket::getReadyState() { return _readyState; } int WebSocket::onSubThreadLoop() { - if (_readyState == STATE_CLOSED || _readyState == STATE_CLOSING) + if (_readyState == kStateClosed || _readyState == kStateClosing) { libwebsocket_context_destroy(_wsContext); // return 1 to exit the loop. return 1; } - if (_wsContext && _readyState != STATE_CLOSED && _readyState != STATE_CLOSING) + if (_wsContext && _readyState != kStateClosed && _readyState != kStateClosing) { libwebsocket_service(_wsContext, 0); } @@ -442,7 +442,7 @@ void WebSocket::onSubThreadStarted() _wsContext = libwebsocket_create_context(&info); if(NULL != _wsContext){ - _readyState = STATE_CONNECTING; + _readyState = kStateConnecting; std::string name; for (int i = 0; _wsProtocols[i].callback != NULL; ++i) { name += (_wsProtocols[i].name); @@ -480,14 +480,14 @@ int WebSocket::onSocketCallback(struct libwebsocket_context *ctx, { WsMessage* msg = new WsMessage(); if (reason == LWS_CALLBACK_CLIENT_CONNECTION_ERROR - || (reason == LWS_CALLBACK_PROTOCOL_DESTROY && _readyState == STATE_CONNECTING) - || (reason == LWS_CALLBACK_DEL_POLL_FD && _readyState == STATE_CONNECTING) + || (reason == LWS_CALLBACK_PROTOCOL_DESTROY && _readyState == kStateConnecting) + || (reason == LWS_CALLBACK_DEL_POLL_FD && _readyState == kStateConnecting) ) { msg->what = WS_MSG_TO_UITHREAD_ERROR; - _readyState = STATE_CLOSING; + _readyState = kStateClosing; } - else if (reason == LWS_CALLBACK_PROTOCOL_DESTROY && _readyState == STATE_CLOSING) + else if (reason == LWS_CALLBACK_PROTOCOL_DESTROY && _readyState == kStateClosing) { msg->what = WS_MSG_TO_UITHREAD_CLOSE; } @@ -498,7 +498,7 @@ int WebSocket::onSocketCallback(struct libwebsocket_context *ctx, { WsMessage* msg = new WsMessage(); msg->what = WS_MSG_TO_UITHREAD_OPEN; - _readyState = STATE_OPEN; + _readyState = kStateOpen; /* * start the ball rolling, * LWS_CALLBACK_CLIENT_WRITEABLE will come next service @@ -572,10 +572,10 @@ int WebSocket::onSocketCallback(struct libwebsocket_context *ctx, _wsHelper->quitSubThread(); - if (_readyState != STATE_CLOSED) + if (_readyState != kStateClosed) { WsMessage* msg = new WsMessage(); - _readyState = STATE_CLOSED; + _readyState = kStateClosed; msg->what = WS_MSG_TO_UITHREAD_CLOSE; _wsHelper->sendMessageToUIThread(msg); } @@ -646,7 +646,8 @@ void WebSocket::onUIThreadReceiveMessage(WsMessage* msg) break; case WS_MSG_TO_UITHREAD_ERROR: { - WebSocket::ERROR err = ERROR_CONNECTION_FAILS; + // FIXME: The exact error needs to be checked. + WebSocket::ErrorCode err = kErrorConnectionFailure; _delegate->onError(this, err); } break; diff --git a/extensions/network/WebSocket.h b/extensions/network/WebSocket.h index f7698fff60..068f341d60 100644 --- a/extensions/network/WebSocket.h +++ b/extensions/network/WebSocket.h @@ -57,11 +57,11 @@ public: /** * @brief Errors in websocket */ - enum ERROR + enum ErrorCode { - ERROR_TIMEOUT = 0, - ERROR_CONNECTION_FAILS, - ERROR_UNKNOWN + kErrorTimeout = 0, + kErrorConnectionFailure, + kErrorUnknown }; /** @@ -74,7 +74,7 @@ public: virtual void onOpen(WebSocket* ws) = 0; virtual void onMessage(WebSocket* ws, const Data& data) = 0; virtual void onClose(WebSocket* ws) = 0; - virtual void onError(WebSocket* ws, const ERROR& error) = 0; + virtual void onError(WebSocket* ws, const ErrorCode& error) = 0; }; @@ -107,18 +107,18 @@ public: /** * Websocket state */ - enum STATE + enum State { - STATE_CONNECTING = 0, - STATE_OPEN, - STATE_CLOSING, - STATE_CLOSED + kStateConnecting = 0, + kStateOpen, + kStateClosing, + kStateClosed }; /** * @brief Gets current state of connection. */ - STATE getReadyState(); + State getReadyState(); private: virtual void onSubThreadStarted(); @@ -134,7 +134,7 @@ private: void *user, void *in, size_t len); private: - STATE _readyState; + State _readyState; std::string _host; unsigned int _port; std::string _path; @@ -142,7 +142,7 @@ private: friend class WsThreadHelper; WsThreadHelper* _wsHelper; - struct libwebsocket* _wsInstance; + struct libwebsocket* _wsInstance; struct libwebsocket_context* _wsContext; Delegate* _delegate; int _SSLConnection; diff --git a/samples/Cpp/TestCpp/Classes/ExtensionsTest/NetworkTest/WebSocketTest.cpp b/samples/Cpp/TestCpp/Classes/ExtensionsTest/NetworkTest/WebSocketTest.cpp index e80a0a8dae..c568c521aa 100644 --- a/samples/Cpp/TestCpp/Classes/ExtensionsTest/NetworkTest/WebSocketTest.cpp +++ b/samples/Cpp/TestCpp/Classes/ExtensionsTest/NetworkTest/WebSocketTest.cpp @@ -180,7 +180,7 @@ void WebSocketTestLayer::onClose(cocos2d::extension::WebSocket* ws) CC_SAFE_DELETE(ws); } -void WebSocketTestLayer::onError(cocos2d::extension::WebSocket* ws, const cocos2d::extension::WebSocket::ERROR& error) +void WebSocketTestLayer::onError(cocos2d::extension::WebSocket* ws, const cocos2d::extension::WebSocket::ErrorCode& error) { CCLog("Error was fired, error code: %d", error); if (ws == _wsiError) @@ -201,7 +201,7 @@ void WebSocketTestLayer::toExtensionsMainLayer(cocos2d::CCObject *sender) // Menu Callbacks void WebSocketTestLayer::onMenuSendTextClicked(cocos2d::CCObject *sender) { - if (_wsiSendText->getReadyState() == WebSocket::STATE_OPEN) + if (_wsiSendText->getReadyState() == WebSocket::kStateOpen) { _sendTextStatus->setString("Send Text WS is waiting..."); _wsiSendText->send("Hello WebSocket, I'm a text message."); @@ -216,7 +216,7 @@ void WebSocketTestLayer::onMenuSendTextClicked(cocos2d::CCObject *sender) void WebSocketTestLayer::onMenuSendBinaryClicked(cocos2d::CCObject *sender) { - if (_wsiSendBinary->getReadyState() == WebSocket::STATE_OPEN) + if (_wsiSendBinary->getReadyState() == WebSocket::kStateOpen) { _sendBinaryStatus->setString("Send Binary WS is waiting..."); char buf[] = "Hello WebSocket,\0 I'm\0 a\0 binary\0 message\0."; diff --git a/samples/Cpp/TestCpp/Classes/ExtensionsTest/NetworkTest/WebSocketTest.h b/samples/Cpp/TestCpp/Classes/ExtensionsTest/NetworkTest/WebSocketTest.h index dd4d1991cd..087c0bedaa 100644 --- a/samples/Cpp/TestCpp/Classes/ExtensionsTest/NetworkTest/WebSocketTest.h +++ b/samples/Cpp/TestCpp/Classes/ExtensionsTest/NetworkTest/WebSocketTest.h @@ -24,7 +24,7 @@ public: virtual void onOpen(cocos2d::extension::WebSocket* ws); virtual void onMessage(cocos2d::extension::WebSocket* ws, const cocos2d::extension::WebSocket::Data& data); virtual void onClose(cocos2d::extension::WebSocket* ws); - virtual void onError(cocos2d::extension::WebSocket* ws, const cocos2d::extension::WebSocket::ERROR& error); + virtual void onError(cocos2d::extension::WebSocket* ws, const cocos2d::extension::WebSocket::ErrorCode& error); void toExtensionsMainLayer(cocos2d::CCObject *sender); diff --git a/scripting/javascript/bindings/jsb_websocket.cpp b/scripting/javascript/bindings/jsb_websocket.cpp index eea1ad41ff..12c97b5e57 100644 --- a/scripting/javascript/bindings/jsb_websocket.cpp +++ b/scripting/javascript/bindings/jsb_websocket.cpp @@ -129,7 +129,7 @@ public: CC_SAFE_DELETE(ws); } - virtual void onError(WebSocket* ws, const WebSocket::ERROR& error) + virtual void onError(WebSocket* ws, const WebSocket::ErrorCode& error) { js_proxy_t * p; JS_GET_PROXY(p, ws); @@ -371,13 +371,13 @@ void register_jsb_websocket(JSContext *cx, JSObject *global) { JSObject* jsclassObj = JSVAL_TO_OBJECT(anonEvaluate(cx, global, "(function () { return WebSocket; })()")); - JS_DefineProperty(cx, jsclassObj, "CONNECTING", INT_TO_JSVAL((int)WebSocket::STATE_CONNECTING) + JS_DefineProperty(cx, jsclassObj, "CONNECTING", INT_TO_JSVAL((int)WebSocket::kStateConnecting) , NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY); - JS_DefineProperty(cx, jsclassObj, "OPEN", INT_TO_JSVAL((int)WebSocket::STATE_OPEN) + JS_DefineProperty(cx, jsclassObj, "OPEN", INT_TO_JSVAL((int)WebSocket::kStateOpen) , NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY); - JS_DefineProperty(cx, jsclassObj, "CLOSING", INT_TO_JSVAL((int)WebSocket::STATE_CLOSING) + JS_DefineProperty(cx, jsclassObj, "CLOSING", INT_TO_JSVAL((int)WebSocket::kStateClosing) , NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY); - JS_DefineProperty(cx, jsclassObj, "CLOSED", INT_TO_JSVAL((int)WebSocket::STATE_CLOSED) + JS_DefineProperty(cx, jsclassObj, "CLOSED", INT_TO_JSVAL((int)WebSocket::kStateClosed) , NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY); // make the class enumerable in the registered namespace From 2fdeab46b1520110b6e5fad0997ac6f9d5f38c34 Mon Sep 17 00:00:00 2001 From: James Chen Date: Mon, 3 Jun 2013 10:03:38 +0800 Subject: [PATCH 8/8] fixed #1647: [WebSocket] Fixing compilation errors on win32. --- samples/Cpp/TestCpp/proj.win32/TestCpp.vcxproj | 10 ++++++++++ .../TestJavascript/proj.win32/TestJavascript.vcxproj | 6 ++++-- .../bindings/proj.win32/libJSBinding.vcxproj | 2 +- .../bindings/proj.win32/libJSBinding.vcxproj.filters | 4 ++-- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/samples/Cpp/TestCpp/proj.win32/TestCpp.vcxproj b/samples/Cpp/TestCpp/proj.win32/TestCpp.vcxproj index e080de91cb..3a4146d74a 100644 --- a/samples/Cpp/TestCpp/proj.win32/TestCpp.vcxproj +++ b/samples/Cpp/TestCpp/proj.win32/TestCpp.vcxproj @@ -88,6 +88,11 @@ + + if not exist "$(OutDir)" mkdir "$(OutDir)" +xcopy /Y /Q "$(ProjectDir)..\..\..\..\external\libwebsockets\win32\lib\*.*" "$(OutDir)" + + @@ -117,6 +122,11 @@ + + if not exist "$(OutDir)" mkdir "$(OutDir)" +xcopy /Y /Q "$(ProjectDir)..\..\..\..\external\libwebsockets\win32\lib\*.*" "$(OutDir)" + + diff --git a/samples/Javascript/TestJavascript/proj.win32/TestJavascript.vcxproj b/samples/Javascript/TestJavascript/proj.win32/TestJavascript.vcxproj index 2a9a2f02ab..2aa3f0ac5c 100644 --- a/samples/Javascript/TestJavascript/proj.win32/TestJavascript.vcxproj +++ b/samples/Javascript/TestJavascript/proj.win32/TestJavascript.vcxproj @@ -94,10 +94,11 @@ if not exist "$(OutDir)" mkdir "$(OutDir)" xcopy /Y /Q "$(ProjectDir)..\..\..\..\scripting\javascript\spidermonkey-win32\lib\*.*" "$(OutDir)" +xcopy /Y /Q "$(ProjectDir)..\..\..\..\external\libwebsockets\win32\lib\*.*" "$(OutDir)" - libcocos2d.lib;libExtensions.lib;opengl32.lib;glew32.lib;libCocosDenshion.lib;libchipmunk.lib;libJSBinding.lib;libcurl_imp.lib;mozjs.lib;ws2_32.lib;sqlite3.lib;pthreadVCE2.lib;%(AdditionalDependencies) + libcocos2d.lib;libExtensions.lib;opengl32.lib;glew32.lib;libCocosDenshion.lib;libchipmunk.lib;libJSBinding.lib;libcurl_imp.lib;mozjs.lib;ws2_32.lib;sqlite3.lib;pthreadVCE2.lib;websockets.lib;%(AdditionalDependencies) $(OutDir);%(AdditionalLibraryDirectories) true Windows @@ -148,10 +149,11 @@ xcopy "$(ProjectDir)..\..\Shared\tests" "$(OutDir)\TestJavascriptRes\" /e /Y if not exist "$(OutDir)" mkdir "$(OutDir)" xcopy /Y /Q "$(ProjectDir)..\..\..\..\scripting\javascript\spidermonkey-win32\lib\*.*" "$(OutDir)" +xcopy /Y /Q "$(ProjectDir)..\..\..\..\external\libwebsockets\win32\lib\*.*" "$(OutDir)" - libcocos2d.lib;libExtensions.lib;opengl32.lib;glew32.lib;libCocosDenshion.lib;libchipmunk.lib;libJSBinding.lib;libcurl_imp.lib;mozjs.lib;ws2_32.lib;sqlite3.lib;pthreadVCE2.lib;%(AdditionalDependencies) + libcocos2d.lib;libExtensions.lib;opengl32.lib;glew32.lib;libCocosDenshion.lib;libchipmunk.lib;libJSBinding.lib;libcurl_imp.lib;mozjs.lib;ws2_32.lib;sqlite3.lib;pthreadVCE2.lib;websockets.lib;%(AdditionalDependencies) $(OutDir);%(AdditionalLibraryDirectories) Windows MachineX86 diff --git a/scripting/javascript/bindings/proj.win32/libJSBinding.vcxproj b/scripting/javascript/bindings/proj.win32/libJSBinding.vcxproj index 59164d2b19..9813d7722f 100644 --- a/scripting/javascript/bindings/proj.win32/libJSBinding.vcxproj +++ b/scripting/javascript/bindings/proj.win32/libJSBinding.vcxproj @@ -39,6 +39,7 @@ + @@ -59,7 +60,6 @@ - diff --git a/scripting/javascript/bindings/proj.win32/libJSBinding.vcxproj.filters b/scripting/javascript/bindings/proj.win32/libJSBinding.vcxproj.filters index f49e00a20f..28046317c8 100644 --- a/scripting/javascript/bindings/proj.win32/libJSBinding.vcxproj.filters +++ b/scripting/javascript/bindings/proj.win32/libJSBinding.vcxproj.filters @@ -154,10 +154,10 @@ manual - + manual - + manual