forked from Hay1tsme/segatools
ekt: partial y3ws implementation
This commit is contained in:
@ -14,6 +14,10 @@ HRESULT y3_io_init() {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT y3_io_close() {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT y3_io_get_cards(struct CardInfo* pCardInfo, int* numCards) {
|
||||
memset(pCardInfo, 0, sizeof(struct CardInfo) * *numCards);
|
||||
|
||||
|
20
common/y3io/impl/websockets/3rdparty/cjson/LICENSE
vendored
Normal file
20
common/y3io/impl/websockets/3rdparty/cjson/LICENSE
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
3191
common/y3io/impl/websockets/3rdparty/cjson/cJSON.c
vendored
Normal file
3191
common/y3io/impl/websockets/3rdparty/cjson/cJSON.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
306
common/y3io/impl/websockets/3rdparty/cjson/cJSON.h
vendored
Normal file
306
common/y3io/impl/websockets/3rdparty/cjson/cJSON.h
vendored
Normal file
@ -0,0 +1,306 @@
|
||||
/*
|
||||
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef cJSON__h
|
||||
#define cJSON__h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
|
||||
#define __WINDOWS__
|
||||
#endif
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
|
||||
/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options:
|
||||
|
||||
CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
|
||||
CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)
|
||||
CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol
|
||||
|
||||
For *nix builds that support visibility attribute, you can define similar behavior by
|
||||
|
||||
setting default visibility to hidden by adding
|
||||
-fvisibility=hidden (for gcc)
|
||||
or
|
||||
-xldscope=hidden (for sun cc)
|
||||
to CFLAGS
|
||||
|
||||
then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does
|
||||
|
||||
*/
|
||||
|
||||
#define CJSON_CDECL __cdecl
|
||||
#define CJSON_STDCALL __stdcall
|
||||
|
||||
/* export symbols by default, this is necessary for copy pasting the C and header file */
|
||||
#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)
|
||||
#define CJSON_EXPORT_SYMBOLS
|
||||
#endif
|
||||
|
||||
#if defined(CJSON_HIDE_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) type CJSON_STDCALL
|
||||
#elif defined(CJSON_EXPORT_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL
|
||||
#elif defined(CJSON_IMPORT_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL
|
||||
#endif
|
||||
#else /* !__WINDOWS__ */
|
||||
#define CJSON_CDECL
|
||||
#define CJSON_STDCALL
|
||||
|
||||
#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
|
||||
#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type
|
||||
#else
|
||||
#define CJSON_PUBLIC(type) type
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* project version */
|
||||
#define CJSON_VERSION_MAJOR 1
|
||||
#define CJSON_VERSION_MINOR 7
|
||||
#define CJSON_VERSION_PATCH 18
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/* cJSON Types: */
|
||||
#define cJSON_Invalid (0)
|
||||
#define cJSON_False (1 << 0)
|
||||
#define cJSON_True (1 << 1)
|
||||
#define cJSON_NULL (1 << 2)
|
||||
#define cJSON_Number (1 << 3)
|
||||
#define cJSON_String (1 << 4)
|
||||
#define cJSON_Array (1 << 5)
|
||||
#define cJSON_Object (1 << 6)
|
||||
#define cJSON_Raw (1 << 7) /* raw json */
|
||||
|
||||
#define cJSON_IsReference 256
|
||||
#define cJSON_StringIsConst 512
|
||||
|
||||
/* The cJSON structure: */
|
||||
typedef struct cJSON
|
||||
{
|
||||
/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
|
||||
struct cJSON *next;
|
||||
struct cJSON *prev;
|
||||
/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
|
||||
struct cJSON *child;
|
||||
|
||||
/* The type of the item, as above. */
|
||||
int type;
|
||||
|
||||
/* The item's string, if type==cJSON_String and type == cJSON_Raw */
|
||||
char *valuestring;
|
||||
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
|
||||
int valueint;
|
||||
/* The item's number, if type==cJSON_Number */
|
||||
double valuedouble;
|
||||
|
||||
/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
|
||||
char *string;
|
||||
} cJSON;
|
||||
|
||||
typedef struct cJSON_Hooks
|
||||
{
|
||||
/* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */
|
||||
void *(CJSON_CDECL *malloc_fn)(size_t sz);
|
||||
void (CJSON_CDECL *free_fn)(void *ptr);
|
||||
} cJSON_Hooks;
|
||||
|
||||
typedef int cJSON_bool;
|
||||
|
||||
/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
|
||||
* This is to prevent stack overflows. */
|
||||
#ifndef CJSON_NESTING_LIMIT
|
||||
#define CJSON_NESTING_LIMIT 1000
|
||||
#endif
|
||||
|
||||
/* Limits the length of circular references can be before cJSON rejects to parse them.
|
||||
* This is to prevent stack overflows. */
|
||||
#ifndef CJSON_CIRCULAR_LIMIT
|
||||
#define CJSON_CIRCULAR_LIMIT 10000
|
||||
#endif
|
||||
|
||||
/* returns the version of cJSON as a string */
|
||||
CJSON_PUBLIC(const char*) cJSON_Version(void);
|
||||
|
||||
/* Supply malloc, realloc and free functions to cJSON */
|
||||
CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
|
||||
|
||||
/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */
|
||||
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length);
|
||||
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
|
||||
/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated);
|
||||
|
||||
/* Render a cJSON entity to text for transfer/storage. */
|
||||
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
|
||||
/* Render a cJSON entity to text for transfer/storage without any formatting. */
|
||||
CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
|
||||
/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
|
||||
CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
|
||||
/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */
|
||||
/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
|
||||
/* Delete a cJSON entity and all subentities. */
|
||||
CJSON_PUBLIC(void) cJSON_Delete(cJSON *item);
|
||||
|
||||
/* Returns the number of items in an array (or object). */
|
||||
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
|
||||
/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
|
||||
/* Get item "string" from object. Case insensitive. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string);
|
||||
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
|
||||
CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
|
||||
|
||||
/* Check item type and return its value */
|
||||
CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item);
|
||||
CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item);
|
||||
|
||||
/* These functions check the type of an item */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);
|
||||
|
||||
/* These calls create a cJSON item of the appropriate type. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
|
||||
/* raw json */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
|
||||
|
||||
/* Create a string where valuestring references a string so
|
||||
* it will not be freed by cJSON_Delete */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
|
||||
/* Create an object/array that only references it's elements so
|
||||
* they will not be freed by cJSON_Delete */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
|
||||
|
||||
/* These utilities create an Array of count items.
|
||||
* The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count);
|
||||
|
||||
/* Append item to the specified array/object. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
|
||||
/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object.
|
||||
* WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before
|
||||
* writing to `item->string` */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
|
||||
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
|
||||
|
||||
/* Remove/Detach items from Arrays/Objects. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
|
||||
|
||||
/* Update array items. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem);
|
||||
|
||||
/* Duplicate a cJSON item */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);
|
||||
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
|
||||
* need to be released. With recurse!=0, it will duplicate any children connected to the item.
|
||||
* The item->next and ->prev pointers are always zero on return from Duplicate. */
|
||||
/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal.
|
||||
* case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive);
|
||||
|
||||
/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings.
|
||||
* The input pointer json cannot point to a read-only address area, such as a string constant,
|
||||
* but should point to a readable and writable address area. */
|
||||
CJSON_PUBLIC(void) cJSON_Minify(char *json);
|
||||
|
||||
/* Helper functions for creating and adding items to an object at the same time.
|
||||
* They return the added item or NULL on failure. */
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);
|
||||
|
||||
/* When assigning an integer value, it needs to be propagated to valuedouble too. */
|
||||
#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
|
||||
/* helper for the cJSON_SetNumberValue macro */
|
||||
CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
|
||||
#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
|
||||
/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */
|
||||
CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring);
|
||||
|
||||
/* If the object is not a boolean type this does nothing and returns cJSON_Invalid else it returns the new type*/
|
||||
#define cJSON_SetBoolValue(object, boolValue) ( \
|
||||
(object != NULL && ((object)->type & (cJSON_False|cJSON_True))) ? \
|
||||
(object)->type=((object)->type &(~(cJSON_False|cJSON_True)))|((boolValue)?cJSON_True:cJSON_False) : \
|
||||
cJSON_Invalid\
|
||||
)
|
||||
|
||||
/* Macro for iterating over an array or object */
|
||||
#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)
|
||||
|
||||
/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */
|
||||
CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
|
||||
CJSON_PUBLIC(void) cJSON_free(void *object);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
1481
common/y3io/impl/websockets/3rdparty/cjson/cJSON_Utils.c
vendored
Normal file
1481
common/y3io/impl/websockets/3rdparty/cjson/cJSON_Utils.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
88
common/y3io/impl/websockets/3rdparty/cjson/cJSON_Utils.h
vendored
Normal file
88
common/y3io/impl/websockets/3rdparty/cjson/cJSON_Utils.h
vendored
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef cJSON_Utils__h
|
||||
#define cJSON_Utils__h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include "cJSON.h"
|
||||
|
||||
/* Implement RFC6901 (https://tools.ietf.org/html/rfc6901) JSON Pointer spec. */
|
||||
CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointer(cJSON * const object, const char *pointer);
|
||||
CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointerCaseSensitive(cJSON * const object, const char *pointer);
|
||||
|
||||
/* Implement RFC6902 (https://tools.ietf.org/html/rfc6902) JSON Patch spec. */
|
||||
/* NOTE: This modifies objects in 'from' and 'to' by sorting the elements by their key */
|
||||
CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatches(cJSON * const from, cJSON * const to);
|
||||
CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatchesCaseSensitive(cJSON * const from, cJSON * const to);
|
||||
/* Utility for generating patch array entries. */
|
||||
CJSON_PUBLIC(void) cJSONUtils_AddPatchToArray(cJSON * const array, const char * const operation, const char * const path, const cJSON * const value);
|
||||
/* Returns 0 for success. */
|
||||
CJSON_PUBLIC(int) cJSONUtils_ApplyPatches(cJSON * const object, const cJSON * const patches);
|
||||
CJSON_PUBLIC(int) cJSONUtils_ApplyPatchesCaseSensitive(cJSON * const object, const cJSON * const patches);
|
||||
|
||||
/*
|
||||
// Note that ApplyPatches is NOT atomic on failure. To implement an atomic ApplyPatches, use:
|
||||
//int cJSONUtils_AtomicApplyPatches(cJSON **object, cJSON *patches)
|
||||
//{
|
||||
// cJSON *modme = cJSON_Duplicate(*object, 1);
|
||||
// int error = cJSONUtils_ApplyPatches(modme, patches);
|
||||
// if (!error)
|
||||
// {
|
||||
// cJSON_Delete(*object);
|
||||
// *object = modme;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// cJSON_Delete(modme);
|
||||
// }
|
||||
//
|
||||
// return error;
|
||||
//}
|
||||
// Code not added to library since this strategy is a LOT slower.
|
||||
*/
|
||||
|
||||
/* Implement RFC7386 (https://tools.ietf.org/html/rfc7396) JSON Merge Patch spec. */
|
||||
/* target will be modified by patch. return value is new ptr for target. */
|
||||
CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, const cJSON * const patch);
|
||||
CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatchCaseSensitive(cJSON *target, const cJSON * const patch);
|
||||
/* generates a patch to move from -> to */
|
||||
/* NOTE: This modifies objects in 'from' and 'to' by sorting the elements by their key */
|
||||
CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatch(cJSON * const from, cJSON * const to);
|
||||
CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatchCaseSensitive(cJSON * const from, cJSON * const to);
|
||||
|
||||
/* Given a root object and a target object, construct a pointer from one to the other. */
|
||||
CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(const cJSON * const object, const cJSON * const target);
|
||||
|
||||
/* Sorts the members of the object into alphabetical order. */
|
||||
CJSON_PUBLIC(void) cJSONUtils_SortObject(cJSON * const object);
|
||||
CJSON_PUBLIC(void) cJSONUtils_SortObjectCaseSensitive(cJSON * const object);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
69
common/y3io/impl/websockets/3rdparty/websockets/aw-base64.h
vendored
Normal file
69
common/y3io/impl/websockets/3rdparty/websockets/aw-base64.h
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
|
||||
/*
|
||||
Copyright (c) 2014 Malte Hildingsson, malte (at) afterwi.se
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef AW_BASE64_H
|
||||
#define AW_BASE64_H
|
||||
|
||||
#include <stddef.h>
|
||||
#ifdef __AVR__
|
||||
#include <avr/pgmspace.h>
|
||||
#else
|
||||
#define PROGMEM
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static inline size_t base64len(size_t n) {
|
||||
return (n + 2) / 3 * 4;
|
||||
}
|
||||
|
||||
static size_t base64(char *buf, size_t nbuf, const unsigned char *p, size_t n) {
|
||||
const char t[64] PROGMEM = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
size_t i, m = base64len(n);
|
||||
unsigned x;
|
||||
|
||||
if (nbuf >= m)
|
||||
for (i = 0; i < n; ++i) {
|
||||
x = p[i] << 0x10;
|
||||
x |= (++i < n ? p[i] : 0) << 0x08;
|
||||
x |= (++i < n ? p[i] : 0) << 0x00;
|
||||
|
||||
*buf++ = t[x >> 3 * 6 & 0x3f];
|
||||
*buf++ = t[x >> 2 * 6 & 0x3f];
|
||||
*buf++ = (((n - 0 - i) >> 31) & '=') |
|
||||
(~((n - 0 - i) >> 31) & t[x >> 1 * 6 & 0x3f]);
|
||||
*buf++ = (((n - 1 - i) >> 31) & '=') |
|
||||
(~((n - 1 - i) >> 31) & t[x >> 0 * 6 & 0x3f]);
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* AW_BASE64_H */
|
||||
|
137
common/y3io/impl/websockets/3rdparty/websockets/aw-sha1.h
vendored
Normal file
137
common/y3io/impl/websockets/3rdparty/websockets/aw-sha1.h
vendored
Normal file
@ -0,0 +1,137 @@
|
||||
/*
|
||||
Copyright (c) 2014 Malte Hildingsson, malte (at) afterwi.se
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef AW_SHA1_H
|
||||
#define AW_SHA1_H
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wparentheses"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#if _MSC_VER
|
||||
# define _sha1_restrict __restrict
|
||||
#else
|
||||
# define _sha1_restrict __restrict__
|
||||
#endif
|
||||
|
||||
#define SHA1_SIZE 20
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static inline void sha1mix(unsigned *_sha1_restrict r, unsigned *_sha1_restrict w) {
|
||||
unsigned a = r[0];
|
||||
unsigned b = r[1];
|
||||
unsigned c = r[2];
|
||||
unsigned d = r[3];
|
||||
unsigned e = r[4];
|
||||
unsigned t, i = 0;
|
||||
|
||||
#define rol(x,s) ((x) << (s) | (unsigned) (x) >> (32 - (s)))
|
||||
#define mix(f,v) do { \
|
||||
t = (f) + (v) + rol(a, 5) + e + w[i & 0xf]; \
|
||||
e = d; \
|
||||
d = c; \
|
||||
c = rol(b, 30); \
|
||||
b = a; \
|
||||
a = t; \
|
||||
} while (0)
|
||||
|
||||
for (; i < 16; ++i)
|
||||
mix(d ^ (b & (c ^ d)), 0x5a827999);
|
||||
|
||||
for (; i < 20; ++i) {
|
||||
w[i & 0xf] = rol(w[i + 13 & 0xf] ^ w[i + 8 & 0xf] ^ w[i + 2 & 0xf] ^ w[i & 0xf], 1);
|
||||
mix(d ^ (b & (c ^ d)), 0x5a827999);
|
||||
}
|
||||
|
||||
for (; i < 40; ++i) {
|
||||
w[i & 0xf] = rol(w[i + 13 & 0xf] ^ w[i + 8 & 0xf] ^ w[i + 2 & 0xf] ^ w[i & 0xf], 1);
|
||||
mix(b ^ c ^ d, 0x6ed9eba1);
|
||||
}
|
||||
|
||||
for (; i < 60; ++i) {
|
||||
w[i & 0xf] = rol(w[i + 13 & 0xf] ^ w[i + 8 & 0xf] ^ w[i + 2 & 0xf] ^ w[i & 0xf], 1);
|
||||
mix((b & c) | (d & (b | c)), 0x8f1bbcdc);
|
||||
}
|
||||
|
||||
for (; i < 80; ++i) {
|
||||
w[i & 0xf] = rol(w[i + 13 & 0xf] ^ w[i + 8 & 0xf] ^ w[i + 2 & 0xf] ^ w[i & 0xf], 1);
|
||||
mix(b ^ c ^ d, 0xca62c1d6);
|
||||
}
|
||||
|
||||
#undef mix
|
||||
#undef rol
|
||||
|
||||
r[0] += a;
|
||||
r[1] += b;
|
||||
r[2] += c;
|
||||
r[3] += d;
|
||||
r[4] += e;
|
||||
}
|
||||
|
||||
static void sha1(unsigned char h[static SHA1_SIZE], const void *_sha1_restrict p, size_t n) {
|
||||
size_t i = 0;
|
||||
unsigned w[16], r[5] = {0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0};
|
||||
|
||||
for (; i < (n & ~0x3f);) {
|
||||
do w[i >> 2 & 0xf] =
|
||||
((const unsigned char *) p)[i + 3] << 0x00 |
|
||||
((const unsigned char *) p)[i + 2] << 0x08 |
|
||||
((const unsigned char *) p)[i + 1] << 0x10 |
|
||||
((const unsigned char *) p)[i + 0] << 0x18;
|
||||
while ((i += 4) & 0x3f);
|
||||
sha1mix(r, w);
|
||||
}
|
||||
|
||||
memset(w, 0, sizeof w);
|
||||
|
||||
for (; i < n; ++i)
|
||||
w[i >> 2 & 0xf] |= ((const unsigned char *) p)[i] << ((3 ^ i & 3) << 3);
|
||||
|
||||
w[i >> 2 & 0xf] |= 0x80 << ((3 ^ i & 3) << 3);
|
||||
|
||||
if ((n & 0x3f) > 56) {
|
||||
sha1mix(r, w);
|
||||
memset(w, 0, sizeof w);
|
||||
}
|
||||
|
||||
w[15] = n << 3;
|
||||
sha1mix(r, w);
|
||||
|
||||
for (i = 0; i < 5; ++i)
|
||||
h[(i << 2) + 0] = (unsigned char) (r[i] >> 0x18),
|
||||
h[(i << 2) + 1] = (unsigned char) (r[i] >> 0x10),
|
||||
h[(i << 2) + 2] = (unsigned char) (r[i] >> 0x08),
|
||||
h[(i << 2) + 3] = (unsigned char) (r[i] >> 0x00);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
#endif /* AW_SHA1_H */
|
||||
|
328
common/y3io/impl/websockets/3rdparty/websockets/websocket.c
vendored
Normal file
328
common/y3io/impl/websockets/3rdparty/websockets/websocket.c
vendored
Normal file
@ -0,0 +1,328 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Putilov Andrey
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
#include <wtypes.h>
|
||||
#include <winsock2.h>
|
||||
|
||||
#include "websocket.h"
|
||||
|
||||
static char rn[] PROGMEM = "\r\n";
|
||||
|
||||
void nullHandshake(struct handshake *hs)
|
||||
{
|
||||
hs->host = NULL;
|
||||
hs->origin = NULL;
|
||||
hs->resource = NULL;
|
||||
hs->key = NULL;
|
||||
hs->frameType = WS_EMPTY_FRAME;
|
||||
}
|
||||
|
||||
void freeHandshake(struct handshake *hs)
|
||||
{
|
||||
if (hs->host) {
|
||||
free(hs->host);
|
||||
}
|
||||
if (hs->origin) {
|
||||
free(hs->origin);
|
||||
}
|
||||
if (hs->resource) {
|
||||
free(hs->resource);
|
||||
}
|
||||
if (hs->key) {
|
||||
free(hs->key);
|
||||
}
|
||||
nullHandshake(hs);
|
||||
}
|
||||
|
||||
static char* getUptoLinefeed(const char *startFrom)
|
||||
{
|
||||
char *writeTo = NULL;
|
||||
uint8_t newLength = strstr_P(startFrom, rn) - startFrom;
|
||||
assert(newLength);
|
||||
writeTo = (char *)malloc(newLength+1); //+1 for '\x00'
|
||||
assert(writeTo);
|
||||
memcpy(writeTo, startFrom, newLength);
|
||||
writeTo[ newLength ] = 0;
|
||||
|
||||
return writeTo;
|
||||
}
|
||||
|
||||
enum wsFrameType wsParseHandshake(const uint8_t *inputFrame, size_t inputLength,
|
||||
struct handshake *hs)
|
||||
{
|
||||
const char *inputPtr = (const char *)inputFrame;
|
||||
const char *endPtr = (const char *)inputFrame + inputLength;
|
||||
|
||||
if (!strstr((const char *)inputFrame, "\r\n\r\n"))
|
||||
return WS_INCOMPLETE_FRAME;
|
||||
|
||||
if (memcmp_P(inputFrame, PSTR("GET "), 4) != 0)
|
||||
return WS_ERROR_FRAME;
|
||||
// measure resource size
|
||||
char *first = strchr((const char *)inputFrame, ' ');
|
||||
if (!first)
|
||||
return WS_ERROR_FRAME;
|
||||
first++;
|
||||
char *second = strchr(first, ' ');
|
||||
if (!second)
|
||||
return WS_ERROR_FRAME;
|
||||
|
||||
if (hs->resource) {
|
||||
free(hs->resource);
|
||||
hs->resource = NULL;
|
||||
}
|
||||
hs->resource = (char *)malloc(second - first + 1); // +1 is for \x00 symbol
|
||||
assert(hs->resource);
|
||||
|
||||
if (sscanf_P(inputPtr, PSTR("GET %s HTTP/1.1\r\n"), hs->resource) != 1)
|
||||
return WS_ERROR_FRAME;
|
||||
inputPtr = strstr_P(inputPtr, rn) + 2;
|
||||
|
||||
/*
|
||||
parse next lines
|
||||
*/
|
||||
#define prepare(x) do {if (x) { free(x); x = NULL; }} while(0)
|
||||
#define strtolower(x) do { int i; for (i = 0; x[i]; i++) x[i] = tolower(x[i]); } while(0)
|
||||
uint8_t connectionFlag = FALSE;
|
||||
uint8_t upgradeFlag = FALSE;
|
||||
uint8_t subprotocolFlag = FALSE;
|
||||
uint8_t versionMismatch = FALSE;
|
||||
while (inputPtr < endPtr && inputPtr[0] != '\r' && inputPtr[1] != '\n') {
|
||||
if (memcmp_P(inputPtr, hostField, strlen_P(hostField)) == 0) {
|
||||
inputPtr += strlen_P(hostField);
|
||||
prepare(hs->host);
|
||||
hs->host = getUptoLinefeed(inputPtr);
|
||||
} else
|
||||
if (memcmp_P(inputPtr, originField, strlen_P(originField)) == 0) {
|
||||
inputPtr += strlen_P(originField);
|
||||
prepare(hs->origin);
|
||||
hs->origin = getUptoLinefeed(inputPtr);
|
||||
} else
|
||||
if (memcmp_P(inputPtr, protocolField, strlen_P(protocolField)) == 0) {
|
||||
inputPtr += strlen_P(protocolField);
|
||||
subprotocolFlag = TRUE;
|
||||
} else
|
||||
if (memcmp_P(inputPtr, keyField, strlen_P(keyField)) == 0) {
|
||||
inputPtr += strlen_P(keyField);
|
||||
prepare(hs->key);
|
||||
hs->key = getUptoLinefeed(inputPtr);
|
||||
} else
|
||||
if (memcmp_P(inputPtr, versionField, strlen_P(versionField)) == 0) {
|
||||
inputPtr += strlen_P(versionField);
|
||||
char *versionString = NULL;
|
||||
versionString = getUptoLinefeed(inputPtr);
|
||||
if (memcmp_P(versionString, version, strlen_P(version)) != 0)
|
||||
versionMismatch = TRUE;
|
||||
free(versionString);
|
||||
} else
|
||||
if (memcmp_P(inputPtr, connectionField, strlen_P(connectionField)) == 0) {
|
||||
inputPtr += strlen_P(connectionField);
|
||||
char *connectionValue = NULL;
|
||||
connectionValue = getUptoLinefeed(inputPtr);
|
||||
strtolower(connectionValue);
|
||||
assert(connectionValue);
|
||||
if (strstr_P(connectionValue, upgrade) != NULL)
|
||||
connectionFlag = TRUE;
|
||||
free(connectionValue);
|
||||
} else
|
||||
if (memcmp_P(inputPtr, upgradeField, strlen_P(upgradeField)) == 0) {
|
||||
inputPtr += strlen_P(upgradeField);
|
||||
char *compare = NULL;
|
||||
compare = getUptoLinefeed(inputPtr);
|
||||
strtolower(compare);
|
||||
assert(compare);
|
||||
if (memcmp_P(compare, websocket, strlen_P(websocket)) == 0)
|
||||
upgradeFlag = TRUE;
|
||||
free(compare);
|
||||
};
|
||||
|
||||
inputPtr = strstr_P(inputPtr, rn) + 2;
|
||||
}
|
||||
|
||||
// we have read all data, so check them
|
||||
if (!hs->host || !hs->key || !connectionFlag || !upgradeFlag || subprotocolFlag
|
||||
|| versionMismatch)
|
||||
{
|
||||
hs->frameType = WS_ERROR_FRAME;
|
||||
} else {
|
||||
hs->frameType = WS_OPENING_FRAME;
|
||||
}
|
||||
|
||||
return hs->frameType;
|
||||
}
|
||||
|
||||
void wsGetHandshakeAnswer(const struct handshake *hs, uint8_t *outFrame,
|
||||
size_t *outLength)
|
||||
{
|
||||
assert(outFrame && *outLength);
|
||||
assert(hs->frameType == WS_OPENING_FRAME);
|
||||
assert(hs && hs->key);
|
||||
|
||||
char *responseKey = NULL;
|
||||
uint8_t length = strlen(hs->key)+strlen_P(secret);
|
||||
responseKey = malloc(length);
|
||||
memcpy(responseKey, hs->key, strlen(hs->key));
|
||||
memcpy_P(&(responseKey[strlen(hs->key)]), secret, strlen_P(secret));
|
||||
unsigned char shaHash[20];
|
||||
memset(shaHash, 0, sizeof(shaHash));
|
||||
sha1(shaHash, responseKey, length);
|
||||
size_t base64Length = base64(responseKey, length, shaHash, 20);
|
||||
responseKey[base64Length] = '\0';
|
||||
|
||||
int written = sprintf_P((char *)outFrame,
|
||||
PSTR("HTTP/1.1 101 Switching Protocols\r\n"
|
||||
"%s%s\r\n"
|
||||
"%s%s\r\n"
|
||||
"Sec-WebSocket-Accept: %s\r\n\r\n"),
|
||||
upgradeField,
|
||||
websocket,
|
||||
connectionField,
|
||||
upgrade2,
|
||||
responseKey);
|
||||
|
||||
free(responseKey);
|
||||
// if assert fail, that means, that we corrupt memory
|
||||
assert(written <= *outLength);
|
||||
*outLength = written;
|
||||
}
|
||||
|
||||
void wsMakeFrame(const uint8_t *data, size_t dataLength,
|
||||
uint8_t *outFrame, size_t *outLength, enum wsFrameType frameType)
|
||||
{
|
||||
assert(outFrame && *outLength);
|
||||
assert(frameType < 0x10);
|
||||
if (dataLength > 0)
|
||||
assert(data);
|
||||
|
||||
outFrame[0] = 0x80 | frameType;
|
||||
|
||||
if (dataLength <= 125) {
|
||||
outFrame[1] = dataLength;
|
||||
*outLength = 2;
|
||||
} else if (dataLength <= 0xFFFF) {
|
||||
outFrame[1] = 126;
|
||||
uint16_t payloadLength16b = htons(dataLength);
|
||||
memcpy(&outFrame[2], &payloadLength16b, 2);
|
||||
*outLength = 4;
|
||||
} else {
|
||||
assert(dataLength <= 0xFFFF);
|
||||
|
||||
/* implementation for 64bit systems
|
||||
outFrame[1] = 127;
|
||||
dataLength = htonll(dataLength);
|
||||
memcpy(&outFrame[2], &dataLength, 8);
|
||||
*outLength = 10;
|
||||
*/
|
||||
}
|
||||
memcpy(&outFrame[*outLength], data, dataLength);
|
||||
*outLength+= dataLength;
|
||||
}
|
||||
|
||||
static size_t getPayloadLength(const uint8_t *inputFrame, size_t inputLength,
|
||||
uint8_t *payloadFieldExtraBytes, enum wsFrameType *frameType)
|
||||
{
|
||||
size_t payloadLength = inputFrame[1] & 0x7F;
|
||||
*payloadFieldExtraBytes = 0;
|
||||
if ((payloadLength == 0x7E && inputLength < 4) || (payloadLength == 0x7F && inputLength < 10)) {
|
||||
*frameType = WS_INCOMPLETE_FRAME;
|
||||
return 0;
|
||||
}
|
||||
if (payloadLength == 0x7F && (inputFrame[3] & 0x80) != 0x0) {
|
||||
*frameType = WS_ERROR_FRAME;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (payloadLength == 0x7E) {
|
||||
uint16_t payloadLength16b = 0;
|
||||
*payloadFieldExtraBytes = 2;
|
||||
memcpy(&payloadLength16b, &inputFrame[2], *payloadFieldExtraBytes);
|
||||
payloadLength = ntohs(payloadLength16b);
|
||||
} else if (payloadLength == 0x7F) {
|
||||
*frameType = WS_ERROR_FRAME;
|
||||
return 0;
|
||||
|
||||
/* // implementation for 64bit systems
|
||||
uint64_t payloadLength64b = 0;
|
||||
*payloadFieldExtraBytes = 8;
|
||||
memcpy(&payloadLength64b, &inputFrame[2], *payloadFieldExtraBytes);
|
||||
if (payloadLength64b > SIZE_MAX) {
|
||||
*frameType = WS_ERROR_FRAME;
|
||||
return 0;
|
||||
}
|
||||
payloadLength = (size_t)ntohll(payloadLength64b);
|
||||
*/
|
||||
}
|
||||
|
||||
return payloadLength;
|
||||
}
|
||||
|
||||
enum wsFrameType wsParseInputFrame(uint8_t *inputFrame, size_t inputLength,
|
||||
uint8_t **dataPtr, size_t *dataLength)
|
||||
{
|
||||
assert(inputFrame && inputLength);
|
||||
|
||||
if (inputLength < 2)
|
||||
return WS_INCOMPLETE_FRAME;
|
||||
|
||||
if ((inputFrame[0] & 0x70) != 0x0) // checks extensions off
|
||||
return WS_ERROR_FRAME;
|
||||
if ((inputFrame[0] & 0x80) != 0x80) // we haven't continuation frames support
|
||||
return WS_ERROR_FRAME; // so, fin flag must be set
|
||||
if ((inputFrame[1] & 0x80) != 0x80) // checks masking bit
|
||||
return WS_ERROR_FRAME;
|
||||
|
||||
uint8_t opcode = inputFrame[0] & 0x0F;
|
||||
if (opcode == WS_TEXT_FRAME ||
|
||||
opcode == WS_BINARY_FRAME ||
|
||||
opcode == WS_CLOSING_FRAME ||
|
||||
opcode == WS_PING_FRAME ||
|
||||
opcode == WS_PONG_FRAME
|
||||
){
|
||||
enum wsFrameType frameType = opcode;
|
||||
|
||||
uint8_t payloadFieldExtraBytes = 0;
|
||||
size_t payloadLength = getPayloadLength(inputFrame, inputLength,
|
||||
&payloadFieldExtraBytes, &frameType);
|
||||
if (payloadLength > 0) {
|
||||
if (payloadLength + 6 + payloadFieldExtraBytes > inputLength) // 4-maskingKey, 2-header
|
||||
return WS_INCOMPLETE_FRAME;
|
||||
uint8_t *maskingKey = &inputFrame[2 + payloadFieldExtraBytes];
|
||||
|
||||
assert(payloadLength == inputLength - 6 - payloadFieldExtraBytes);
|
||||
|
||||
*dataPtr = &inputFrame[2 + payloadFieldExtraBytes + 4];
|
||||
*dataLength = payloadLength;
|
||||
|
||||
size_t i;
|
||||
for (i = 0; i < *dataLength; i++) {
|
||||
(*dataPtr)[i] = (*dataPtr)[i] ^ maskingKey[i%4];
|
||||
}
|
||||
}
|
||||
return frameType;
|
||||
}
|
||||
|
||||
return WS_ERROR_FRAME;
|
||||
}
|
151
common/y3io/impl/websockets/3rdparty/websockets/websocket.h
vendored
Normal file
151
common/y3io/impl/websockets/3rdparty/websockets/websocket.h
vendored
Normal file
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Putilov Andrey
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBSOCKET_H
|
||||
#define WEBSOCKET_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h> /* uint8_t */
|
||||
#include <stdlib.h> /* strtoul */
|
||||
#include <string.h>
|
||||
#include <stdio.h> /* sscanf */
|
||||
#include <ctype.h> /* isdigit */
|
||||
//#include <stddef.h> /* size_t */
|
||||
#include "aw-base64.h"
|
||||
#include "aw-sha1.h"
|
||||
#ifdef __AVR__
|
||||
#include <avr/pgmspace.h>
|
||||
#else
|
||||
#define PROGMEM
|
||||
#define PSTR
|
||||
#define strstr_P strstr
|
||||
#define sscanf_P sscanf
|
||||
#define sprintf_P sprintf
|
||||
#define strlen_P strlen
|
||||
#define memcmp_P memcmp
|
||||
#define memcpy_P memcpy
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
static const char connectionField[] PROGMEM = "Connection: ";
|
||||
static const char upgrade[] PROGMEM = "upgrade";
|
||||
static const char upgrade2[] PROGMEM = "Upgrade";
|
||||
static const char upgradeField[] PROGMEM = "Upgrade: ";
|
||||
static const char websocket[] PROGMEM = "websocket";
|
||||
static const char hostField[] PROGMEM = "Host: ";
|
||||
static const char originField[] PROGMEM = "Origin: ";
|
||||
static const char keyField[] PROGMEM = "Sec-WebSocket-Key: ";
|
||||
static const char protocolField[] PROGMEM = "Sec-WebSocket-Protocol: ";
|
||||
static const char versionField[] PROGMEM = "Sec-WebSocket-Version: ";
|
||||
static const char version[] PROGMEM = "13";
|
||||
static const char secret[] PROGMEM = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
||||
|
||||
enum wsFrameType { // errors starting from 0xF0
|
||||
WS_EMPTY_FRAME = 0xF0,
|
||||
WS_ERROR_FRAME = 0xF1,
|
||||
WS_INCOMPLETE_FRAME = 0xF2,
|
||||
WS_TEXT_FRAME = 0x01,
|
||||
WS_BINARY_FRAME = 0x02,
|
||||
WS_PING_FRAME = 0x09,
|
||||
WS_PONG_FRAME = 0x0A,
|
||||
WS_OPENING_FRAME = 0xF3,
|
||||
WS_CLOSING_FRAME = 0x08
|
||||
};
|
||||
|
||||
enum wsState {
|
||||
WS_STATE_OPENING,
|
||||
WS_STATE_NORMAL,
|
||||
WS_STATE_CLOSING
|
||||
};
|
||||
|
||||
struct handshake {
|
||||
char *host;
|
||||
char *origin;
|
||||
char *key;
|
||||
char *resource;
|
||||
enum wsFrameType frameType;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param inputFrame Pointer to input frame
|
||||
* @param inputLength Length of input frame
|
||||
* @param hs Cleared with nullHandshake() handshake structure
|
||||
* @return Type of parsed frame
|
||||
*/
|
||||
enum wsFrameType wsParseHandshake(const uint8_t *inputFrame, size_t inputLength,
|
||||
struct handshake *hs);
|
||||
|
||||
/**
|
||||
* @param hs Filled handshake structure
|
||||
* @param outFrame Pointer to frame buffer
|
||||
* @param outLength Length of frame buffer. Return length of out frame
|
||||
*/
|
||||
void wsGetHandshakeAnswer(const struct handshake *hs, uint8_t *outFrame,
|
||||
size_t *outLength);
|
||||
|
||||
/**
|
||||
* @param data Pointer to input data array
|
||||
* @param dataLength Length of data array
|
||||
* @param outFrame Pointer to frame buffer
|
||||
* @param outLength Length of out frame buffer. Return length of out frame
|
||||
* @param frameType [WS_TEXT_FRAME] frame type to build
|
||||
*/
|
||||
void wsMakeFrame(const uint8_t *data, size_t dataLength,
|
||||
uint8_t *outFrame, size_t *outLength, enum wsFrameType frameType);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param inputFrame Pointer to input frame. Frame will be modified.
|
||||
* @param inputLen Length of input frame
|
||||
* @param outDataPtr Return pointer to extracted data in input frame
|
||||
* @param outLen Return length of extracted data
|
||||
* @return Type of parsed frame
|
||||
*/
|
||||
enum wsFrameType wsParseInputFrame(uint8_t *inputFrame, size_t inputLength,
|
||||
uint8_t **dataPtr, size_t *dataLength);
|
||||
|
||||
/**
|
||||
* @param hs NULL handshake structure
|
||||
*/
|
||||
void nullHandshake(struct handshake *hs);
|
||||
|
||||
/**
|
||||
* @param hs free and NULL handshake structure
|
||||
*/
|
||||
void freeHandshake(struct handshake *hs);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* WEBSOCKET_H */
|
310
common/y3io/impl/websockets/y3io.c
Normal file
310
common/y3io/impl/websockets/y3io.c
Normal file
@ -0,0 +1,310 @@
|
||||
#include <stdint.h>
|
||||
#include <windows.h>
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
|
||||
#include "3rdparty/websockets/websocket.h"
|
||||
#include "3rdparty/cjson/cJSON.h"
|
||||
#include "util/dprintf.h"
|
||||
#include "y3io/y3.h"
|
||||
|
||||
DWORD __stdcall y3_websocket_thread_proc(LPVOID ctx);
|
||||
|
||||
// TODO: make these settings configurable
|
||||
#define Y3WS_DEBUG true
|
||||
#define PORT 3497
|
||||
#define WS_PATH "/y3io"
|
||||
|
||||
#define PROTOCOL_VERSION 1
|
||||
|
||||
static bool is_initialized = false;
|
||||
|
||||
static SOCKET ws_socket = 0;
|
||||
static HANDLE server_thread = INVALID_HANDLE_VALUE;
|
||||
|
||||
static struct CardInfo card_info[32];
|
||||
static int card_info_size = 0;
|
||||
static CRITICAL_SECTION card_info_lock;
|
||||
|
||||
uint16_t y3_io_get_api_version() {
|
||||
return 0x0100;
|
||||
}
|
||||
|
||||
HRESULT y3_io_init() {
|
||||
if (is_initialized) {
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
memset(card_info, 0, sizeof(card_info));
|
||||
|
||||
InitializeCriticalSection(&card_info_lock);
|
||||
|
||||
ws_socket = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (ws_socket == -1) {
|
||||
dprintf("Y3WS: Failed to create socket\n");
|
||||
return E_FAIL;
|
||||
}
|
||||
struct sockaddr_in local;
|
||||
memset(&local, 0, sizeof(local));
|
||||
local.sin_family = AF_INET;
|
||||
local.sin_addr.s_addr = INADDR_ANY;
|
||||
local.sin_port = htons(PORT);
|
||||
if (bind(ws_socket, (struct sockaddr *) &local, sizeof(local)) == -1) {
|
||||
dprintf("Y3WS: Failed to bind socket\n");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
if (listen(ws_socket, 1) == -1) {
|
||||
dprintf("Y3WS: Failed to listen on socket\n");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
server_thread = CreateThread(NULL, 0, y3_websocket_thread_proc, NULL, 0, NULL);
|
||||
|
||||
is_initialized = true;
|
||||
|
||||
dprintf("Y3WS: Started server on port %d\n", PORT);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT y3_io_close() {
|
||||
dprintf("Y3WS: Exiting\n");
|
||||
|
||||
if (ws_socket != 0) {
|
||||
closesocket(ws_socket);
|
||||
ws_socket = 0;
|
||||
}
|
||||
if (server_thread != NULL) {
|
||||
WaitForSingleObject(server_thread, INFINITE);
|
||||
server_thread = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
is_initialized = false;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
int safeSend(SOCKET client, const uint8_t* buffer, size_t bufferSize) {
|
||||
ssize_t written = send(client, (char *) buffer, (int) bufferSize, 0);
|
||||
if (written == -1) {
|
||||
closesocket(client);
|
||||
dprintf("Y3WS: send failed");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (written != bufferSize) {
|
||||
closesocket(client);
|
||||
perror("Y3WS: connection interrupted");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
static void y3ws_make_error_packet(const char* message, uint8_t* output_data, size_t* output_size) {
|
||||
dprintf("Y3WS: Error: %s\n", message);
|
||||
*output_size = sprintf_s((char*)output_data, *output_size, "{\"version\":\"%d\", \"success\":false,\"error\":\"%s\"}", PROTOCOL_VERSION, message);
|
||||
}
|
||||
|
||||
static void y3ws_make_success_packet(uint8_t* output_data, size_t* output_size) {
|
||||
*output_size = sprintf_s((char*)output_data, *output_size, "{\"version\":\"%d\", \"success\":true}", PROTOCOL_VERSION);
|
||||
}
|
||||
|
||||
static void y3ws_handle(const char* input_data, uint32_t input_length, uint8_t* output_data, size_t* output_size) {
|
||||
#if Y3WS_DEBUG
|
||||
dprintf("Y3WS: Message was: %s\n", input_data);
|
||||
#endif
|
||||
cJSON* json = cJSON_ParseWithLength(input_data, input_length);
|
||||
if (json == NULL) {
|
||||
const char *error_ptr = cJSON_GetErrorPtr();
|
||||
|
||||
dprintf("Y3WS: Invalid JSON received!\n");
|
||||
dprintf("Y3WS: Message was: %s\n", input_data);
|
||||
dprintf("Y3WS: Error at: %s\n", error_ptr);
|
||||
}
|
||||
|
||||
const cJSON* ver = cJSON_GetObjectItemCaseSensitive(json, "version");
|
||||
const cJSON* cmd = cJSON_GetObjectItemCaseSensitive(json, "command");
|
||||
|
||||
if (!cJSON_IsNumber(ver) || ver->valueint <= 0) {
|
||||
y3ws_make_error_packet("Missing version attribute", output_data, output_size);
|
||||
goto end;
|
||||
}
|
||||
if (ver->valueint != PROTOCOL_VERSION) {
|
||||
y3ws_make_error_packet("Incompatible version", output_data, output_size);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (strcmp(cmd->valuestring, "get_game_id") == 0) {
|
||||
// TODO: send current game id (SDGY, SDDD)
|
||||
} else if (strcmp(cmd->valuestring, "get_cards") == 0) {
|
||||
// TODO: get array of {image_filename, card_id}
|
||||
} else if (strcmp(cmd->valuestring, "set_field") == 0) {
|
||||
const cJSON* cards = cJSON_GetObjectItemCaseSensitive(json, "cards");
|
||||
const cJSON* card = NULL;
|
||||
card_info_size = 0;
|
||||
|
||||
EnterCriticalSection(&card_info_lock);
|
||||
memset(card_info, 0, sizeof(card_info));
|
||||
cJSON_ArrayForEach(card, cards) {
|
||||
cJSON* x = cJSON_GetObjectItemCaseSensitive(card, "x");
|
||||
cJSON* y = cJSON_GetObjectItemCaseSensitive(card, "y");
|
||||
cJSON* r = cJSON_GetObjectItemCaseSensitive(card, "rotation");
|
||||
cJSON* id = cJSON_GetObjectItemCaseSensitive(card, "id");
|
||||
|
||||
if (cJSON_IsNumber(x) && cJSON_IsNumber(y) && cJSON_IsNumber(r) && cJSON_IsNumber(id)) {
|
||||
card_info[card_info_size].eCardStatus = VALID;
|
||||
card_info[card_info_size].fX = (float)x->valuedouble;
|
||||
card_info[card_info_size].fY = (float)y->valuedouble;
|
||||
card_info[card_info_size].fAngle = (float)r->valuedouble;
|
||||
card_info[card_info_size].uID = r->valueint;
|
||||
}
|
||||
|
||||
card_info_size++;
|
||||
}
|
||||
LeaveCriticalSection(&card_info_lock);
|
||||
y3ws_make_success_packet(output_data, output_size);
|
||||
} else {
|
||||
y3ws_make_error_packet("Unknown command", output_data, output_size);
|
||||
}
|
||||
|
||||
end:
|
||||
cJSON_Delete(json);
|
||||
}
|
||||
|
||||
static void y3ws_handle_messages(SOCKET client) {
|
||||
enum wsFrameType frameType = WS_INCOMPLETE_FRAME;
|
||||
enum wsState state = WS_STATE_OPENING;
|
||||
const int BUFFER_SIZE = 4096;
|
||||
uint8_t in_buf[BUFFER_SIZE];
|
||||
uint8_t out_buf[BUFFER_SIZE];
|
||||
size_t out_size;
|
||||
|
||||
uint8_t* message = NULL;
|
||||
size_t message_size = 0;
|
||||
|
||||
struct handshake hs;
|
||||
nullHandshake(&hs);
|
||||
|
||||
while (frameType == WS_INCOMPLETE_FRAME) {
|
||||
ssize_t read = recv(client, (char *) in_buf, BUFFER_SIZE, 0);
|
||||
if (!read) {
|
||||
dprintf("Y3WS: Accept failed\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (state == WS_STATE_OPENING) {
|
||||
frameType = wsParseHandshake(in_buf, read, &hs);
|
||||
} else {
|
||||
frameType = wsParseInputFrame(in_buf, read, &message, &message_size);
|
||||
}
|
||||
|
||||
if ((frameType == WS_INCOMPLETE_FRAME && read == BUFFER_SIZE) || frameType == WS_ERROR_FRAME) {
|
||||
if (frameType == WS_INCOMPLETE_FRAME) {
|
||||
dprintf("Y3WS: buffer too small");
|
||||
} else {
|
||||
dprintf("Y3WS: error in incoming frame\n");
|
||||
}
|
||||
|
||||
if (state == WS_STATE_OPENING) {
|
||||
memset(out_buf, 0, BUFFER_SIZE);
|
||||
out_size = sprintf((char *) out_buf,
|
||||
"HTTP/1.1 400 Bad Request\r\n"
|
||||
"%s%s\r\n\r\n",
|
||||
versionField,
|
||||
version);
|
||||
safeSend(client, out_buf, out_size);
|
||||
break;
|
||||
} else {
|
||||
memset(out_buf, 0, BUFFER_SIZE);
|
||||
wsMakeFrame(NULL, 0, out_buf, &out_size, WS_CLOSING_FRAME);
|
||||
if (safeSend(client, out_buf, out_size) == EXIT_FAILURE) {
|
||||
break;
|
||||
}
|
||||
state = WS_STATE_CLOSING;
|
||||
frameType = WS_INCOMPLETE_FRAME;
|
||||
}
|
||||
}
|
||||
|
||||
if (state == WS_STATE_OPENING) {
|
||||
assert(frameType == WS_OPENING_FRAME);
|
||||
if (frameType == WS_OPENING_FRAME) {
|
||||
if (strcmp(hs.resource, WS_PATH) != 0) {
|
||||
dprintf("Y3WS: Invalid path: %s\n", hs.resource);
|
||||
memset(out_buf, 0, BUFFER_SIZE);
|
||||
out_size = sprintf((char *) out_buf, "HTTP/1.1 404 Not Found\r\n\r\n");
|
||||
safeSend(client, out_buf, out_size);
|
||||
break;
|
||||
}
|
||||
|
||||
memset(out_buf, 0, BUFFER_SIZE);
|
||||
wsGetHandshakeAnswer(&hs, out_buf, &out_size);
|
||||
freeHandshake(&hs);
|
||||
if (safeSend(client, out_buf, out_size) == EXIT_FAILURE)
|
||||
break;
|
||||
state = WS_STATE_NORMAL;
|
||||
frameType = WS_INCOMPLETE_FRAME;
|
||||
}
|
||||
} else {
|
||||
if (frameType == WS_CLOSING_FRAME) {
|
||||
if (state == WS_STATE_CLOSING) {
|
||||
break;
|
||||
} else {
|
||||
memset(out_buf, 0, BUFFER_SIZE);
|
||||
wsMakeFrame(NULL, 0, out_buf, &out_size, WS_CLOSING_FRAME);
|
||||
safeSend(client, out_buf, out_size);
|
||||
break;
|
||||
}
|
||||
} else if (frameType == WS_TEXT_FRAME) {
|
||||
uint8_t* input_data = malloc(message_size + 1);
|
||||
memcpy(input_data, message, message_size);
|
||||
input_data[message_size] = 0;
|
||||
|
||||
uint8_t* output_data = malloc(BUFFER_SIZE);
|
||||
size_t output_size = BUFFER_SIZE;
|
||||
|
||||
y3ws_handle((const char*)input_data, message_size, output_data, &output_size);
|
||||
|
||||
wsMakeFrame(output_data, output_size, out_buf, &out_size, WS_TEXT_FRAME);
|
||||
free(input_data);
|
||||
if (safeSend(client, out_buf, out_size) == EXIT_FAILURE) {
|
||||
break;
|
||||
}
|
||||
frameType = WS_INCOMPLETE_FRAME;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closesocket(client);
|
||||
}
|
||||
|
||||
DWORD __stdcall y3_websocket_thread_proc(LPVOID ctx) {
|
||||
while (true) {
|
||||
struct sockaddr_in remote;
|
||||
socklen_t sockaddr_len = sizeof(remote);
|
||||
SOCKET client = accept(ws_socket, (struct sockaddr *) &remote, &sockaddr_len);
|
||||
if (client == -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
dprintf("Y3WS: Connected %s:%d\n", inet_ntoa(remote.sin_addr), ntohs(remote.sin_port));
|
||||
|
||||
y3ws_handle_messages(client);
|
||||
|
||||
dprintf("Y3WS: Disconnected\n");
|
||||
}
|
||||
|
||||
closesocket(ws_socket);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
HRESULT y3_io_get_cards(struct CardInfo* pCardInfo, int* numCards) {
|
||||
EnterCriticalSection(&card_info_lock);
|
||||
for (int i = 0; i < card_info_size; i++) {
|
||||
memcpy(&pCardInfo[i], &card_info[i], sizeof(struct CardInfo));
|
||||
}
|
||||
*numCards = card_info_size;
|
||||
LeaveCriticalSection(&card_info_lock);
|
||||
return S_OK;
|
||||
}
|
@ -18,6 +18,15 @@ y3io_lib = static_library(
|
||||
'y3.c',
|
||||
'y3.h',
|
||||
'impl/dummy/y3io.c',
|
||||
'impl/websockets/y3io.c',
|
||||
'impl/websockets/3rdparty/websockets/aw-base64.h',
|
||||
'impl/websockets/3rdparty/websockets/aw-sha1.h',
|
||||
'impl/websockets/3rdparty/websockets/websocket.c',
|
||||
'impl/websockets/3rdparty/websockets/websocket.h',
|
||||
'impl/websockets/3rdparty/cjson/cJSON.c',
|
||||
'impl/websockets/3rdparty/cjson/cJSON.h',
|
||||
'impl/websockets/3rdparty/cjson/cJSON_Utils.c',
|
||||
'impl/websockets/3rdparty/cjson/cJSON_Utils.h',
|
||||
'impl/y3io.h',
|
||||
],
|
||||
)
|
||||
|
@ -16,6 +16,9 @@ const struct dll_bind_sym y3_dll_syms[] = {
|
||||
}, {
|
||||
.sym = "y3_io_get_cards",
|
||||
.off = offsetof(struct y3_dll, get_cards),
|
||||
}, {
|
||||
.sym = "y3_io_close",
|
||||
.off = offsetof(struct y3_dll, close),
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
struct y3_dll {
|
||||
uint16_t api_version;
|
||||
HRESULT (*init)(void);
|
||||
HRESULT (*close)(void);
|
||||
HRESULT (*get_cards)(struct CardInfo* cards, int* len);
|
||||
};
|
||||
|
||||
|
@ -17,6 +17,7 @@ EXPORTS
|
||||
ekt_io_led_set_colors
|
||||
y3_io_get_api_version
|
||||
y3_io_init
|
||||
y3_io_close
|
||||
y3_io_get_cards
|
||||
API_DLLVersion @1
|
||||
API_GetLastError @2
|
||||
|
Reference in New Issue
Block a user