Webserver+3d print
Diff: cyclone_tcp/web_socket/web_socket.h
- Revision:
- 0:8918a71cdbe9
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cyclone_tcp/web_socket/web_socket.h Sat Feb 04 18:15:49 2017 +0000 @@ -0,0 +1,507 @@ +/** + * @file web_socket.h + * @brief WebSocket API (client and server) + * + * @section License + * + * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved. + * + * This file is part of CycloneTCP Open. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * @author Oryx Embedded SARL (www.oryx-embedded.com) + * @version 1.7.6 + **/ + +#ifndef _WEB_SOCKET_H +#define _WEB_SOCKET_H + +//Dependencies +#include "core/net.h" +#include "core/socket.h" + +//WebSocket support +#ifndef WEB_SOCKET_SUPPORT + #define WEB_SOCKET_SUPPORT DISABLED +#elif (WEB_SOCKET_SUPPORT != ENABLED && WEB_SOCKET_SUPPORT != DISABLED) + #error WEB_SOCKET_SUPPORT parameter is not valid +#endif + +//Number of WebSockets that can be opened simultaneously +#ifndef WEB_SOCKET_MAX_COUNT + #define WEB_SOCKET_MAX_COUNT 4 +#elif (WEB_SOCKET_MAX_COUNT < 1) + #error WEB_SOCKET_MAX_COUNT parameter is not valid +#endif + +//Support for WebSocket connections over SSL/TLS +#ifndef WEB_SOCKET_TLS_SUPPORT + #define WEB_SOCKET_TLS_SUPPORT DISABLED +#elif (WEB_SOCKET_TLS_SUPPORT != ENABLED && WEB_SOCKET_TLS_SUPPORT != DISABLED) + #error WEB_SOCKET_TLS_SUPPORT parameter is not valid +#endif + +//Basic access authentication support +#ifndef WEB_SOCKET_BASIC_AUTH_SUPPORT + #define WEB_SOCKET_BASIC_AUTH_SUPPORT DISABLED +#elif (WEB_SOCKET_BASIC_AUTH_SUPPORT != ENABLED && WEB_SOCKET_BASIC_AUTH_SUPPORT != DISABLED) + #error WEB_SOCKET_BASIC_AUTH_SUPPORT parameter is not valid +#endif + +//Digest access authentication support +#ifndef WEB_SOCKET_DIGEST_AUTH_SUPPORT + #define WEB_SOCKET_DIGEST_AUTH_SUPPORT DISABLED +#elif (WEB_SOCKET_DIGEST_AUTH_SUPPORT != ENABLED && WEB_SOCKET_DIGEST_AUTH_SUPPORT != DISABLED) + #error WEB_SOCKET_DIGEST_AUTH_SUPPORT parameter is not valid +#endif + +//Maximum number of connection attempts +#ifndef WEB_SOCKET_MAX_CONN_RETRIES + #define WEB_SOCKET_MAX_CONN_RETRIES 3 +#elif (WEB_SOCKET_MAX_CONN_RETRIES < 1) + #error WEB_SOCKET_MAX_CONN_RETRIES parameter is not valid +#endif + +//Size of the WebSocket buffer +#ifndef WEB_SOCKET_BUFFER_SIZE + #define WEB_SOCKET_BUFFER_SIZE 1024 +#elif (WEB_SOCKET_BUFFER_SIZE < 128) + #error WEB_SOCKET_BUFFER_SIZE parameter is not valid +#endif + +//Maximum length of the hostname +#ifndef WEB_SOCKET_HOST_MAX_LEN + #define WEB_SOCKET_HOST_MAX_LEN 32 +#elif (WEB_SOCKET_HOST_MAX_LEN < 1) + #error WEB_SOCKET_HOST_MAX_LEN parameter is not valid +#endif + +//Maximum length of the origin header field +#ifndef WEB_SOCKET_ORIGIN_MAX_LEN + #define WEB_SOCKET_ORIGIN_MAX_LEN 16 +#elif (WEB_SOCKET_ORIGIN_MAX_LEN < 1) + #error WEB_SOCKET_ORIGIN_MAX_LEN parameter is not valid +#endif + +//Maximum length of the sub-protocol +#ifndef WEB_SOCKET_SUB_PROTOCOL_MAX_LEN + #define WEB_SOCKET_SUB_PROTOCOL_MAX_LEN 8 +#elif (WEB_SOCKET_SUB_PROTOCOL_MAX_LEN < 1) + #error WEB_SOCKET_SUB_PROTOCOL_MAX_LEN parameter is not valid +#endif + +//Maximum length of the URI +#ifndef WEB_SOCKET_URI_MAX_LEN + #define WEB_SOCKET_URI_MAX_LEN 32 +#elif (WEB_SOCKET_URI_MAX_LEN < 1) + #error WEB_SOCKET_URI_MAX_LEN parameter is not valid +#endif + +//Maximum length of the query string +#ifndef WEB_SOCKET_QUERY_STRING_MAX_LEN + #define WEB_SOCKET_QUERY_STRING_MAX_LEN 32 +#elif (WEB_SOCKET_QUERY_STRING_MAX_LEN < 1) + #error WEB_SOCKET_QUERY_STRING_MAX_LEN parameter is not valid +#endif + +//Maximum length of the realm +#ifndef WEB_SOCKET_REALM_MAX_LEN + #define WEB_SOCKET_REALM_MAX_LEN 32 +#elif (WEB_SOCKET_REALM_MAX_LEN < 1) + #error WEB_SOCKET_REALM_MAX_LEN parameter is not valid +#endif + +//Maximum length of the user name +#ifndef WEB_SOCKET_USERNAME_MAX_LEN + #define WEB_SOCKET_USERNAME_MAX_LEN 16 +#elif (WEB_SOCKET_USERNAME_MAX_LEN < 1) + #error WEB_SOCKET_USERNAME_MAX_LEN parameter is not valid +#endif + +//Maximum length of the password +#ifndef WEB_SOCKET_PASSWORD_MAX_LEN + #define WEB_SOCKET_PASSWORD_MAX_LEN 16 +#elif (WEB_SOCKET_PASSWORD_MAX_LEN < 1) + #error WEB_SOCKET_PASSWORD_MAX_LEN parameter is not valid +#endif + +//Maximum length of the nonce +#ifndef WEB_SOCKET_NONCE_MAX_LEN + #define WEB_SOCKET_NONCE_MAX_LEN 32 +#elif (WEB_SOCKET_NONCE_MAX_LEN < 1) + #error WEB_SOCKET_NONCE_MAX_LEN parameter is not valid +#endif + +//Maximum length of the opaque parameter +#ifndef WEB_SOCKET_OPAQUE_MAX_LEN + #define WEB_SOCKET_OPAQUE_MAX_LEN 32 +#elif (WEB_SOCKET_OPAQUE_MAX_LEN < 1) + #error WEB_SOCKET_OPAQUE_MAX_LEN parameter is not valid +#endif + +//Cnonce size +#ifndef WEB_SOCKET_CNONCE_SIZE + #define WEB_SOCKET_CNONCE_SIZE 16 +#elif (WEB_SOCKET_CNONCE_SIZE < 1) + #error WEB_SOCKET_CNONCE_SIZE parameter is not valid +#endif + +//TLS supported? +#if (WEB_SOCKET_TLS_SUPPORT == ENABLED) + #include "crypto.h" + #include "tls.h" +#endif + +//Client key size +#define WEB_SOCKET_CLIENT_KEY_SIZE 24 +//Server key size +#define WEB_SOCKET_SERVER_KEY_SIZE 28 + +//Forward declaration of WebSocket structure +struct _WebSocket; +#define WebSocket struct _WebSocket + + +/** + * @brief WebSocket endpoint types + **/ + +typedef enum +{ + WS_ENDPOINT_CLIENT = 0, + WS_ENDPOINT_SERVER = 1 +} WebSocketEndpoint; + + +/** + * @brief HTTP version numbers + **/ + +typedef enum +{ + WS_HTTP_VERSION_0_9 = 0x0009, + WS_HTTP_VERSION_1_0 = 0x0100, + WS_HTTP_VERSION_1_1 = 0x0101 +} WebSocketHttpVersion; + + +/** + * @brief Authentication schemes + **/ + +typedef enum +{ + WS_AUTH_MODE_NONE = 0x00, + WS_AUTH_MODE_BASIC = 0x01, + WS_AUTH_MODE_DIGEST = 0x02 +} WebSocketAuthMode; + + +/** + * @brief WebSocket states + **/ + +typedef enum +{ + WS_STATE_UNUSED = 0, + WS_STATE_CLOSED = 1, + WS_STATE_INIT = 2, + WS_STATE_CONNECTING = 3, + WS_STATE_CLIENT_HANDSHAKE = 4, + WS_STATE_SERVER_HANDSHAKE = 5, + WS_STATE_SERVER_RESP_BODY = 6, + WS_STATE_OPEN = 7, + WS_STATE_CLOSING_TX = 8, + WS_STATE_CLOSING_RX = 9, + WS_STATE_SHUTDOWN = 10, +} WebSocketState; + + +/** + * @brief WebSocket sub-states + **/ + +typedef enum +{ + WS_SUB_STATE_INIT = 0, + //Handshake decoding + WS_SUB_STATE_HANDSHAKE_LEADING_LINE = 1, + WS_SUB_STATE_HANDSHAKE_HEADER_FIELD = 2, + WS_SUB_STATE_HANDSHAKE_LWSP = 3, + //WebSocket frame decoding + WS_SUB_STATE_FRAME_HEADER = 4, + WS_SUB_STATE_FRAME_EXT_HEADER = 5, + WS_SUB_STATE_FRAME_PAYLOAD = 6 +} WebSocketSubState; + + +/** + * @brief WebSocket frame types + **/ + +typedef enum +{ + WS_FRAME_TYPE_CONTINUATION = 0x00, + WS_FRAME_TYPE_TEXT = 0x01, + WS_FRAME_TYPE_BINARY = 0x02, + WS_FRAME_TYPE_CLOSE = 0x08, + WS_FRAME_TYPE_PING = 0x09, + WS_FRAME_TYPE_PONG = 0x0A +} WebSocketFrameType; + + +/** + * @brief WebSocket status codes + **/ + +typedef enum +{ + WS_STATUS_CODE_NORMAL_CLOSURE = 1000, + WS_STATUS_CODE_GOING_AWAY = 1001, + WS_STATUS_CODE_PROTOCOL_ERROR = 1002, + WS_STATUS_CODE_UNSUPPORTED_DATA = 1003, + WS_STATUS_CODE_NO_STATUS_RCVD = 1005, + WS_STATUS_CODE_ABNORMAL_CLOSURE = 1006, + WS_STATUS_CODE_INVALID_PAYLOAD_DATA = 1007, + WS_STATUS_CODE_POLICY_VIOLATION = 1008, + WS_STATUS_CODE_MESSAGE_TOO_BIG = 1009, + WS_STATUS_CODE_MANDATORY_EXT = 1010, + WS_STATUS_CODE_INTERNAL_ERROR = 1011, + WS_STATUS_CODE_TLS_HANDSHAKE = 1015 +} WebSocketStatusCode; + + +//CodeWarrior or Win32 compiler? +#if defined(__CWCC__) || defined(_WIN32) + #pragma pack(push, 1) +#endif + + +/** + * @brief WebSocket frame + **/ + +typedef __start_packed struct +{ +#ifdef _CPU_BIG_ENDIAN + uint8_t fin : 1; //0 + uint8_t reserved : 3; + uint8_t opcode : 4; + uint8_t mask : 1; //1 + uint8_t payloadLen: 7; +#else + uint8_t opcode : 4; //0 + uint8_t reserved : 3; + uint8_t fin : 1; + uint8_t payloadLen: 7; //1 + uint8_t mask : 1; +#endif + uint8_t extPayloadLen[]; //2 +} __end_packed WebSocketFrame; + + +//CodeWarrior or Win32 compiler? +#if defined(__CWCC__) || defined(_WIN32) + #pragma pack(pop) +#endif + + +/** + * @brief Random data generation callback function + **/ + +typedef error_t (*WebSocketRandCallback)(uint8_t *data, size_t length); + + +//WebSocket connections over SSL/TLS supported? +#if (WEB_SOCKET_TLS_SUPPORT == ENABLED) + +/** + * @brief SSL/TLS initialization callback function + **/ + +typedef error_t (*WebSocketTlsInitCallback)(WebSocket *webSocket, + TlsContext *tlsContext); + +#endif + + +/** + * @brief Authentication context + **/ + +typedef struct +{ + uint_t allowedAuthModes; + WebSocketAuthMode requiredAuthMode; + WebSocketAuthMode selectedAuthMode; + char_t username[WEB_SOCKET_USERNAME_MAX_LEN + 1]; + char_t password[WEB_SOCKET_PASSWORD_MAX_LEN + 1]; + char_t realm[WEB_SOCKET_REALM_MAX_LEN + 1]; +#if (WEB_SOCKET_DIGEST_AUTH_SUPPORT == ENABLED) + uint32_t nc; + char_t nonce[WEB_SOCKET_NONCE_MAX_LEN + 1]; + char_t cnonce[WEB_SOCKET_CNONCE_SIZE * 2 + 1]; + char_t opaque[WEB_SOCKET_OPAQUE_MAX_LEN + 1]; + bool_t stale; +#endif +} WebSocketAuthContext; + + +/** + * @brief Handshake context + **/ + +typedef struct +{ + uint_t version; + uint_t statusCode; + bool_t upgradeWebSocket; + bool_t connectionUpgrade; + bool_t connectionClose; + size_t contentLength; + char_t clientKey[WEB_SOCKET_CLIENT_KEY_SIZE + 1]; + char_t serverKey[WEB_SOCKET_SERVER_KEY_SIZE + 1]; + bool_t closingFrameSent; + bool_t closingFrameReceived; +} WebSocketHandshakeContext; + + +/** + * @brief Frame encoding/decoding context + **/ + +typedef struct +{ + WebSocketSubState state; ///FSM state + WebSocketFrameType dataFrameType; ///<Data frame type + WebSocketFrameType controlFrameType; ///<Control frame type + bool_t fin; ///<Final fragment in a message + bool_t mask; ///<Defines whether the payload data is masked + uint8_t maskingKey[4]; ///<Masking key + size_t payloadLen; ///<Payload length + size_t payloadPos; ///<Current position + uint8_t buffer[WEB_SOCKET_BUFFER_SIZE]; ///<Data buffer + size_t bufferLen; ///<Length of the data buffer + size_t bufferPos; ///<Current position +} WebSocketFrameContext; + + +/** + * @brief UTF-8 decoding context + **/ + +typedef struct +{ + uint_t utf8CharSize; + uint_t utf8CharIndex; + uint32_t utf8CodePoint; +} WebSocketUtf8Context; + + +/** + * @brief Structure describing a WebSocket + **/ + +struct _WebSocket +{ + WebSocketEndpoint endpoint; ///<Endpoint type (client or server) + WebSocketState state; ///<WebSocket connection state + uint16_t statusCode; + systime_t timestamp; + uint_t retryCount; + char_t host[WEB_SOCKET_HOST_MAX_LEN + 1]; + char_t origin[WEB_SOCKET_ORIGIN_MAX_LEN + 1]; + char_t subProtocol[WEB_SOCKET_SUB_PROTOCOL_MAX_LEN + 1]; + char_t uri[WEB_SOCKET_URI_MAX_LEN + 1]; + char_t queryString[WEB_SOCKET_QUERY_STRING_MAX_LEN + 1]; + systime_t timeout; ///<timeout value for blocking operations + NetInterface *interface; ///<Underlying network interface + Socket *socket; ///<Underlying TCP socket +#if (WEB_SOCKET_TLS_SUPPORT == ENABLED) + TlsContext *tlsContext; ///<SSL/TLS context + TlsSession tlsSession; ///<SSL/TLS session + WebSocketTlsInitCallback tlsInitCallback; ///<SSL/TLS initialization callback function +#endif +#if (WEB_SOCKET_BASIC_AUTH_SUPPORT == ENABLED || WEB_SOCKET_DIGEST_AUTH_SUPPORT == ENABLED) + WebSocketAuthContext authContext; +#endif + WebSocketHandshakeContext handshakeContext; + WebSocketFrameContext txContext; + WebSocketFrameContext rxContext; + WebSocketUtf8Context utf8Context; +}; + + +//Random data generation callback function +extern WebSocketRandCallback webSockRandCallback; + +//WebSocket related functions +error_t webSocketInit(void); + +error_t webSocketRegisterRandCallback(WebSocketRandCallback callback); + +WebSocket *webSocketOpen(void); +WebSocket *webSocketUpgradeSocket(Socket *socket); + +#if (WEB_SOCKET_TLS_SUPPORT == ENABLED) + +WebSocket *webSocketUpgradeSecureSocket(Socket *socket, TlsContext *tlsContext); + +error_t webSocketRegisterTlsInitCallback(WebSocket *webSocket, + WebSocketTlsInitCallback callback); + +#endif + +error_t webSocketSetTimeout(WebSocket *webSocket, systime_t timeout); + +error_t webSocketSetHost(WebSocket *webSocket, const char_t *host); +error_t webSocketSetOrigin(WebSocket *webSocket, const char_t *origin); +error_t webSocketSetSubProtocol(WebSocket *webSocket, const char_t *subProtocol); + +error_t webSocketSetAuthInfo(WebSocket *webSocket, const char_t *username, + const char_t *password, uint_t allowedAuthModes); + +error_t webSocketBindToInterface(WebSocket *webSocket, NetInterface *interface); + +error_t webSocketConnect(WebSocket *webSocket, const IpAddr *serverIpAddr, + uint16_t serverPort, const char_t *uri); + +error_t webSocketSetClientKey(WebSocket *webSocket, const char_t *clientKey); +error_t webSocketParseClientHandshake(WebSocket *webSocket); +error_t webSocketSendServerHandshake(WebSocket *webSocket); + +error_t webSocketSendErrorResponse(WebSocket *webSocket, + uint_t statusCode, const char_t *message); + +error_t webSocketSend(WebSocket *webSocket, const void *data, + size_t length, WebSocketFrameType type, size_t *written); + +error_t webSocketSendEx(WebSocket *webSocket, const void *data, size_t length, + WebSocketFrameType type, size_t *written, bool_t firstFrag, bool_t lastFrag); + +error_t webSocketReceive(WebSocket *webSocket, void *data, + size_t size, WebSocketFrameType *type, size_t *received); + +error_t webSocketReceiveEx(WebSocket *webSocket, void *data, size_t size, + WebSocketFrameType *type, size_t *received, bool_t *firstFrag, bool_t *lastFrag); + +bool_t webSocketIsRxReady(WebSocket *webSocket); +error_t webSocketShutdown(WebSocket *webSocket); +void webSocketClose(WebSocket *webSocket); + +#endif +