Add websocket example that supports permessage-deflate extension
This commit is contained in:
parent
71f4609cb5
commit
145479f095
19 changed files with 2175 additions and 1 deletions
4
examples/websocket_mbedtls/Makefile
Normal file
4
examples/websocket_mbedtls/Makefile
Normal file
|
@ -0,0 +1,4 @@
|
|||
PROGRAM=websocket_mbedtls
|
||||
COMPONENTS = FreeRTOS lwip core extras/mbedtls
|
||||
|
||||
include ../../common.mk
|
78
examples/websocket_mbedtls/adler32.c
Normal file
78
examples/websocket_mbedtls/adler32.c
Normal file
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Adler-32 checksum
|
||||
*
|
||||
* Copyright (c) 2003 by Joergen Ibsen / Jibz
|
||||
* All Rights Reserved
|
||||
*
|
||||
* http://www.ibsensoftware.com/
|
||||
*
|
||||
* This software is provided 'as-is', without any express
|
||||
* or implied warranty. In no event will the authors be
|
||||
* held liable for any damages arising from the use of
|
||||
* this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software
|
||||
* for any purpose, including commercial applications,
|
||||
* and to alter it and redistribute it freely, subject to
|
||||
* the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be
|
||||
* misrepresented; you must not claim that you
|
||||
* wrote the original software. If you use this
|
||||
* software in a product, an acknowledgment in
|
||||
* the product documentation would be appreciated
|
||||
* but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked
|
||||
* as such, and must not be misrepresented as
|
||||
* being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from
|
||||
* any source distribution.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Adler-32 algorithm taken from the zlib source, which is
|
||||
* Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler
|
||||
*/
|
||||
|
||||
#include "tinf.h"
|
||||
|
||||
#define A32_BASE 65521
|
||||
#define A32_NMAX 5552
|
||||
|
||||
unsigned int tinf_adler32(const void *data, unsigned int length)
|
||||
{
|
||||
const unsigned char *buf = (const unsigned char *)data;
|
||||
|
||||
unsigned int s1 = 1;
|
||||
unsigned int s2 = 0;
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
int k = length < A32_NMAX ? length : A32_NMAX;
|
||||
int i;
|
||||
|
||||
for (i = k / 16; i; --i, buf += 16)
|
||||
{
|
||||
s1 += buf[0]; s2 += s1; s1 += buf[1]; s2 += s1;
|
||||
s1 += buf[2]; s2 += s1; s1 += buf[3]; s2 += s1;
|
||||
s1 += buf[4]; s2 += s1; s1 += buf[5]; s2 += s1;
|
||||
s1 += buf[6]; s2 += s1; s1 += buf[7]; s2 += s1;
|
||||
|
||||
s1 += buf[8]; s2 += s1; s1 += buf[9]; s2 += s1;
|
||||
s1 += buf[10]; s2 += s1; s1 += buf[11]; s2 += s1;
|
||||
s1 += buf[12]; s2 += s1; s1 += buf[13]; s2 += s1;
|
||||
s1 += buf[14]; s2 += s1; s1 += buf[15]; s2 += s1;
|
||||
}
|
||||
|
||||
for (i = k % 16; i; --i) { s1 += *buf++; s2 += s1; }
|
||||
|
||||
s1 %= A32_BASE;
|
||||
s2 %= A32_BASE;
|
||||
|
||||
length -= k;
|
||||
}
|
||||
|
||||
return (s2 << 16) | s1;
|
||||
}
|
44
examples/websocket_mbedtls/cert.c
Normal file
44
examples/websocket_mbedtls/cert.c
Normal file
|
@ -0,0 +1,44 @@
|
|||
/* This is the CA certificate for the CA trust chain of
|
||||
www.howsmyssl.com in PEM format, as dumped via:
|
||||
|
||||
openssl s_client -showcerts -connect www.howsmyssl.com:443 </dev/null
|
||||
|
||||
The CA cert is the last cert in the chain output by the server.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
1 s:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
|
||||
i:/O=Digital Signature Trust Co./CN=DST Root CA X3
|
||||
*/
|
||||
const char *server_root_cert = "-----BEGIN CERTIFICATE-----\r\n"
|
||||
"MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/\r\n"
|
||||
"MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\r\n"
|
||||
"DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow\r\n"
|
||||
"SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT\r\n"
|
||||
"GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC\r\n"
|
||||
"AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF\r\n"
|
||||
"q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8\r\n"
|
||||
"SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0\r\n"
|
||||
"Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA\r\n"
|
||||
"a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj\r\n"
|
||||
"/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T\r\n"
|
||||
"AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG\r\n"
|
||||
"CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv\r\n"
|
||||
"bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k\r\n"
|
||||
"c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw\r\n"
|
||||
"VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC\r\n"
|
||||
"ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz\r\n"
|
||||
"MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu\r\n"
|
||||
"Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF\r\n"
|
||||
"AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo\r\n"
|
||||
"uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/\r\n"
|
||||
"wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu\r\n"
|
||||
"X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG\r\n"
|
||||
"PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6\r\n"
|
||||
"KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==\r\n"
|
||||
"-----END CERTIFICATE-----\r\n";
|
||||
|
||||
|
229
examples/websocket_mbedtls/conn.c
Normal file
229
examples/websocket_mbedtls/conn.c
Normal file
|
@ -0,0 +1,229 @@
|
|||
#include "espressif/esp_common.h"
|
||||
#include "esp/uart.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/sockets.h"
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/netdb.h"
|
||||
#include "lwip/dns.h"
|
||||
#include "lwip/api.h"
|
||||
|
||||
#include "ssid_config.h"
|
||||
|
||||
/* mbedtls/config.h MUST appear before all other mbedtls headers, or
|
||||
you'll get the default config.
|
||||
|
||||
(Although mostly that isn't a big problem, you just might get
|
||||
errors at link time if functions don't exist.) */
|
||||
#include "mbedtls/config.h"
|
||||
|
||||
#include "mbedtls/net.h"
|
||||
#include "mbedtls/debug.h"
|
||||
#include "mbedtls/ssl.h"
|
||||
#include "mbedtls/entropy.h"
|
||||
#include "mbedtls/ctr_drbg.h"
|
||||
#include "mbedtls/error.h"
|
||||
#include "mbedtls/certs.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "conn.h"
|
||||
|
||||
/* SSL file descriptors */
|
||||
#define SSL_HANDLES_SIZE 4
|
||||
mbedtls_ssl_context* sslHandles[SSL_HANDLES_SIZE] = {NULL, NULL, NULL, NULL};
|
||||
unsigned char ctxC = 0;
|
||||
|
||||
mbedtls_ssl_config conf;
|
||||
mbedtls_x509_crt cacert;
|
||||
mbedtls_ctr_drbg_context ctr_drbg;
|
||||
mbedtls_entropy_context entropy;
|
||||
|
||||
/* Connect to a hostname and port using TLS 1.2 and
|
||||
return a index for one SSL connection on the pool or -1 if error
|
||||
*/
|
||||
int ConnConnect(char *hostname, int port) {
|
||||
int ret = 0;
|
||||
mbedtls_ssl_context *sslFD;
|
||||
mbedtls_net_context *socketFD;
|
||||
int sslHandle = 0;
|
||||
char s_port[10];
|
||||
|
||||
// configure mbedtls
|
||||
if (!ctxC) {
|
||||
mbedtls_ssl_config_init( &conf );
|
||||
mbedtls_x509_crt_init( &cacert );
|
||||
mbedtls_ctr_drbg_init( &ctr_drbg );
|
||||
mbedtls_entropy_init( &entropy );
|
||||
|
||||
if( ( ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy,
|
||||
(const unsigned char *) "ssl_client1",
|
||||
strlen( "ssl_client1" ) ) ) != 0 )
|
||||
{
|
||||
printf( " failed\n ! mbedtls_ctr_drbg_seed returned %d\n", ret );
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = mbedtls_x509_crt_parse( &cacert, (const unsigned char *) mbedtls_test_cas_pem,
|
||||
mbedtls_test_cas_pem_len );
|
||||
if( ret < 0 )
|
||||
{
|
||||
printf( " failed\n ! mbedtls_x509_crt_parse returned -0x%x\n\n", -ret );
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if( ( ret = mbedtls_ssl_config_defaults( &conf,
|
||||
MBEDTLS_SSL_IS_CLIENT,
|
||||
MBEDTLS_SSL_TRANSPORT_STREAM,
|
||||
MBEDTLS_SSL_PRESET_DEFAULT ) ) != 0 )
|
||||
{
|
||||
printf( " failed\n ! mbedtls_ssl_config_defaults returned %d\n\n", ret );
|
||||
return -1;
|
||||
}
|
||||
|
||||
mbedtls_ssl_conf_authmode( &conf, MBEDTLS_SSL_VERIFY_OPTIONAL );
|
||||
mbedtls_ssl_conf_ca_chain( &conf, &cacert, NULL );
|
||||
mbedtls_ssl_conf_rng( &conf, mbedtls_ctr_drbg_random, &ctr_drbg );
|
||||
|
||||
ctxC = 1;
|
||||
}
|
||||
|
||||
// find a free slot at sslHandles
|
||||
while(sslHandle < SSL_HANDLES_SIZE) {
|
||||
if (sslHandles[sslHandle] == NULL) {
|
||||
sslFD = malloc(sizeof(mbedtls_ssl_context));
|
||||
socketFD = malloc(sizeof(mbedtls_net_context));
|
||||
mbedtls_ssl_init( sslFD );
|
||||
mbedtls_net_init( socketFD );
|
||||
sslHandles[sslHandle] = sslFD;
|
||||
break;
|
||||
}
|
||||
sslHandle++;
|
||||
}
|
||||
|
||||
// no free slot at sslHandles
|
||||
if (sslHandle == SSL_HANDLES_SIZE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// connect mbedtls socket
|
||||
memset(s_port, 0, sizeof(s_port));
|
||||
sprintf(s_port, "%d", port);
|
||||
ret = mbedtls_net_connect(socketFD, hostname, s_port, MBEDTLS_NET_PROTO_TCP);
|
||||
if (ret != 0) {
|
||||
ConnClose(sslHandle);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(( ret = mbedtls_ssl_setup( sslFD, &conf ) ) != 0 )
|
||||
{
|
||||
printf( " failed\n ! mbedtls_ssl_setup returned %d\n\n", ret );
|
||||
ConnClose(sslHandle);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if( ( ret = mbedtls_ssl_set_hostname( sslFD, "mbed TLS Server 1" ) ) != 0 )
|
||||
{
|
||||
printf( " failed\n ! mbedtls_ssl_set_hostname returned %d\n\n", ret );
|
||||
ConnClose(sslHandle);
|
||||
return -1;
|
||||
}
|
||||
|
||||
mbedtls_ssl_set_bio( sslFD, socketFD, mbedtls_net_send, mbedtls_net_recv, NULL );
|
||||
|
||||
while( ( ret = mbedtls_ssl_handshake( sslFD ) ) != 0 )
|
||||
{
|
||||
if( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE )
|
||||
{
|
||||
printf( " failed\n ! mbedtls_ssl_handshake returned -0x%x\n\n", -ret );
|
||||
ConnClose(sslHandle);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return sslHandle;
|
||||
}
|
||||
|
||||
int ConnReadBytesAvailable(int sslHandle) {
|
||||
mbedtls_ssl_context* sslFD = NULL;
|
||||
mbedtls_net_context* socketFD = NULL;
|
||||
int count = 0;
|
||||
|
||||
if (sslHandle >= 0) sslFD = sslHandles[sslHandle];
|
||||
else return -1;
|
||||
|
||||
if (sslFD) {
|
||||
socketFD = (mbedtls_net_context *) sslFD->p_bio;
|
||||
lwip_ioctl(socketFD->fd, FIONREAD, &count);
|
||||
return count;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read bytes from a valid SSL connection on the pool. Blocking! */
|
||||
int ConnRead(int sslHandle, void *buf, int num) {
|
||||
mbedtls_ssl_context* sslFD = NULL;
|
||||
int ret;
|
||||
|
||||
if (sslHandle >= 0) sslFD = sslHandles[sslHandle];
|
||||
else return -1;
|
||||
|
||||
if (sslFD) {
|
||||
if (num == 0) return 0;
|
||||
ret = mbedtls_ssl_read(sslFD, buf, num);
|
||||
return ret;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write bytes to a valid SSL connection on the pool */
|
||||
int ConnWrite(int sslHandle, const void *buf, int num) {
|
||||
mbedtls_ssl_context* sslFD = NULL;
|
||||
int ret;
|
||||
|
||||
if (sslHandle >= 0) sslFD = sslHandles[sslHandle];
|
||||
else return -1;
|
||||
|
||||
if (sslFD) {
|
||||
if (num == 0) return 0;
|
||||
ret = mbedtls_ssl_write(sslFD, buf, num);
|
||||
return ret;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Close a valid SSL connection on the pool, release the resources and
|
||||
open the slot to another connection */
|
||||
void ConnClose(int sslHandle) {
|
||||
mbedtls_ssl_context *sslFD = NULL;
|
||||
|
||||
if (sslHandle >= 0) sslFD = sslHandles[sslHandle];
|
||||
else return;
|
||||
|
||||
if (sslFD) {
|
||||
mbedtls_ssl_close_notify( sslFD );
|
||||
|
||||
mbedtls_net_free( sslFD->p_bio );
|
||||
free(sslFD->p_bio);
|
||||
|
||||
mbedtls_ssl_free( sslFD );
|
||||
free(sslFD);
|
||||
}
|
||||
|
||||
sslHandles[sslHandle] = NULL;
|
||||
}
|
||||
|
||||
void sleep_ms(int milliseconds)
|
||||
{
|
||||
vTaskDelay(milliseconds / portTICK_RATE_MS);
|
||||
}
|
11
examples/websocket_mbedtls/conn.h
Normal file
11
examples/websocket_mbedtls/conn.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
#ifndef CONN
|
||||
#define CONN
|
||||
|
||||
int ConnConnect(char *host, int port);
|
||||
int ConnReadBytesAvailable(int sslHandle);
|
||||
int ConnRead(int sslHandle, void *buf, int num);
|
||||
int ConnWrite(int sslHandle, const void *buf, int num);
|
||||
void ConnClose(int sslHandle);
|
||||
void sleep_ms(int milliseconds);
|
||||
|
||||
#endif
|
64
examples/websocket_mbedtls/crc32.c
Normal file
64
examples/websocket_mbedtls/crc32.c
Normal file
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* CRC32 checksum
|
||||
*
|
||||
* Copyright (c) 1998-2003 by Joergen Ibsen / Jibz
|
||||
* All Rights Reserved
|
||||
*
|
||||
* http://www.ibsensoftware.com/
|
||||
*
|
||||
* This software is provided 'as-is', without any express
|
||||
* or implied warranty. In no event will the authors be
|
||||
* held liable for any damages arising from the use of
|
||||
* this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software
|
||||
* for any purpose, including commercial applications,
|
||||
* and to alter it and redistribute it freely, subject to
|
||||
* the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be
|
||||
* misrepresented; you must not claim that you
|
||||
* wrote the original software. If you use this
|
||||
* software in a product, an acknowledgment in
|
||||
* the product documentation would be appreciated
|
||||
* but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked
|
||||
* as such, and must not be misrepresented as
|
||||
* being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from
|
||||
* any source distribution.
|
||||
*/
|
||||
|
||||
/*
|
||||
* CRC32 algorithm taken from the zlib source, which is
|
||||
* Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler
|
||||
*/
|
||||
|
||||
#include "tinf.h"
|
||||
|
||||
static const unsigned int tinf_crc32tab[16] = {
|
||||
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190,
|
||||
0x6b6b51f4, 0x4db26158, 0x5005713c, 0xedb88320, 0xf00f9344,
|
||||
0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278,
|
||||
0xbdbdf21c
|
||||
};
|
||||
|
||||
unsigned int tinf_crc32(const void *data, unsigned int length)
|
||||
{
|
||||
const unsigned char *buf = (const unsigned char *)data;
|
||||
unsigned int crc = 0xffffffff;
|
||||
unsigned int i;
|
||||
|
||||
if (length == 0) return 0;
|
||||
|
||||
for (i = 0; i < length; ++i)
|
||||
{
|
||||
crc ^= buf[i];
|
||||
crc = tinf_crc32tab[crc & 0x0f] ^ (crc >> 4);
|
||||
crc = tinf_crc32tab[crc & 0x0f] ^ (crc >> 4);
|
||||
}
|
||||
|
||||
return crc ^ 0xffffffff;
|
||||
}
|
308
examples/websocket_mbedtls/defl_static.c
Normal file
308
examples/websocket_mbedtls/defl_static.c
Normal file
|
@ -0,0 +1,308 @@
|
|||
/*
|
||||
|
||||
Routines in this file are based on:
|
||||
Zlib (RFC1950 / RFC1951) compression for PuTTY.
|
||||
|
||||
PuTTY is copyright 1997-2014 Simon Tatham.
|
||||
|
||||
Portions copyright Robert de Bath, Joris van Rantwijk, Delian
|
||||
Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry,
|
||||
Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, Markus
|
||||
Kuhn, Colin Watson, and CORE SDI S.A.
|
||||
|
||||
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 COPYRIGHT HOLDERS BE LIABLE
|
||||
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "defl_static.h"
|
||||
|
||||
#define snew(type) ( (type *) malloc(sizeof(type)) )
|
||||
#define snewn(n, type) ( (type *) malloc((n) * sizeof(type)) )
|
||||
#define sresize(x, n, type) ( (type *) realloc((x), (n) * sizeof(type)) )
|
||||
#define sfree(x) ( free((x)) )
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#define TRUE (!FALSE)
|
||||
#endif
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
* Zlib compression. We always use the static Huffman tree option.
|
||||
* Mostly this is because it's hard to scan a block in advance to
|
||||
* work out better trees; dynamic trees are great when you're
|
||||
* compressing a large file under no significant time constraint,
|
||||
* but when you're compressing little bits in real time, things get
|
||||
* hairier.
|
||||
*
|
||||
* I suppose it's possible that I could compute Huffman trees based
|
||||
* on the frequencies in the _previous_ block, as a sort of
|
||||
* heuristic, but I'm not confident that the gain would balance out
|
||||
* having to transmit the trees.
|
||||
*/
|
||||
|
||||
void outbits(struct Outbuf *out, unsigned long bits, int nbits)
|
||||
{
|
||||
assert(out->noutbits + nbits <= 32);
|
||||
out->outbits |= bits << out->noutbits;
|
||||
out->noutbits += nbits;
|
||||
while (out->noutbits >= 8) {
|
||||
if (out->outlen >= out->outsize) {
|
||||
out->outsize = out->outlen + 64;
|
||||
out->outbuf = sresize(out->outbuf, out->outsize, unsigned char);
|
||||
}
|
||||
out->outbuf[out->outlen++] = (unsigned char) (out->outbits & 0xFF);
|
||||
out->outbits >>= 8;
|
||||
out->noutbits -= 8;
|
||||
}
|
||||
}
|
||||
|
||||
static const unsigned char mirrorbytes[256] = {
|
||||
0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
|
||||
0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
|
||||
0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
|
||||
0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
|
||||
0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
|
||||
0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
|
||||
0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
|
||||
0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
|
||||
0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
|
||||
0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
|
||||
0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
|
||||
0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
|
||||
0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
|
||||
0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
|
||||
0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
|
||||
0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
|
||||
0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
|
||||
0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
|
||||
0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
|
||||
0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
|
||||
0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
|
||||
0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
|
||||
0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
|
||||
0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
|
||||
0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
|
||||
0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
|
||||
0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
|
||||
0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
|
||||
0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
|
||||
0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
|
||||
0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
|
||||
0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
short code, extrabits;
|
||||
int min, max;
|
||||
} coderecord;
|
||||
|
||||
static const coderecord lencodes[] = {
|
||||
{257, 0, 3, 3},
|
||||
{258, 0, 4, 4},
|
||||
{259, 0, 5, 5},
|
||||
{260, 0, 6, 6},
|
||||
{261, 0, 7, 7},
|
||||
{262, 0, 8, 8},
|
||||
{263, 0, 9, 9},
|
||||
{264, 0, 10, 10},
|
||||
{265, 1, 11, 12},
|
||||
{266, 1, 13, 14},
|
||||
{267, 1, 15, 16},
|
||||
{268, 1, 17, 18},
|
||||
{269, 2, 19, 22},
|
||||
{270, 2, 23, 26},
|
||||
{271, 2, 27, 30},
|
||||
{272, 2, 31, 34},
|
||||
{273, 3, 35, 42},
|
||||
{274, 3, 43, 50},
|
||||
{275, 3, 51, 58},
|
||||
{276, 3, 59, 66},
|
||||
{277, 4, 67, 82},
|
||||
{278, 4, 83, 98},
|
||||
{279, 4, 99, 114},
|
||||
{280, 4, 115, 130},
|
||||
{281, 5, 131, 162},
|
||||
{282, 5, 163, 194},
|
||||
{283, 5, 195, 226},
|
||||
{284, 5, 227, 257},
|
||||
{285, 0, 258, 258},
|
||||
};
|
||||
|
||||
static const coderecord distcodes[] = {
|
||||
{0, 0, 1, 1},
|
||||
{1, 0, 2, 2},
|
||||
{2, 0, 3, 3},
|
||||
{3, 0, 4, 4},
|
||||
{4, 1, 5, 6},
|
||||
{5, 1, 7, 8},
|
||||
{6, 2, 9, 12},
|
||||
{7, 2, 13, 16},
|
||||
{8, 3, 17, 24},
|
||||
{9, 3, 25, 32},
|
||||
{10, 4, 33, 48},
|
||||
{11, 4, 49, 64},
|
||||
{12, 5, 65, 96},
|
||||
{13, 5, 97, 128},
|
||||
{14, 6, 129, 192},
|
||||
{15, 6, 193, 256},
|
||||
{16, 7, 257, 384},
|
||||
{17, 7, 385, 512},
|
||||
{18, 8, 513, 768},
|
||||
{19, 8, 769, 1024},
|
||||
{20, 9, 1025, 1536},
|
||||
{21, 9, 1537, 2048},
|
||||
{22, 10, 2049, 3072},
|
||||
{23, 10, 3073, 4096},
|
||||
{24, 11, 4097, 6144},
|
||||
{25, 11, 6145, 8192},
|
||||
{26, 12, 8193, 12288},
|
||||
{27, 12, 12289, 16384},
|
||||
{28, 13, 16385, 24576},
|
||||
{29, 13, 24577, 32768},
|
||||
};
|
||||
|
||||
void zlib_literal(struct Outbuf *out, unsigned char c)
|
||||
{
|
||||
if (out->comp_disabled) {
|
||||
/*
|
||||
* We're in an uncompressed block, so just output the byte.
|
||||
*/
|
||||
outbits(out, c, 8);
|
||||
return;
|
||||
}
|
||||
|
||||
if (c <= 143) {
|
||||
/* 0 through 143 are 8 bits long starting at 00110000. */
|
||||
outbits(out, mirrorbytes[0x30 + c], 8);
|
||||
} else {
|
||||
/* 144 through 255 are 9 bits long starting at 110010000. */
|
||||
outbits(out, 1 + 2 * mirrorbytes[0x90 - 144 + c], 9);
|
||||
}
|
||||
}
|
||||
|
||||
void zlib_match(struct Outbuf *out, int distance, int len)
|
||||
{
|
||||
const coderecord *d, *l;
|
||||
int i, j, k;
|
||||
|
||||
assert(!out->comp_disabled);
|
||||
|
||||
while (len > 0) {
|
||||
int thislen;
|
||||
|
||||
/*
|
||||
* We can transmit matches of lengths 3 through 258
|
||||
* inclusive. So if len exceeds 258, we must transmit in
|
||||
* several steps, with 258 or less in each step.
|
||||
*
|
||||
* Specifically: if len >= 261, we can transmit 258 and be
|
||||
* sure of having at least 3 left for the next step. And if
|
||||
* len <= 258, we can just transmit len. But if len == 259
|
||||
* or 260, we must transmit len-3.
|
||||
*/
|
||||
thislen = (len > 260 ? 258 : len <= 258 ? len : len - 3);
|
||||
len -= thislen;
|
||||
|
||||
/*
|
||||
* Binary-search to find which length code we're
|
||||
* transmitting.
|
||||
*/
|
||||
i = -1;
|
||||
j = sizeof(lencodes) / sizeof(*lencodes);
|
||||
while (1) {
|
||||
assert(j - i >= 2);
|
||||
k = (j + i) / 2;
|
||||
if (thislen < lencodes[k].min)
|
||||
j = k;
|
||||
else if (thislen > lencodes[k].max)
|
||||
i = k;
|
||||
else {
|
||||
l = &lencodes[k];
|
||||
break; /* found it! */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Transmit the length code. 256-279 are seven bits
|
||||
* starting at 0000000; 280-287 are eight bits starting at
|
||||
* 11000000.
|
||||
*/
|
||||
if (l->code <= 279) {
|
||||
outbits(out, mirrorbytes[(l->code - 256) * 2], 7);
|
||||
} else {
|
||||
outbits(out, mirrorbytes[0xc0 - 280 + l->code], 8);
|
||||
}
|
||||
|
||||
/*
|
||||
* Transmit the extra bits.
|
||||
*/
|
||||
if (l->extrabits)
|
||||
outbits(out, thislen - l->min, l->extrabits);
|
||||
|
||||
/*
|
||||
* Binary-search to find which distance code we're
|
||||
* transmitting.
|
||||
*/
|
||||
i = -1;
|
||||
j = sizeof(distcodes) / sizeof(*distcodes);
|
||||
while (1) {
|
||||
assert(j - i >= 2);
|
||||
k = (j + i) / 2;
|
||||
if (distance < distcodes[k].min)
|
||||
j = k;
|
||||
else if (distance > distcodes[k].max)
|
||||
i = k;
|
||||
else {
|
||||
d = &distcodes[k];
|
||||
break; /* found it! */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Transmit the distance code. Five bits starting at 00000.
|
||||
*/
|
||||
outbits(out, mirrorbytes[d->code * 8], 5);
|
||||
|
||||
/*
|
||||
* Transmit the extra bits.
|
||||
*/
|
||||
if (d->extrabits)
|
||||
outbits(out, distance - d->min, d->extrabits);
|
||||
}
|
||||
}
|
||||
|
||||
void zlib_start_block(struct Outbuf *out)
|
||||
{
|
||||
// outbits(out, 0x9C78, 16);
|
||||
outbits(out, 1, 1); /* Final block */
|
||||
outbits(out, 1, 2); /* Static huffman block */
|
||||
}
|
||||
|
||||
void zlib_finish_block(struct Outbuf *out)
|
||||
{
|
||||
outbits(out, 0, 7); /* close block */
|
||||
outbits(out, 0, 7); /* Make sure all bits are flushed */
|
||||
}
|
||||
|
||||
void zlib_free_block(struct Outbuf *out) {
|
||||
sfree(out->outbuf);
|
||||
}
|
14
examples/websocket_mbedtls/defl_static.h
Normal file
14
examples/websocket_mbedtls/defl_static.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
struct Outbuf {
|
||||
unsigned char *outbuf;
|
||||
int outlen, outsize;
|
||||
unsigned long outbits;
|
||||
int noutbits;
|
||||
int comp_disabled;
|
||||
};
|
||||
|
||||
void outbits(struct Outbuf *out, unsigned long bits, int nbits);
|
||||
void zlib_start_block(struct Outbuf *ctx);
|
||||
void zlib_finish_block(struct Outbuf *ctx);
|
||||
void zlib_literal(struct Outbuf *ectx, unsigned char c);
|
||||
void zlib_match(struct Outbuf *ectx, int distance, int len);
|
||||
void zlib_free_block(struct Outbuf *out);
|
116
examples/websocket_mbedtls/genlz77.c
Normal file
116
examples/websocket_mbedtls/genlz77.c
Normal file
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* genlz77 - Generic LZ77 compressor
|
||||
*
|
||||
* Copyright (c) 2014 by Paul Sokolovsky
|
||||
*
|
||||
* This software is provided 'as-is', without any express
|
||||
* or implied warranty. In no event will the authors be
|
||||
* held liable for any damages arising from the use of
|
||||
* this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software
|
||||
* for any purpose, including commercial applications,
|
||||
* and to alter it and redistribute it freely, subject to
|
||||
* the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be
|
||||
* misrepresented; you must not claim that you
|
||||
* wrote the original software. If you use this
|
||||
* software in a product, an acknowledgment in
|
||||
* the product documentation would be appreciated
|
||||
* but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked
|
||||
* as such, and must not be misrepresented as
|
||||
* being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from
|
||||
* any source distribution.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "defl_static.h"
|
||||
|
||||
#define HASH_BITS 10
|
||||
#define HASH_SIZE (1<<HASH_BITS)
|
||||
|
||||
/* Minimum and maximum length of matches to look for, inclusive */
|
||||
#define MIN_MATCH 3
|
||||
#define MAX_MATCH 258
|
||||
/* Max offset of the match to look for, inclusive */
|
||||
#define MAX_OFFSET 32768
|
||||
|
||||
/* Hash function can be defined as macro or as inline function */
|
||||
|
||||
/*#define HASH(p) (p[0] + p[1] + p[2])*/
|
||||
|
||||
/* This is hash function from liblzf */
|
||||
static int HASH(const uint8_t *p) {
|
||||
int v = (p[0] << 16) | (p[1] << 8) | p[2];
|
||||
int hash = ((v >> (3*8 - HASH_BITS)) - v) & (HASH_SIZE - 1);
|
||||
return hash;
|
||||
}
|
||||
|
||||
#ifdef DUMP_LZTXT
|
||||
|
||||
/* Counter for approximate compressed length in LZTXT mode. */
|
||||
/* Literal is counted as 1, copy as 2 bytes. */
|
||||
unsigned approx_compressed_len;
|
||||
|
||||
void literal(void *data, uint8_t val)
|
||||
{
|
||||
printf("L%02x # %c\n", val, (val >= 0x20 && val <= 0x7e) ? val : '?');
|
||||
approx_compressed_len++;
|
||||
}
|
||||
|
||||
void copy(void *data, unsigned offset, unsigned len)
|
||||
{
|
||||
printf("C-%u,%u\n", offset, len);
|
||||
approx_compressed_len += 2;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static void literal(void *data, uint8_t val)
|
||||
{
|
||||
zlib_literal(data, val);
|
||||
}
|
||||
|
||||
static void copy(void *data, unsigned offset, unsigned len)
|
||||
{
|
||||
zlib_match(data, offset, len);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
void tinf_compress(void *data, const uint8_t *src, unsigned slen)
|
||||
{
|
||||
const uint8_t *hashtable[HASH_SIZE] = {0};
|
||||
|
||||
const uint8_t *top = src + slen - MIN_MATCH;
|
||||
while (src < top) {
|
||||
int h = HASH(src);
|
||||
const uint8_t **bucket = &hashtable[h & (HASH_SIZE - 1)];
|
||||
const uint8_t *subs = *bucket;
|
||||
*bucket = src;
|
||||
if (subs && src > subs && (src - subs) <= MAX_OFFSET && !memcmp(src, subs, MIN_MATCH)) {
|
||||
src += MIN_MATCH;
|
||||
const uint8_t *m = subs + MIN_MATCH;
|
||||
int len = MIN_MATCH;
|
||||
while (*src == *m && len < MAX_MATCH) {
|
||||
src++; m++; len++;
|
||||
}
|
||||
copy(data, src - len - subs, len);
|
||||
} else {
|
||||
literal(data, *src++);
|
||||
}
|
||||
}
|
||||
// Process buffer tail, which is less than MIN_MATCH
|
||||
// (and so it doesn't make sense to look for matches there)
|
||||
top += MIN_MATCH;
|
||||
while (src < top) {
|
||||
literal(data, *src++);
|
||||
}
|
||||
}
|
27
examples/websocket_mbedtls/include/mbedtls/config.h
Normal file
27
examples/websocket_mbedtls/include/mbedtls/config.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
/* Special mbedTLS config file for http_get_mbedtls example,
|
||||
overrides supported cipher suite list.
|
||||
|
||||
Overriding the set of cipher suites saves small amounts of ROM and
|
||||
RAM, and is a good practice in general if you know what server(s)
|
||||
you want to connect to.
|
||||
|
||||
However it's extra important here because the howsmyssl API sends
|
||||
back the list of ciphers we send it as a JSON list in the, and we
|
||||
only have a 4096kB receive buffer. If the server supported maximum
|
||||
fragment length option then we wouldn't have this problem either,
|
||||
but we do so this is a good workaround.
|
||||
|
||||
The ciphers chosen below are common ECDHE ciphers, the same ones
|
||||
Firefox uses when connecting to a TLSv1.2 server.
|
||||
*/
|
||||
#ifndef MBEDTLS_CONFIG_H
|
||||
|
||||
/* include_next picks up default config from extras/mbedtls/include/mbedtls/config.h */
|
||||
#include_next<mbedtls/config.h>
|
||||
|
||||
#define MBEDTLS_SSL_CIPHERSUITES MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
|
||||
|
||||
/* uncomment next line to include debug output from example */
|
||||
//#define MBEDTLS_DEBUG_C
|
||||
|
||||
#endif
|
102
examples/websocket_mbedtls/tinf.h
Normal file
102
examples/websocket_mbedtls/tinf.h
Normal file
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* uzlib - tiny deflate/inflate library (deflate, gzip, zlib)
|
||||
*
|
||||
* Copyright (c) 2003 by Joergen Ibsen / Jibz
|
||||
* All Rights Reserved
|
||||
* http://www.ibsensoftware.com/
|
||||
*
|
||||
* Copyright (c) 2014 by Paul Sokolovsky
|
||||
*/
|
||||
|
||||
#ifndef TINF_H_INCLUDED
|
||||
#define TINF_H_INCLUDED
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* calling convention */
|
||||
#ifndef TINFCC
|
||||
#ifdef __WATCOMC__
|
||||
#define TINFCC __cdecl
|
||||
#else
|
||||
#define TINFCC
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define TINF_OK 0
|
||||
#define TINF_DATA_ERROR (-3)
|
||||
#define TINF_DEST_OVERFLOW (-4)
|
||||
|
||||
/* data structures */
|
||||
|
||||
typedef struct {
|
||||
unsigned short table[16]; /* table of code length counts */
|
||||
unsigned short trans[288]; /* code -> symbol translation table */
|
||||
} TINF_TREE;
|
||||
|
||||
struct TINF_DATA;
|
||||
typedef struct TINF_DATA {
|
||||
const unsigned char *source;
|
||||
unsigned int tag;
|
||||
unsigned int bitcount;
|
||||
|
||||
/* Buffer start */
|
||||
unsigned char *destStart;
|
||||
/* Buffer total size */
|
||||
unsigned int destSize;
|
||||
/* Current pointer in buffer */
|
||||
unsigned char *dest;
|
||||
/* Remaining bytes in buffer */
|
||||
unsigned int destRemaining;
|
||||
/* Argument is the allocation size which didn't fit into buffer. Note that
|
||||
exact mimumum size to grow buffer by is lastAlloc - destRemaining. But
|
||||
growing by this exact size is ineficient, as the next allocation will
|
||||
fail again. */
|
||||
int (*destGrow)(struct TINF_DATA *data, unsigned int lastAlloc);
|
||||
|
||||
TINF_TREE ltree; /* dynamic length/symbol tree */
|
||||
TINF_TREE dtree; /* dynamic distance tree */
|
||||
} TINF_DATA;
|
||||
|
||||
|
||||
/* low-level API */
|
||||
|
||||
/* Step 1: Allocate TINF_DATA structure */
|
||||
/* Step 2: Set destStart, destSize, and destGrow fields */
|
||||
/* Step 3: Set source field */
|
||||
/* Step 4: Call tinf_uncompress_dyn() */
|
||||
/* Step 5: In response to destGrow callback, update destStart and destSize fields */
|
||||
/* Step 6: When tinf_uncompress_dyn() returns, buf.dest points to a byte past last uncompressed byte */
|
||||
|
||||
int TINFCC tinf_uncompress_dyn(TINF_DATA *d);
|
||||
int TINFCC tinf_zlib_uncompress_dyn(TINF_DATA *d, unsigned int sourceLen);
|
||||
|
||||
/* high-level API */
|
||||
|
||||
void TINFCC tinf_init(void);
|
||||
|
||||
int TINFCC tinf_uncompress(void *dest, unsigned int *destLen,
|
||||
const void *source, unsigned int sourceLen);
|
||||
|
||||
int TINFCC tinf_gzip_uncompress(void *dest, unsigned int *destLen,
|
||||
const void *source, unsigned int sourceLen);
|
||||
|
||||
int TINFCC tinf_zlib_uncompress(void *dest, unsigned int *destLen,
|
||||
const void *source, unsigned int sourceLen);
|
||||
|
||||
unsigned int TINFCC tinf_adler32(const void *data, unsigned int length);
|
||||
|
||||
unsigned int TINFCC tinf_crc32(const void *data, unsigned int length);
|
||||
|
||||
/* compression API */
|
||||
|
||||
void TINFCC tinf_compress(void *data, const uint8_t *src, unsigned slen);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* TINF_H_INCLUDED */
|
124
examples/websocket_mbedtls/tinfgzip.c
Normal file
124
examples/websocket_mbedtls/tinfgzip.c
Normal file
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* tinfgzip - tiny gzip decompressor
|
||||
*
|
||||
* Copyright (c) 2003 by Joergen Ibsen / Jibz
|
||||
* All Rights Reserved
|
||||
*
|
||||
* http://www.ibsensoftware.com/
|
||||
*
|
||||
* This software is provided 'as-is', without any express
|
||||
* or implied warranty. In no event will the authors be
|
||||
* held liable for any damages arising from the use of
|
||||
* this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software
|
||||
* for any purpose, including commercial applications,
|
||||
* and to alter it and redistribute it freely, subject to
|
||||
* the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be
|
||||
* misrepresented; you must not claim that you
|
||||
* wrote the original software. If you use this
|
||||
* software in a product, an acknowledgment in
|
||||
* the product documentation would be appreciated
|
||||
* but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked
|
||||
* as such, and must not be misrepresented as
|
||||
* being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from
|
||||
* any source distribution.
|
||||
*/
|
||||
|
||||
#include "tinf.h"
|
||||
|
||||
#define FTEXT 1
|
||||
#define FHCRC 2
|
||||
#define FEXTRA 4
|
||||
#define FNAME 8
|
||||
#define FCOMMENT 16
|
||||
|
||||
int tinf_gzip_uncompress(void *dest, unsigned int *destLen,
|
||||
const void *source, unsigned int sourceLen)
|
||||
{
|
||||
unsigned char *src = (unsigned char *)source;
|
||||
unsigned char *dst = (unsigned char *)dest;
|
||||
unsigned char *start;
|
||||
unsigned int dlen, crc32;
|
||||
int res;
|
||||
unsigned char flg;
|
||||
|
||||
/* -- check format -- */
|
||||
|
||||
/* check id bytes */
|
||||
if (src[0] != 0x1f || src[1] != 0x8b) return TINF_DATA_ERROR;
|
||||
|
||||
/* check method is deflate */
|
||||
if (src[2] != 8) return TINF_DATA_ERROR;
|
||||
|
||||
/* get flag byte */
|
||||
flg = src[3];
|
||||
|
||||
/* check that reserved bits are zero */
|
||||
if (flg & 0xe0) return TINF_DATA_ERROR;
|
||||
|
||||
/* -- find start of compressed data -- */
|
||||
|
||||
/* skip base header of 10 bytes */
|
||||
start = src + 10;
|
||||
|
||||
/* skip extra data if present */
|
||||
if (flg & FEXTRA)
|
||||
{
|
||||
unsigned int xlen = start[1];
|
||||
xlen = 256*xlen + start[0];
|
||||
start += xlen + 2;
|
||||
}
|
||||
|
||||
/* skip file name if present */
|
||||
if (flg & FNAME) { while (*start) ++start; ++start; }
|
||||
|
||||
/* skip file comment if present */
|
||||
if (flg & FCOMMENT) { while (*start) ++start; ++start; }
|
||||
|
||||
/* check header crc if present */
|
||||
if (flg & FHCRC)
|
||||
{
|
||||
unsigned int hcrc = start[1];
|
||||
hcrc = 256*hcrc + start[0];
|
||||
|
||||
if (hcrc != (tinf_crc32(src, start - src) & 0x0000ffff))
|
||||
return TINF_DATA_ERROR;
|
||||
|
||||
start += 2;
|
||||
}
|
||||
|
||||
/* -- get decompressed length -- */
|
||||
|
||||
dlen = src[sourceLen - 1];
|
||||
dlen = 256*dlen + src[sourceLen - 2];
|
||||
dlen = 256*dlen + src[sourceLen - 3];
|
||||
dlen = 256*dlen + src[sourceLen - 4];
|
||||
|
||||
/* -- get crc32 of decompressed data -- */
|
||||
|
||||
crc32 = src[sourceLen - 5];
|
||||
crc32 = 256*crc32 + src[sourceLen - 6];
|
||||
crc32 = 256*crc32 + src[sourceLen - 7];
|
||||
crc32 = 256*crc32 + src[sourceLen - 8];
|
||||
|
||||
/* -- decompress data -- */
|
||||
|
||||
res = tinf_uncompress(dst, destLen, start, src + sourceLen - start - 8);
|
||||
|
||||
if (res != TINF_OK) return TINF_DATA_ERROR;
|
||||
|
||||
if (*destLen != dlen) return TINF_DATA_ERROR;
|
||||
|
||||
/* -- check CRC32 checksum -- */
|
||||
|
||||
if (crc32 != tinf_crc32(dst, dlen)) return TINF_DATA_ERROR;
|
||||
|
||||
return TINF_OK;
|
||||
}
|
518
examples/websocket_mbedtls/tinflate.c
Normal file
518
examples/websocket_mbedtls/tinflate.c
Normal file
|
@ -0,0 +1,518 @@
|
|||
/*
|
||||
* tinflate - tiny inflate
|
||||
*
|
||||
* Copyright (c) 2003 by Joergen Ibsen / Jibz
|
||||
* All Rights Reserved
|
||||
* http://www.ibsensoftware.com/
|
||||
*
|
||||
* Copyright (c) 2014 by Paul Sokolovsky
|
||||
*
|
||||
* This software is provided 'as-is', without any express
|
||||
* or implied warranty. In no event will the authors be
|
||||
* held liable for any damages arising from the use of
|
||||
* this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software
|
||||
* for any purpose, including commercial applications,
|
||||
* and to alter it and redistribute it freely, subject to
|
||||
* the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be
|
||||
* misrepresented; you must not claim that you
|
||||
* wrote the original software. If you use this
|
||||
* software in a product, an acknowledgment in
|
||||
* the product documentation would be appreciated
|
||||
* but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked
|
||||
* as such, and must not be misrepresented as
|
||||
* being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from
|
||||
* any source distribution.
|
||||
*/
|
||||
|
||||
#include "tinf.h"
|
||||
|
||||
/* --------------------------------------------------- *
|
||||
* -- uninitialized global data (static structures) -- *
|
||||
* --------------------------------------------------- */
|
||||
|
||||
#ifdef RUNTIME_BITS_TABLES
|
||||
|
||||
/* extra bits and base tables for length codes */
|
||||
unsigned char length_bits[30];
|
||||
unsigned short length_base[30];
|
||||
|
||||
/* extra bits and base tables for distance codes */
|
||||
unsigned char dist_bits[30];
|
||||
unsigned short dist_base[30];
|
||||
|
||||
#else
|
||||
|
||||
const unsigned char length_bits[30] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 1, 1, 2, 2, 2, 2,
|
||||
3, 3, 3, 3, 4, 4, 4, 4,
|
||||
5, 5, 5, 5
|
||||
};
|
||||
const unsigned short length_base[30] = {
|
||||
3, 4, 5, 6, 7, 8, 9, 10,
|
||||
11, 13, 15, 17, 19, 23, 27, 31,
|
||||
35, 43, 51, 59, 67, 83, 99, 115,
|
||||
131, 163, 195, 227, 258
|
||||
};
|
||||
|
||||
const unsigned char dist_bits[30] = {
|
||||
0, 0, 0, 0, 1, 1, 2, 2,
|
||||
3, 3, 4, 4, 5, 5, 6, 6,
|
||||
7, 7, 8, 8, 9, 9, 10, 10,
|
||||
11, 11, 12, 12, 13, 13
|
||||
};
|
||||
const unsigned short dist_base[30] = {
|
||||
1, 2, 3, 4, 5, 7, 9, 13,
|
||||
17, 25, 33, 49, 65, 97, 129, 193,
|
||||
257, 385, 513, 769, 1025, 1537, 2049, 3073,
|
||||
4097, 6145, 8193, 12289, 16385, 24577
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/* special ordering of code length codes */
|
||||
const unsigned char clcidx[] = {
|
||||
16, 17, 18, 0, 8, 7, 9, 6,
|
||||
10, 5, 11, 4, 12, 3, 13, 2,
|
||||
14, 1, 15
|
||||
};
|
||||
|
||||
/* ----------------------- *
|
||||
* -- utility functions -- *
|
||||
* ----------------------- */
|
||||
|
||||
/* Execute callback to grow destination buffer */
|
||||
static int tinf_grow_dest_buf(TINF_DATA *d, unsigned int lastAlloc)
|
||||
{
|
||||
unsigned int oldsize = d->dest - d->destStart;
|
||||
|
||||
/* This will update only destStart and destSize */
|
||||
if (!d->destGrow)
|
||||
{
|
||||
return TINF_DEST_OVERFLOW;
|
||||
}
|
||||
|
||||
d->destGrow(d, lastAlloc);
|
||||
d->dest = d->destStart + oldsize;
|
||||
d->destRemaining = d->destSize - oldsize;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef RUNTIME_BITS_TABLES
|
||||
/* build extra bits and base tables */
|
||||
static void tinf_build_bits_base(unsigned char *bits, unsigned short *base, int delta, int first)
|
||||
{
|
||||
int i, sum;
|
||||
|
||||
/* build bits table */
|
||||
for (i = 0; i < delta; ++i) bits[i] = 0;
|
||||
for (i = 0; i < 30 - delta; ++i) bits[i + delta] = i / delta;
|
||||
|
||||
/* build base table */
|
||||
for (sum = first, i = 0; i < 30; ++i)
|
||||
{
|
||||
base[i] = sum;
|
||||
sum += 1 << bits[i];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* build the fixed huffman trees */
|
||||
static void tinf_build_fixed_trees(TINF_TREE *lt, TINF_TREE *dt)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* build fixed length tree */
|
||||
for (i = 0; i < 7; ++i) lt->table[i] = 0;
|
||||
|
||||
lt->table[7] = 24;
|
||||
lt->table[8] = 152;
|
||||
lt->table[9] = 112;
|
||||
|
||||
for (i = 0; i < 24; ++i) lt->trans[i] = 256 + i;
|
||||
for (i = 0; i < 144; ++i) lt->trans[24 + i] = i;
|
||||
for (i = 0; i < 8; ++i) lt->trans[24 + 144 + i] = 280 + i;
|
||||
for (i = 0; i < 112; ++i) lt->trans[24 + 144 + 8 + i] = 144 + i;
|
||||
|
||||
/* build fixed distance tree */
|
||||
for (i = 0; i < 5; ++i) dt->table[i] = 0;
|
||||
|
||||
dt->table[5] = 32;
|
||||
|
||||
for (i = 0; i < 32; ++i) dt->trans[i] = i;
|
||||
}
|
||||
|
||||
/* given an array of code lengths, build a tree */
|
||||
static void tinf_build_tree(TINF_TREE *t, const unsigned char *lengths, unsigned int num)
|
||||
{
|
||||
unsigned short offs[16];
|
||||
unsigned int i, sum;
|
||||
|
||||
/* clear code length count table */
|
||||
for (i = 0; i < 16; ++i) t->table[i] = 0;
|
||||
|
||||
/* scan symbol lengths, and sum code length counts */
|
||||
for (i = 0; i < num; ++i) t->table[lengths[i]]++;
|
||||
|
||||
t->table[0] = 0;
|
||||
|
||||
/* compute offset table for distribution sort */
|
||||
for (sum = 0, i = 0; i < 16; ++i)
|
||||
{
|
||||
offs[i] = sum;
|
||||
sum += t->table[i];
|
||||
}
|
||||
|
||||
/* create code->symbol translation table (symbols sorted by code) */
|
||||
for (i = 0; i < num; ++i)
|
||||
{
|
||||
if (lengths[i]) t->trans[offs[lengths[i]]++] = i;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------------- *
|
||||
* -- decode functions -- *
|
||||
* ---------------------- */
|
||||
|
||||
/* get one bit from source stream */
|
||||
static int tinf_getbit(TINF_DATA *d)
|
||||
{
|
||||
unsigned int bit;
|
||||
|
||||
/* check if tag is empty */
|
||||
if (!d->bitcount--)
|
||||
{
|
||||
/* load next tag */
|
||||
d->tag = *d->source++;
|
||||
d->bitcount = 7;
|
||||
}
|
||||
|
||||
/* shift bit out of tag */
|
||||
bit = d->tag & 0x01;
|
||||
d->tag >>= 1;
|
||||
|
||||
return bit;
|
||||
}
|
||||
|
||||
/* read a num bit value from a stream and add base */
|
||||
static unsigned int tinf_read_bits(TINF_DATA *d, int num, int base)
|
||||
{
|
||||
unsigned int val = 0;
|
||||
|
||||
/* read num bits */
|
||||
if (num)
|
||||
{
|
||||
unsigned int limit = 1 << (num);
|
||||
unsigned int mask;
|
||||
|
||||
for (mask = 1; mask < limit; mask *= 2)
|
||||
if (tinf_getbit(d)) val += mask;
|
||||
}
|
||||
|
||||
return val + base;
|
||||
}
|
||||
|
||||
/* given a data stream and a tree, decode a symbol */
|
||||
static int tinf_decode_symbol(TINF_DATA *d, TINF_TREE *t)
|
||||
{
|
||||
int sum = 0, cur = 0, len = 0;
|
||||
|
||||
/* get more bits while code value is above sum */
|
||||
do {
|
||||
|
||||
cur = 2*cur + tinf_getbit(d);
|
||||
|
||||
++len;
|
||||
|
||||
sum += t->table[len];
|
||||
cur -= t->table[len];
|
||||
|
||||
} while (cur >= 0);
|
||||
|
||||
return t->trans[sum + cur];
|
||||
}
|
||||
|
||||
/* given a data stream, decode dynamic trees from it */
|
||||
static void tinf_decode_trees(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt)
|
||||
{
|
||||
unsigned char lengths[288+32];
|
||||
unsigned int hlit, hdist, hclen;
|
||||
unsigned int i, num, length;
|
||||
|
||||
/* get 5 bits HLIT (257-286) */
|
||||
hlit = tinf_read_bits(d, 5, 257);
|
||||
|
||||
/* get 5 bits HDIST (1-32) */
|
||||
hdist = tinf_read_bits(d, 5, 1);
|
||||
|
||||
/* get 4 bits HCLEN (4-19) */
|
||||
hclen = tinf_read_bits(d, 4, 4);
|
||||
|
||||
for (i = 0; i < 19; ++i) lengths[i] = 0;
|
||||
|
||||
/* read code lengths for code length alphabet */
|
||||
for (i = 0; i < hclen; ++i)
|
||||
{
|
||||
/* get 3 bits code length (0-7) */
|
||||
unsigned int clen = tinf_read_bits(d, 3, 0);
|
||||
|
||||
lengths[clcidx[i]] = clen;
|
||||
}
|
||||
|
||||
/* build code length tree, temporarily use length tree */
|
||||
tinf_build_tree(lt, lengths, 19);
|
||||
|
||||
/* decode code lengths for the dynamic trees */
|
||||
for (num = 0; num < hlit + hdist; )
|
||||
{
|
||||
int sym = tinf_decode_symbol(d, lt);
|
||||
|
||||
switch (sym)
|
||||
{
|
||||
case 16:
|
||||
/* copy previous code length 3-6 times (read 2 bits) */
|
||||
{
|
||||
unsigned char prev = lengths[num - 1];
|
||||
for (length = tinf_read_bits(d, 2, 3); length; --length)
|
||||
{
|
||||
lengths[num++] = prev;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 17:
|
||||
/* repeat code length 0 for 3-10 times (read 3 bits) */
|
||||
for (length = tinf_read_bits(d, 3, 3); length; --length)
|
||||
{
|
||||
lengths[num++] = 0;
|
||||
}
|
||||
break;
|
||||
case 18:
|
||||
/* repeat code length 0 for 11-138 times (read 7 bits) */
|
||||
for (length = tinf_read_bits(d, 7, 11); length; --length)
|
||||
{
|
||||
lengths[num++] = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* values 0-15 represent the actual code lengths */
|
||||
lengths[num++] = sym;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* build dynamic trees */
|
||||
tinf_build_tree(lt, lengths, hlit);
|
||||
tinf_build_tree(dt, lengths + hlit, hdist);
|
||||
}
|
||||
|
||||
/* ----------------------------- *
|
||||
* -- block inflate functions -- *
|
||||
* ----------------------------- */
|
||||
|
||||
/* given a stream and two trees, inflate a block of data */
|
||||
static int tinf_inflate_block_data(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
int sym = tinf_decode_symbol(d, lt);
|
||||
|
||||
/* check for end of block */
|
||||
if (sym == 256)
|
||||
{
|
||||
return TINF_OK;
|
||||
}
|
||||
|
||||
if (sym < 256)
|
||||
{
|
||||
if (d->destRemaining == 0)
|
||||
{
|
||||
int res = tinf_grow_dest_buf(d, 1);
|
||||
if (res) return res;
|
||||
}
|
||||
|
||||
*d->dest++ = sym;
|
||||
d->destRemaining--;
|
||||
|
||||
} else {
|
||||
|
||||
unsigned int length, offs, i;
|
||||
int dist;
|
||||
|
||||
sym -= 257;
|
||||
|
||||
/* possibly get more bits from length code */
|
||||
length = tinf_read_bits(d, length_bits[sym], length_base[sym]);
|
||||
|
||||
dist = tinf_decode_symbol(d, dt);
|
||||
|
||||
/* possibly get more bits from distance code */
|
||||
offs = tinf_read_bits(d, dist_bits[dist], dist_base[dist]);
|
||||
|
||||
if (d->destRemaining < length)
|
||||
{
|
||||
int res = tinf_grow_dest_buf(d, length);
|
||||
if (res) return res;
|
||||
}
|
||||
|
||||
/* copy match */
|
||||
for (i = 0; i < length; ++i)
|
||||
{
|
||||
d->dest[i] = d->dest[(int)(i - offs)];
|
||||
}
|
||||
|
||||
d->dest += length;
|
||||
d->destRemaining -= length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* inflate an uncompressed block of data */
|
||||
static int tinf_inflate_uncompressed_block(TINF_DATA *d)
|
||||
{
|
||||
unsigned int length, invlength;
|
||||
unsigned int i;
|
||||
|
||||
/* get length */
|
||||
length = d->source[1];
|
||||
length = 256*length + d->source[0];
|
||||
|
||||
/* get one's complement of length */
|
||||
invlength = d->source[3];
|
||||
invlength = 256*invlength + d->source[2];
|
||||
|
||||
/* check length */
|
||||
if (length != (~invlength & 0x0000ffff)) return TINF_DATA_ERROR;
|
||||
|
||||
if (d->destRemaining < length)
|
||||
{
|
||||
int res = tinf_grow_dest_buf(d, length);
|
||||
if (res) return res;
|
||||
}
|
||||
|
||||
d->source += 4;
|
||||
|
||||
/* copy block */
|
||||
for (i = length; i; --i) *d->dest++ = *d->source++;
|
||||
d->destRemaining -= length;
|
||||
|
||||
/* make sure we start next block on a byte boundary */
|
||||
d->bitcount = 0;
|
||||
|
||||
return TINF_OK;
|
||||
}
|
||||
|
||||
/* inflate a block of data compressed with fixed huffman trees */
|
||||
static int tinf_inflate_fixed_block(TINF_DATA *d)
|
||||
{
|
||||
/* build fixed huffman trees */
|
||||
tinf_build_fixed_trees(&d->ltree, &d->dtree);
|
||||
|
||||
/* decode block using fixed trees */
|
||||
return tinf_inflate_block_data(d, &d->ltree, &d->dtree);
|
||||
}
|
||||
|
||||
/* inflate a block of data compressed with dynamic huffman trees */
|
||||
static int tinf_inflate_dynamic_block(TINF_DATA *d)
|
||||
{
|
||||
/* decode trees from stream */
|
||||
tinf_decode_trees(d, &d->ltree, &d->dtree);
|
||||
|
||||
/* decode block using decoded trees */
|
||||
return tinf_inflate_block_data(d, &d->ltree, &d->dtree);
|
||||
}
|
||||
|
||||
/* ---------------------- *
|
||||
* -- public functions -- *
|
||||
* ---------------------- */
|
||||
|
||||
/* initialize global (static) data */
|
||||
void tinf_init(void)
|
||||
{
|
||||
#ifdef RUNTIME_BITS_TABLES
|
||||
/* build extra bits and base tables */
|
||||
tinf_build_bits_base(length_bits, length_base, 4, 3);
|
||||
tinf_build_bits_base(dist_bits, dist_base, 2, 1);
|
||||
|
||||
/* fix a special case */
|
||||
length_bits[28] = 0;
|
||||
length_base[28] = 258;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* inflate stream from source to dest */
|
||||
int tinf_uncompress(void *dest, unsigned int *destLen,
|
||||
const void *source, unsigned int sourceLen)
|
||||
{
|
||||
(void)sourceLen;
|
||||
TINF_DATA d;
|
||||
int res;
|
||||
|
||||
/* initialise data */
|
||||
d.source = (const unsigned char *)source;
|
||||
|
||||
d.destStart = (unsigned char *)dest;
|
||||
d.destRemaining = *destLen;
|
||||
d.destSize = *destLen;
|
||||
|
||||
res = tinf_uncompress_dyn(&d);
|
||||
|
||||
*destLen = d.dest - d.destStart;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* inflate stream from source to dest */
|
||||
int tinf_uncompress_dyn(TINF_DATA *d)
|
||||
{
|
||||
int bfinal;
|
||||
|
||||
/* initialise data */
|
||||
d->bitcount = 0;
|
||||
|
||||
d->dest = d->destStart;
|
||||
d->destRemaining = d->destSize;
|
||||
|
||||
do {
|
||||
|
||||
unsigned int btype;
|
||||
int res;
|
||||
|
||||
/* read final block flag */
|
||||
bfinal = tinf_getbit(d);
|
||||
|
||||
/* read block type (2 bits) */
|
||||
btype = tinf_read_bits(d, 2, 0);
|
||||
|
||||
/* decompress block */
|
||||
switch (btype)
|
||||
{
|
||||
case 0:
|
||||
/* decompress uncompressed block */
|
||||
res = tinf_inflate_uncompressed_block(d);
|
||||
break;
|
||||
case 1:
|
||||
/* decompress block with fixed huffman trees */
|
||||
res = tinf_inflate_fixed_block(d);
|
||||
break;
|
||||
case 2:
|
||||
/* decompress block with dynamic huffman trees */
|
||||
res = tinf_inflate_dynamic_block(d);
|
||||
break;
|
||||
default:
|
||||
return TINF_DATA_ERROR;
|
||||
}
|
||||
|
||||
if (res != TINF_OK) return TINF_DATA_ERROR;
|
||||
|
||||
} while (!bfinal);
|
||||
|
||||
return TINF_OK;
|
||||
}
|
101
examples/websocket_mbedtls/tinfzlib.c
Normal file
101
examples/websocket_mbedtls/tinfzlib.c
Normal file
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* tinfzlib - tiny zlib decompressor
|
||||
*
|
||||
* Copyright (c) 2003 by Joergen Ibsen / Jibz
|
||||
* All Rights Reserved
|
||||
*
|
||||
* http://www.ibsensoftware.com/
|
||||
*
|
||||
* This software is provided 'as-is', without any express
|
||||
* or implied warranty. In no event will the authors be
|
||||
* held liable for any damages arising from the use of
|
||||
* this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software
|
||||
* for any purpose, including commercial applications,
|
||||
* and to alter it and redistribute it freely, subject to
|
||||
* the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be
|
||||
* misrepresented; you must not claim that you
|
||||
* wrote the original software. If you use this
|
||||
* software in a product, an acknowledgment in
|
||||
* the product documentation would be appreciated
|
||||
* but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked
|
||||
* as such, and must not be misrepresented as
|
||||
* being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from
|
||||
* any source distribution.
|
||||
*/
|
||||
|
||||
#include "tinf.h"
|
||||
|
||||
int tinf_zlib_uncompress(void *dest, unsigned int *destLen,
|
||||
const void *source, unsigned int sourceLen)
|
||||
{
|
||||
TINF_DATA d;
|
||||
int res;
|
||||
|
||||
/* initialise data */
|
||||
d.source = (const unsigned char *)source;
|
||||
|
||||
d.destStart = (unsigned char *)dest;
|
||||
d.destRemaining = *destLen;
|
||||
|
||||
res = tinf_zlib_uncompress_dyn(&d, sourceLen);
|
||||
|
||||
*destLen = d.dest - d.destStart;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int tinf_zlib_uncompress_dyn(TINF_DATA *d, unsigned int sourceLen)
|
||||
{
|
||||
unsigned int a32;
|
||||
int res;
|
||||
unsigned char cmf, flg;
|
||||
|
||||
/* -- get header bytes -- */
|
||||
|
||||
cmf = d->source[0];
|
||||
flg = d->source[1];
|
||||
|
||||
/* -- check format -- */
|
||||
|
||||
/* check checksum */
|
||||
if ((256*cmf + flg) % 31) return TINF_DATA_ERROR;
|
||||
|
||||
/* check method is deflate */
|
||||
if ((cmf & 0x0f) != 8) return TINF_DATA_ERROR;
|
||||
|
||||
/* check window size is valid */
|
||||
if ((cmf >> 4) > 7) return TINF_DATA_ERROR;
|
||||
|
||||
/* check there is no preset dictionary */
|
||||
if (flg & 0x20) return TINF_DATA_ERROR;
|
||||
|
||||
/* -- get adler32 checksum -- */
|
||||
|
||||
a32 = d->source[sourceLen - 4];
|
||||
a32 = 256*a32 + d->source[sourceLen - 3];
|
||||
a32 = 256*a32 + d->source[sourceLen - 2];
|
||||
a32 = 256*a32 + d->source[sourceLen - 1];
|
||||
|
||||
d->source += 2;
|
||||
|
||||
/* -- inflate -- */
|
||||
|
||||
res = tinf_uncompress_dyn(d);
|
||||
|
||||
if (res != TINF_OK) return res;
|
||||
|
||||
/* -- check adler32 checksum -- */
|
||||
|
||||
if (a32 != tinf_adler32(d->destStart, d->dest - d->destStart)) return TINF_DATA_ERROR;
|
||||
|
||||
return TINF_OK;
|
||||
}
|
||||
|
28
examples/websocket_mbedtls/util.h
Normal file
28
examples/websocket_mbedtls/util.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
// util
|
||||
void hex_dump(const char *desc, const void *addr, const size_t len);
|
||||
|
||||
#define Int32 signed long
|
||||
#define Uint32 unsigned long
|
||||
#define Byte unsigned char
|
||||
#define Word unsigned short
|
||||
#define Bool char
|
||||
#define true 1
|
||||
#define false 0
|
||||
|
||||
#define MAKEWORD(a, b) ((Word)(((Byte)((a) & 0xff)) | ((Word)((Byte)((b) & 0xff))) << 8))
|
||||
#define MAKELONG(low,high) ((Int32)(((Word)(low)) | (((Uint32)((Word)(high))) << 16)))
|
||||
#define LOWORD(l) ((Word)((l) & 0xffff))
|
||||
#define HIWORD(l) ((Word)((l) >> 16))
|
||||
#define LOBYTE(w) ((Byte)((w) & 0xff))
|
||||
#define HIBYTE(w) ((Byte)((w) >> 8))
|
||||
#define HH(x) HIBYTE(HIWORD( x ))
|
||||
#define HL(x) LOBYTE(HIWORD( x ))
|
||||
#define LH(x) HIBYTE(LOWORD( x ))
|
||||
#define LL(x) LOBYTE(LOWORD( x ))
|
||||
#define LONIBLE(x) (((Byte)x) & 0x0F )
|
||||
#define HINIBLE(x) ((((Byte)x) * 0xF0)>>4)
|
||||
|
||||
#define _SWAPS(x) ((unsigned short)( \
|
||||
((((unsigned short) x) & 0x000000FF) << 8) | \
|
||||
((((unsigned short) x) & 0x0000FF00) >> 8) \
|
||||
))
|
108
examples/websocket_mbedtls/websocket_mbedtls.c
Normal file
108
examples/websocket_mbedtls/websocket_mbedtls.c
Normal file
|
@ -0,0 +1,108 @@
|
|||
/* websocket_mbedtls - Websocket example using mbed TLS.
|
||||
*
|
||||
* It creates a websocket with a server running on Heroku. It uses TLS v1.2.
|
||||
* I already implemented support to the permessage-deflate extension that
|
||||
* reduces the footprint of the websocket frames using the inflate deflate
|
||||
* algorithm.
|
||||
|
||||
* The remaining memory when using the websocket on top of mbed TLS 1.2 is ~14Kb
|
||||
*
|
||||
* There is room for memory optimization. Feel free to improve the code.
|
||||
*
|
||||
* After get the esp8266 connected, go to ruby-websockets-chat.herokuapp.com
|
||||
* and type some commands like break (to reconnect), turn led on and turn led off.
|
||||
*
|
||||
* If you wanna check the source code from the server:
|
||||
* https://github.com/heroku-examples/ruby-websockets-chat-demo
|
||||
*
|
||||
* If you wanna work with the permessage-deflate extension, connect to the
|
||||
* host serene-escarpment-15149.herokuapp.com and the path /echo . It is a websocket
|
||||
* server echoing back your messages and supporting the permessage-deflate extension:
|
||||
* https://github.com/luisbebop/websocket-echo-deflate
|
||||
*/
|
||||
|
||||
#include "espressif/esp_common.h"
|
||||
#include "esp/uart.h"
|
||||
#include <string.h>
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "ssid_config.h"
|
||||
#include "conn.h"
|
||||
#include "ws.h"
|
||||
#include "util.h"
|
||||
|
||||
const int gpio = 2;
|
||||
|
||||
void websocket_task(void *pvParameters)
|
||||
{
|
||||
//char * host = "serene-escarpment-15149.herokuapp.com";
|
||||
//char * path = "/echo";
|
||||
|
||||
char *host = "ruby-websockets-chat.herokuapp.com";
|
||||
char *path = "/";
|
||||
|
||||
int socket = 0, ret = 0;
|
||||
int port = 443;
|
||||
Bool compression = false, timeout = false;
|
||||
char text[2048];
|
||||
|
||||
gpio_enable(gpio, GPIO_OUTPUT);
|
||||
gpio_write(gpio, 1);
|
||||
|
||||
while(1) {
|
||||
vTaskDelay(5000 / portTICK_RATE_MS);
|
||||
printf("top of loop, free heap = %u\n", xPortGetFreeHeapSize());
|
||||
|
||||
socket = ConnConnect(host, port);
|
||||
printf("\nConnConnect socket %d\n", socket);
|
||||
|
||||
ret = wsConnect(socket, host, path, &compression);
|
||||
printf("wsConnect ret %d compression %d\n", ret, compression);
|
||||
if ( ret < 0)
|
||||
{
|
||||
printf("websocket handshake error ret=%d\n", ret);
|
||||
}
|
||||
|
||||
strcpy(text, "{\"handle\":\"websocket-c-client\", \"text\": \"hello from low level ~*~ esp8266\"}");
|
||||
wsSendText(socket, text, compression);
|
||||
|
||||
while(1) {
|
||||
printf("top of loop, free heap = %u\n", xPortGetFreeHeapSize());
|
||||
|
||||
memset(text, 0, sizeof(text));
|
||||
wsReceiveText(socket, text, 2048, compression, &timeout, 15);
|
||||
|
||||
if (timeout) {
|
||||
printf("wsReceiveText timeout\n");
|
||||
} else {
|
||||
printf("no timeout ...\n");
|
||||
printf("%s\n", text);
|
||||
|
||||
if(strstr(text, "break") != 0) break;
|
||||
if(strstr(text, "turn led on") != 0) gpio_write(gpio, 0);
|
||||
if(strstr(text, "turn led off") != 0) gpio_write(gpio, 1);
|
||||
}
|
||||
}
|
||||
|
||||
printf("Before ConnClose top of loop, free heap = %u\n", xPortGetFreeHeapSize());
|
||||
ConnClose(socket);
|
||||
printf("After ConnClose top of loop, free heap = %u\n", xPortGetFreeHeapSize());
|
||||
}
|
||||
}
|
||||
|
||||
void user_init(void)
|
||||
{
|
||||
uart_set_baud(0, 115200);
|
||||
printf("SDK version:%s\n", sdk_system_get_sdk_version());
|
||||
|
||||
struct sdk_station_config config = {
|
||||
.ssid = WIFI_SSID,
|
||||
.password = WIFI_PASS,
|
||||
};
|
||||
|
||||
/* required to call wifi_set_opmode before station_set_config */
|
||||
sdk_wifi_set_opmode(STATION_MODE);
|
||||
sdk_wifi_station_set_config(&config);
|
||||
|
||||
xTaskCreate(&websocket_task, (signed char *)"websocket_task", 2048, NULL, 2, NULL);
|
||||
}
|
270
examples/websocket_mbedtls/ws.c
Normal file
270
examples/websocket_mbedtls/ws.c
Normal file
|
@ -0,0 +1,270 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "tinf.h"
|
||||
#include "defl_static.h"
|
||||
#include "conn.h"
|
||||
#include "ws.h"
|
||||
|
||||
const static char http_get[] = "GET wss://%s%s HTTP/1.1\r\n";
|
||||
const static char http_host[] = "Host: %s\r\n";
|
||||
const static char http_origin[] = "Origin: https://%s\r\n";
|
||||
const static char http_upgrade[] = "Upgrade: websocket\r\n";
|
||||
const static char http_connection[] = "Connection: Upgrade\r\n";
|
||||
const static char http_ws_key[] = "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\nSec-WebSocket-Extensions: permessage-deflate\r\n";
|
||||
const static char http_ws_version[] = "Sec-WebSocket-Version: 13\r\n";
|
||||
|
||||
#define WS_OPCODE_CONTINUATION 0x00
|
||||
#define WS_OPCODE_TEXT 0x01
|
||||
#define WS_OPCODE_BINARY 0x02
|
||||
#define WS_OPCODE_CONECTION_CLOSE 0x08
|
||||
#define WS_OPCODE_PING 0x09
|
||||
#define WS_OPCODE_PONG 0x0A
|
||||
|
||||
int wsConnect(int socket, const char *host, const char *path, Bool *compression) {
|
||||
char server_reply[1024];
|
||||
char buffer[1024];
|
||||
|
||||
memset(server_reply, 0, sizeof(server_reply));
|
||||
*compression = false;
|
||||
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
sprintf(buffer, http_get, host, path);
|
||||
ConnWrite(socket, buffer, strlen(buffer));
|
||||
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
sprintf(buffer, http_host, host);
|
||||
ConnWrite(socket, buffer, strlen(buffer));
|
||||
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
sprintf(buffer, http_origin, host);
|
||||
ConnWrite(socket, buffer, strlen(buffer));
|
||||
|
||||
ConnWrite(socket, http_upgrade, strlen(http_upgrade));
|
||||
ConnWrite(socket, http_connection, strlen(http_connection));
|
||||
ConnWrite(socket, http_ws_key, strlen(http_ws_key));
|
||||
ConnWrite(socket, http_ws_version, strlen(http_ws_version));
|
||||
ConnWrite(socket, "\r\n", 2);
|
||||
|
||||
if (ConnRead(socket, server_reply, 300) <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strstr(server_reply, "HTTP/1.1 101 Switching Protocols") == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strstr(server_reply, "permessage-deflate") != 0) {
|
||||
*compression = true;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void wsInitFrame(WsFrame *frame) {
|
||||
frame->finFlag = 0;
|
||||
frame->maskingFlag = 0;
|
||||
frame->opcode = 0;
|
||||
frame->payloadLenght = 0;
|
||||
frame->maskingMap = 0;
|
||||
frame->payload = 0;
|
||||
}
|
||||
|
||||
void wsCreateTextFrame(WsFrame *frame, const char *text) {
|
||||
frame->finFlag = 1;
|
||||
frame->maskingFlag = 1;
|
||||
frame->opcode = WS_OPCODE_TEXT;
|
||||
frame->payloadLenght = strlen(text);
|
||||
frame->maskingMap = 0x00000000;
|
||||
frame->payload = (uint8_t *)text;
|
||||
}
|
||||
|
||||
void wsSendFrame(int socket, WsFrame *frame) {
|
||||
uint8_t finOpcode = (frame->finFlag) ? frame->opcode | 0x80 : frame->opcode;
|
||||
uint8_t maskPayloadLength = (frame->maskingFlag) ? frame->payloadLenght | 0x80 : frame->payloadLenght;
|
||||
unsigned short sizePayload;
|
||||
|
||||
// todo support extended payloadLength
|
||||
// The length of the "Payload data", in bytes: if 0-125, that is the
|
||||
// payload length. If 126, the following 2 bytes interpreted as a
|
||||
// 16-bit unsigned integer are the payload length. If 127, the
|
||||
// following 8 bytes interpreted as a 64-bit unsigned integer (the
|
||||
// most significant bit MUST be 0) are the payload length. Multibyte
|
||||
// length quantities are expressed in network byte order. Note that
|
||||
// in all cases, the minimal number of bytes MUST be used to encode
|
||||
// the length, for example, the length of a 124-byte-long string
|
||||
// can't be encoded as the sequence 126, 0, 124. The payload length
|
||||
// is the length of the "Extension data" + the length of the
|
||||
// "Application data". The length of the "Extension data" may be
|
||||
// zero, in which case the payload length is the length of the
|
||||
// "Application data".
|
||||
// FE = 126
|
||||
if (frame->payloadLenght > 125) {
|
||||
maskPayloadLength = 0xfe;
|
||||
sizePayload = MAKEWORD(LL(frame->payloadLenght), LH(frame->payloadLenght));
|
||||
}
|
||||
|
||||
|
||||
ConnWrite(socket, &finOpcode, 1);
|
||||
ConnWrite(socket, &maskPayloadLength, 1);
|
||||
|
||||
if (frame->payloadLenght > 125) {
|
||||
sizePayload = _SWAPS(sizePayload);
|
||||
ConnWrite(socket, &sizePayload, 2);
|
||||
}
|
||||
|
||||
ConnWrite(socket, &frame->maskingMap , 4);
|
||||
ConnWrite(socket, frame->payload, frame->payloadLenght);
|
||||
}
|
||||
|
||||
void wsReceiveFrame(int socket, WsFrame *frame, Bool *timeout, int seconds) {
|
||||
unsigned char inBuffer[2048];
|
||||
int receivedTotal = 0;
|
||||
int receivedLength = 0;
|
||||
int i = 0, ret = 0;
|
||||
|
||||
*timeout = false;
|
||||
memset(inBuffer, 0, sizeof(inBuffer));
|
||||
|
||||
while((ret = ConnReadBytesAvailable(socket)) == 0) {
|
||||
i++;
|
||||
sleep_ms(10);
|
||||
if ((i > (seconds * 100)) && ret == 0) {
|
||||
*timeout = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
while((receivedLength = ConnRead(socket, inBuffer + receivedTotal, 2 - receivedTotal)) > 0 && receivedTotal < 2) {
|
||||
receivedTotal += receivedLength;
|
||||
}
|
||||
|
||||
frame->finFlag = (inBuffer[0] & 0x80) >> 7;
|
||||
frame->opcode = inBuffer[0] & 0x0F;
|
||||
frame->maskingFlag = inBuffer[1] & 0x80;
|
||||
frame->payloadLenght = MAKEWORD(inBuffer[1], 0x00);
|
||||
|
||||
if (frame->payloadLenght > 125) {
|
||||
receivedLength = ConnRead(socket, inBuffer, 2);
|
||||
frame->payloadLenght = MAKEWORD(inBuffer[1], inBuffer[0]);
|
||||
}
|
||||
|
||||
while((receivedLength = ConnRead(socket, inBuffer + receivedTotal, frame->payloadLenght + 2 - receivedTotal)) > 0 && receivedTotal < frame->payloadLenght) {
|
||||
receivedTotal += receivedLength;
|
||||
if ((receivedTotal - 2) == frame->payloadLenght) break;
|
||||
}
|
||||
|
||||
memcpy(frame->payload, inBuffer + 2, receivedTotal - 2);
|
||||
|
||||
if (frame->opcode == WS_OPCODE_PING) {
|
||||
wsSendPong(socket, frame);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char gzipBuffer[2048];
|
||||
void wsInflateFrame(WsFrame *frame) {
|
||||
unsigned int outlen = 2048;
|
||||
|
||||
memset(gzipBuffer, 0, sizeof(gzipBuffer));
|
||||
|
||||
// https://tools.ietf.org/html/draft-ietf-hybi-permessage-compression-28#page-22
|
||||
// 7.2.2 Decompression
|
||||
frame->payload[frame->payloadLenght-1] = 0x01;
|
||||
frame->payload[frame->payloadLenght] = 0x00;
|
||||
frame->payload[frame->payloadLenght+1] = 0x00;
|
||||
frame->payload[frame->payloadLenght+2] = 0xff;
|
||||
frame->payload[frame->payloadLenght+3] = 0xff;
|
||||
|
||||
tinf_uncompress(gzipBuffer, &outlen, frame->payload, frame->payloadLenght+4);
|
||||
|
||||
memset(frame->payload, 0, frame->payloadLenght+3);
|
||||
memcpy(frame->payload, gzipBuffer, outlen);
|
||||
}
|
||||
|
||||
void wsDeflateFrame(WsFrame *frame) {
|
||||
struct Outbuf out = {0};
|
||||
memset(gzipBuffer, 0, sizeof(gzipBuffer));
|
||||
|
||||
//Deflate payload
|
||||
zlib_start_block(&out);
|
||||
tinf_compress(&out, frame->payload, frame->payloadLenght);
|
||||
zlib_finish_block(&out);
|
||||
|
||||
memcpy(gzipBuffer, out.outbuf, out.outlen);
|
||||
|
||||
frame->finFlag = 0;
|
||||
frame->opcode = 0xc1;
|
||||
frame->payloadLenght = out.outlen;
|
||||
frame->payload = (uint8_t *)gzipBuffer;
|
||||
|
||||
zlib_free_block(&out);
|
||||
}
|
||||
|
||||
void wsSendPong(int socket, WsFrame *frame) {
|
||||
frame->maskingFlag = 1;
|
||||
frame->opcode = WS_OPCODE_PONG;
|
||||
frame->payloadLenght = 0;
|
||||
wsSendFrame(socket, frame);
|
||||
}
|
||||
|
||||
void wsSendText(int socket, const char *text, Bool compression) {
|
||||
WsFrame frame;
|
||||
wsInitFrame(&frame);
|
||||
wsCreateTextFrame(&frame, text);
|
||||
if (compression) wsDeflateFrame(&frame);
|
||||
wsSendFrame(socket, &frame);
|
||||
}
|
||||
|
||||
void wsReceiveText(int socket, char *buffer, int bufferSize, Bool compression, Bool *timeout, int seconds) {
|
||||
WsFrame frame;
|
||||
wsInitFrame(&frame);
|
||||
memset(buffer, 0, bufferSize);
|
||||
frame.payload = (uint8_t *)buffer;
|
||||
wsReceiveFrame(socket, &frame, timeout, seconds);
|
||||
if (frame.opcode == WS_OPCODE_TEXT && compression) wsInflateFrame(&frame);
|
||||
if (frame.opcode == WS_OPCODE_PONG) strcpy(buffer, "OPCODE_PING");
|
||||
}
|
||||
|
||||
void hex_dump(const char *desc, const void *addr, const size_t len) {
|
||||
int i;
|
||||
unsigned char buff[17];
|
||||
unsigned char *pc = (unsigned char*)addr;
|
||||
|
||||
// Output description if given.
|
||||
if (desc != NULL)
|
||||
printf ("%s:\n", desc);
|
||||
|
||||
// Process every byte in the data.
|
||||
for (i = 0; i < len; i++) {
|
||||
// Multiple of 16 means new line (with line offset).
|
||||
|
||||
if ((i % 16) == 0) {
|
||||
// Just don't print ASCII for the zeroth line.
|
||||
if (i != 0)
|
||||
printf (" %s\n", buff);
|
||||
|
||||
// Output the offset.
|
||||
printf (" %04x ", i);
|
||||
}
|
||||
|
||||
// Now the hex code for the specific character.
|
||||
printf (" %02x", pc[i]);
|
||||
|
||||
// And store a printable ASCII character for later.
|
||||
if ((pc[i] < 0x20) || (pc[i] > 0x7e))
|
||||
buff[i % 16] = '.';
|
||||
else
|
||||
buff[i % 16] = pc[i];
|
||||
buff[(i % 16) + 1] = '\0';
|
||||
}
|
||||
|
||||
// Pad out last line if not exactly 16 characters.
|
||||
while ((i % 16) != 0) {
|
||||
printf (" ");
|
||||
i++;
|
||||
}
|
||||
|
||||
// And print the final ASCII bit.
|
||||
printf (" %s\n", buff);
|
||||
}
|
27
examples/websocket_mbedtls/ws.h
Normal file
27
examples/websocket_mbedtls/ws.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
#ifndef WEBSOCKETS
|
||||
#define WEBSOCKETS
|
||||
|
||||
#include "util.h"
|
||||
|
||||
typedef struct WsFrame_ {
|
||||
Byte finFlag;
|
||||
Byte maskingFlag;
|
||||
Byte opcode;
|
||||
Uint32 payloadLenght;
|
||||
Uint32 maskingMap;
|
||||
Byte *payload;
|
||||
} WsFrame;
|
||||
|
||||
int wsConnect(int socket, const char *host, const char *path, Bool *compression);
|
||||
void wsInitFrame(WsFrame *frame);
|
||||
void wsCreateTextFrame(WsFrame *frame, const char *text);
|
||||
void wsSendFrame(int socket, WsFrame *frame);
|
||||
void wsReceiveFrame(int socket, WsFrame *frame, Bool *timeout, int seconds);
|
||||
void wsInflateFrame(WsFrame *frame);
|
||||
void wsDeflateFrame(WsFrame *frame);
|
||||
void wsSendPong(int socket, WsFrame *frame);
|
||||
void wsSendText(int socket, const char *text, Bool compression);
|
||||
void wsReceiveText(int socket, char *buffer, int bufferSize, Bool compression, Bool *timeout, int seconds);
|
||||
void hex_dump(const char *desc, const void *addr, const size_t len);
|
||||
|
||||
#endif
|
|
@ -345,7 +345,8 @@
|
|||
/**
|
||||
* LWIP_SO_RCVBUF==1: Enable SO_RCVBUF processing.
|
||||
*/
|
||||
#define LWIP_SO_RCVBUF 0
|
||||
#define LWIP_SO_RCVBUF 1
|
||||
#define INT_MAX __INT_MAX__
|
||||
|
||||
/**
|
||||
* SO_REUSE==1: Enable SO_REUSEADDR option.
|
||||
|
|
Loading…
Reference in a new issue