Initial migration to platformIO
This commit is contained in:
		
							
								
								
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | .pio | ||||||
|  | .vscode/.browse.c_cpp.db* | ||||||
|  | .vscode/c_cpp_properties.json | ||||||
|  | .vscode/launch.json | ||||||
|  | .vscode/ipch | ||||||
							
								
								
									
										39
									
								
								include/README
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								include/README
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | |||||||
|  |  | ||||||
|  | This directory is intended for project header files. | ||||||
|  |  | ||||||
|  | A header file is a file containing C declarations and macro definitions | ||||||
|  | to be shared between several project source files. You request the use of a | ||||||
|  | header file in your project source file (C, C++, etc) located in `src` folder | ||||||
|  | by including it, with the C preprocessing directive `#include'. | ||||||
|  |  | ||||||
|  | ```src/main.c | ||||||
|  |  | ||||||
|  | #include "header.h" | ||||||
|  |  | ||||||
|  | int main (void) | ||||||
|  | { | ||||||
|  |  ... | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | Including a header file produces the same results as copying the header file | ||||||
|  | into each source file that needs it. Such copying would be time-consuming | ||||||
|  | and error-prone. With a header file, the related declarations appear | ||||||
|  | in only one place. If they need to be changed, they can be changed in one | ||||||
|  | place, and programs that include the header file will automatically use the | ||||||
|  | new version when next recompiled. The header file eliminates the labor of | ||||||
|  | finding and changing all the copies as well as the risk that a failure to | ||||||
|  | find one copy will result in inconsistencies within a program. | ||||||
|  |  | ||||||
|  | In C, the usual convention is to give header files names that end with `.h'. | ||||||
|  | It is most portable to use only letters, digits, dashes, and underscores in | ||||||
|  | header file names, and at most one dot. | ||||||
|  |  | ||||||
|  | Read more about using header files in official GCC documentation: | ||||||
|  |  | ||||||
|  | * Include Syntax | ||||||
|  | * Include Operation | ||||||
|  | * Once-Only Headers | ||||||
|  | * Computed Includes | ||||||
|  |  | ||||||
|  | https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html | ||||||
							
								
								
									
										46
									
								
								lib/README
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								lib/README
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | |||||||
|  |  | ||||||
|  | This directory is intended for project specific (private) libraries. | ||||||
|  | PlatformIO will compile them to static libraries and link into executable file. | ||||||
|  |  | ||||||
|  | The source code of each library should be placed in a an own separate directory | ||||||
|  | ("lib/your_library_name/[here are source files]"). | ||||||
|  |  | ||||||
|  | For example, see a structure of the following two libraries `Foo` and `Bar`: | ||||||
|  |  | ||||||
|  | |--lib | ||||||
|  | |  | | ||||||
|  | |  |--Bar | ||||||
|  | |  |  |--docs | ||||||
|  | |  |  |--examples | ||||||
|  | |  |  |--src | ||||||
|  | |  |     |- Bar.c | ||||||
|  | |  |     |- Bar.h | ||||||
|  | |  |  |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html | ||||||
|  | |  | | ||||||
|  | |  |--Foo | ||||||
|  | |  |  |- Foo.c | ||||||
|  | |  |  |- Foo.h | ||||||
|  | |  | | ||||||
|  | |  |- README --> THIS FILE | ||||||
|  | | | ||||||
|  | |- platformio.ini | ||||||
|  | |--src | ||||||
|  |    |- main.c | ||||||
|  |  | ||||||
|  | and a contents of `src/main.c`: | ||||||
|  | ``` | ||||||
|  | #include <Foo.h> | ||||||
|  | #include <Bar.h> | ||||||
|  |  | ||||||
|  | int main (void) | ||||||
|  | { | ||||||
|  |   ... | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | PlatformIO Library Dependency Finder will find automatically dependent | ||||||
|  | libraries scanning project source files. | ||||||
|  |  | ||||||
|  | More information about PlatformIO Library Dependency Finder | ||||||
|  | - https://docs.platformio.org/page/librarymanager/ldf.html | ||||||
							
								
								
									
										16
									
								
								platformio.ini
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								platformio.ini
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | |||||||
|  | ; PlatformIO Project Configuration File | ||||||
|  | ; | ||||||
|  | ;   Build options: build flags, source filter | ||||||
|  | ;   Upload options: custom upload port, speed and extra flags | ||||||
|  | ;   Library options: dependencies, extra library storages | ||||||
|  | ;   Advanced options: extra scripting | ||||||
|  | ; | ||||||
|  | ; Please visit documentation for the other options and examples | ||||||
|  | ; https://docs.platformio.org/page/projectconf.html | ||||||
|  |  | ||||||
|  | [env:megaatmega2560] | ||||||
|  | platform = atmelavr | ||||||
|  | board = megaatmega2560 | ||||||
|  | framework = arduino | ||||||
|  | lib_deps = arduino-libraries/Ethernet@^2.0.2 | ||||||
|  | build_flags -DHOST_NAME=DepartureSign | ||||||
| @@ -1,80 +0,0 @@ | |||||||
| #include "ProtocolDL.hpp" |  | ||||||
|  |  | ||||||
| ProtocolDL::ProtocolDL(Image& img): |  | ||||||
|     image(&img) |  | ||||||
| { |  | ||||||
|  |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void ProtocolDL::newByte(uint8_t data) |  | ||||||
| { |  | ||||||
|     switch(cnt) |  | ||||||
|     { |  | ||||||
|         case 0: |  | ||||||
|             complete = false; |  | ||||||
|             source.width = (data << 8); |  | ||||||
|             cnt = 1; |  | ||||||
|             break; |  | ||||||
|          |  | ||||||
|         case 1: |  | ||||||
|             source.width |= data; |  | ||||||
|             cnt = 2; |  | ||||||
|             break; |  | ||||||
|          |  | ||||||
|         case 2: |  | ||||||
|             source.height = (data << 8); |  | ||||||
|             cnt = 3; |  | ||||||
|             break; |  | ||||||
|          |  | ||||||
|         case 3: |  | ||||||
|             source.height |= data; |  | ||||||
|             cnt = 4; |  | ||||||
|             break; |  | ||||||
|  |  | ||||||
|         case 4: |  | ||||||
|             source.delay = (data << 8); |  | ||||||
|             cnt = 5; |  | ||||||
|             break; |  | ||||||
|          |  | ||||||
|         case 5: |  | ||||||
|             source.delay |= data; |  | ||||||
|             image->set_size(source.width, source.height); |  | ||||||
|             source.x = 0; |  | ||||||
|             source.y = 0; |  | ||||||
|             cnt = 6; |  | ||||||
|             break; |  | ||||||
|  |  | ||||||
|         default: |  | ||||||
|             for (int shift = 7; shift >= 0; shift--) { |  | ||||||
|                 byte pixel = (data >> shift) & 1; |  | ||||||
|                 image->set_pixel(source.x, source.y, pixel); |  | ||||||
|  |  | ||||||
|                 if(source.x == (source.width - 1) && source.y == (source.height - 1)) |  | ||||||
|                 { |  | ||||||
|                     //this was the last pixel |  | ||||||
|                     complete = true; |  | ||||||
|                     cnt = 0; |  | ||||||
|                 } |  | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
|                     source.x++; |  | ||||||
|                     if (source.x >= source.width) { |  | ||||||
|                         source.x = 0; |  | ||||||
|                         source.y++; |  | ||||||
|                         if (source.y >= source.height) { |  | ||||||
|                             source.y = 0; |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             break; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|      |  | ||||||
| } |  | ||||||
|  |  | ||||||
| bool ProtocolDL::isComplete() |  | ||||||
| { |  | ||||||
|     return complete; |  | ||||||
| } |  | ||||||
| @@ -1,35 +0,0 @@ | |||||||
| #ifndef PROTOCOL_DL_HPP |  | ||||||
| #define PROTOCOL_DL_HPP |  | ||||||
|  |  | ||||||
| #include "image.hpp" |  | ||||||
|  |  | ||||||
| class ProtocolDL |  | ||||||
| { |  | ||||||
|     public: |  | ||||||
|     ProtocolDL(Image& img); |  | ||||||
|     void newByte(uint8_t data); |  | ||||||
|     bool isComplete(); |  | ||||||
|  |  | ||||||
|     private: |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     struct source_t { |  | ||||||
|         // width and height of current frame |  | ||||||
|         unsigned int width; |  | ||||||
|         unsigned int height; |  | ||||||
|  |  | ||||||
|         // delay until next frame is shown |  | ||||||
|         unsigned int delay; |  | ||||||
|  |  | ||||||
|         // position of current pixel |  | ||||||
|         int x; |  | ||||||
|         int y; |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     source_t source; |  | ||||||
|     uint16_t cnt = 0; |  | ||||||
|     bool complete = true; |  | ||||||
|     Image* image; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
| @@ -1,592 +0,0 @@ | |||||||
| /** |  | ||||||
|  * @file WebSockets.cpp |  | ||||||
|  * @date 20.05.2015 |  | ||||||
|  * @author Markus Sattler |  | ||||||
|  * |  | ||||||
|  * Copyright (c) 2015 Markus Sattler. All rights reserved. |  | ||||||
|  * This file is part of the WebSockets for Arduino. |  | ||||||
|  * |  | ||||||
|  * 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 St, Fifth Floor, Boston, MA  02110-1301  USA |  | ||||||
|  * |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #include "WebSockets.h" |  | ||||||
|  |  | ||||||
| #define LEGACY_SHA1 |  | ||||||
|  |  | ||||||
| #ifdef ESP8266 |  | ||||||
| #include <core_esp8266_features.h> |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| extern "C" { |  | ||||||
| #ifdef CORE_HAS_LIBB64 |  | ||||||
|     #include <libb64/cencode.h> |  | ||||||
| #else |  | ||||||
|     #include "libb64/cencode_inc.h" |  | ||||||
| #endif |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #ifdef ESP8266 |  | ||||||
| #include <Hash.h> |  | ||||||
| #else |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #ifdef LEGACY_SHA1 |  | ||||||
|     #include "sha1/sha1.h" |  | ||||||
| #else |  | ||||||
|     extern "C" { |  | ||||||
|         #include "libsha1/libsha1.h" |  | ||||||
|     } |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #define WEBSOCKETS_MAX_HEADER_SIZE  (14) |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * |  | ||||||
|  * @param client WSclient_t *  ptr to the client struct |  | ||||||
|  * @param code uint16_t see RFC |  | ||||||
|  * @param reason |  | ||||||
|  * @param reasonLen |  | ||||||
|  */ |  | ||||||
| void WebSockets::clientDisconnect(WSclient_t * client, uint16_t code, char * reason, size_t reasonLen) { |  | ||||||
|     DEBUG_WEBSOCKETS("[WS]["); |  | ||||||
| 	DEBUG_WEBSOCKETS(client->num); |  | ||||||
|     DEBUG_WEBSOCKETS("][handleWebsocket] clientDisconnect code: "); |  | ||||||
| 	DEBUG_WEBSOCKETS(code); |  | ||||||
|     DEBUG_WEBSOCKETS("\n"); |  | ||||||
|     if(client->status == WSC_CONNECTED && code) { |  | ||||||
|         if(reason) { |  | ||||||
|             sendFrame(client, WSop_close, (uint8_t *) reason, reasonLen); |  | ||||||
|         } else { |  | ||||||
|             uint8_t buffer[2]; |  | ||||||
|             buffer[0] = ((code >> 8) & 0xFF); |  | ||||||
|             buffer[1] = (code & 0xFF); |  | ||||||
|             sendFrame(client, WSop_close, &buffer[0], 2); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     clientDisconnect(client); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * |  | ||||||
|  * @param client WSclient_t *   ptr to the client struct |  | ||||||
|  * @param opcode WSopcode_t |  | ||||||
|  * @param payload uint8_t * |  | ||||||
|  * @param length size_t |  | ||||||
|  * @param mask bool             add dummy mask to the frame (needed for web browser) |  | ||||||
|  * @param fin bool              can be used to send data in more then one frame (set fin on the last frame) |  | ||||||
|  * @param headerToPayload bool  set true if the payload has reserved 14 Byte at the beginning to dynamically add the Header (payload neet to be in RAM!) |  | ||||||
|  */ |  | ||||||
| bool WebSockets::sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool mask, bool fin, bool headerToPayload) { |  | ||||||
|  |  | ||||||
|     if(client->tcp && !client->tcp->connected()) { |  | ||||||
|         DEBUG_WEBSOCKETS("[WS]["); |  | ||||||
| 	    DEBUG_WEBSOCKETS(client->num); |  | ||||||
|         DEBUG_WEBSOCKETS("][sendFrame] not Connected!?\n"); |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if(client->status != WSC_CONNECTED) { |  | ||||||
|         DEBUG_WEBSOCKETS("[WS][");         |  | ||||||
| 	    DEBUG_WEBSOCKETS(client->num); |  | ||||||
|         DEBUG_WEBSOCKETS("][sendFrame] not in WSC_CONNECTED state!?\n"); |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     DEBUG_WEBSOCKETS("[WS][");     |  | ||||||
| 	DEBUG_WEBSOCKETS(client->num); |  | ||||||
|     DEBUG_WEBSOCKETS("][sendFrame] ------- send massage frame -------\n"); |  | ||||||
|      |  | ||||||
|     DEBUG_WEBSOCKETS("[WS]["); |  | ||||||
| 	DEBUG_WEBSOCKETS(client->num); |  | ||||||
|     DEBUG_WEBSOCKETS("][sendFrame] fin: "); |  | ||||||
| 	DEBUG_WEBSOCKETS(fin); |  | ||||||
|     DEBUG_WEBSOCKETS(" opCode: "); |  | ||||||
| 	DEBUG_WEBSOCKETS(opcode); |  | ||||||
|     DEBUG_WEBSOCKETS(" mask: "); |  | ||||||
| 	DEBUG_WEBSOCKETS(mask); |  | ||||||
|     DEBUG_WEBSOCKETS(" length: "); |  | ||||||
| 	DEBUG_WEBSOCKETS(length); |  | ||||||
|     DEBUG_WEBSOCKETS(" headerToPayload: "); |  | ||||||
| 	DEBUG_WEBSOCKETS(headerToPayload); |  | ||||||
|     DEBUG_WEBSOCKETS("\n"); |  | ||||||
|  |  | ||||||
|     if(opcode == WSop_text) { |  | ||||||
|         DEBUG_WEBSOCKETS("[WS]["); |  | ||||||
|         DEBUG_WEBSOCKETS(client->num); |  | ||||||
|         DEBUG_WEBSOCKETS("][sendFrame] text: "); |  | ||||||
|         DEBUG_WEBSOCKETS((char*) (payload + (headerToPayload ? 14 : 0))); |  | ||||||
|         DEBUG_WEBSOCKETS("\n"); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     uint8_t maskKey[4] = { 0x00, 0x00, 0x00, 0x00 }; |  | ||||||
|     uint8_t buffer[WEBSOCKETS_MAX_HEADER_SIZE] = { 0 }; |  | ||||||
|  |  | ||||||
|     uint8_t headerSize; |  | ||||||
|     uint8_t * headerPtr; |  | ||||||
|     uint8_t * payloadPtr = payload; |  | ||||||
|     bool useInternBuffer = false; |  | ||||||
|     bool ret = true; |  | ||||||
|  |  | ||||||
|     // calculate header Size |  | ||||||
|     if(length < 126) { |  | ||||||
|         headerSize = 2; |  | ||||||
|     } else if(length < 0xFFFF) { |  | ||||||
|         headerSize = 4; |  | ||||||
|     } else { |  | ||||||
|         headerSize = 10; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if(mask) { |  | ||||||
|         headerSize += 4; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #ifdef WEBSOCKETS_USE_BIG_MEM |  | ||||||
|     // only for ESP since AVR has less HEAP |  | ||||||
|     // try to send data in one TCP package (only if some free Heap is there) |  | ||||||
|     if(!headerToPayload && ((length > 0) && (length < 1400)) && (ESP.getFreeHeap() > 6000)) { |  | ||||||
|         DEBUG_WEBSOCKETS("[WS]["); |  | ||||||
|         DEBUG_WEBSOCKETS(client->num); |  | ||||||
|         DEBUG_WEBSOCKETS("][sendFrame] pack to one TCP package...\n"); |  | ||||||
|          |  | ||||||
|         uint8_t * dataPtr = (uint8_t *) malloc(length + WEBSOCKETS_MAX_HEADER_SIZE); |  | ||||||
|         if(dataPtr) { |  | ||||||
|             memcpy((dataPtr + WEBSOCKETS_MAX_HEADER_SIZE), payload, length); |  | ||||||
|             headerToPayload = true; |  | ||||||
|             useInternBuffer = true; |  | ||||||
|             payloadPtr = dataPtr; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|     // set Header Pointer |  | ||||||
|     if(headerToPayload) { |  | ||||||
|         // calculate offset in payload |  | ||||||
|         headerPtr = (payloadPtr + (WEBSOCKETS_MAX_HEADER_SIZE - headerSize)); |  | ||||||
|     } else { |  | ||||||
|         headerPtr = &buffer[0]; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // create header |  | ||||||
|  |  | ||||||
|     // byte 0 |  | ||||||
|     *headerPtr = 0x00; |  | ||||||
|     if(fin) { |  | ||||||
|         *headerPtr |= bit(7);    ///< set Fin |  | ||||||
|     } |  | ||||||
|     *headerPtr |= opcode;        ///< set opcode |  | ||||||
|     headerPtr++; |  | ||||||
|  |  | ||||||
|     // byte 1 |  | ||||||
|     *headerPtr = 0x00; |  | ||||||
|     if(mask) { |  | ||||||
|         *headerPtr |= bit(7);    ///< set mask |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if(length < 126) { |  | ||||||
|         *headerPtr |= length;                   headerPtr++; |  | ||||||
|     } else if(length < 0xFFFF) { |  | ||||||
|         *headerPtr |= 126;                      headerPtr++; |  | ||||||
|         *headerPtr = ((length >> 8) & 0xFF);    headerPtr++; |  | ||||||
|         *headerPtr = (length & 0xFF);           headerPtr++; |  | ||||||
|     } else { |  | ||||||
|         // Normally we never get here (to less memory) |  | ||||||
|         *headerPtr |= 127;                      headerPtr++; |  | ||||||
|         *headerPtr = 0x00;                      headerPtr++; |  | ||||||
|         *headerPtr = 0x00;                      headerPtr++; |  | ||||||
|         *headerPtr = 0x00;                      headerPtr++; |  | ||||||
|         *headerPtr = 0x00;                      headerPtr++; |  | ||||||
|         *headerPtr = ((length >> 24) & 0xFF);   headerPtr++; |  | ||||||
|         *headerPtr = ((length >> 16) & 0xFF);   headerPtr++; |  | ||||||
|         *headerPtr = ((length >> 8) & 0xFF);    headerPtr++; |  | ||||||
|         *headerPtr = (length & 0xFF);           headerPtr++; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if(mask) { |  | ||||||
|         if(useInternBuffer) { |  | ||||||
|             // if we use a Intern Buffer we can modify the data |  | ||||||
|             // by this fact its possible the do the masking |  | ||||||
|             for(uint8_t x = 0; x < sizeof(maskKey); x++) { |  | ||||||
|                 maskKey[x] = random(0xFF); |  | ||||||
|                 *headerPtr = maskKey[x];       headerPtr++; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             uint8_t * dataMaskPtr; |  | ||||||
|  |  | ||||||
|             if(headerToPayload) { |  | ||||||
|                 dataMaskPtr = (payloadPtr + WEBSOCKETS_MAX_HEADER_SIZE); |  | ||||||
|             } else { |  | ||||||
|                 dataMaskPtr = payloadPtr; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             for(size_t x = 0; x < length; x++) { |  | ||||||
|                 dataMaskPtr[x] = (dataMaskPtr[x] ^ maskKey[x % 4]); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|         } else { |  | ||||||
|             *headerPtr = maskKey[0];          headerPtr++; |  | ||||||
|             *headerPtr = maskKey[1];          headerPtr++; |  | ||||||
|             *headerPtr = maskKey[2];          headerPtr++; |  | ||||||
|             *headerPtr = maskKey[3];          headerPtr++; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| #ifndef NODEBUG_WEBSOCKETS |  | ||||||
|     unsigned long start = micros(); |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|     if(headerToPayload) { |  | ||||||
|         // header has be added to payload |  | ||||||
|         // payload is forced to reserved 14 Byte but we may not need all based on the length and mask settings |  | ||||||
|         // offset in payload is calculatetd 14 - headerSize |  | ||||||
|         if (client->tcp->write(&payloadPtr[(WEBSOCKETS_MAX_HEADER_SIZE - headerSize)], (length + headerSize)) != (length + headerSize)) { |  | ||||||
|             ret = false; |  | ||||||
|         } |  | ||||||
|     } else { |  | ||||||
|         // send header |  | ||||||
|         if (client->tcp->write(&buffer[0], headerSize) != headerSize) { |  | ||||||
|             ret = false; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if(payloadPtr && length > 0) { |  | ||||||
|             // send payload |  | ||||||
|             if(client->tcp->write(&payloadPtr[0], length) != length) { |  | ||||||
|                 ret = false; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     DEBUG_WEBSOCKETS("[WS]["); |  | ||||||
| 	DEBUG_WEBSOCKETS(client->num); |  | ||||||
|     DEBUG_WEBSOCKETS("][sendFrame] sending Frame Done ("); |  | ||||||
| 	DEBUG_WEBSOCKETS((micros() - start)); |  | ||||||
|     DEBUG_WEBSOCKETS("us).\n"); |  | ||||||
|  |  | ||||||
| #ifdef WEBSOCKETS_USE_BIG_MEM |  | ||||||
|     if(useInternBuffer && payloadPtr) { |  | ||||||
|         free(payloadPtr); |  | ||||||
|     } |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|     return ret; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * handle the WebSocket stream |  | ||||||
|  * @param client WSclient_t *  ptr to the client struct |  | ||||||
|  */ |  | ||||||
| void WebSockets::handleWebsocket(WSclient_t * client) { |  | ||||||
|  |  | ||||||
|     uint8_t buffer[8] = { 0 }; |  | ||||||
|  |  | ||||||
|     bool fin; |  | ||||||
|     bool rsv1; |  | ||||||
|     bool rsv2; |  | ||||||
|     bool rsv3; |  | ||||||
|     WSopcode_t opCode; |  | ||||||
|     bool mask; |  | ||||||
|     size_t payloadLen; |  | ||||||
|  |  | ||||||
|     uint8_t maskKey[4]; |  | ||||||
|  |  | ||||||
|     uint8_t * payload = NULL; |  | ||||||
|  |  | ||||||
|     DEBUG_WEBSOCKETS("[WS]["); |  | ||||||
| 	DEBUG_WEBSOCKETS(client->num); |  | ||||||
|     DEBUG_WEBSOCKETS("][handleWebsocket] ------- read massage frame -------\n"); |  | ||||||
|  |  | ||||||
|     if(!readWait(client, buffer, 2)) { |  | ||||||
|         //timeout |  | ||||||
|         clientDisconnect(client, 1002); |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // split first 2 bytes in the data |  | ||||||
|     fin = ((buffer[0] >> 7) & 0x01); |  | ||||||
|     rsv1 = ((buffer[0] >> 6) & 0x01); |  | ||||||
|     rsv2 = ((buffer[0] >> 5) & 0x01); |  | ||||||
|     rsv3 = ((buffer[0] >> 4) & 0x01); |  | ||||||
|     opCode = (WSopcode_t) (buffer[0] & 0x0F); |  | ||||||
|  |  | ||||||
|     mask = ((buffer[1] >> 7) & 0x01); |  | ||||||
|     payloadLen = (WSopcode_t) (buffer[1] & 0x7F); |  | ||||||
|  |  | ||||||
|     if(payloadLen == 126) { |  | ||||||
|         if(!readWait(client, buffer, 2)) { |  | ||||||
|             //timeout |  | ||||||
|             clientDisconnect(client, 1002); |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|         payloadLen = buffer[0] << 8 | buffer[1]; |  | ||||||
|     } else if(payloadLen == 127) { |  | ||||||
|         // read 64bit integer as length |  | ||||||
|         if(!readWait(client, buffer, 8)) { |  | ||||||
|             //timeout |  | ||||||
|             clientDisconnect(client, 1002); |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if(buffer[0] != 0 || buffer[1] != 0 || buffer[2] != 0 || buffer[3] != 0) { |  | ||||||
|             // really to big! |  | ||||||
|             payloadLen = 0xFFFFFFFF; |  | ||||||
|         } else { |  | ||||||
|             payloadLen = buffer[4] << 24 | buffer[5] << 16 | buffer[6] << 8 | buffer[7]; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     DEBUG_WEBSOCKETS("[WS]["); |  | ||||||
| 	DEBUG_WEBSOCKETS(client->num); |  | ||||||
|     DEBUG_WEBSOCKETS("][handleWebsocket] fin: "); |  | ||||||
| 	DEBUG_WEBSOCKETS(fin); |  | ||||||
|     DEBUG_WEBSOCKETS(" rsv1: "); |  | ||||||
| 	DEBUG_WEBSOCKETS(rsv1); |  | ||||||
|     DEBUG_WEBSOCKETS(" rsv2: "); |  | ||||||
| 	DEBUG_WEBSOCKETS(rsv2); |  | ||||||
|     DEBUG_WEBSOCKETS(" rsv3: "); |  | ||||||
| 	DEBUG_WEBSOCKETS(rsv3); |  | ||||||
|     DEBUG_WEBSOCKETS(" opCode: "); |  | ||||||
| 	DEBUG_WEBSOCKETS(opCode); |  | ||||||
|     DEBUG_WEBSOCKETS("\n"); |  | ||||||
|      |  | ||||||
|     DEBUG_WEBSOCKETS("[WS]["); |  | ||||||
| 	DEBUG_WEBSOCKETS(client->num); |  | ||||||
|     DEBUG_WEBSOCKETS("][handleWebsocket] mask: "); |  | ||||||
| 	DEBUG_WEBSOCKETS(mask); |  | ||||||
|     DEBUG_WEBSOCKETS(" payloadLen: "); |  | ||||||
| 	DEBUG_WEBSOCKETS(payloadLen); |  | ||||||
|     DEBUG_WEBSOCKETS("\n"); |  | ||||||
|  |  | ||||||
|     if(payloadLen > WEBSOCKETS_MAX_DATA_SIZE) { |  | ||||||
|         DEBUG_WEBSOCKETS("[WS]["); |  | ||||||
| 	    DEBUG_WEBSOCKETS(client->num); |  | ||||||
|         DEBUG_WEBSOCKETS("][handleWebsocket] payload to big! ("); |  | ||||||
|         DEBUG_WEBSOCKETS(payloadLen); |  | ||||||
|         DEBUG_WEBSOCKETS(")\n"); |  | ||||||
|         clientDisconnect(client, 1009); |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if(mask) { |  | ||||||
|         if(!readWait(client, maskKey, 4)) { |  | ||||||
|             //timeout |  | ||||||
|             clientDisconnect(client, 1002); |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if(payloadLen > 0) { |  | ||||||
|         // if text data we need one more |  | ||||||
|         payload = (uint8_t *) malloc(payloadLen + 1); |  | ||||||
|  |  | ||||||
|         if(!payload) { |  | ||||||
|             DEBUG_WEBSOCKETS("[WS]["); |  | ||||||
|             DEBUG_WEBSOCKETS(client->num); |  | ||||||
|             DEBUG_WEBSOCKETS("][handleWebsocket] to less memory to handle payload "); |  | ||||||
|             DEBUG_WEBSOCKETS(payloadLen); |  | ||||||
|             DEBUG_WEBSOCKETS("!\n"); |  | ||||||
|             clientDisconnect(client, 1011); |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if(!readWait(client, payload, payloadLen)) { |  | ||||||
|             DEBUG_WEBSOCKETS("[WS]["); |  | ||||||
|             DEBUG_WEBSOCKETS(client->num); |  | ||||||
|             DEBUG_WEBSOCKETS("][handleWebsocket] missing data!\n"); |  | ||||||
|             free(payload); |  | ||||||
|             clientDisconnect(client, 1002); |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         payload[payloadLen] = 0x00; |  | ||||||
|  |  | ||||||
|         if(mask) { |  | ||||||
|             //decode XOR |  | ||||||
|             for(size_t i = 0; i < payloadLen; i++) { |  | ||||||
|                 payload[i] = (payload[i] ^ maskKey[i % 4]); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     switch(opCode) { |  | ||||||
|         case WSop_text: |  | ||||||
|             DEBUG_WEBSOCKETS("[WS]["); |  | ||||||
|             DEBUG_WEBSOCKETS(client->num); |  | ||||||
|             DEBUG_WEBSOCKETS("][handleWebsocket] text: "); |  | ||||||
|             DEBUG_WEBSOCKETS((char*) payload); |  | ||||||
|             DEBUG_WEBSOCKETS("\n"); |  | ||||||
|             // no break here! |  | ||||||
|         case WSop_binary: |  | ||||||
|             messageRecived(client, opCode, payload, payloadLen); |  | ||||||
|             break; |  | ||||||
|         case WSop_ping: |  | ||||||
|             // send pong back |  | ||||||
|             sendFrame(client, WSop_pong, payload, payloadLen); |  | ||||||
|             break; |  | ||||||
|         case WSop_pong: |  | ||||||
|             DEBUG_WEBSOCKETS("[WS]["); |  | ||||||
|             DEBUG_WEBSOCKETS(client->num); |  | ||||||
|             DEBUG_WEBSOCKETS("][handleWebsocket] get pong  ("); |  | ||||||
|             DEBUG_WEBSOCKETS((char*) payload); |  | ||||||
|             DEBUG_WEBSOCKETS(")\n"); |  | ||||||
|             break; |  | ||||||
|         case WSop_close: |  | ||||||
|             { |  | ||||||
|                 uint16_t reasonCode = 1000; |  | ||||||
|                 if(payloadLen >= 2) { |  | ||||||
|                     reasonCode = payload[0] << 8 | payload[1]; |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 DEBUG_WEBSOCKETS("[WS]["); |  | ||||||
|                 DEBUG_WEBSOCKETS(client->num); |  | ||||||
|                 DEBUG_WEBSOCKETS("][handleWebsocket] get ask for close. Code: "); |  | ||||||
|                 DEBUG_WEBSOCKETS(reasonCode); |  | ||||||
|                 if(payloadLen > 2) { |  | ||||||
|                     DEBUG_WEBSOCKETS(" ("); |  | ||||||
|                     DEBUG_WEBSOCKETS((char*) (payload+2)); |  | ||||||
|                     DEBUG_WEBSOCKETS(")\n"); |  | ||||||
|                 } else { |  | ||||||
|                     DEBUG_WEBSOCKETS("\n"); |  | ||||||
|                 } |  | ||||||
|                 clientDisconnect(client, 1000); |  | ||||||
|             } |  | ||||||
|             break; |  | ||||||
|         case WSop_continuation: |  | ||||||
|             // continuation is not supported |  | ||||||
|             clientDisconnect(client, 1003); |  | ||||||
|             break; |  | ||||||
|         default: |  | ||||||
|             clientDisconnect(client, 1002); |  | ||||||
|             break; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if(payload) { |  | ||||||
|         free(payload); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * generate the key for Sec-WebSocket-Accept |  | ||||||
|  * @param clientKey String |  | ||||||
|  * @return String Accept Key |  | ||||||
|  */ |  | ||||||
| String WebSockets::acceptKey(String clientKey) { |  | ||||||
|     uint8_t sha1HashBin[20] = { 0 }; |  | ||||||
| #ifdef ESP8266 |  | ||||||
|     sha1(clientKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", &sha1HashBin[0]); |  | ||||||
| #else |  | ||||||
|     clientKey += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; |  | ||||||
|     #ifdef LEGACY_SHA1 |  | ||||||
|       // Miha Nahtigal |  | ||||||
|       char cbuff[clientKey.length()+1]; |  | ||||||
|       clientKey.toCharArray(cbuff, clientKey.length()+1);//Converts String into character array  |  | ||||||
|       Sha1.init(); |  | ||||||
|       Sha1.print(cbuff); |  | ||||||
|       strcpy(sha1HashBin, Sha1.result()); |  | ||||||
|       Serial.println(cbuff); |  | ||||||
|       //old:uint8_t *sha1HashBin = Sha1.result();      |  | ||||||
|     #else |  | ||||||
|       SHA1_CTX ctx; |  | ||||||
|       SHA1Init(&ctx);            |  | ||||||
|       SHA1Update(&ctx, (const unsigned char*)clientKey.c_str(), clientKey.length()); |  | ||||||
|       SHA1Final(&sha1HashBin[0], &ctx);  |  | ||||||
|     #endif |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|     String key = base64_encode(sha1HashBin, 20);  |  | ||||||
|     key.trim(); |  | ||||||
|  |  | ||||||
|     return key; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * base64_encode |  | ||||||
|  * @param data uint8_t * |  | ||||||
|  * @param length size_t |  | ||||||
|  * @return base64 encoded String |  | ||||||
|  */ |  | ||||||
| String WebSockets::base64_encode(uint8_t * data, size_t length) { |  | ||||||
|     size_t size = ((length*1.6f)+1); |  | ||||||
|     char * buffer = (char *) malloc(size); |  | ||||||
|     if(buffer) { |  | ||||||
|         base64_encodestate _state; |  | ||||||
|         base64_init_encodestate(&_state); |  | ||||||
|         int len = base64_encode_block((const char *) &data[0], length, &buffer[0], &_state); |  | ||||||
|         len = base64_encode_blockend((buffer + len), &_state); |  | ||||||
|  |  | ||||||
|         String base64 = String(buffer); |  | ||||||
|         free(buffer); |  | ||||||
|         return base64; |  | ||||||
|     } |  | ||||||
|     return String("-FAIL-"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * read x byte from tcp or get timeout |  | ||||||
|  * @param client WSclient_t * |  | ||||||
|  * @param out  uint8_t * data buffer |  | ||||||
|  * @param n size_t byte count |  | ||||||
|  * @return true if ok |  | ||||||
|  */ |  | ||||||
| bool WebSockets::readWait(WSclient_t * client, uint8_t *out, size_t n) { |  | ||||||
|     unsigned long t = millis(); |  | ||||||
|     size_t len; |  | ||||||
|  |  | ||||||
|     while(n > 0) { |  | ||||||
|         if(!client->tcp) { |  | ||||||
|             DEBUG_WEBSOCKETS("[readWait] tcp is null!\n"); |  | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if(!client->tcp->connected()) { |  | ||||||
|             DEBUG_WEBSOCKETS("[readWait] not connected!\n"); |  | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if((millis() - t) > WEBSOCKETS_TCP_TIMEOUT) { |  | ||||||
|             DEBUG_WEBSOCKETS("[readWait] receive TIMEOUT!\n"); |  | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if(!client->tcp->available()) { |  | ||||||
| #ifdef ESP8266 |  | ||||||
|             delay(0); |  | ||||||
| #endif |  | ||||||
|             continue; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         len = client->tcp->read((uint8_t*) out, n); |  | ||||||
|         if(len) { |  | ||||||
|             t = millis(); |  | ||||||
|             out += len; |  | ||||||
|             n -= len; |  | ||||||
|             //DEBUG_WEBSOCKETS("Receive %d left %d!\n", len, n); |  | ||||||
|         } else { |  | ||||||
|             //DEBUG_WEBSOCKETS("Receive %d left %d!\n", len, n); |  | ||||||
|         } |  | ||||||
|         //DEBUG_WEBSOCKETS("Receive "); |  | ||||||
|         //DEBUG_WEBSOCKETS(len); |  | ||||||
|         //DEBUG_WEBSOCKETS("left "); |  | ||||||
|         //DEBUG_WEBSOCKETS(n);       |  | ||||||
|         //DEBUG_WEBSOCKETS("!\n");                   |  | ||||||
| #ifdef ESP8266 |  | ||||||
|         delay(0); |  | ||||||
| #endif |  | ||||||
|     } |  | ||||||
|     return true; |  | ||||||
| } |  | ||||||
							
								
								
									
										159
									
								
								src/WebSockets.h
									
									
									
									
									
								
							
							
						
						
									
										159
									
								
								src/WebSockets.h
									
									
									
									
									
								
							| @@ -1,159 +0,0 @@ | |||||||
| /** |  | ||||||
|  * @file WebSockets.h |  | ||||||
|  * @date 20.05.2015 |  | ||||||
|  * @author Markus Sattler |  | ||||||
|  * |  | ||||||
|  * Copyright (c) 2015 Markus Sattler. All rights reserved. |  | ||||||
|  * This file is part of the WebSockets for Arduino. |  | ||||||
|  * |  | ||||||
|  * 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 St, Fifth Floor, Boston, MA  02110-1301  USA |  | ||||||
|  * |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #ifndef WEBSOCKETS_H_ |  | ||||||
| #define WEBSOCKETS_H_ |  | ||||||
|  |  | ||||||
| #include <Arduino.h> |  | ||||||
|  |  | ||||||
| //#define DEBUG_WEBSOCKETS(...) Serial.print( __VA_ARGS__ ) |  | ||||||
|  |  | ||||||
| #ifndef DEBUG_WEBSOCKETS |  | ||||||
| #define DEBUG_WEBSOCKETS(...) |  | ||||||
| #define NODEBUG_WEBSOCKETS |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #ifdef ESP8266 |  | ||||||
| #define WEBSOCKETS_MAX_DATA_SIZE  (15*1024) |  | ||||||
| #define WEBSOCKETS_USE_BIG_MEM |  | ||||||
| #else |  | ||||||
| //atmega328p has only 2KB ram! |  | ||||||
| #define WEBSOCKETS_MAX_DATA_SIZE  (2048) |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #define WEBSOCKETS_TCP_TIMEOUT    (1500) |  | ||||||
|  |  | ||||||
| #define NETWORK_ESP8266     (1) |  | ||||||
| #define NETWORK_W5100       (2) |  | ||||||
| #define NETWORK_ENC28J60    (3) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| // select Network type based |  | ||||||
| #ifdef ESP8266 |  | ||||||
| #define WEBSOCKETS_NETWORK_TYPE NETWORK_ESP8266 |  | ||||||
| #else |  | ||||||
| #define WEBSOCKETS_NETWORK_TYPE NETWORK_W5100 |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) |  | ||||||
|  |  | ||||||
| #ifndef ESP8266 |  | ||||||
| #error "network type ESP8266 only possible on the ESP mcu!" |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #include <ESP8266WiFi.h> |  | ||||||
| #define WEBSOCKETS_NETWORK_CLASS WiFiClient |  | ||||||
| #define WEBSOCKETS_NETWORK_SERVER_CLASS WiFiServer |  | ||||||
|  |  | ||||||
| #elif (WEBSOCKETS_NETWORK_TYPE == NETWORK_W5100) |  | ||||||
|  |  | ||||||
| #include <Ethernet.h> |  | ||||||
| #include <SPI.h> |  | ||||||
| #define WEBSOCKETS_NETWORK_CLASS EthernetClient |  | ||||||
| #define WEBSOCKETS_NETWORK_SERVER_CLASS EthernetServer |  | ||||||
|  |  | ||||||
| #elif (WEBSOCKETS_NETWORK_TYPE == NETWORK_ENC28J60) |  | ||||||
|  |  | ||||||
| #include <UIPEthernet.h> |  | ||||||
| #define WEBSOCKETS_NETWORK_CLASS UIPClient |  | ||||||
| #define WEBSOCKETS_NETWORK_SERVER_CLASS UIPServer |  | ||||||
|  |  | ||||||
| #else |  | ||||||
| #error "no network type selected!" |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  |  | ||||||
| typedef enum { |  | ||||||
|     WSC_NOT_CONNECTED, |  | ||||||
|     WSC_HEADER, |  | ||||||
|     WSC_CONNECTED |  | ||||||
| } WSclientsStatus_t; |  | ||||||
|  |  | ||||||
| typedef enum { |  | ||||||
|     WStype_ERROR, |  | ||||||
|     WStype_DISCONNECTED, |  | ||||||
|     WStype_CONNECTED, |  | ||||||
|     WStype_TEXT, |  | ||||||
|     WStype_BIN |  | ||||||
| } WStype_t; |  | ||||||
|  |  | ||||||
| typedef enum { |  | ||||||
|     WSop_continuation = 0x00, ///< %x0 denotes a continuation frame |  | ||||||
|     WSop_text = 0x01,         ///< %x1 denotes a text frame |  | ||||||
|     WSop_binary = 0x02,       ///< %x2 denotes a binary frame |  | ||||||
|                               ///< %x3-7 are reserved for further non-control frames |  | ||||||
|     WSop_close = 0x08,        ///< %x8 denotes a connection close |  | ||||||
|     WSop_ping = 0x09,         ///< %x9 denotes a ping |  | ||||||
|     WSop_pong = 0x0A          ///< %xA denotes a pong |  | ||||||
|                               ///< %xB-F are reserved for further control frames |  | ||||||
| } WSopcode_t; |  | ||||||
|  |  | ||||||
| typedef struct { |  | ||||||
|         uint8_t num; ///< connection number |  | ||||||
|  |  | ||||||
|         WSclientsStatus_t status; |  | ||||||
|  |  | ||||||
|         WEBSOCKETS_NETWORK_CLASS * tcp; |  | ||||||
|  |  | ||||||
| #if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) |  | ||||||
|         bool isSSL;             ///< run in ssl mode |  | ||||||
|         WiFiClientSecure * ssl; |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|         String cUrl;        ///< http url |  | ||||||
|         uint16_t cCode;     ///< http code |  | ||||||
|  |  | ||||||
|         bool cIsUpgrade;    ///< Connection == Upgrade |  | ||||||
|         bool cIsWebsocket;  ///< Upgrade == websocket |  | ||||||
|  |  | ||||||
|         String cKey;        ///< client Sec-WebSocket-Key |  | ||||||
|         String cAccept;     ///< client Sec-WebSocket-Accept |  | ||||||
|         String cProtocol;   ///< client Sec-WebSocket-Protocol |  | ||||||
|         String cExtensions; ///< client Sec-WebSocket-Extensions |  | ||||||
|         uint16_t cVersion;  ///< client Sec-WebSocket-Version |  | ||||||
|  |  | ||||||
| } WSclient_t; |  | ||||||
|  |  | ||||||
| class WebSockets { |  | ||||||
|     protected: |  | ||||||
|         virtual void clientDisconnect(WSclient_t * client); |  | ||||||
|         virtual bool clientIsConnected(WSclient_t * client); |  | ||||||
|  |  | ||||||
|         virtual void messageRecived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length); |  | ||||||
|  |  | ||||||
|         void clientDisconnect(WSclient_t * client, uint16_t code, char * reason = NULL, size_t reasonLen = 0); |  | ||||||
|         bool sendFrame(WSclient_t * client, WSopcode_t opcode, uint8_t * payload = NULL, size_t length = 0, bool mask = false, bool fin = true, bool headerToPayload = false); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         void handleWebsocket(WSclient_t * client); |  | ||||||
|  |  | ||||||
|         bool readWait(WSclient_t * client, uint8_t *out, size_t n); |  | ||||||
|  |  | ||||||
|         String acceptKey(String clientKey); |  | ||||||
|         String base64_encode(uint8_t * data, size_t length); |  | ||||||
|  |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| #endif /* WEBSOCKETS_H_ */ |  | ||||||
| @@ -1,506 +0,0 @@ | |||||||
| /** |  | ||||||
|  * @file WebSocketsClient.cpp |  | ||||||
|  * @date 20.05.2015 |  | ||||||
|  * @author Markus Sattler |  | ||||||
|  * |  | ||||||
|  * Copyright (c) 2015 Markus Sattler. All rights reserved. |  | ||||||
|  * This file is part of the WebSockets for Arduino. |  | ||||||
|  * |  | ||||||
|  * 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 St, Fifth Floor, Boston, MA  02110-1301  USA |  | ||||||
|  * |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #include "WebSockets.h" |  | ||||||
| #include "WebSocketsClient.h" |  | ||||||
|  |  | ||||||
| WebSocketsClient::WebSocketsClient() { |  | ||||||
|     _cbEvent = NULL; |  | ||||||
|     _client.num = 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| WebSocketsClient::~WebSocketsClient() { |  | ||||||
|     disconnect(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * calles to init the Websockets server |  | ||||||
|  */ |  | ||||||
| void WebSocketsClient::begin(const char *host, uint16_t port, const char * url) { |  | ||||||
|     _host = host; |  | ||||||
|     _port = port; |  | ||||||
| #if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) |  | ||||||
|     _fingerprint = ""; |  | ||||||
| #endif |  | ||||||
|      |  | ||||||
|     _client.num = 0; |  | ||||||
|     _client.status = WSC_NOT_CONNECTED; |  | ||||||
|     _client.tcp = NULL; |  | ||||||
| #if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) |  | ||||||
|     _client.isSSL = false; |  | ||||||
|     _client.ssl = NULL; |  | ||||||
| #endif |  | ||||||
|     _client.cUrl = url; |  | ||||||
|     _client.cCode = 0; |  | ||||||
|     _client.cIsUpgrade = false; |  | ||||||
|     _client.cIsWebsocket = true; |  | ||||||
|     _client.cKey = ""; |  | ||||||
|     _client.cAccept = ""; |  | ||||||
|     _client.cProtocol = ""; |  | ||||||
|     _client.cExtensions = ""; |  | ||||||
|     _client.cVersion = 0; |  | ||||||
|  |  | ||||||
| #ifdef ESP8266 |  | ||||||
|     randomSeed(RANDOM_REG32); |  | ||||||
| #else |  | ||||||
|     // todo find better seed |  | ||||||
|     randomSeed(millis()); |  | ||||||
| #endif |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void WebSocketsClient::begin(String host, uint16_t port, String url) { |  | ||||||
|     begin(host.c_str(), port, url.c_str()); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) |  | ||||||
| void WebSocketsClient::beginSSL(const char *host, uint16_t port, const char * url, const char * fingerprint) { |  | ||||||
|     begin(host, port, url); |  | ||||||
|     _client.isSSL = true; |  | ||||||
|     _fingerprint = fingerprint; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void WebSocketsClient::beginSSL(String host, uint16_t port, String url, String fingerprint) { |  | ||||||
|     beginSSL(host.c_str(), port, url.c_str(), fingerprint.c_str()); |  | ||||||
| } |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * called in arduino loop |  | ||||||
|  */ |  | ||||||
| void WebSocketsClient::loop(void) { |  | ||||||
|     if(!clientIsConnected(&_client)) { |  | ||||||
|  |  | ||||||
| #if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) |  | ||||||
|         if(_client.isSSL) { |  | ||||||
|             DEBUG_WEBSOCKETS("[WS-Client] connect wss...\n"); |  | ||||||
|             if(_client.ssl) { |  | ||||||
|                 delete _client.ssl; |  | ||||||
|                 _client.ssl = NULL; |  | ||||||
|                 _client.tcp = NULL; |  | ||||||
|             } |  | ||||||
|             _client.ssl = new WiFiClientSecure(); |  | ||||||
|             _client.tcp = _client.ssl; |  | ||||||
|         } else { |  | ||||||
|             DEBUG_WEBSOCKETS("[WS-Client] connect ws...\n"); |  | ||||||
|             if(_client.tcp) { |  | ||||||
|                 delete _client.tcp; |  | ||||||
|                 _client.tcp = NULL; |  | ||||||
|             } |  | ||||||
|             _client.tcp = new WiFiClient(); |  | ||||||
|         } |  | ||||||
| #else |  | ||||||
|         _client.tcp = new WEBSOCKETS_NETWORK_CLASS(); |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|         if(!_client.tcp) { |  | ||||||
|             DEBUG_WEBSOCKETS("[WS-Client] creating Network class failed!"); |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if(_client.tcp->connect(_host.c_str(), _port)) { |  | ||||||
|             DEBUG_WEBSOCKETS("[WS-Client] connected to %s:%u.\n"); |  | ||||||
| 	//DEBUG_WEBSOCKETS(_host.c_str()); |  | ||||||
| 	//DEBUG_WEBSOCKETS(_port); |  | ||||||
|  |  | ||||||
|             _client.status = WSC_HEADER; |  | ||||||
|  |  | ||||||
|             // set Timeout for readBytesUntil and readStringUntil |  | ||||||
|             _client.tcp->setTimeout(WEBSOCKETS_TCP_TIMEOUT); |  | ||||||
|  |  | ||||||
| #if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) |  | ||||||
|             _client.tcp->setNoDelay(true); |  | ||||||
|  |  | ||||||
|             if(_client.isSSL && _fingerprint.length()) { |  | ||||||
|                 if(!_client.ssl->verify(_fingerprint.c_str(), _host.c_str())) { |  | ||||||
|                     DEBUG_WEBSOCKETS("[WS-Client] certificate mismatch\n"); |  | ||||||
|                     WebSockets::clientDisconnect(&_client, 1000); |  | ||||||
|                     return; |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|             // send Header to Server |  | ||||||
|             sendHeader(&_client); |  | ||||||
|  |  | ||||||
|         } else { |  | ||||||
|             DEBUG_WEBSOCKETS("[WS-Client] connection to %s:%u Faild\n"); |  | ||||||
| 	///EBUG_WEBSOCKETS(_host.c_str()); |  | ||||||
| 	//DEBUG_WEBSOCKETS(_port); |  | ||||||
|             delay(10); //some litle delay to not flood the server |  | ||||||
|         } |  | ||||||
|     } else { |  | ||||||
|         handleClientData(); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * set callback function |  | ||||||
|  * @param cbEvent WebSocketServerEvent |  | ||||||
|  */ |  | ||||||
| void WebSocketsClient::onEvent(WebSocketClientEvent cbEvent) { |  | ||||||
|     _cbEvent = cbEvent; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * send text data to client |  | ||||||
|  * @param num uint8_t client id |  | ||||||
|  * @param payload uint8_t * |  | ||||||
|  * @param length size_t |  | ||||||
|  * @param headerToPayload bool  (see sendFrame for more details) |  | ||||||
|  */ |  | ||||||
| void WebSocketsClient::sendTXT(uint8_t * payload, size_t length, bool headerToPayload) { |  | ||||||
|     if(length == 0) { |  | ||||||
|         length = strlen((const char *) payload); |  | ||||||
|     } |  | ||||||
|     if(clientIsConnected(&_client)) { |  | ||||||
|         sendFrame(&_client, WSop_text, payload, length, true, true, headerToPayload); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void WebSocketsClient::sendTXT(const uint8_t * payload, size_t length) { |  | ||||||
|     sendTXT((uint8_t *) payload, length); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void WebSocketsClient::sendTXT(char * payload, size_t length, bool headerToPayload) { |  | ||||||
|     sendTXT((uint8_t *) payload, length, headerToPayload); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void WebSocketsClient::sendTXT(const char * payload, size_t length) { |  | ||||||
|     sendTXT((uint8_t *) payload, length); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void WebSocketsClient::sendTXT(String payload) { |  | ||||||
|     sendTXT((uint8_t *) payload.c_str(), payload.length()); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * send binary data to client |  | ||||||
|  * @param num uint8_t client id |  | ||||||
|  * @param payload uint8_t * |  | ||||||
|  * @param length size_t |  | ||||||
|  * @param headerToPayload bool  (see sendFrame for more details) |  | ||||||
|  */ |  | ||||||
| void WebSocketsClient::sendBIN(uint8_t * payload, size_t length, bool headerToPayload) { |  | ||||||
|     if(clientIsConnected(&_client)) { |  | ||||||
|         sendFrame(&_client, WSop_binary, payload, length, true, true, headerToPayload); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void WebSocketsClient::sendBIN(const uint8_t * payload, size_t length) { |  | ||||||
|     sendBIN((uint8_t *) payload, length); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * disconnect one client |  | ||||||
|  * @param num uint8_t client id |  | ||||||
|  */ |  | ||||||
| void WebSocketsClient::disconnect(void) { |  | ||||||
|     if(clientIsConnected(&_client)) { |  | ||||||
|         WebSockets::clientDisconnect(&_client, 1000); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| //################################################################################# |  | ||||||
| //################################################################################# |  | ||||||
| //################################################################################# |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * |  | ||||||
|  * @param client WSclient_t *  ptr to the client struct |  | ||||||
|  * @param opcode WSopcode_t |  | ||||||
|  * @param payload  uint8_t * |  | ||||||
|  * @param lenght size_t |  | ||||||
|  */ |  | ||||||
| void WebSocketsClient::messageRecived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t lenght) { |  | ||||||
|     WStype_t type = WStype_ERROR; |  | ||||||
|  |  | ||||||
|     switch(opcode) { |  | ||||||
|         case WSop_text: |  | ||||||
|             type = WStype_TEXT; |  | ||||||
|             break; |  | ||||||
|         case WSop_binary: |  | ||||||
|             type = WStype_BIN; |  | ||||||
|             break; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     runCbEvent(type, payload, lenght); |  | ||||||
|  |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Disconnect an client |  | ||||||
|  * @param client WSclient_t *  ptr to the client struct |  | ||||||
|  */ |  | ||||||
| void WebSocketsClient::clientDisconnect(WSclient_t * client) { |  | ||||||
|  |  | ||||||
| #if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) |  | ||||||
|     if(client->isSSL && client->ssl) { |  | ||||||
|         if(client->ssl->connected()) { |  | ||||||
|             client->ssl->flush(); |  | ||||||
|             client->ssl->stop(); |  | ||||||
|         } |  | ||||||
|         delete client->ssl; |  | ||||||
|         client->ssl = NULL; |  | ||||||
|         client->tcp = NULL; |  | ||||||
|     } |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|     if(client->tcp) { |  | ||||||
|         if(client->tcp->connected()) { |  | ||||||
|             client->tcp->flush(); |  | ||||||
|             client->tcp->stop(); |  | ||||||
|         } |  | ||||||
|         delete client->tcp; |  | ||||||
|         client->tcp = NULL; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     client->cCode = 0; |  | ||||||
|     client->cKey = ""; |  | ||||||
|     client->cAccept = ""; |  | ||||||
|     client->cProtocol = ""; |  | ||||||
|     client->cVersion = 0; |  | ||||||
|     client->cIsUpgrade = false; |  | ||||||
|     client->cIsWebsocket = false; |  | ||||||
|  |  | ||||||
|     client->status = WSC_NOT_CONNECTED; |  | ||||||
|  |  | ||||||
|     DEBUG_WEBSOCKETS("[WS-Client] client disconnected.\n"); |  | ||||||
|  |  | ||||||
|     runCbEvent(WStype_DISCONNECTED, NULL, 0); |  | ||||||
|  |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * get client state |  | ||||||
|  * @param client WSclient_t *  ptr to the client struct |  | ||||||
|  * @return true = conneted |  | ||||||
|  */ |  | ||||||
| bool WebSocketsClient::clientIsConnected(WSclient_t * client) { |  | ||||||
|  |  | ||||||
|     if(!client->tcp) { |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if(client->tcp->connected()) { |  | ||||||
|         if(client->status != WSC_NOT_CONNECTED) { |  | ||||||
|             return true; |  | ||||||
|         } |  | ||||||
|     } else { |  | ||||||
|         // client lost |  | ||||||
|         if(client->status != WSC_NOT_CONNECTED) { |  | ||||||
|             DEBUG_WEBSOCKETS("[WS-Client] connection lost.\n"); |  | ||||||
|             // do cleanup |  | ||||||
|             clientDisconnect(client); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if(client->tcp) { |  | ||||||
|         // do cleanup |  | ||||||
|         clientDisconnect(client); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return false; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Handel incomming data from Client |  | ||||||
|  */ |  | ||||||
| void WebSocketsClient::handleClientData(void) { |  | ||||||
|     int len = _client.tcp->available(); |  | ||||||
|     if(len > 0) { |  | ||||||
|         switch(_client.status) { |  | ||||||
|             case WSC_HEADER: |  | ||||||
|                 handleHeader(&_client); |  | ||||||
|                 break; |  | ||||||
|             case WSC_CONNECTED: |  | ||||||
|                 WebSockets::handleWebsocket(&_client); |  | ||||||
|                 break; |  | ||||||
|             default: |  | ||||||
|                 WebSockets::clientDisconnect(&_client, 1002); |  | ||||||
|                 break; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| #ifdef ESP8266 |  | ||||||
|     delay(0); |  | ||||||
| #endif |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * send the WebSocket header to Server |  | ||||||
|  * @param client WSclient_t *  ptr to the client struct |  | ||||||
|  */ |  | ||||||
| void WebSocketsClient::sendHeader(WSclient_t * client) { |  | ||||||
|  |  | ||||||
|     DEBUG_WEBSOCKETS("[WS-Client][sendHeader] sending header...\n"); |  | ||||||
|  |  | ||||||
|     uint8_t randomKey[16] = { 0 }; |  | ||||||
|  |  | ||||||
|     for(uint8_t i = 0; i < sizeof(randomKey); i++) { |  | ||||||
|         randomKey[i] = random(0xFF); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     client->cKey = base64_encode(&randomKey[0], 16); |  | ||||||
|  |  | ||||||
| #ifndef NODEBUG_WEBSOCKETS |  | ||||||
|     unsigned long start = micros(); |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|     String handshake =  "GET " + client->cUrl + " HTTP/1.1\r\n" |  | ||||||
|                         "Host: " + _host + "\r\n" |  | ||||||
|                         "Upgrade: websocket\r\n" |  | ||||||
|                         "Connection: Upgrade\r\n" |  | ||||||
|                         "User-Agent: arduino-WebSocket-Client\r\n" |  | ||||||
|                         "Sec-WebSocket-Version: 13\r\n" |  | ||||||
|                         "Sec-WebSocket-Protocol: arduino\r\n" |  | ||||||
|                         "Sec-WebSocket-Key: " + client->cKey + "\r\n"; |  | ||||||
|  |  | ||||||
|     if(client->cExtensions.length() > 0) { |  | ||||||
|         handshake += "Sec-WebSocket-Extensions: " + client->cExtensions + "\r\n"; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     handshake += "\r\n"; |  | ||||||
|  |  | ||||||
|     client->tcp->write(handshake.c_str(), handshake.length()); |  | ||||||
|  |  | ||||||
|     DEBUG_WEBSOCKETS("[WS-Client][sendHeader] sending header... Done (%uus).\n"); |  | ||||||
| 	//DEBUG_WEBSOCKETS((micros() - start)); |  | ||||||
|  |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * handle the WebSocket header reading |  | ||||||
|  * @param client WSclient_t *  ptr to the client struct |  | ||||||
|  */ |  | ||||||
| void WebSocketsClient::handleHeader(WSclient_t * client) { |  | ||||||
|  |  | ||||||
|     String headerLine = client->tcp->readStringUntil('\n'); |  | ||||||
|     headerLine.trim(); // remove \r |  | ||||||
|  |  | ||||||
|     if(headerLine.length() > 0) { |  | ||||||
|         DEBUG_WEBSOCKETS("[WS-Client][handleHeader] RX: %s\n"); |  | ||||||
| 	DEBUG_WEBSOCKETS(headerLine.c_str()); |  | ||||||
|  |  | ||||||
|         if(headerLine.startsWith("HTTP/1.")) { |  | ||||||
|             // "HTTP/1.1 101 Switching Protocols" |  | ||||||
|             client->cCode = headerLine.substring(9, headerLine.indexOf(' ', 9)).toInt(); |  | ||||||
|         } else if(headerLine.indexOf(':')) { |  | ||||||
|             String headerName = headerLine.substring(0, headerLine.indexOf(':')); |  | ||||||
|             String headerValue = headerLine.substring(headerLine.indexOf(':') + 2); |  | ||||||
|  |  | ||||||
|             if(headerName.equalsIgnoreCase("Connection")) { |  | ||||||
|                 if(headerValue.indexOf("Upgrade") >= 0) { |  | ||||||
|                     client->cIsUpgrade = true; |  | ||||||
|                 } |  | ||||||
|             } else if(headerName.equalsIgnoreCase("Upgrade")) { |  | ||||||
|                 if(headerValue.equalsIgnoreCase("websocket")) { |  | ||||||
|                     client->cIsWebsocket = true; |  | ||||||
|                 } |  | ||||||
|             } else if(headerName.equalsIgnoreCase("Sec-WebSocket-Accept")) { |  | ||||||
|                 client->cAccept = headerValue; |  | ||||||
|                 client->cAccept.trim(); // see rfc6455 |  | ||||||
|             } else if(headerName.equalsIgnoreCase("Sec-WebSocket-Protocol")) { |  | ||||||
|                 client->cProtocol = headerValue; |  | ||||||
|             } else if(headerName.equalsIgnoreCase("Sec-WebSocket-Extensions")) { |  | ||||||
|                 client->cExtensions = headerValue; |  | ||||||
|             } else if(headerName.equalsIgnoreCase("Sec-WebSocket-Version")) { |  | ||||||
|                 client->cVersion = headerValue.toInt(); |  | ||||||
|             } |  | ||||||
|         } else { |  | ||||||
|             DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Header error (%s)\n"); |  | ||||||
| 			DEBUG_WEBSOCKETS(headerLine.c_str()); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     } else { |  | ||||||
|         DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Header read fin.\n"); |  | ||||||
|         DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Client settings:\n"); |  | ||||||
|  |  | ||||||
|         DEBUG_WEBSOCKETS("[WS-Client][handleHeader]  - cURL: %s\n"); |  | ||||||
| 	//DEBUG_WEBSOCKETS(client->cUrl.c_str()); |  | ||||||
|         DEBUG_WEBSOCKETS("[WS-Client][handleHeader]  - cKey: %s\n"); |  | ||||||
| 	//DEBUG_WEBSOCKETS(client->cKey.c_str()); |  | ||||||
|  |  | ||||||
|         DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Server header:\n"); |  | ||||||
|         DEBUG_WEBSOCKETS("[WS-Client][handleHeader]  - cCode: %d\n"); |  | ||||||
| 	//DEBUG_WEBSOCKETS(client->cCode); |  | ||||||
|         DEBUG_WEBSOCKETS("[WS-Client][handleHeader]  - cIsUpgrade: %d\n"); |  | ||||||
| 	//DEBUG_WEBSOCKETS(client->cIsUpgrade); |  | ||||||
|         DEBUG_WEBSOCKETS("[WS-Client][handleHeader]  - cIsWebsocket: %d\n"); |  | ||||||
| 	//DEBUG_WEBSOCKETS(client->cIsWebsocket); |  | ||||||
|         DEBUG_WEBSOCKETS("[WS-Client][handleHeader]  - cAccept: %s\n"); |  | ||||||
| 	//DEBUG_WEBSOCKETS(client->cAccept.c_str()); |  | ||||||
|         DEBUG_WEBSOCKETS("[WS-Client][handleHeader]  - cProtocol: %s\n"); |  | ||||||
| 	//DEBUG_WEBSOCKETS(client->cProtocol.c_str()); |  | ||||||
|         DEBUG_WEBSOCKETS("[WS-Client][handleHeader]  - cExtensions: %s\n"); |  | ||||||
| 	//DEBUG_WEBSOCKETS(client->cExtensions.c_str()); |  | ||||||
|         DEBUG_WEBSOCKETS("[WS-Client][handleHeader]  - cVersion: %d\n"); |  | ||||||
| 	//DEBUG_WEBSOCKETS(client->cVersion); |  | ||||||
|  |  | ||||||
|         bool ok = (client->cIsUpgrade && client->cIsWebsocket); |  | ||||||
|  |  | ||||||
|         if(ok) { |  | ||||||
|             switch(client->cCode) { |  | ||||||
|                 case 101:  ///< Switching Protocols |  | ||||||
|  |  | ||||||
|                     break; |  | ||||||
|                 case 403: ///< Forbidden |  | ||||||
|                     // todo handle login |  | ||||||
|                 default:   ///< Server dont unterstand requrst |  | ||||||
|                     ok = false; |  | ||||||
|                     DEBUG_WEBSOCKETS("[WS-Client][handleHeader] serverCode is not 101 (%d)\n"); |  | ||||||
| 	//DEBUG_WEBSOCKETS(client->cCode); |  | ||||||
|                     clientDisconnect(client); |  | ||||||
|                     break; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if(ok) { |  | ||||||
|             if(client->cAccept.length() == 0) { |  | ||||||
|                 ok = false; |  | ||||||
|             } else { |  | ||||||
|                 // generate Sec-WebSocket-Accept key for check |  | ||||||
|                 String sKey = acceptKey(client->cKey); |  | ||||||
|                 if(sKey != client->cAccept) { |  | ||||||
|                     DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Sec-WebSocket-Accept is wrong\n"); |  | ||||||
|                     ok = false; |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if(ok) { |  | ||||||
|  |  | ||||||
|             DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Websocket connection init done.\n"); |  | ||||||
|  |  | ||||||
|             client->status = WSC_CONNECTED; |  | ||||||
|  |  | ||||||
|             runCbEvent(WStype_CONNECTED, (uint8_t *) client->cUrl.c_str(), client->cUrl.length()); |  | ||||||
|  |  | ||||||
|         } else { |  | ||||||
|             DEBUG_WEBSOCKETS("[WS-Client][handleHeader] no Websocket connection close.\n"); |  | ||||||
|             client->tcp->write("This is a webSocket client!"); |  | ||||||
|             clientDisconnect(client); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| @@ -1,98 +0,0 @@ | |||||||
| /** |  | ||||||
|  * @file WebSocketsClient.h |  | ||||||
|  * @date 20.05.2015 |  | ||||||
|  * @author Markus Sattler |  | ||||||
|  * |  | ||||||
|  * Copyright (c) 2015 Markus Sattler. All rights reserved. |  | ||||||
|  * This file is part of the WebSockets for Arduino. |  | ||||||
|  * |  | ||||||
|  * 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 St, Fifth Floor, Boston, MA  02110-1301  USA |  | ||||||
|  * |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #ifndef WEBSOCKETSCLIENT_H_ |  | ||||||
| #define WEBSOCKETSCLIENT_H_ |  | ||||||
|  |  | ||||||
| #include <Arduino.h> |  | ||||||
| #include "WebSockets.h" |  | ||||||
|  |  | ||||||
| class WebSocketsClient: private WebSockets { |  | ||||||
|     public: |  | ||||||
|  |  | ||||||
|         typedef void (*WebSocketClientEvent)(WStype_t type, uint8_t * payload, size_t length); |  | ||||||
|  |  | ||||||
|         WebSocketsClient(void); |  | ||||||
|         ~WebSocketsClient(void); |  | ||||||
|  |  | ||||||
|         void begin(const char *host, uint16_t port, const char * url = "/"); |  | ||||||
|         void begin(String host, uint16_t port, String url = "/"); |  | ||||||
|  |  | ||||||
| #if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) |  | ||||||
|         void beginSSL(const char *host, uint16_t port, const char * url = "/", const char * = ""); |  | ||||||
|         void beginSSL(String host, uint16_t port, String url = "/", String fingerprint = ""); |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|         void loop(void); |  | ||||||
|  |  | ||||||
|         void onEvent(WebSocketClientEvent cbEvent); |  | ||||||
|  |  | ||||||
|         void sendTXT(uint8_t * payload, size_t length = 0, bool headerToPayload = false); |  | ||||||
|         void sendTXT(const uint8_t * payload, size_t length = 0); |  | ||||||
|         void sendTXT(char * payload, size_t length = 0, bool headerToPayload = false); |  | ||||||
|         void sendTXT(const char * payload, size_t length = 0); |  | ||||||
|         void sendTXT(String payload); |  | ||||||
|  |  | ||||||
|         void sendBIN(uint8_t * payload, size_t length, bool headerToPayload = false); |  | ||||||
|         void sendBIN(const uint8_t * payload, size_t length); |  | ||||||
|  |  | ||||||
|         void disconnect(void); |  | ||||||
|  |  | ||||||
|     protected: |  | ||||||
|         String _host; |  | ||||||
|         uint16_t _port; |  | ||||||
|  |  | ||||||
| #if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) |  | ||||||
|         String _fingerprint; |  | ||||||
| #endif |  | ||||||
|         WSclient_t _client; |  | ||||||
|  |  | ||||||
|         WebSocketClientEvent _cbEvent; |  | ||||||
|  |  | ||||||
|         void messageRecived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length); |  | ||||||
|  |  | ||||||
|         void clientDisconnect(WSclient_t * client); |  | ||||||
|         bool clientIsConnected(WSclient_t * client); |  | ||||||
|  |  | ||||||
|         void handleNewClients(void); |  | ||||||
|         void handleClientData(void); |  | ||||||
|  |  | ||||||
|         void sendHeader(WSclient_t * client); |  | ||||||
|         void handleHeader(WSclient_t * client); |  | ||||||
|  |  | ||||||
|         /** |  | ||||||
|          * called for sending a Event to the app |  | ||||||
|          * @param type WStype_t |  | ||||||
|          * @param payload uint8_t * |  | ||||||
|          * @param length size_t |  | ||||||
|          */ |  | ||||||
|         virtual void runCbEvent(WStype_t type, uint8_t * payload, size_t length) { |  | ||||||
|             if(_cbEvent) { |  | ||||||
|                 _cbEvent(type, payload, length); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| #endif /* WEBSOCKETSCLIENT_H_ */ |  | ||||||
| @@ -1,714 +0,0 @@ | |||||||
| /** |  | ||||||
|  * @file WebSocketsServer.cpp |  | ||||||
|  * @date 20.05.2015 |  | ||||||
|  * @author Markus Sattler |  | ||||||
|  * |  | ||||||
|  * Copyright (c) 2015 Markus Sattler. All rights reserved. |  | ||||||
|  * This file is part of the WebSockets for Arduino. |  | ||||||
|  * |  | ||||||
|  * 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 St, Fifth Floor, Boston, MA  02110-1301  USA |  | ||||||
|  * |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #include "WebSockets.h" |  | ||||||
| #include "WebSocketsServer.h" |  | ||||||
|  |  | ||||||
| WebSocketsServer::WebSocketsServer(uint16_t port) { |  | ||||||
|     _port = port; |  | ||||||
|     _server = new WEBSOCKETS_NETWORK_SERVER_CLASS(port); |  | ||||||
|  |  | ||||||
|     _cbEvent = NULL; |  | ||||||
|  |  | ||||||
| } |  | ||||||
|  |  | ||||||
| WebSocketsServer::~WebSocketsServer() { |  | ||||||
|     // disconnect all clients |  | ||||||
|     disconnect(); |  | ||||||
|  |  | ||||||
|     // TODO how to close server? |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * calles to init the Websockets server |  | ||||||
|  */ |  | ||||||
| void WebSocketsServer::begin(void) { |  | ||||||
|     WSclient_t * client; |  | ||||||
|  |  | ||||||
|     // init client storage |  | ||||||
|     for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) { |  | ||||||
|         client = &_clients[i]; |  | ||||||
|  |  | ||||||
|         client->num = i; |  | ||||||
|         client->status = WSC_NOT_CONNECTED; |  | ||||||
|         client->tcp = NULL; |  | ||||||
| #if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) |  | ||||||
|         client->isSSL = false; |  | ||||||
|         client->ssl = NULL; |  | ||||||
| #endif |  | ||||||
|         client->cUrl = ""; |  | ||||||
|         client->cCode = 0; |  | ||||||
|         client->cKey = ""; |  | ||||||
|         client->cProtocol = ""; |  | ||||||
|         client->cVersion = 0; |  | ||||||
|         client->cIsUpgrade = false; |  | ||||||
|         client->cIsWebsocket = false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| #ifdef ESP8266 |  | ||||||
|     randomSeed(RANDOM_REG32); |  | ||||||
| #else |  | ||||||
|     // TODO find better seed |  | ||||||
|     randomSeed(millis()); |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|     _server->begin(); |  | ||||||
|  |  | ||||||
|     DEBUG_WEBSOCKETS("[WS-Server] Server Started.\n"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * called in arduino loop |  | ||||||
|  */ |  | ||||||
| void WebSocketsServer::loop(void) { |  | ||||||
|     handleNewClients(); |  | ||||||
|     handleClientData(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * set callback function |  | ||||||
|  * @param cbEvent WebSocketServerEvent |  | ||||||
|  */ |  | ||||||
| void WebSocketsServer::onEvent(WebSocketServerEvent cbEvent) { |  | ||||||
|     _cbEvent = cbEvent; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * send text data to client |  | ||||||
|  * @param num uint8_t client id |  | ||||||
|  * @param payload uint8_t * |  | ||||||
|  * @param length size_t |  | ||||||
|  * @param headerToPayload bool  (see sendFrame for more details) |  | ||||||
|  */ |  | ||||||
| void WebSocketsServer::sendTXT(uint8_t num, uint8_t * payload, size_t length, bool headerToPayload) { |  | ||||||
|     if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) { |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
|     if(length == 0) { |  | ||||||
|         length = strlen((const char *) payload); |  | ||||||
|     } |  | ||||||
|     WSclient_t * client = &_clients[num]; |  | ||||||
|     if(clientIsConnected(client)) { |  | ||||||
|         sendFrame(client, WSop_text, payload, length, false, true, headerToPayload); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void WebSocketsServer::sendTXT(uint8_t num, const uint8_t * payload, size_t length) { |  | ||||||
|     sendTXT(num, (uint8_t *) payload, length); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void WebSocketsServer::sendTXT(uint8_t num, char * payload, size_t length, bool headerToPayload) { |  | ||||||
|     sendTXT(num, (uint8_t *) payload, length, headerToPayload); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void WebSocketsServer::sendTXT(uint8_t num, const char * payload, size_t length) { |  | ||||||
|     sendTXT(num, (uint8_t *) payload, length); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void WebSocketsServer::sendTXT(uint8_t num, String payload) { |  | ||||||
|     sendTXT(num, (uint8_t *) payload.c_str(), payload.length()); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * send text data to client all |  | ||||||
|  * @param payload uint8_t * |  | ||||||
|  * @param length size_t |  | ||||||
|  * @param headerToPayload bool  (see sendFrame for more details) |  | ||||||
|  */ |  | ||||||
| void WebSocketsServer::broadcastTXT(uint8_t * payload, size_t length, bool headerToPayload) { |  | ||||||
|     WSclient_t * client; |  | ||||||
|     if(length == 0) { |  | ||||||
|         length = strlen((const char *) payload); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) { |  | ||||||
|         client = &_clients[i]; |  | ||||||
|         if(clientIsConnected(client)) { |  | ||||||
|             sendFrame(client, WSop_text, payload, length, false, true, headerToPayload); |  | ||||||
|         } |  | ||||||
| #ifdef ESP8266 |  | ||||||
|         delay(0); |  | ||||||
| #endif |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void WebSocketsServer::broadcastTXT(const uint8_t * payload, size_t length) { |  | ||||||
|     broadcastTXT((uint8_t *) payload, length); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void WebSocketsServer::broadcastTXT(char * payload, size_t length, bool headerToPayload) { |  | ||||||
|     broadcastTXT((uint8_t *) payload, length, headerToPayload); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void WebSocketsServer::broadcastTXT(const char * payload, size_t length) { |  | ||||||
|     broadcastTXT((uint8_t *) payload, length); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void WebSocketsServer::broadcastTXT(String payload) { |  | ||||||
|     broadcastTXT((uint8_t *) payload.c_str(), payload.length()); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * send binary data to client |  | ||||||
|  * @param num uint8_t client id |  | ||||||
|  * @param payload uint8_t * |  | ||||||
|  * @param length size_t |  | ||||||
|  * @param headerToPayload bool  (see sendFrame for more details) |  | ||||||
|  */ |  | ||||||
| void WebSocketsServer::sendBIN(uint8_t num, uint8_t * payload, size_t length, bool headerToPayload) { |  | ||||||
|     if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) { |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
|     WSclient_t * client = &_clients[num]; |  | ||||||
|     if(clientIsConnected(client)) { |  | ||||||
|         sendFrame(client, WSop_binary, payload, length, false, true, headerToPayload); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void WebSocketsServer::sendBIN(uint8_t num, const uint8_t * payload, size_t length) { |  | ||||||
|     sendBIN(num, (uint8_t *) payload, length); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * send binary data to client all |  | ||||||
|  * @param payload uint8_t * |  | ||||||
|  * @param length size_t |  | ||||||
|  * @param headerToPayload bool  (see sendFrame for more details) |  | ||||||
|  */ |  | ||||||
| void WebSocketsServer::broadcastBIN(uint8_t * payload, size_t length, bool headerToPayload) { |  | ||||||
|     WSclient_t * client; |  | ||||||
|     for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) { |  | ||||||
|         client = &_clients[i]; |  | ||||||
|         if(clientIsConnected(client)) { |  | ||||||
|             sendFrame(client, WSop_binary, payload, length, false, true, headerToPayload); |  | ||||||
|         } |  | ||||||
| #ifdef ESP8266 |  | ||||||
|         delay(0); |  | ||||||
| #endif |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void WebSocketsServer::broadcastBIN(const uint8_t * payload, size_t length) { |  | ||||||
|     broadcastBIN((uint8_t *) payload, length); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * sends a WS ping to Client |  | ||||||
|  * @param num uint8_t client id |  | ||||||
|  * @param payload uint8_t * |  | ||||||
|  * @param length size_t |  | ||||||
|  * @return true if ping is send out |  | ||||||
|  */ |  | ||||||
| bool WebSocketsServer::sendPing(uint8_t num, uint8_t * payload, size_t length) { |  | ||||||
|     if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) { |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|     WSclient_t * client; |  | ||||||
|     client = &_clients[num]; |  | ||||||
|     if(clientIsConnected(client)) { |  | ||||||
|         return sendFrame(client, WSop_ping, payload, length); |  | ||||||
|     } |  | ||||||
|     return false; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| bool WebSocketsServer::sendPing(uint8_t num, String & payload) { |  | ||||||
|     return sendPing(num, (uint8_t *) payload.c_str(), payload.length()); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  *  sends a WS ping to all Client |  | ||||||
|  * @param payload uint8_t * |  | ||||||
|  * @param length size_t |  | ||||||
|  * @return true if ping is send out |  | ||||||
|  */ |  | ||||||
| bool WebSocketsServer::broadcastPing(uint8_t * payload, size_t length) { |  | ||||||
|     WSclient_t * client; |  | ||||||
|     bool ret = true; |  | ||||||
|     for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) { |  | ||||||
|         client = &_clients[i]; |  | ||||||
|         if(clientIsConnected(client)) { |  | ||||||
|             if(!sendFrame(client, WSop_ping, payload, length)) { |  | ||||||
|                 ret = false; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| #if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) |  | ||||||
|         delay(0); |  | ||||||
| #endif |  | ||||||
|     } |  | ||||||
|     return ret; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| bool WebSocketsServer::broadcastPing(String & payload) { |  | ||||||
|     return broadcastPing((uint8_t *) payload.c_str(), payload.length()); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| bool WebSocketsServer::clientConnected(uint8_t num) { |  | ||||||
|     WSclient_t * client; |  | ||||||
|     client = &_clients[num]; |  | ||||||
|     return clientIsConnected(client); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * disconnect all clients |  | ||||||
|  */ |  | ||||||
| void WebSocketsServer::disconnect(void) { |  | ||||||
|     WSclient_t * client; |  | ||||||
|     for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) { |  | ||||||
|         client = &_clients[i]; |  | ||||||
|         if(clientIsConnected(client)) { |  | ||||||
|             WebSockets::clientDisconnect(client, 1000); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * disconnect one client |  | ||||||
|  * @param num uint8_t client id |  | ||||||
|  */ |  | ||||||
| void WebSocketsServer::disconnect(uint8_t num) { |  | ||||||
|     if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) { |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
|     WSclient_t * client = &_clients[num]; |  | ||||||
|     if(clientIsConnected(client)) { |  | ||||||
|         WebSockets::clientDisconnect(client, 1000); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) |  | ||||||
| /** |  | ||||||
|  * get an IP for a client |  | ||||||
|  * @param num uint8_t client id |  | ||||||
|  * @return IPAddress |  | ||||||
|  */ |  | ||||||
| IPAddress WebSocketsServer::remoteIP(uint8_t num) { |  | ||||||
|     if(num < WEBSOCKETS_SERVER_CLIENT_MAX) { |  | ||||||
|         WSclient_t * client = &_clients[num]; |  | ||||||
|         if(clientIsConnected(client)) { |  | ||||||
|             return client->tcp->remoteIP(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return IPAddress(); |  | ||||||
| } |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| //################################################################################# |  | ||||||
| //################################################################################# |  | ||||||
| //################################################################################# |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * |  | ||||||
|  * @param client WSclient_t *  ptr to the client struct |  | ||||||
|  * @param opcode WSopcode_t |  | ||||||
|  * @param payload  uint8_t * |  | ||||||
|  * @param lenght size_t |  | ||||||
|  */ |  | ||||||
| void WebSocketsServer::messageRecived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t lenght) { |  | ||||||
|     WStype_t type = WStype_ERROR; |  | ||||||
|  |  | ||||||
|     switch(opcode) { |  | ||||||
|         case WSop_text: |  | ||||||
|             type = WStype_TEXT; |  | ||||||
|             break; |  | ||||||
|         case WSop_binary: |  | ||||||
|             type = WStype_BIN; |  | ||||||
|             break; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     runCbEvent(client->num, type, payload, lenght); |  | ||||||
|  |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Disconnect an client |  | ||||||
|  * @param client WSclient_t *  ptr to the client struct |  | ||||||
|  */ |  | ||||||
| void WebSocketsServer::clientDisconnect(WSclient_t * client) { |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) |  | ||||||
|     if(client->isSSL && client->ssl) { |  | ||||||
|         if(client->ssl->connected()) { |  | ||||||
|             client->ssl->flush(); |  | ||||||
|             client->ssl->stop(); |  | ||||||
|         } |  | ||||||
|         delete client->ssl; |  | ||||||
|         client->ssl = NULL; |  | ||||||
|         client->tcp = NULL; |  | ||||||
|     } |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|     if(client->tcp) { |  | ||||||
|         if(client->tcp->connected()) { |  | ||||||
|             client->tcp->flush(); |  | ||||||
|             client->tcp->stop(); |  | ||||||
|         } |  | ||||||
|         delete client->tcp; |  | ||||||
|         client->tcp = NULL; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     client->cUrl = ""; |  | ||||||
|     client->cKey = ""; |  | ||||||
|     client->cProtocol = ""; |  | ||||||
|     client->cVersion = 0; |  | ||||||
|     client->cIsUpgrade = false; |  | ||||||
|     client->cIsWebsocket = false; |  | ||||||
|  |  | ||||||
|     client->status = WSC_NOT_CONNECTED; |  | ||||||
|  |  | ||||||
| 	DEBUG_WEBSOCKETS("[WS-Server][");DEBUG_WEBSOCKETS(client->num);DEBUG_WEBSOCKETS("]"); |  | ||||||
|     DEBUG_WEBSOCKETS(" client disconnected.\n"); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     runCbEvent(client->num, WStype_DISCONNECTED, NULL, 0); |  | ||||||
|  |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * get client state |  | ||||||
|  * @param client WSclient_t *  ptr to the client struct |  | ||||||
|  * @return true = conneted |  | ||||||
|  */ |  | ||||||
| bool WebSocketsServer::clientIsConnected(WSclient_t * client) { |  | ||||||
|  |  | ||||||
|     if(!client->tcp) { |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if(client->tcp->connected()) { |  | ||||||
|         if(client->status != WSC_NOT_CONNECTED) { |  | ||||||
|             return true; |  | ||||||
|         } |  | ||||||
|     } else { |  | ||||||
|         // client lost |  | ||||||
| 		DEBUG_WEBSOCKETS(client->status); |  | ||||||
|         if(client->status != WSC_NOT_CONNECTED) { |  | ||||||
| 			DEBUG_WEBSOCKETS("[WS-Server][");DEBUG_WEBSOCKETS(client->num);DEBUG_WEBSOCKETS("]"); |  | ||||||
| 			DEBUG_WEBSOCKETS(" client connection lost.\n"); |  | ||||||
|  |  | ||||||
|             // do cleanup |  | ||||||
|             clientDisconnect(client); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if(client->tcp) { |  | ||||||
|         // do cleanup |  | ||||||
|         clientDisconnect(client); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return false; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #if (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266) |  | ||||||
|   bool WebSocketsServer::clientExists(const WEBSOCKETS_NETWORK_CLASS &c) |  | ||||||
|   { |  | ||||||
| 	WSclient_t * client; |  | ||||||
|     for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) { |  | ||||||
| 	  client = &_clients[i]; |  | ||||||
|       if (clientIsConnected(client) && (*client->tcp == c)) |  | ||||||
|         return true; |  | ||||||
| 	} |  | ||||||
|     return false; |  | ||||||
|   } |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Handle incomming Connection Request |  | ||||||
|  */ |  | ||||||
| void WebSocketsServer::handleNewClients(void) { |  | ||||||
|     WSclient_t * client; |  | ||||||
| #if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) |  | ||||||
|     while(_server->hasClient()) { |  | ||||||
| #endif                          |  | ||||||
|         bool ok = false; |  | ||||||
|         // search free list entry for client |  | ||||||
|         for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) { |  | ||||||
|             client = &_clients[i]; |  | ||||||
|  |  | ||||||
|             // state is not connected or tcp connection is lost |  | ||||||
|             if(!clientIsConnected(client)) { |  | ||||||
| #if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) |  | ||||||
|                 // store new connection |  | ||||||
|                 client->tcp = new WEBSOCKETS_NETWORK_CLASS(_server->available()); |  | ||||||
| #else |  | ||||||
| 				WEBSOCKETS_NETWORK_CLASS newClient = _server->available(); |  | ||||||
| 				if (newClient && !clientExists(newClient)) { |  | ||||||
| 					client->tcp = new WEBSOCKETS_NETWORK_CLASS(newClient); |  | ||||||
| 				} else { |  | ||||||
| 					return; |  | ||||||
| 				} |  | ||||||
| 				//if (!client->tcp->connected() || !client->tcp->available()) { |  | ||||||
| 				//	DEBUG_WEBSOCKETS("[WS-Client] Not Connected!\n"); |  | ||||||
| 				//	return; |  | ||||||
| 				//} |  | ||||||
| #endif |  | ||||||
|                 if(!client->tcp) { |  | ||||||
|                     DEBUG_WEBSOCKETS("[WS-Server] creating Network class failed!"); |  | ||||||
|                     return; |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
| #if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) |  | ||||||
|                 client->isSSL = false; |  | ||||||
|                 client->tcp->setNoDelay(true); |  | ||||||
| #endif |  | ||||||
|                 // set Timeout for readBytesUntil and readStringUntil |  | ||||||
|                 client->tcp->setTimeout(WEBSOCKETS_TCP_TIMEOUT); |  | ||||||
|                 client->status = WSC_HEADER; |  | ||||||
| #if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) |  | ||||||
|                 IPAddress ip = client->tcp->remoteIP(); |  | ||||||
|                 DEBUG_WEBSOCKETS("[WS-Server][");DEBUG_WEBSOCKETS(client->num);DEBUG_WEBSOCKETS("]"); |  | ||||||
| 				DEBUG_WEBSOCKETS(" new client from %d.%d.%d.%d\n"); |  | ||||||
|  |  | ||||||
| 				//DEBUG_WEBSOCKETS(ip[0]); |  | ||||||
| 				//DEBUG_WEBSOCKETS(ip[1]); |  | ||||||
| 				//DEBUG_WEBSOCKETS(ip[2]); |  | ||||||
| 				//DEBUG_WEBSOCKETS(ip[3]); |  | ||||||
| #else |  | ||||||
|                 DEBUG_WEBSOCKETS("[WS-Server][");DEBUG_WEBSOCKETS(client->num);DEBUG_WEBSOCKETS("]"); |  | ||||||
| 				DEBUG_WEBSOCKETS(" new client\n"); |  | ||||||
| #endif |  | ||||||
|                 ok = true; |  | ||||||
|                 break; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if(!ok) { |  | ||||||
|             // no free space to handle client |  | ||||||
|             WEBSOCKETS_NETWORK_CLASS tcpClient = _server->available(); |  | ||||||
| #if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) |  | ||||||
|             IPAddress ip = client->tcp->remoteIP(); |  | ||||||
|             DEBUG_WEBSOCKETS("[WS-Server] no free space new client from %d.%d.%d.%d\n"); |  | ||||||
| 			//DEBUG_WEBSOCKETS(ip[0]); |  | ||||||
| 			//DEBUG_WEBSOCKETS(ip[1]); |  | ||||||
| 			//DEBUG_WEBSOCKETS(ip[2]); |  | ||||||
| 			//DEBUG_WEBSOCKETS(ip[3]); |  | ||||||
| #else |  | ||||||
|             DEBUG_WEBSOCKETS("[WS-Server] no free space new client\n"); |  | ||||||
| #endif |  | ||||||
|             tcpClient.stop(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
| #ifdef ESP8266 |  | ||||||
|         delay(0); |  | ||||||
| #endif |  | ||||||
| #if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) |  | ||||||
|     } |  | ||||||
| #endif |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Handel incomming data from Client |  | ||||||
|  */ |  | ||||||
| void WebSocketsServer::handleClientData(void) { |  | ||||||
|  |  | ||||||
|     WSclient_t * client; |  | ||||||
|     for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) { |  | ||||||
|         client = &_clients[i]; |  | ||||||
|         if(clientIsConnected(client)) { |  | ||||||
|             int len = client->tcp->available(); |  | ||||||
|             if(len > 0) { |  | ||||||
|                 switch(client->status) { |  | ||||||
|                     case WSC_HEADER: |  | ||||||
|                         handleHeader(client); |  | ||||||
|                         break; |  | ||||||
|                     case WSC_CONNECTED: |  | ||||||
|                         WebSockets::handleWebsocket(client); |  | ||||||
|                         break; |  | ||||||
|                     default: |  | ||||||
|                         WebSockets::clientDisconnect(client, 1002); |  | ||||||
|                         break; |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| #ifdef ESP8266 |  | ||||||
|         delay(0); |  | ||||||
| #endif |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * handle the WebSocket header reading |  | ||||||
|  * @param client WSclient_t *  ptr to the client struct |  | ||||||
|  */ |  | ||||||
| void WebSocketsServer::handleHeader(WSclient_t * client) { |  | ||||||
|  |  | ||||||
|     String headerLine = client->tcp->readStringUntil('\n'); |  | ||||||
|     headerLine.trim(); // remove \r |  | ||||||
|  |  | ||||||
|     if(headerLine.length() > 0) { |  | ||||||
|         DEBUG_WEBSOCKETS("[WS-Server][");DEBUG_WEBSOCKETS(client->num);DEBUG_WEBSOCKETS("]"); |  | ||||||
|         DEBUG_WEBSOCKETS("[handleHeader] RX: "); |  | ||||||
| 		DEBUG_WEBSOCKETS(headerLine.c_str()); |  | ||||||
| 		DEBUG_WEBSOCKETS("\n"); |  | ||||||
|  |  | ||||||
|         // websocket request starts allways with GET see rfc6455 |  | ||||||
|         if(headerLine.startsWith("GET ")) { |  | ||||||
|             // cut URL out |  | ||||||
|             client->cUrl = headerLine.substring(4, headerLine.indexOf(' ', 4)); |  | ||||||
|         } else if(headerLine.indexOf(':')) { |  | ||||||
|             String headerName = headerLine.substring(0, headerLine.indexOf(':')); |  | ||||||
|             String headerValue = headerLine.substring(headerLine.indexOf(':') + 2); |  | ||||||
|             //Serial.print(headerName);  Serial.print(":");  Serial.println(headerValue); |  | ||||||
|  |  | ||||||
|             if(headerName.equalsIgnoreCase("Connection")) { |  | ||||||
|                 if(headerValue.indexOf("Upgrade") >= 0) { |  | ||||||
|                     client->cIsUpgrade = true; |  | ||||||
|                 } |  | ||||||
|             } else if(headerName.equalsIgnoreCase("Upgrade")) { |  | ||||||
|                 if(headerValue.equalsIgnoreCase("websocket")) { |  | ||||||
|                     client->cIsWebsocket = true; |  | ||||||
|                 } |  | ||||||
|             } else if(headerName.equalsIgnoreCase("Sec-WebSocket-Version")) { |  | ||||||
|                 client->cVersion = headerValue.toInt(); |  | ||||||
|             } else if(headerName.equalsIgnoreCase("Sec-WebSocket-Key")) { |  | ||||||
|                 client->cKey = headerValue; |  | ||||||
|                 client->cKey.trim(); // see rfc6455 |  | ||||||
|             } else if(headerName.equalsIgnoreCase("Sec-WebSocket-Protocol")) { |  | ||||||
|                 client->cProtocol = headerValue; |  | ||||||
|             } else if(headerName.equalsIgnoreCase("Sec-WebSocket-Extensions")) { |  | ||||||
|                 client->cExtensions = headerValue; |  | ||||||
|             } |  | ||||||
|         } else { |  | ||||||
|             Serial.print("[WS-Client][handleHeader] Header error (%s)\n"); |  | ||||||
| 			Serial.print(headerLine.c_str()); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     } else { |  | ||||||
| 		DEBUG_WEBSOCKETS("[WS-Server][");DEBUG_WEBSOCKETS(client->num);DEBUG_WEBSOCKETS("]"); |  | ||||||
|         DEBUG_WEBSOCKETS("[handleHeader] Header read fin.\n"); |  | ||||||
| 	 |  | ||||||
| 		DEBUG_WEBSOCKETS("[WS-Server][");DEBUG_WEBSOCKETS(client->num);DEBUG_WEBSOCKETS("]"); |  | ||||||
|         DEBUG_WEBSOCKETS("[handleHeader]  - cURL: "); |  | ||||||
| 		DEBUG_WEBSOCKETS(client->cUrl.c_str()); |  | ||||||
| 		DEBUG_WEBSOCKETS("\n"); |  | ||||||
|  |  | ||||||
|         DEBUG_WEBSOCKETS("[WS-Server][");DEBUG_WEBSOCKETS(client->num);DEBUG_WEBSOCKETS("]"); |  | ||||||
|         DEBUG_WEBSOCKETS("[handleHeader]  - cIsUpgrade: "); |  | ||||||
| 		DEBUG_WEBSOCKETS(client->cIsUpgrade); |  | ||||||
| 		DEBUG_WEBSOCKETS("\n"); |  | ||||||
|  |  | ||||||
|         DEBUG_WEBSOCKETS("[WS-Server][");DEBUG_WEBSOCKETS(client->num);DEBUG_WEBSOCKETS("]"); |  | ||||||
|         DEBUG_WEBSOCKETS("[handleHeader]  - cIsWebsocket: "); |  | ||||||
| 		DEBUG_WEBSOCKETS(client->cIsWebsocket); |  | ||||||
| 		DEBUG_WEBSOCKETS("\n"); |  | ||||||
|  |  | ||||||
|         DEBUG_WEBSOCKETS("[WS-Server][");DEBUG_WEBSOCKETS(client->num);DEBUG_WEBSOCKETS("]"); |  | ||||||
|         DEBUG_WEBSOCKETS("[handleHeader]  - cKey: "); |  | ||||||
| 		DEBUG_WEBSOCKETS(client->cKey.c_str()); |  | ||||||
| 		DEBUG_WEBSOCKETS("\n"); |  | ||||||
|  |  | ||||||
|         DEBUG_WEBSOCKETS("[WS-Server][");DEBUG_WEBSOCKETS(client->num);DEBUG_WEBSOCKETS("]"); |  | ||||||
|         DEBUG_WEBSOCKETS("[handleHeader]  - cProtocol: "); |  | ||||||
| 		DEBUG_WEBSOCKETS(client->cProtocol.c_str()); |  | ||||||
| 		DEBUG_WEBSOCKETS("\n"); |  | ||||||
|  |  | ||||||
|         DEBUG_WEBSOCKETS("[WS-Server][");DEBUG_WEBSOCKETS(client->num);DEBUG_WEBSOCKETS("]"); |  | ||||||
|         DEBUG_WEBSOCKETS("[handleHeader]  - cExtensions: "); |  | ||||||
| 		DEBUG_WEBSOCKETS(client->cExtensions.c_str()); |  | ||||||
| 		DEBUG_WEBSOCKETS("\n"); |  | ||||||
|  |  | ||||||
|         DEBUG_WEBSOCKETS("[WS-Server][");DEBUG_WEBSOCKETS(client->num);DEBUG_WEBSOCKETS("]"); |  | ||||||
|         DEBUG_WEBSOCKETS("[handleHeader]  - cVersion: "); |  | ||||||
| 		DEBUG_WEBSOCKETS(client->cVersion); |  | ||||||
| 		DEBUG_WEBSOCKETS("\n\n"); |  | ||||||
|  |  | ||||||
|         bool ok = (client->cIsUpgrade && client->cIsWebsocket); |  | ||||||
|         Serial.println("here0"); |  | ||||||
|  |  | ||||||
| 		if (!client->cIsUpgrade) { |  | ||||||
| 			DEBUG_WEBSOCKETS("[WS-Server][");DEBUG_WEBSOCKETS(client->num);DEBUG_WEBSOCKETS("]"); |  | ||||||
| 			DEBUG_WEBSOCKETS("[handleHeader] Error! Not an Upgrade\n"); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if (!client->cIsWebsocket) { |  | ||||||
| 			DEBUG_WEBSOCKETS("[WS-Server][");DEBUG_WEBSOCKETS(client->num);DEBUG_WEBSOCKETS("]"); |  | ||||||
| 			DEBUG_WEBSOCKETS("[handleHeader] Error! Not a Websocket\n"); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
|         if(ok) { |  | ||||||
|             Serial.println("here1"); |  | ||||||
| 			DEBUG_WEBSOCKETS("[WS-Server][");DEBUG_WEBSOCKETS(client->num);DEBUG_WEBSOCKETS("]"); |  | ||||||
| 			DEBUG_WEBSOCKETS("[handleHeader] First ok test success.\n"); |  | ||||||
|  |  | ||||||
|             if(client->cUrl.length() == 0) { |  | ||||||
|                 Serial.println("here2"); |  | ||||||
|                 ok = false; |  | ||||||
|             } |  | ||||||
|             if(client->cKey.length() == 0) { |  | ||||||
|                 Serial.println("here3"); |  | ||||||
|                 ok = false; |  | ||||||
|             } |  | ||||||
|             if(client->cVersion != 13) { |  | ||||||
|                 Serial.println("here4"); |  | ||||||
|                 ok = false; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if(ok) { |  | ||||||
|             Serial.println("here5"); |  | ||||||
|             DEBUG_WEBSOCKETS("[WS-Server][");DEBUG_WEBSOCKETS(client->num);DEBUG_WEBSOCKETS("]"); |  | ||||||
| 			DEBUG_WEBSOCKETS("[handleHeader] Websocket connection incomming.\n"); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|             // generate Sec-WebSocket-Accept key |  | ||||||
|             String sKey = acceptKey(client->cKey); |  | ||||||
|  |  | ||||||
|             DEBUG_WEBSOCKETS("[WS-Server][");DEBUG_WEBSOCKETS(client->num);DEBUG_WEBSOCKETS("]"); |  | ||||||
| 			DEBUG_WEBSOCKETS("[handleHeader]  - sKey: "); |  | ||||||
| 			DEBUG_WEBSOCKETS(sKey.c_str()); |  | ||||||
| 			DEBUG_WEBSOCKETS("\n"); |  | ||||||
|  |  | ||||||
|             client->status = WSC_CONNECTED; |  | ||||||
|  |  | ||||||
|             client->tcp->write("HTTP/1.1 101 Switching Protocols\r\n" |  | ||||||
|                     "Server: arduino-WebSocketsServer\r\n" |  | ||||||
|                     "Upgrade: websocket\r\n" |  | ||||||
|                     "Connection: Upgrade\r\n" |  | ||||||
|                     "Sec-WebSocket-Version: 13\r\n" |  | ||||||
|                     "Sec-WebSocket-Accept: "); |  | ||||||
|             client->tcp->write(sKey.c_str(), sKey.length()); |  | ||||||
|             client->tcp->write("\r\n"); |  | ||||||
|  |  | ||||||
|             if(client->cProtocol.length() > 0) { |  | ||||||
|                 // TODO add api to set Protocol of Server |  | ||||||
|                 client->tcp->write("Sec-WebSocket-Protocol: arduino\r\n"); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             // header end |  | ||||||
|             client->tcp->write("\r\n"); |  | ||||||
|  |  | ||||||
|             // send ping |  | ||||||
|             WebSockets::sendFrame(client, WSop_ping); |  | ||||||
|  |  | ||||||
|             runCbEvent(client->num, WStype_CONNECTED, (uint8_t *) client->cUrl.c_str(), client->cUrl.length()); |  | ||||||
|  |  | ||||||
|         } else { |  | ||||||
|             handleNonWebsocketConnection(client); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1,143 +0,0 @@ | |||||||
| /** |  | ||||||
|  * @file WebSocketsServer.h |  | ||||||
|  * @date 20.05.2015 |  | ||||||
|  * @author Markus Sattler |  | ||||||
|  * |  | ||||||
|  * Copyright (c) 2015 Markus Sattler. All rights reserved. |  | ||||||
|  * This file is part of the WebSockets for Arduino. |  | ||||||
|  * |  | ||||||
|  * 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 St, Fifth Floor, Boston, MA  02110-1301  USA |  | ||||||
|  * |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #ifndef WEBSOCKETSSERVER_H_ |  | ||||||
| #define WEBSOCKETSSERVER_H_ |  | ||||||
|  |  | ||||||
| #include <Arduino.h> |  | ||||||
| #include "WebSockets.h" |  | ||||||
|  |  | ||||||
| #define WEBSOCKETS_SERVER_CLIENT_MAX  (5) |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class WebSocketsServer: private WebSockets { |  | ||||||
| public: |  | ||||||
|  |  | ||||||
|         typedef void (*WebSocketServerEvent)(uint8_t num, WStype_t type, uint8_t * payload, size_t length); |  | ||||||
|  |  | ||||||
|         WebSocketsServer(uint16_t port); |  | ||||||
|         ~WebSocketsServer(void); |  | ||||||
|  |  | ||||||
|         void begin(void); |  | ||||||
|         void loop(void); |  | ||||||
|  |  | ||||||
|         void onEvent(WebSocketServerEvent cbEvent); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         void sendTXT(uint8_t num, uint8_t * payload, size_t length = 0, bool headerToPayload = false); |  | ||||||
|         void sendTXT(uint8_t num, const uint8_t * payload, size_t length = 0); |  | ||||||
|         void sendTXT(uint8_t num, char * payload, size_t length = 0, bool headerToPayload = false); |  | ||||||
|         void sendTXT(uint8_t num, const char * payload, size_t length = 0); |  | ||||||
|         void sendTXT(uint8_t num, String payload); |  | ||||||
|  |  | ||||||
|         void broadcastTXT(uint8_t * payload, size_t length = 0, bool headerToPayload = false); |  | ||||||
|         void broadcastTXT(const uint8_t * payload, size_t length = 0); |  | ||||||
|         void broadcastTXT(char * payload, size_t length = 0, bool headerToPayload = false); |  | ||||||
|         void broadcastTXT(const char * payload, size_t length = 0); |  | ||||||
|         void broadcastTXT(String payload); |  | ||||||
|  |  | ||||||
|         void sendBIN(uint8_t num, uint8_t * payload, size_t length, bool headerToPayload = false); |  | ||||||
|         void sendBIN(uint8_t num, const uint8_t * payload, size_t length); |  | ||||||
|          |  | ||||||
|         bool sendPing(uint8_t num, uint8_t * payload = NULL, size_t length = 0); |  | ||||||
|         bool sendPing(uint8_t num, String & payload); |  | ||||||
|          |  | ||||||
|         bool broadcastPing(uint8_t * payload = NULL, size_t length = 0); |  | ||||||
|         bool broadcastPing(String & payload); |  | ||||||
|  |  | ||||||
|         void broadcastBIN(uint8_t * payload, size_t length, bool headerToPayload = false); |  | ||||||
|         void broadcastBIN(const uint8_t * payload, size_t length); |  | ||||||
|  |  | ||||||
|         void disconnect(void); |  | ||||||
|         void disconnect(uint8_t num); |  | ||||||
|          |  | ||||||
|         bool clientConnected(uint8_t num); |  | ||||||
|  |  | ||||||
| #if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) |  | ||||||
|         IPAddress remoteIP(uint8_t num); |  | ||||||
| #else |  | ||||||
| 		bool clientExists(const WEBSOCKETS_NETWORK_CLASS &c); |  | ||||||
|          |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| protected: |  | ||||||
|         uint16_t _port; |  | ||||||
|  |  | ||||||
|         WEBSOCKETS_NETWORK_SERVER_CLASS * _server; |  | ||||||
|  |  | ||||||
|         WSclient_t _clients[WEBSOCKETS_SERVER_CLIENT_MAX]; |  | ||||||
|  |  | ||||||
|         WebSocketServerEvent _cbEvent; |  | ||||||
|  |  | ||||||
|         void messageRecived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length); |  | ||||||
|  |  | ||||||
|         void clientDisconnect(WSclient_t * client); |  | ||||||
|         bool clientIsConnected(WSclient_t * client); |  | ||||||
|  |  | ||||||
|         void handleNewClients(void); |  | ||||||
|         void handleClientData(void); |  | ||||||
|  |  | ||||||
|         void handleHeader(WSclient_t * client); |  | ||||||
|  |  | ||||||
|         /** |  | ||||||
|          * called if a non Websocket connection is comming in. |  | ||||||
|          * Note: can be overrided |  | ||||||
|          * @param client WSclient_t *  ptr to the client struct |  | ||||||
|          */ |  | ||||||
|         virtual void handleNonWebsocketConnection(WSclient_t * client) { |  | ||||||
|             DEBUG_WEBSOCKETS("[WS-Server]["); |  | ||||||
|             DEBUG_WEBSOCKETS(client->num); |  | ||||||
|             DEBUG_WEBSOCKETS("][handleHeader] no Websocket connection close.\n"); |  | ||||||
|              |  | ||||||
|             client->tcp->write("HTTP/1.1 400 Bad Request\r\n" |  | ||||||
|                     "Server: arduino-WebSocket-Server\r\n" |  | ||||||
|                     "Content-Type: text/plain\r\n" |  | ||||||
|                     "Content-Length: 32\r\n" |  | ||||||
|                     "Connection: close\r\n" |  | ||||||
|                     "Sec-WebSocket-Version: 13\r\n" |  | ||||||
|                     "\r\n" |  | ||||||
|                     "This is a Websocket server only!"); |  | ||||||
|             clientDisconnect(client); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /** |  | ||||||
|          * called for sending a Event to the app |  | ||||||
|          * @param num uint8_t |  | ||||||
|          * @param type WStype_t |  | ||||||
|          * @param payload uint8_t * |  | ||||||
|          * @param length size_t |  | ||||||
|          */ |  | ||||||
|         virtual void runCbEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) { |  | ||||||
|             if(_cbEvent) { |  | ||||||
|                 _cbEvent(num, type, payload, length); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
| }; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #endif /* WEBSOCKETSSERVER_H_ */ |  | ||||||
		Reference in New Issue
	
	Block a user