diff --git a/netutils/cwebsocket/0001-Porting-the-code-for-NuttX.patch b/netutils/cwebsocket/0001-Porting-the-code-for-NuttX.patch new file mode 100644 index 000000000..dc3348b04 --- /dev/null +++ b/netutils/cwebsocket/0001-Porting-the-code-for-NuttX.patch @@ -0,0 +1,1737 @@ +From 3898d4b6601f951f630f615098f5546f7184fe90 Mon Sep 17 00:00:00 2001 +From: SPRESENSE <41312067+SPRESENSE@users.noreply.github.com> +Date: Fri, 19 Apr 2019 17:40:58 +0900 +Subject: [PATCH 1/2] Porting the code for NuttX + +--- + cwebsocket/src/cwebsocket/client.c | 801 +++++++++++++++++++---------- + cwebsocket/src/cwebsocket/client.h | 177 ++++++- + cwebsocket/src/cwebsocket/common.c | 29 +- + cwebsocket/src/cwebsocket/common.h | 68 ++- + 4 files changed, 752 insertions(+), 323 deletions(-) + +diff --git a/cwebsocket/src/cwebsocket/client.c b/cwebsocket/src/cwebsocket/client.c +index 09f7a06..50747f0 100755 +--- a/cwebsocket/src/cwebsocket/client.c ++++ b/cwebsocket/src/cwebsocket/client.c +@@ -24,116 +24,198 @@ + + #include "client.h" + +-void cwebsocket_client_init(cwebsocket_client *websocket, cwebsocket_subprotocol *subprotocols[], int subprotocol_len) { ++/* for NUTTX */ ++extern int getaddrinfo(const char *nodename, const char *servname, ++ const struct addrinfo *hints, struct addrinfo **res); ++extern void freeaddrinfo(struct addrinfo *res); ++extern int ws_sscanf(FAR const char *buf, FAR const char *fmt, ...); ++ ++int cwebsocket_client_init(cwebsocket_client *websocket, cwebsocket_subprotocol **subprotocols, int subprotocol_len) { ++ if (subprotocol_len > WEBSOCKET_SUBPROTOCOL_MAX) ++ return -1; + websocket->fd = 0; + websocket->retry = 0; + websocket->uri = '\0'; + websocket->flags = 0; + websocket->state = WEBSOCKET_STATE_CLOSED; ++ websocket->proxy_addr = NULL; ++ websocket->proxy_port = NULL; ++ websocket->headers = NULL; ++ websocket->num_headers = 0; + websocket->subprotocol_len = subprotocol_len; + int i; + for(i=0; iname); ++ WS_DEBUG("client_init: loading subprotocol %s\n", subprotocols[i]->name); ++ + websocket->subprotocols[i] = subprotocols[i]; + } +- const rlim_t kStackSize = CWS_STACK_SIZE_MIN * 1024 * 1024; +- struct rlimit rl; +- int result; +- result = getrlimit(RLIMIT_STACK, &rl); +- if (result == 0) { +- if (rl.rlim_cur < kStackSize) { +- rl.rlim_cur = kStackSize; +- result = setrlimit(RLIMIT_STACK, &rl); +- if(result != 0) { +- syslog(LOG_CRIT, "cwebsocket_client_init: unable to set stack space"); +- exit(1); +- } +- } ++ websocket->subprotocol = websocket->subprotocols[0]; ++ return 0; ++} ++ ++void cwebsocket_client_set_proxy(cwebsocket_client *websocket, char *proxy_addr, char *proxy_port) ++{ ++ if (strlen(proxy_addr) > 0 && strlen(proxy_port) > 0){ ++ websocket->flags |= WEBSOCKET_FLAG_PROXY; ++ websocket->proxy_addr = proxy_addr; ++ websocket->proxy_port = proxy_port; ++ }else { ++ WS_DEBUG("client_set_proxy: invalid proxy_addr\n"); ++ } ++} ++void cwebsocket_client_unset_proxy(cwebsocket_client *websocket) ++{ ++ if (websocket->flags & WEBSOCKET_FLAG_PROXY){ ++ websocket->proxy_addr = NULL; ++ websocket->proxy_port = NULL; ++ websocket->flags |= ~WEBSOCKET_FLAG_PROXY; + } +- getrlimit(RLIMIT_STACK, &rl); +- syslog(LOG_DEBUG, "cwebsocket_client_init: stack limit min=%ld, max=%ld\n", rl.rlim_cur, rl.rlim_max); + } + + void cwebsocket_client_parse_uri(cwebsocket_client *websocket, const char *uri, + char *hostname, char *port, char *resource, char *querystring) { + +- if(sscanf(uri, "ws://%[^:]:%[^/]%[^?]%s", hostname, port, resource, querystring) == 4) { ++ if(ws_sscanf(uri, "ws://%[^:]:%[^/]%[^?]%s", hostname, port, resource, querystring) == 4) { + return; + } +- else if(sscanf(uri, "ws://%[^:]:%[^/]%s", hostname, port, resource) == 3) { ++ else if(ws_sscanf(uri, "ws://%[^:]:%[^/]%s", hostname, port, resource) == 3) { + strcpy(querystring, ""); + return; + } +- else if(sscanf(uri, "ws://%[^:]:%[^/]%s", hostname, port, resource) == 2) { +- strcpy(resource, "/"); ++ else if(ws_sscanf(uri, "ws://%[^:]:%[^/]%s", hostname, port, resource) == 2) { ++ strncpy(resource, "/", strlen("/")); + strcpy(querystring, ""); + return; + } +- else if(sscanf(uri, "ws://%[^/]%s", hostname, resource) == 2) { +- strcpy(port, "80"); ++ else if(ws_sscanf(uri, "ws://%[^/]%s", hostname, resource) == 2) { ++ strncpy(port, "80", strlen("80")); + strcpy(querystring, ""); + return; + } +- else if(sscanf(uri, "ws://%[^/]", hostname) == 1) { +- strcpy(port, "80"); +- strcpy(resource, "/"); ++ else if(ws_sscanf(uri, "ws://%[^/]", hostname) == 1) { ++ strncpy(port, "80", strlen("80")); ++ strncpy(resource, "/", strlen("/")); + strcpy(querystring, ""); + return; + } + #ifdef ENABLE_SSL +- else if(sscanf(uri, "wss://%[^:]:%[^/]%[^?]%s", hostname, port, resource, querystring) == 4) { ++ else if(ws_sscanf(uri, "wss://%[^:]:%[^/]%[^?]%s", hostname, port, resource, querystring) == 4) { + websocket->flags |= WEBSOCKET_FLAG_SSL; + return; + } +- else if(sscanf(uri, "wss://%[^:]:%[^/]%s", hostname, port, resource) == 3) { ++ else if(ws_sscanf(uri, "wss://%[^:]:%[^/]%s", hostname, port, resource) == 3) { + strcpy(querystring, ""); + websocket->flags |= WEBSOCKET_FLAG_SSL; + return; + } +- else if(sscanf(uri, "wss://%[^:]:%[^/]%s", hostname, port, resource) == 2) { +- strcpy(resource, "/"); ++ else if(ws_sscanf(uri, "wss://%[^:]:%[^/]%s", hostname, port, resource) == 2) { ++ strncpy(resource, "/", strlen("/")); + strcpy(querystring, ""); + websocket->flags |= WEBSOCKET_FLAG_SSL; + return; + } +- else if(sscanf(uri, "wss://%[^/]%s", hostname, resource) == 2) { +- strcpy(port, "443"); ++ else if(ws_sscanf(uri, "wss://%[^/]%s", hostname, resource) == 2) { ++ strncpy(port, "443", strlen("443")); + strcpy(querystring, ""); + websocket->flags |= WEBSOCKET_FLAG_SSL; + return; + } +- else if(sscanf(uri, "wss://%[^/]", hostname) == 1) { +- strcpy(port, "443"); +- strcpy(resource, "/"); ++ else if(ws_sscanf(uri, "wss://%[^/]", hostname) == 1) { ++ strncpy(port, "443", strlen("443")); ++ strncpy(resource, "/", strlen("/")); + strcpy(querystring, ""); + websocket->flags |= WEBSOCKET_FLAG_SSL; + return; + } + #endif + else if(strstr(uri, "wss://") > 0) { +- syslog(LOG_CRIT, "cwebsocket_client_parse_uri: recompile with SSL support to use a secure connection"); ++ WS_DEBUG("client_parse_uri: recompile with SSL support to use a secure connection"); + exit(1); + } + else { +- syslog(LOG_CRIT, "cwebsocket_client_parse_uri: invalid websocket URL\n"); ++ WS_DEBUG("client_parse_uri: invalid websocket URL : %s\n", uri); + exit(1); + } + } + ++ ++int cwebsocket_client_ssl_init(cwebsocket_client *websocket, char *cert_name, char *cli_cert, char *cli_key, char *passphrase) { ++#ifdef ENABLE_SSL ++ int ret= 0; ++ ++ WS_DEBUG("client_connect: using secure (SSL) connection\n"); ++ ++ mbedtls_net_init( &websocket->ssl_net_ctx ); ++ mbedtls_ssl_init( &websocket->ssl ); ++ mbedtls_ssl_config_init( &websocket->conf ); ++ mbedtls_x509_crt_init( &websocket->cacert ); ++ mbedtls_ctr_drbg_init( &websocket->ctr_drbg ); ++ mbedtls_entropy_init( &websocket->entropy ); ++ ++ if( ( ret = mbedtls_ctr_drbg_seed( &websocket->ctr_drbg, NULL, &websocket->entropy, ++ (const unsigned char *) "ssl_client1", ++ strlen( "ssl_client1" ) ) ) != 0 ) ++ { ++ WS_DEBUG(" failed\n ! mbedtls_ctr_drbg_seed returned %d\n", ret ); ++ return -1; ++ } ++ ret = mbedtls_x509_crt_parse_file( &websocket->cacert, cert_name ); ++ if( ret != 0 ) ++ { ++ WS_DEBUG("nothing file = -0x%x\n", -ret); ++ return -1; ++ } ++ ++ if( ( ret = mbedtls_ssl_config_defaults( &websocket->conf, ++ MBEDTLS_SSL_IS_CLIENT, ++ MBEDTLS_SSL_TRANSPORT_STREAM, ++ MBEDTLS_SSL_PRESET_DEFAULT ) ) != 0 ) ++ { ++ WS_DEBUG(" failed\n ! mbedtls_ssl_config_defaults returned -0x%x\n\n", ret ); ++ return -1; ++ } ++ ++ /* OPTIONAL is not optimal for security, ++ * but makes interop easier in this simplified example */ ++ mbedtls_ssl_conf_authmode( &websocket->conf, MBEDTLS_SSL_VERIFY_OPTIONAL ); ++ mbedtls_ssl_conf_ca_chain( &websocket->conf, &websocket->cacert, NULL ); ++ mbedtls_ssl_conf_rng( &websocket->conf, NULL, &websocket->ctr_drbg ); ++ ++ if (cli_cert != NULL && cli_key != NULL){ ++ ret = mbedtls_x509_crt_parse_file(&websocket->clicert, cli_cert); ++ if (ret == 0) { ++ ret = mbedtls_pk_parse_keyfile(&websocket->pkey, cli_key, passphrase); ++ if (ret != 0) { ++ WS_DEBUG("Private Key not found\n"); ++ return -1; ++ } ++ } else { ++ WS_DEBUG("Client certificate not found\n"); ++ return -1; ++ } ++ mbedtls_ssl_conf_own_cert(&websocket->conf, &websocket->clicert, &websocket->pkey); ++ } ++ ++ return ret; ++#else ++ return -1; ++#endif ++} ++ + int cwebsocket_client_connect(cwebsocket_client *websocket) { + + if(websocket->state & WEBSOCKET_STATE_CONNECTED) { +- syslog(LOG_CRIT, "cwebsocket_client_connect: socket already connected"); ++ WS_DEBUG("client_connect: socket already connected"); + return -1; + } + + if(websocket->state & WEBSOCKET_STATE_CONNECTING) { +- syslog(LOG_CRIT, "cwebsocket_client_connect: socket already connecting"); ++ WS_DEBUG("client_connect: socket already connecting"); + return -1; + } + + if(websocket->state & WEBSOCKET_STATE_OPEN) { +- syslog(LOG_CRIT, "cwebsocket_client_connect: socket already open"); ++ WS_DEBUG("client_connect: socket already open"); + return -1; + } + +@@ -154,24 +236,35 @@ int cwebsocket_client_connect(cwebsocket_client *websocket) { + #else + websocket->state = WEBSOCKET_STATE_CONNECTING; + #endif +- ++#ifdef ENABLE_SSL ++ uint32_t flags; ++ int ret; ++#endif + char hostname[100]; + char port[6]; + char resource[256]; + char querystring[256]; ++ ++ memset(hostname, 0, 100); ++ memset(port, 0, 6); ++ memset(resource, 0, 256); ++ memset(querystring, 0, 100); ++ + cwebsocket_client_parse_uri(websocket, websocket->uri, hostname, port, resource, querystring); + +- syslog(LOG_DEBUG, "cwebsocket_client_connect: hostname=%s, port=%s, resource=%s, querystring=%s, secure=%i\n", ++ WS_DEBUG ("client_connect: hostname=%s, port=%s, resource=%s, querystring=%s, secure=%i\n", + hostname, port, resource, querystring, (websocket->flags & WEBSOCKET_FLAG_SSL)); + +- char handshake[1024]; +- struct addrinfo hints, *servinfo; ++ char handshake[CWS_HANDSHAKE_BUFFER_MAX]; ++ struct addrinfo hints, *servinfo; ++ time_t Tick0 = 0; ++ time(&Tick0); + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + +- srand(time(NULL)); ++ srand(Tick0); + char nonce[16]; + static const char alphanum[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz"; + int i; +@@ -180,100 +273,178 @@ int cwebsocket_client_connect(cwebsocket_client *websocket) { + } + char *seckey = cwebsocket_base64_encode((const unsigned char *)nonce, sizeof(nonce)); + +- snprintf(handshake, 1024, +- "GET %s%s HTTP/1.1\r\n" +- "Host: %s:%s\r\n" +- "Upgrade: WebSocket\r\n" +- "Connection: Upgrade\r\n" +- "Sec-WebSocket-Key: %s\r\n" +- "Sec-WebSocket-Version: 13\r\n" ++ snprintf(handshake, CWS_HANDSHAKE_BUFFER_MAX, ++ "GET %s%s HTTP/1.1\r\n" ++ "Host: %s:%s\r\n" ++ "Upgrade: WebSocket\r\n" ++ "Connection: Upgrade\r\n" ++ "Sec-WebSocket-Key: %s\r\n" ++ "Sec-WebSocket-Version: 13\r\n" + ,resource, querystring, hostname, port, seckey); + ++ if((websocket->headers != NULL) && (websocket->num_headers > 0)) { ++ for(i = 0; i < websocket->num_headers; i++) { ++ strncat(handshake, websocket->headers[i], (CWS_HANDSHAKE_BUFFER_MAX - strlen(handshake))); ++ strncat(handshake, "\r\n", (CWS_HANDSHAKE_BUFFER_MAX - strlen(handshake))); ++ } ++ } ++ + if(websocket->subprotocol_len > 0) { +- strcat(handshake, "Sec-WebSocket-Protocol: "); ++ strncat(handshake, "Sec-WebSocket-Protocol: ", (CWS_HANDSHAKE_BUFFER_MAX - strlen(handshake))); + for(i=0; isubprotocol_len; i++) { +- strcat(handshake, websocket->subprotocols[i]->name); ++ strncat(handshake, websocket->subprotocols[i]->name, (CWS_HANDSHAKE_BUFFER_MAX - strlen(handshake))); + if(isubprotocol_len) { +- strcat(handshake, " "); ++ strncat(handshake, " ", (CWS_HANDSHAKE_BUFFER_MAX - strlen(handshake))); + } + else { +- strcat(handshake, "\r\n"); ++ strncat(handshake, "\r\n", (CWS_HANDSHAKE_BUFFER_MAX - strlen(handshake))); + } + } ++ strncat(handshake, "\r\n", (CWS_HANDSHAKE_BUFFER_MAX - strlen(handshake))); + } + +- strcat(handshake, "\r\n"); ++ strncat(handshake, "\r\n", (CWS_HANDSHAKE_BUFFER_MAX - strlen(handshake))); + +- if(getaddrinfo(hostname, port, &hints, &servinfo) != 0 ) { +- freeaddrinfo(servinfo); +- const char *errmsg = "invalid hostname or IP"; +- syslog(LOG_ERR, "cwebsocket_client_connect: %s", errmsg); +- cwebsocket_client_onerror(websocket, errmsg); +- return -1; +- } ++ if(websocket->flags & WEBSOCKET_FLAG_SSL) { ++#ifdef ENABLE_SSL ++ if( ( ret = mbedtls_ssl_setup( &websocket->ssl, &websocket->conf ) ) != 0 ) ++ { ++ WS_DEBUG( " failed\n ! mbedtls_ssl_setup returned -0x%x\n\n", -ret ); ++ goto fail; ++ } ++ if(websocket->flags & WEBSOCKET_FLAG_PROXY) { ++ /* SSL On / Proxy On ++ Execute CONNECT command of non-secure message after connecting to proxy server. ++ */ ++ if( ( ret = mbedtls_net_connect( &websocket->ssl_net_ctx, websocket->proxy_addr, ++ websocket->proxy_port, MBEDTLS_NET_PROTO_TCP ) ) != 0 ) ++ { ++ WS_DEBUG(" failed\n ! mbedtls_net_connect proxy returned %d\n\n", ret ); ++ goto fail; ++ } ++ if(websocket->flags & WEBSOCKET_FLAG_PROXY) { ++ char proxy_connect[CWS_HANDSHAKE_BUFFER_MAX]; ++ ++ snprintf(proxy_connect, CWS_HANDSHAKE_BUFFER_MAX, ++ "CONNECT %s:%s HTTP/1.1\r\n" ++ "Host: %s\r\n" ++ , hostname, port, hostname); ++ strncat(proxy_connect, "\r\n", (CWS_HANDSHAKE_BUFFER_MAX - strlen(proxy_connect))); ++ if(write(websocket->ssl_net_ctx.fd, proxy_connect, strlen(proxy_connect)) == -1) { ++ WS_DEBUG("proxy_client_write: NG A\n"); ++ goto fail; ++ } ++ if(cwebsocket_client_read_handshake(websocket, seckey, websocket->flags) == -1) { ++ WS_DEBUG("proxy_client_read_handshake for SSL: %s\n", seckey); ++ goto fail; ++ } ++ } ++ }else{ ++ /* SSL On / Proxy OFF ++ Connecting to websocket server. ++ */ ++ if( ( ret = mbedtls_net_connect( &websocket->ssl_net_ctx, hostname, ++ port, MBEDTLS_NET_PROTO_TCP ) ) != 0 ) ++ { ++ WS_DEBUG(" failed\n ! mbedtls_net_connect returned %d\n\n", ret ); ++ goto fail; ++ } ++ } + +- websocket->fd = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol); +- if(websocket->fd < 0) { +- freeaddrinfo(servinfo); +- syslog(LOG_ERR, "cwebsocket_client_connect: %s", strerror(errno)); +- cwebsocket_client_onerror(websocket, strerror(errno)); +- return -1; +- } ++ mbedtls_ssl_set_bio( &websocket->ssl, &websocket->ssl_net_ctx, NULL, NULL, NULL); + +- if(connect(websocket->fd, servinfo->ai_addr, servinfo->ai_addrlen) != 0 ) { +- syslog(LOG_ERR, "cwebsocket_client_connect: %s", strerror(errno)); +- cwebsocket_client_onerror(websocket, strerror(errno)); +- websocket->state = WEBSOCKET_STATE_CLOSED; +- if(websocket->retry > 0) { +- sleep(websocket->retry); +- cwebsocket_client_connect(websocket); ++ while( ( ret = mbedtls_ssl_handshake( &websocket->ssl ) ) != 0 ) ++ { ++ if( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE ) ++ { ++ WS_DEBUG(" failed\n ! mbedtls_ssl_handshake returned -0x%x\n\n", -ret ); ++ goto fail; ++ } + } +- return -1; +- } +- freeaddrinfo(servinfo); ++ websocket->fd = websocket->ssl_net_ctx.fd; + +- int optval = 1; +- if(setsockopt(websocket->fd, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof optval) == -1) { +- syslog(LOG_ERR, "cwebsocket_client_connect: %s", strerror(errno)); +- cwebsocket_client_onerror(websocket, strerror(errno)); +- return -1; +- } ++ /* In real life, we probably want to bail out when ret != 0 */ ++ if( ( flags = mbedtls_ssl_get_verify_result( &websocket->ssl ) ) != 0 ) ++ { ++ char vrfy_buf[512]; + +-#ifdef ENABLE_SSL ++ mbedtls_x509_crt_verify_info( vrfy_buf, sizeof( vrfy_buf ), " ! ", flags ); + +- websocket->ssl = NULL; +- websocket->sslctx = NULL; ++ WS_DEBUG("%s\n", vrfy_buf ); + +- if(websocket->flags & WEBSOCKET_FLAG_SSL) { +- +- syslog(LOG_DEBUG, "cwebsocket_client_connect: using secure (SSL) connection"); ++ } ++ else ++ WS_DEBUG(" certificate ok\n"); ++#endif ++ }else { ++ if(websocket->flags & WEBSOCKET_FLAG_PROXY) { ++ if(getaddrinfo(websocket->proxy_addr, websocket->proxy_port, &hints, &servinfo) != 0 ) { ++ freeaddrinfo(servinfo); ++ const char *errmsg = "invalid hostname or IP"; ++ WS_DEBUG("client_proxy_connect: %s", websocket->proxy_addr); ++ cwebsocket_client_onerror(websocket, errmsg); ++ goto fail; ++ } ++ }else { ++ if(getaddrinfo(hostname, port, &hints, &servinfo) != 0 ) { ++ freeaddrinfo(servinfo); ++ const char *errmsg = "invalid hostname or IP"; ++ WS_DEBUG("client_non_proxy_connect: %s", errmsg); ++ cwebsocket_client_onerror(websocket, errmsg); ++ goto fail; ++ } ++ } + +- SSL_load_error_strings(); +- SSL_library_init(); ++ websocket->fd = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol); ++ if(websocket->fd < 0) { ++ freeaddrinfo(servinfo); ++ goto fail; ++ } + +- websocket->sslctx = SSL_CTX_new(SSLv23_client_method()); +- if(websocket->sslctx == NULL) { +- ERR_print_errors_fp(stderr); +- return -1; +- } ++ if(connect(websocket->fd, servinfo->ai_addr, servinfo->ai_addrlen) != 0 ) { ++ freeaddrinfo(servinfo); ++ websocket->state = WEBSOCKET_STATE_CLOSED; ++ if(websocket->retry > 0) { ++ usleep(websocket->retry * 1000); ++ cwebsocket_client_connect(websocket); ++ } ++ goto fail; ++ } ++ freeaddrinfo(servinfo); + +- websocket->ssl = SSL_new(websocket->sslctx); +- if(websocket->ssl == NULL) { +- ERR_print_errors_fp(stderr); +- return -1; +- } ++ int optval = 1; ++ if(setsockopt(websocket->fd, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof optval) == -1) { ++ goto fail; ++ } ++ struct timeval tv; ++ tv.tv_sec = 1; /* 1 second Timeout */ ++ tv.tv_usec = 0; + +- if(!SSL_set_fd(websocket->ssl, websocket->fd)) { +- ERR_print_errors_fp(stderr); +- return -1; +- } ++ if(setsockopt(websocket->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval)) == -1) { ++ goto fail; ++ } + +- if(SSL_connect(websocket->ssl) != 1) { +- ERR_print_errors_fp(stderr); +- return -1; +- } ++ if(websocket->flags & WEBSOCKET_FLAG_PROXY) { ++ /* SSL Off / Proxy On ++ Execute CONNECT command after connecting to proxy server. ++ */ ++ char proxy_connect[CWS_HANDSHAKE_BUFFER_MAX]; ++ ++ snprintf(proxy_connect, CWS_HANDSHAKE_BUFFER_MAX, ++ "CONNECT %s:%s HTTP/1.1\r\n" ++ "Host: %s\r\n" ++ , hostname, port, hostname); ++ strncat(proxy_connect, "\r\n", (CWS_HANDSHAKE_BUFFER_MAX - strlen(proxy_connect))); ++ if(write(websocket->fd, proxy_connect, strlen(proxy_connect)) == -1) { ++ WS_DEBUG("proxy_client_write: NG\n"); ++ goto fail; ++ } ++ if(cwebsocket_client_read_handshake(websocket, seckey, websocket->flags) == -1) { ++ WS_DEBUG("proxy_client_read_handshake: %s\n", seckey); ++ goto fail; ++ } ++ } + } +-#endif + + #ifdef ENABLE_THREADS + pthread_mutex_lock(&websocket->lock); +@@ -284,17 +455,16 @@ int cwebsocket_client_connect(cwebsocket_client *websocket) { + #endif + + if(cwebsocket_client_write(websocket, handshake, strlen(handshake)) == -1) { +- syslog(LOG_ERR, "cwebsocket_client_connect: %s", strerror(errno)); +- cwebsocket_client_onerror(websocket, strerror(errno)); +- return -1; ++ WS_DEBUG("client_connect: NG\n"); ++ goto fail; + } + +- if(cwebsocket_client_read_handshake(websocket, seckey) == -1) { +- syslog(LOG_ERR, "cwebsocket_client_connect: %s", strerror(errno)); +- cwebsocket_client_onerror(websocket, strerror(errno)); +- return -1; ++ if(cwebsocket_client_read_handshake(websocket, seckey, 0) == -1) { ++ WS_DEBUG("client_connect: %s\n", seckey); ++ goto fail; + } + ++ free(seckey); + #ifdef ENABLE_THREADS + pthread_mutex_lock(&websocket->lock); + websocket->state = WEBSOCKET_STATE_OPEN; +@@ -306,11 +476,15 @@ int cwebsocket_client_connect(cwebsocket_client *websocket) { + cwebsocket_client_onopen(websocket); + + return 0; ++fail: ++ free(seckey); ++ cwebsocket_client_close(websocket, 1009, "connect failed"); ++ return -1; + } + + int cwebsocket_client_handshake_handler(cwebsocket_client *websocket, const char *handshake_response, char *seckey) { + uint8_t flags = 0; +- syslog(LOG_DEBUG, "cwebsocket_client_handshake_handler: handshake response: \n%s\n", handshake_response); ++ WS_DEBUG("client_handshake_handler: handshake response: \n%s\n", handshake_response); + char *ptr = NULL, *token = NULL; + for(token = strtok((char *)handshake_response, "\r\n"); token != NULL; token = strtok(NULL, "\r\n")) { + if(*token == 'H' && *(token+1) == 'T' && *(token+2) == 'T' && *(token+3) == 'P') { +@@ -324,20 +498,21 @@ int cwebsocket_client_handshake_handler(cwebsocket_client *websocket, const char + } else { + ptr = strchr(token, ' '); + if(ptr == NULL) { +- syslog(LOG_ERR, "cwebsocket_client_handshake_handler: invalid HTTP header sent: %s", token); ++ WS_DEBUG("client_handshake_handler: invalid HTTP header sent: %s\n", token); + cwebsocket_client_onerror(websocket, "invalid HTTP header sent"); + return -1; + } + *ptr = '\0'; + if(strcasecmp(token, "Upgrade:") == 0) { +- if(strcasecmp(ptr+1, "websocket") != 0) { ++ ++ if(strncasecmp(ptr+1, "websocket", strlen("websocket") -1) != 0) { + cwebsocket_client_onerror(websocket, "cwebsocket_client_handshake_handler: invalid HTTP upgrade header"); + return -1; + } + flags |= CWS_HANDSHAKE_HAS_UPGRADE; + } + if(strcasecmp(token, "Connection:") == 0) { +- if(strcasecmp(ptr+1, "upgrade") != 0) { ++ if(strncasecmp(ptr+1, "upgrade", strlen("upgrade") -1) != 0) { + cwebsocket_client_onerror(websocket, "cwebsocket_client_handshake_handler: invalid HTTP connection header"); + return -1; + } +@@ -346,27 +521,24 @@ int cwebsocket_client_handshake_handler(cwebsocket_client *websocket, const char + if(strcasecmp(token, "Sec-WebSocket-Protocol:") == 0) { + int i; + for(i=0; isubprotocol_len; i++) { +- if(strcasecmp(ptr+1, websocket->subprotocols[i]->name) == 0) { ++ if(strncasecmp(ptr+1, websocket->subprotocols[i]->name, strlen(websocket->subprotocols[i]->name) -1) == 0) { + websocket->subprotocol = websocket->subprotocols[i]; +- syslog(LOG_DEBUG, "cwebsocket_client_handshake_handler: setting subprotocol to %s", websocket->subprotocol->name); ++ WS_DEBUG("client_handshake_handler: setting subprotocol to %s\n", websocket->subprotocol->name); + } + } + } + if(strcasecmp(token, "Sec-WebSocket-Accept:") == 0) { + char* response = cwebsocket_create_key_challenge_response(seckey); +- if(strcmp(ptr+1, response) != 0) { +- free(seckey); ++ if(strncmp(ptr+1, response, strlen(response) -1) != 0) { + if(websocket->subprotocol->onerror != NULL) { + char errmsg[255]; + sprintf(errmsg, "cwebsocket_client_handshake_handler: Sec-WebSocket-Accept header does not match computed sha1/base64 response. expected=%s, actual=%s", response, ptr+1); + cwebsocket_client_onerror(websocket, errmsg); +- free(response); +- return -1; + } ++ free(response); + return -1; + } + free(response); +- free(seckey); + flags |= CWS_HANDSHAKE_HAS_ACCEPT; + } + } +@@ -377,11 +549,11 @@ int cwebsocket_client_handshake_handler(cwebsocket_client *websocket, const char + cwebsocket_client_close(websocket, 1002, "invalid websocket HTTP headers"); + return -1; + } +- syslog(LOG_DEBUG, "cwebsocket_client_handshake_handler: handshake successful"); ++ WS_DEBUG("client_handshake_handler: handshake successful\n"); + return 0; + } + +-int cwebsocket_client_read_handshake(cwebsocket_client *websocket, char *seckey) { ++int cwebsocket_client_read_handshake(cwebsocket_client *websocket, char *seckey, int flags) { + + int byte, tmplen = 0; + uint32_t bytes_read = 0; +@@ -394,12 +566,11 @@ int cwebsocket_client_read_handshake(cwebsocket_client *websocket, char *seckey) + + if(byte == 0) return -1; + if(byte == -1) { +- syslog(LOG_ERR, "cwebsocket_client_read_handshake: %s", strerror(errno)); +- cwebsocket_client_onerror(websocket, strerror(errno)); ++ WS_DEBUG("client_read_handshake: %s", strerror(errno)); + return -1; + } + if(bytes_read == CWS_HANDSHAKE_BUFFER_MAX) { +- syslog(LOG_ERR, "cwebsocket_client_read_handshake: handshake response too large. CWS_HANDSHAKE_BUFFER_MAX = %i bytes.", CWS_HANDSHAKE_BUFFER_MAX); ++ WS_DEBUG("client_read_handshake: handshake response too large. CWS_HANDSHAKE_BUFFER_MAX = %i bytes.", CWS_HANDSHAKE_BUFFER_MAX); + cwebsocket_client_onerror(websocket, "handshake response too large"); + return -1; + } +@@ -414,22 +585,62 @@ int cwebsocket_client_read_handshake(cwebsocket_client *websocket, char *seckey) + memcpy(buf, data, tmplen); + buf[tmplen+1] = '\0'; + +- return cwebsocket_client_handshake_handler(websocket, buf, seckey); ++ if(flags & WEBSOCKET_FLAG_PROXY) { ++ return cwebsocket_proxy_client_handshake_handler(websocket, buf); ++ } else { ++ return cwebsocket_client_handshake_handler(websocket, buf, seckey); ++ } ++} ++ ++int cwebsocket_proxy_client_handshake_handler(cwebsocket_client *websocket, const char *handshake_response) { ++ uint8_t flags = 0; ++ WS_DEBUG("proxy_client_handshake_handler: handshake response: \n%s\n", handshake_response); ++ char *ptr = NULL, *token = NULL; ++ ++ /* ++ The response code from the proxy server allows only 200. ++ */ ++ for(token = strtok((char *)handshake_response, "\r\n"); token != NULL; token = strtok(NULL, "\r\n")) { ++ if(*token == 'H' && *(token+1) == 'T' && *(token+2) == 'T' && *(token+3) == 'P') { ++ ptr = strchr(token, ' '); ++ ptr = strchr(ptr+1, ' '); ++ *ptr = '\0'; ++ if((websocket->flags & WEBSOCKET_FLAG_PROXY) && (strcmp(token, "HTTP/1.1 200") == 0 || strcmp(token, "HTTP/1.0 200") == 0)) { ++ WS_DEBUG("client_handshake_handler: proxy handshake successful\n"); ++ return 0; ++ } ++ } else { ++ ptr = strchr(token, ' '); ++ if(ptr == NULL) { ++ WS_DEBUG("client_handshake_handler: invalid HTTP header sent: %s\n", token); ++ cwebsocket_client_onerror(websocket, "invalid HTTP header sent"); ++ return -1; ++ } ++ *ptr = '\0'; ++ } ++ } ++ if(((flags & CWS_HANDSHAKE_HAS_UPGRADE) == 0) || ((flags & CWS_HANDSHAKE_HAS_CONNECTION) == 0) || ++ ((flags & CWS_HANDSHAKE_HAS_ACCEPT) == 0)) { ++ // TODO send http error code (500?) ++ cwebsocket_client_close(websocket, 1002, "invalid websocket HTTP headers"); ++ return -1; ++ } ++ WS_DEBUG("client_handshake_handler: handshake successful\n"); ++ return 0; + } + + void cwebsocket_client_listen(cwebsocket_client *websocket) { + while(websocket->state & WEBSOCKET_STATE_OPEN) { +- syslog(LOG_DEBUG, "cwebsocket_client_listen: calling cwebsocket_client_read_data"); ++ WS_DEBUG("client_listen: calling cwebsocket_client_read_data"); + cwebsocket_client_read_data(websocket); + } +- syslog(LOG_DEBUG, "cwebsocket_client_listen: shutting down"); ++ WS_DEBUG("client_listen: shutting down"); + } + + #ifdef ENABLE_THREADS + void *cwebsocket_client_onmessage_thread(void *ptr) { + cwebsocket_client_thread_args *args = (cwebsocket_client_thread_args *)ptr; + cwebsocket_client_onmessage(args->socket, args->message); +- //free(args->message->payload); + free(args->message); + free(ptr); + return NULL; +@@ -452,28 +663,23 @@ int cwebsocket_client_send_control_frame(cwebsocket_client *websocket, opcode co + control_frame[4] = masking_key[2]; + control_frame[5] = masking_key[3]; + if(code & CLOSE) { +- uint16_t close_code = 1000; + if(payload_len >= 2) { + if(payload_len > 2) { +- char parsed_payload[payload_len]; +- memcpy(parsed_payload, &payload[0], payload_len); +- parsed_payload[payload_len] = '\0'; +- close_code = (control_frame[6] << 8) + control_frame[7]; + int i; + for(i=0; istate & WEBSOCKET_STATE_OPEN)) { + + if(bytes_read >= CWS_DATA_BUFFER_MAX) { +- syslog(LOG_ERR, "cwebsocket_client_read_data: frame too large. RECEIVE_BUFFER_MAX = %i bytes. bytes_read=%i, header_length=%i", ++ WS_DEBUG("client_read_data: frame too large. RECEIVE_BUFFER_MAX = %i bytes. bytes_read=%i, header_length=%i", + CWS_DATA_BUFFER_MAX, bytes_read, header_length); + cwebsocket_client_close(websocket, 1009, "frame too large"); ++ free(data); + return -1; + } + +@@ -532,11 +739,11 @@ int cwebsocket_client_read_data(cwebsocket_client *websocket) { + char *errmsg = "server closed the connection"; + cwebsocket_client_onerror(websocket, errmsg); + cwebsocket_client_close(websocket, 1006, errmsg); ++ free(data); + return -1; + } + if(byte == -1) { +- syslog(LOG_ERR, "cwebsocket_client_read_data: error reading frame: %s", strerror(errno)); +- cwebsocket_client_onerror(websocket, strerror(errno)); ++ free(data); + return -1; + } + bytes_read++; +@@ -553,8 +760,9 @@ int cwebsocket_client_read_data(cwebsocket_client *websocket) { + + if(frame.mask == 1) { + const char *errmsg = "received masked frame from server"; +- syslog(LOG_CRIT, "cwebsocket_client_read_data: %s", errmsg); ++ WS_DEBUG("client_read_data: %s", errmsg); + cwebsocket_client_onerror(websocket, errmsg); ++ free(data); + return -1; + } + +@@ -596,113 +804,137 @@ int cwebsocket_client_read_data(cwebsocket_client *websocket) { + + char *payload = malloc(sizeof(char) * payload_length+1); + if(payload == NULL) { +- perror("out of memory"); +- exit(-1); ++ WS_DEBUG("client_read_data: payload out of memory"); ++ cwebsocket_client_close(websocket, 1009, "out of memory"); ++ free(data); ++ return -1; + } + memcpy(payload, &data[header_length], payload_length); + payload[payload_length] = '\0'; + free(data); ++ data = NULL; + + size_t utf8_code_points = 0; + if(utf8_count_code_points((uint8_t *)payload, &utf8_code_points)) { +- syslog(LOG_ERR, "cwebsocket_client_read_data: received %lld byte malformed utf8 text payload: %s", payload_length, payload); ++ WS_DEBUG("client_read_data: received %lld byte malformed utf8 text payload: %s", payload_length, payload); + cwebsocket_client_onerror(websocket, "received malformed utf8 payload"); ++ free(payload); + return -1; + } + +- syslog(LOG_DEBUG, "cwebsocket_client_read_data: received %lld byte text payload: %s", payload_length, payload); ++ WS_DEBUG("client_read_data: received %lld byte text payload: %s", payload_length, payload); + + if(websocket->subprotocol != NULL && websocket->subprotocol->onmessage != NULL) { + + #ifdef ENABLE_THREADS +- cwebsocket_message *message = malloc(sizeof(cwebsocket_message)); ++ cwebsocket_dsp_message *message = malloc(sizeof(cwebsocket_dsp_message)); + if(message == NULL) { +- perror("out of memory"); +- exit(-1); ++ WS_DEBUG("client_read_data: text message out of memory"); ++ cwebsocket_client_close(websocket, 1009, "out of memory"); ++ free(payload); ++ return -1; + } +- memset(message, 0, sizeof(cwebsocket_message)); ++ memset(message, 0, sizeof(cwebsocket_dsp_message)); + message->opcode = frame.opcode; +- message->payload_len = frame.payload_len; ++ message->payload_len = payload_length; + message->payload = payload; + + cwebsocket_client_thread_args *args = malloc(sizeof(cwebsocket_client_thread_args)); + if(args == NULL) { +- perror("out of memory"); +- exit(-1); ++ WS_DEBUG ("client_read_data: text args out of memory"); ++ cwebsocket_client_close(websocket, 1009, "out of memory"); ++ free(payload); ++ return -1; + } + memset(args, 0, sizeof(cwebsocket_client_thread_args)); + args->socket = websocket; + args->message = message; + + if(pthread_create(&websocket->thread, NULL, cwebsocket_client_onmessage_thread, (void *)args) == -1) { +- syslog(LOG_ERR, "cwebsocket_client_read_data: %s", strerror(errno)); +- cwebsocket_client_onerror(websocket, strerror(errno)); +- return -1; ++ free(payload); ++ free(message); ++ free(args); ++ return -1; + } ++ free(payload); + return bytes_read; + #else +- cwebsocket_message message = {0}; ++ cwebsocket_dsp_message message = {0}; + message.opcode = frame.opcode; +- message.payload_len = frame.payload_len; ++ message.payload_len = payload_length; + message.payload = payload; +- cwebsocket_client_onmessage(websocket, &message); +- //free(payload); +- return bytes_read; ++ cwebsocket_client_onmessage(websocket, &message); ++ free(payload); ++ return bytes_read; + #endif + } + +- syslog(LOG_WARNING, "cwebsocket_client_read_data: onmessage callback undefined"); ++ WS_DEBUG("client_read_data: onmessage callback undefined\n"); ++ free(payload); + return bytes_read; + } + else if(frame.fin && frame.opcode == BINARY_FRAME) { + +- syslog(LOG_DEBUG, "cwebsocket_client_read_data: received BINARY payload. bytes=%lld", payload_length); ++ WS_DEBUG("client_read_data: received BINARY payload. bytes=%lld\n", payload_length); + + char *payload = malloc(sizeof(char) * payload_length); + if(payload == NULL) { + perror("out of memory"); ++ free(data); + exit(-1); + } + memcpy(payload, &data[header_length], payload_length); + free(data); ++ data = NULL; + + if(websocket->subprotocol->onmessage != NULL) { + + #ifdef ENABLE_THREADS +- cwebsocket_message *message = malloc(sizeof(cwebsocket_message)); ++ cwebsocket_dsp_message *message = malloc(sizeof(cwebsocket_dsp_message)); + if(message == NULL) { +- perror("out of memory"); +- exit(-1); ++ WS_DEBUG("client_read_data: binary message out of memory"); ++ cwebsocket_client_close(websocket, 1009, "out of memory"); ++ free(payload); ++ return -1; + } + message->opcode = frame.opcode; +- message->payload_len = frame.payload_len; ++ message->payload_len = payload_length; + message->payload = payload; + + cwebsocket_client_thread_args *args = malloc(sizeof(cwebsocket_client_thread_args)); ++ if(args == NULL) { ++ WS_DEBUG("client_read_data: binary args out of memory"); ++ cwebsocket_client_close(websocket, 1009, "out of memory"); ++ return -1; ++ } + args->socket = websocket; + args->message = message; + + if(pthread_create(&websocket->thread, NULL, cwebsocket_client_onmessage_thread, (void *)args) == -1) { +- syslog(LOG_ERR, "cwebsocket_client_read_data: %s", strerror(errno)); +- cwebsocket_client_onerror(websocket, strerror(errno)); ++ free(payload); ++ free(message); ++ free(args); + return -1; + } ++ free(payload); + return bytes_read; + #else +- cwebsocket_message message; ++ cwebsocket_dsp_message message; + message.opcode = frame.opcode; +- message.payload_len = frame.payload_len; ++ message.payload_len = payload_length; + message.payload = payload; +- websocket->subprotocol->onmessage(websocket, &message); ++ cwebsocket_client_onmessage(websocket, &message); + free(payload); + return bytes_read; + #endif + } +- syslog(LOG_WARNING, "cwebsocket_client_read_data: onmessage callback undefined"); ++ WS_DEBUG("client_read_data: onmessage callback undefined"); ++ free(payload); + return bytes_read; + } + else if(frame.opcode == CONTINUATION) { +- syslog(LOG_DEBUG, "cwebsocket_client_read_data: received CONTINUATION opcode"); ++ WS_DEBUG("client_read_data: onmessage callback undefined"); ++ free(data); + return 0; + } + else if(frame.opcode == PING) { +@@ -713,20 +945,22 @@ int cwebsocket_client_read_data(cwebsocket_client *websocket) { + cwebsocket_client_close(websocket, 1002, "control frames must not exceed 125 bytes"); + return -1; + } +- syslog(LOG_DEBUG, "cwebsocket_client_read_data: received PING control frame"); ++ WS_DEBUG("client_read_data: received PING control frame"); + uint8_t payload[payload_length]; + memcpy(payload, &data[header_length], payload_length); + payload[payload_length] = '\0'; + free(data); +- return cwebsocket_client_send_control_frame(websocket, 0x0A, "PONG", payload, payload_length); ++ return cwebsocket_client_send_control_frame(websocket, PONG, "PONG", payload, payload_length); + } + else if(frame.opcode == PONG) { +- syslog(LOG_DEBUG, "cwebsocket_client_read_data: received PONG control frame"); ++ WS_DEBUG("client_read_data: received PONG control frame"); ++ free(data); + return 0; + } + else if(frame.opcode == CLOSE) { + if(frame.payload_len > 125) { + cwebsocket_client_close(websocket, 1002, "control frames must not exceed 125 bytes"); ++ free(data); + return -1; + } + int code = 0; +@@ -739,7 +973,7 @@ int cwebsocket_client_read_data(cwebsocket_client *websocket) { + memcpy(payload, &data[header_length], (payload_length) * sizeof(uint8_t)); + payload[payload_length] = '\0'; + free(data); +- syslog(LOG_DEBUG, "cwebsocket_client_read_data: received CLOSE control frame. payload_length=%lld, code=%i, reason=%s", payload_length, code, payload); ++ WS_DEBUG("client_read_data: received CLOSE control frame. payload_length=%lld, code=%i, reason=%s", payload_length, code, payload); + cwebsocket_client_close(websocket, code, NULL); + return 0; + } +@@ -747,7 +981,7 @@ int cwebsocket_client_read_data(cwebsocket_client *websocket) { + free(data); + char closemsg[50]; + sprintf(closemsg, "received unsupported opcode: %#04x", frame.opcode); +- syslog(LOG_ERR, "cwebsocket_client_read_data: %s", closemsg); ++ WS_DEBUG("client_read_data: %s", closemsg); + cwebsocket_print_frame(&frame); + cwebsocket_client_onerror(websocket, closemsg); + cwebsocket_client_close(websocket, 1002, closemsg); +@@ -756,25 +990,26 @@ int cwebsocket_client_read_data(cwebsocket_client *websocket) { + + void cwebsocket_client_create_masking_key(uint8_t *masking_key) { + uint8_t mask_bit; +- struct timeval tv; +- gettimeofday(&tv, NULL); +- srand(tv.tv_usec * tv.tv_sec); ++ time_t Tick0 = 0; ++ ++ time(&Tick0); ++ srand(Tick0); + mask_bit = rand(); + memcpy(masking_key, &mask_bit, 4); + } + +-ssize_t cwebsocket_client_write_data(cwebsocket_client *websocket, const char *data, uint64_t payload_len, opcode code) { ++int cwebsocket_client_write_data(cwebsocket_client *websocket, const char *data, uint64_t payload_len, opcode code) { + + if((websocket->state & WEBSOCKET_STATE_OPEN) == 0) { +- syslog(LOG_DEBUG, "cwebsocket_client_write_data: websocket closed"); ++ WS_DEBUG("client_write_data: websocket closed"); + cwebsocket_client_onerror(websocket, "websocket closed"); + return -1; + } + +- uint32_t header_length = 6 + (payload_len > 125 ? 2 : 0) + (payload_len > 0xffff ? 8 : 0); ++ uint32_t header_length = 6 + (payload_len > 125 ? 2 : 0) + (payload_len > 0xffff ? 6 : 0); + uint8_t masking_key[4]; + uint8_t header[header_length]; +- ssize_t bytes_written; ++ int bytes_written; + + cwebsocket_client_create_masking_key(masking_key); + header[0] = (code | 0x80); +@@ -808,7 +1043,7 @@ ssize_t cwebsocket_client_write_data(cwebsocket_client *websocket, const char *d + header[13] = masking_key[3]; + } + else { +- syslog(LOG_CRIT, "cwebsocket_client_write_data: frame too large"); ++ WS_DEBUG("client_write_data: frame too large"); + cwebsocket_client_close(websocket, 1009, "frame too large"); + return -1; + } +@@ -827,74 +1062,86 @@ ssize_t cwebsocket_client_write_data(cwebsocket_client *websocket, const char *d + bytes_written = cwebsocket_client_write(websocket, framebuf, frame_length); + + if(bytes_written == -1) { +- syslog(LOG_ERR, "cwebsocket_client_write_data: error: %s", strerror(errno)); +- cwebsocket_client_onerror(websocket, strerror(errno)); ++ WS_DEBUG("client_write_data: error: %d", bytes_written); + return -1; + } + +- syslog(LOG_DEBUG, "cwebsocket_client_write_data: bytes_written=%zu, frame_length=%i, payload_len=%lld, payload=%s\n", ++ WS_DEBUG("client_write_data: bytes_written=%zu, frame_length=%i, payload_len=%lld, payload=%s\n", + bytes_written, frame_length, (long long)payload_len, data); + + return bytes_written; + } + + void cwebsocket_client_close(cwebsocket_client *websocket, uint16_t code, const char *message) { ++ int code32 = 0; + +- if((websocket->state & WEBSOCKET_STATE_OPEN) == 0 || websocket->fd < 1) { ++ if(websocket->state == 0) { + return; + } + +-#ifdef ENABLE_THREADS +- pthread_mutex_lock(&websocket->lock); +- websocket->state = WEBSOCKET_STATE_CLOSING; +- pthread_mutex_unlock(&websocket->lock); ++#ifdef ENABLE_SSL ++ if((websocket->state & WEBSOCKET_STATE_OPEN) != 0) { + #else +- websocket->state = WEBSOCKET_STATE_CLOSING; ++ if((websocket->state & WEBSOCKET_STATE_OPEN) != 0 && websocket->fd > 0) { + #endif + +- syslog(LOG_DEBUG, "cwebsocket_client_close: code=%i, message=%s\n", code, message); ++#ifdef ENABLE_THREADS ++ pthread_mutex_lock(&websocket->lock); ++ websocket->state = WEBSOCKET_STATE_CLOSING; ++ pthread_mutex_unlock(&websocket->lock); ++#else ++ websocket->state = WEBSOCKET_STATE_CLOSING; ++#endif + +- int code32 = 0; +- if(code > 0) { +- code = code ? htons(code) : htons(1005); +- int message_len = (message == NULL) ? 0 : strlen(message) + 2; +- uint8_t close_frame[message_len]; +- close_frame[0] = code & 0xFF; +- close_frame[1] = (code >> 8); +- code32 = (close_frame[0] << 8) + (close_frame[1]); +- int i; +- for(i=0; i 0) { ++ code = code ? htons(code) : htons(1005); ++ int message_len = (message == NULL) ? 2 : strlen(message) + 2; ++ uint8_t close_frame[message_len]; ++ close_frame[0] = code & 0xFF; ++ close_frame[1] = (code >> 8); ++ code32 = (close_frame[0] << 8) + (close_frame[1]); ++ int i; ++ for(i=0; issl != NULL) { +- SSL_shutdown(websocket->ssl); +- SSL_free(websocket->ssl); +- } +- if(websocket->sslctx != NULL) { +- SSL_CTX_free(websocket->sslctx); +- } +-#else +- if(shutdown(websocket->fd, SHUT_WR) == -1) { +- syslog(LOG_ERR, "cwebsocket_client_close: unable to shutdown websocket: %s", strerror(errno)); +- } +- char buf[1]; +- while(read(websocket->fd, buf, 1) > 0) { buf[0] = '\0'; } +- if(close(websocket->fd) == -1) { +- syslog(LOG_ERR, "cwebsocket_client_close: error closing websocket: %s\n", strerror(errno)); +- cwebsocket_client_onclose(websocket, 1011, strerror(errno)); ++ if(websocket->flags & WEBSOCKET_FLAG_SSL) { ++ WS_DEBUG("ssl_client_close: code=%i, message=%s\n", code, message); ++ ++ mbedtls_ssl_close_notify( &websocket->ssl ); ++ ++ mbedtls_net_free( &websocket->ssl_net_ctx ); ++ mbedtls_x509_crt_free( &websocket->cacert ); ++ mbedtls_ssl_free( &websocket->ssl ); ++ mbedtls_ssl_config_free( &websocket->conf ); ++ mbedtls_ctr_drbg_free( &websocket->ctr_drbg ); ++ mbedtls_entropy_free( &websocket->entropy ); ++ }else { ++#endif ++ if(shutdown(websocket->fd, SHUT_WR) == -1) { ++ WS_DEBUG("cwebsocket_client_close: unable to shutdown websocket: %s", strerror(errno)); ++ } ++ char buf[1]; ++ while(read(websocket->fd, buf, 1) > 0) { buf[0] = '\0'; } ++ if(close(websocket->fd) == -1) { ++ WS_DEBUG("cwebsocket_client_close: error closing websocket: %s\n", strerror(errno)); ++ } ++#ifdef ENABLE_SSL + } +- websocket->fd = 0; + #endif +- + cwebsocket_client_onclose(websocket, code32, message); + ++ websocket->fd = 0; ++ + #ifdef ENABLE_THREADS + pthread_mutex_lock(&websocket->lock); + websocket->state = WEBSOCKET_STATE_CLOSED; +@@ -904,7 +1151,6 @@ void cwebsocket_client_close(cwebsocket_client *websocket, uint16_t code, const + websocket->state = WEBSOCKET_STATE_CLOSED; + #endif + +- syslog(LOG_DEBUG, "cwebsocket_client_close: websocket closed\n"); + websocket->state = 0; + + if(websocket->flags & WEBSOCKET_FLAG_AUTORECONNECT) { +@@ -912,33 +1158,33 @@ void cwebsocket_client_close(cwebsocket_client *websocket, uint16_t code, const + } + } + +-ssize_t inline cwebsocket_client_read(cwebsocket_client *websocket, void *buf, int len) { ++ssize_t cwebsocket_client_read(cwebsocket_client *websocket, void *buf, int len) { + #ifdef ENABLE_SSL + return (websocket->flags & WEBSOCKET_FLAG_SSL) ? +- SSL_read(websocket->ssl, buf, len) : ++ mbedtls_ssl_read(&websocket->ssl, buf, len ) : + read(websocket->fd, buf, len); + #else + return read(websocket->fd, buf, len); + #endif + } + +-ssize_t inline cwebsocket_client_write(cwebsocket_client *websocket, void *buf, int len) { ++ssize_t cwebsocket_client_write(cwebsocket_client *websocket, void *buf, int len) { + #ifdef ENABLE_THREADS + ssize_t bytes_written; + pthread_mutex_lock(&websocket->write_lock); +- #ifdef USESSL +- bytes_written = (websocket->flags & WEBSOCKET_FLAG_SSL) ? +- SSL_write(websocket->ssl, buf, len) : +- write(websocket->fd, buf, len); +- #else +- bytes_written = write(websocket->fd, buf, len); +- #endif ++#ifdef ENABLE_SSL ++ bytes_written = (websocket->flags & WEBSOCKET_FLAG_SSL) ? ++ mbedtls_ssl_write(&websocket->ssl, buf, len ) : ++ write(websocket->fd, buf, len); ++#else ++ bytes_written = write(websocket->fd, buf, len); ++#endif + pthread_mutex_unlock(&websocket->write_lock); + return bytes_written; + #else + #ifdef ENABLE_SSL + return (websocket->flags & WEBSOCKET_FLAG_SSL) ? +- SSL_write(websocket->ssl, buf, len) : ++ mbedtls_ssl_write(&websocket->ssl, buf, len) : + write(websocket->fd, buf, len); + #else + return write(websocket->fd, buf, len); +@@ -952,20 +1198,41 @@ void cwebsocket_client_onopen(cwebsocket_client *websocket) { + } + } + +-void cwebsocket_client_onmessage(cwebsocket_client *websocket, cwebsocket_message *message) { ++void cwebsocket_client_onmessage(cwebsocket_client *websocket, cwebsocket_dsp_message *message) { + if(websocket->subprotocol != NULL && websocket->subprotocol->onmessage != NULL) { +- websocket->subprotocol->onmessage(websocket, message); ++ uint64_t len; ++ websocket->message.opcode = message->opcode; ++ ++ for (len = 0; len < message->payload_len; len += MAX_CHUNK_SIZE){ ++ if (len + MAX_CHUNK_SIZE > message->payload_len){ ++ websocket->message.chunk_len = (message->payload_len - len); ++ memcpy(websocket->message.payload, &message->payload[len], (message->payload_len - len)); ++ websocket->message.payload[(message->payload_len - len)] = '\0'; ++ } else { ++ websocket->message.chunk_len = MAX_CHUNK_SIZE; ++ memcpy(websocket->message.payload, &message->payload[len], MAX_CHUNK_SIZE); ++ websocket->message.payload[MAX_CHUNK_SIZE] = '\0'; ++ } ++ websocket->message.chunk_pos = len; ++ websocket->message.payload_len = message->payload_len; ++ websocket->subprotocol->onmessage(websocket); ++ } + } + } + + void cwebsocket_client_onclose(cwebsocket_client *websocket, int code, const char *message) { + if(websocket->subprotocol != NULL && websocket->subprotocol->onclose != NULL) { +- websocket->subprotocol->onclose(websocket, code, message); ++ strncpy(websocket->message.payload, message, MAX_CHUNK_SIZE); ++ websocket->code = code; ++ websocket->message.payload_len = strlen(message); ++ websocket->subprotocol->onclose(websocket); + } + } + + void cwebsocket_client_onerror(cwebsocket_client *websocket, const char *error) { + if(websocket->subprotocol != NULL && websocket->subprotocol->onerror != NULL) { +- websocket->subprotocol->onerror(websocket, error); ++ strncpy(websocket->message.payload, error, MAX_CHUNK_SIZE); ++ websocket->message.payload_len = strlen(error); ++ websocket->subprotocol->onerror(websocket); + } + } +diff --git a/cwebsocket/src/cwebsocket/client.h b/cwebsocket/src/cwebsocket/client.h +index 0c4d57c..d11dc0b 100755 +--- a/cwebsocket/src/cwebsocket/client.h ++++ b/cwebsocket/src/cwebsocket/client.h +@@ -26,65 +26,212 @@ + #define CWEBSOCKET_CLIENT_H + + #include ++#include ++#include + #include +-#include +-#include +-#include ++#include ++#include "sys/socket.h" ++#include "netdb.h" ++#include "arpa/inet.h" + #include "common.h" + ++#ifdef ENABLE_THREADS ++#include "pthread.h" ++#endif ++ ++/** ++ * @file client.h ++ * @brief WebSocket API ++ */ ++ ++/** ++ * @ingroup lteiftop ++ * @defgroup netwebsocket WebSocket ++ * @brief WebSocket interface ++ * @{ ++ */ ++ + #define WEBSOCKET_FLAG_AUTORECONNECT (1 << 1) ++#define WEBSOCKET_FLAG_PROXY (1 << 5) ++ ++#define WEBSOCKET_SUBPROTOCOL_MAX 4 + + #ifdef __cplusplus + extern "C" { + #endif + ++/** ++ * @defgroup websockcomstr Structure for common interface ++ * Data structure for common interface ++ * @{ ++ */ ++ + typedef struct _cwebsocket { + int fd; + int retry; + char *uri; + uint8_t flags; + uint8_t state; ++ char *proxy_addr; ++ char *proxy_port; ++ char **headers; ++ int num_headers; + #ifdef ENABLE_SSL +- SSL_CTX *sslctx; +- SSL *ssl; ++ mbedtls_ssl_context ssl; ++ mbedtls_net_context ssl_net_ctx; ++ mbedtls_ssl_config conf; ++ mbedtls_x509_crt cacert; ++ mbedtls_x509_crt clicert; ++ mbedtls_pk_context pkey; ++ mbedtls_entropy_context entropy; ++ mbedtls_ctr_drbg_context ctr_drbg; + #endif + #ifdef ENABLE_THREADS + pthread_t thread; + pthread_mutex_t lock; + pthread_mutex_t write_lock; + #endif ++ cwebsocket_app_message message; ++ int code; + size_t subprotocol_len; + cwebsocket_subprotocol *subprotocol; +- cwebsocket_subprotocol *subprotocols[]; ++ cwebsocket_subprotocol *subprotocols[WEBSOCKET_SUBPROTOCOL_MAX]; + } cwebsocket_client; + + typedef struct { + cwebsocket_client *socket; +- cwebsocket_message *message; ++ cwebsocket_dsp_message *message; + } cwebsocket_client_thread_args; + + // "public" +-void cwebsocket_client_init(cwebsocket_client *websocket, cwebsocket_subprotocol *subprotocols[], int subprotocol_len); ++ ++/** ++ * @brief Initialized the client connection on a websocket ++ * ++ * @param[in] websocket : Data structure for common interface ++ * @param[in] subprotocols : The array information for sub protocol ++ * @param[in] subprotocol_len : Actual size of the subprotocol. ++ * ++ * @retval On success, 0 is returned. On error, -1 is returned. ++ * ++ * @detail Initialized the client connection on a websocket ++ * ++ */ ++int cwebsocket_client_init(cwebsocket_client *websocket, cwebsocket_subprotocol **subprotocols, int subprotocol_len); ++ ++/** ++ * @brief Initialized the ssl information on a websocket ++ * ++ * @param[in] websocket : Data structure for common interface ++ * @param[in] cert_name : Certificate name in file system ++ * @param[in] pers : Personalization data (Device specific identifiers) ++ * (Can be NULL) ++ * ++ * @retval On success, 0 is returned. On error, -1 is returned. ++ * ++ * @detail Initialized the ssl information on a websocket ++ * ++ */ ++int cwebsocket_client_ssl_init(cwebsocket_client *websocket, char *cert_name, char *cli_cert, char *cli_key, char *passphrase); ++ ++/** ++ * @brief Conneted to the websocket server ++ * ++ * @param[in] websocket : Data structure for common interface.(Set the server name to the uri) ++ * ++ * @retval On success, 0 is returned. On error, -1 is returned. ++ * ++ * @detail Conneted to the websocket server ++ * ++ */ + int cwebsocket_client_connect(cwebsocket_client *websocket); ++/** ++ * @brief Read the packet data from the websocket server ++ * ++ * @param[in] websocket : Data structure for common interface. ++ * ++ * @retval On success, Read() shall return the length of the message in bytes. On error, -1 is returned. ++ * On finish, 0 is returne. ++ * ++ * @detail Read the packet data from the websocket server ++ * ++ */ + int cwebsocket_client_read_data(cwebsocket_client *websocket); +-ssize_t cwebsocket_client_write_data(cwebsocket_client *websocket, const char *data, uint64_t len, opcode code); +-void cwebsocket_client_run(cwebsocket_client *websocket); ++ ++/** ++ * @brief Wrote the packet data to the websocket server ++ * ++ * @param[in] websocket : Data structure for common interface. ++ * ++ * @retval On success, Write() shall return the length of the message in bytes. On error, -1 is returned. ++ * ++ * @detail Wrote the packet data to the websocket server ++ * ++ */ ++int cwebsocket_client_write_data(cwebsocket_client *websocket, const char *data, uint64_t len, opcode code); ++ ++/** ++ * @brief Closed the websocket session to server ++ * ++ * @param[in] websocket : Data structure for common interface. ++ * @param[in] code : Closed code. (Refer to chapter 7.4 of RFC6455.) ++ * @param[in] reason : Closed reason. ++ * ++ * @retval Nothing ++ * ++ * @detail Closed the websocket session to server ++ * ++ */ ++ + void cwebsocket_client_close(cwebsocket_client *websocket, uint16_t code, const char *reason); +-void cwebsocket_client_listen(cwebsocket_client *websocket); ++ ++/** ++ * @brief Set the proxy address for websocket ++ * ++ * @param[in] websocket : Data structure for common interface. ++ * @param[in] proxy_addr : Proxy address. ++ * @param[in] proxy_port : Proxy port. ++ * ++ * @retval Nothing ++ * ++ * @detail Set the proxy address for websocket ++ * ++ */ ++void cwebsocket_client_set_proxy(cwebsocket_client *websocket, char *proxy_addr, char *proxy_port); ++ ++/** ++ * @brief Released the proxy features for websocket ++ * ++ * @param[in] websocket : Data structure for common interface. ++ * ++ * @retval Nothing ++ * ++ * @detail Released the proxy address for websocket ++ * ++ */ ++void cwebsocket_client_unset_proxy(cwebsocket_client *websocket); + + // "private" ++void cwebsocket_client_run(cwebsocket_client *websocket); ++void cwebsocket_client_listen(cwebsocket_client *websocket); + void cwebsocket_client_parse_uri(cwebsocket_client *websocket, const char *uri, char *hostname, char *port, char *resource, char *querystring); + int cwebsocket_client_handshake_handler(cwebsocket_client *websocket, const char *handshake_response, char *seckey); +-int cwebsocket_client_read_handshake(cwebsocket_client *websocket, char *seckey); ++int cwebsocket_client_read_handshake(cwebsocket_client *websocket, char *seckey, int flags); + int cwebsocket_client_send_control_frame(cwebsocket_client *websocket, opcode opcode, const char *frame_type, uint8_t *payload, int payload_len); + void cwebsocket_client_create_masking_key(uint8_t *masking_key); +-ssize_t inline cwebsocket_client_read(cwebsocket_client *websocket, void *buf, int len); +-ssize_t inline cwebsocket_client_write(cwebsocket_client *websocket, void *buf, int len); ++int cwebsocket_client_read(cwebsocket_client *websocket, void *buf, int len); ++int cwebsocket_client_write(cwebsocket_client *websocket, void *buf, int len); ++ + void cwebsocket_client_onopen(cwebsocket_client *websocket); +-void cwebsocket_client_onmessage(cwebsocket_client *websocket, cwebsocket_message *message); ++void cwebsocket_client_onmessage(cwebsocket_client *websocket, cwebsocket_dsp_message *message); + void cwebsocket_client_onclose(cwebsocket_client *websocket, int code, const char *message); + void cwebsocket_client_onerror(cwebsocket_client *websocket, const char *error); + ++ssize_t cwebsocket_proxy_client_write(int fd, void *buf, int len); ++int cwebsocket_proxy_client_handshake_handler(cwebsocket_client *websocket, const char *handshake_response); ++int cwebsocket_proxy_client_read_handshake(cwebsocket_client *websocket); ++/**@}*/ ++ + #ifdef __cplusplus + } + #endif +diff --git a/cwebsocket/src/cwebsocket/common.c b/cwebsocket/src/cwebsocket/common.c +index 931bb17..e271ae1 100644 +--- a/cwebsocket/src/cwebsocket/common.c ++++ b/cwebsocket/src/cwebsocket/common.c +@@ -23,25 +23,26 @@ + */ + + #include "common.h" ++#include "mbedtls/base64.h" ++#include "mbedtls/sha1.h" ++ + + char* cwebsocket_base64_encode(const unsigned char *input, int length) { +- BIO *bmem, *b64; +- BUF_MEM *bptr; +- b64 = BIO_new(BIO_f_base64()); +- bmem = BIO_new(BIO_s_mem()); +- b64 = BIO_push(b64, bmem); +- BIO_write(b64, input, length); +- BIO_flush(b64); +- BIO_get_mem_ptr(b64, &bptr); +- char *buff = (char *)malloc(bptr->length); +- memcpy(buff, bptr->data, bptr->length-1); +- buff[bptr->length-1] = '\0'; +- BIO_free_all(b64); ++ ++ unsigned char buffer[128]; ++ size_t olen; ++ ++ mbedtls_base64_encode(buffer, sizeof( buffer ), &olen, input, length ); ++ ++ char *buff = (char *)malloc(olen); ++ memcpy(buff, buffer, olen-1); ++ buff[olen-1] = '\0'; ++ + return buff; + } + + void cwebsocket_print_frame(cwebsocket_frame *frame) { +- syslog(LOG_DEBUG, "cwebsocket_print_frame: fin=%i, rsv1=%i, rsv2=%i, rsv3=%i, opcode=%#04x, mask=%i, payload_len=%lld\n", ++ WS_DEBUG("print_frame: fin=%i, rsv1=%i, rsv2=%i, rsv3=%i, opcode=%#04x, mask=%i, payload_len=%lld\n", + frame->fin, frame->rsv1, frame->rsv2, frame->rsv3, frame->opcode, frame->mask, frame->payload_len); + } + +@@ -53,6 +54,6 @@ char* cwebsocket_create_key_challenge_response(const char *seckey) { + memcpy(sha1buf, seckey, seckey_len); + memcpy(&sha1buf[seckey_len], GUID, 36); + unsigned char sha1_bytes[20]; +- SHA1((const unsigned char *)sha1buf, total_len, sha1_bytes); ++ mbedtls_sha1((const unsigned char *)sha1buf, total_len, sha1_bytes); + return cwebsocket_base64_encode((const unsigned char *)sha1_bytes, sizeof(sha1_bytes)); + } +diff --git a/cwebsocket/src/cwebsocket/common.h b/cwebsocket/src/cwebsocket/common.h +index d6d28c3..faeb8ff 100644 +--- a/cwebsocket/src/cwebsocket/common.h ++++ b/cwebsocket/src/cwebsocket/common.h +@@ -28,31 +28,36 @@ + #include + #include + #include +-#include + #include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include ++ + #include "utf8.h" + ++#include "sys/socket.h" ++ + #ifdef HAVE_CONFIG_H + #include "../../config.h" + #endif + ++//#define ENABLE_WEBSOCKET_DEBUG ++ ++#ifdef ENABLE_WEBSOCKET_DEBUG ++#define WS_DEBUG(...) printf(__VA_ARGS__) ++#else ++#define WS_DEBUG(...) ++#endif ++ ++//#define ENABLE_SSL ++ + #ifdef ENABLE_SSL +- #include +- #include +- #include ++#include "mbedtls/config.h" ++#include "mbedtls/ssl.h" ++#include "mbedtls/net.h" ++#include "mbedtls/entropy.h" ++#include "mbedtls/ctr_drbg.h" ++#include "mbedtls/error.h" ++#if defined(MBEDTLS_SSL_CACHE_C) ++#include "mbedtls/ssl_cache.h" ++#endif + #endif + + #if defined(__linux__) +@@ -72,11 +77,11 @@ + (char)(((p & ((uint64_t)0xff << 48)) >> 48) & 0xff), (char)(((p & ((uint64_t)0xff << 56)) >> 56) & 0xff) } + + #ifndef CWS_HANDSHAKE_BUFFER_MAX +- #define CWS_HANDSHAKE_BUFFER_MAX 256 // bytes ++ #define CWS_HANDSHAKE_BUFFER_MAX 1024 // bytes + #endif + + #ifndef CWS_DATA_BUFFER_MAX +- #define CWS_DATA_BUFFER_MAX 65543 // bytes ++ #define CWS_DATA_BUFFER_MAX 4096 // bytes + #endif + + #ifndef CWS_STACK_SIZE_MIN +@@ -103,10 +108,9 @@ + extern "C" { + #endif + +-typedef enum { +- TRUE, +- FALSE +-} bool; ++#define MAX_CHUNK_SIZE 256 ++ ++typedef int ssize_t; + + typedef enum { + CONTINUATION = 0x00, +@@ -132,20 +136,30 @@ typedef struct { + uint32_t opcode; + uint64_t payload_len; + char *payload; +-} cwebsocket_message; ++} cwebsocket_dsp_message; ++ ++typedef struct { ++ uint32_t opcode; ++ uint64_t payload_len; ++ uint64_t chunk_len; ++ uint64_t chunk_pos; ++ char payload[MAX_CHUNK_SIZE + 1]; ++} cwebsocket_app_message; + + typedef struct { + char *name; + void (*onopen)(void *arg); +- void (*onmessage)(void *arg, cwebsocket_message *message); +- void (*onclose)(void *arg, int code, const char *message); +- void (*onerror)(void *arg, const char *error); ++ void (*onmessage)(void *arg); ++ void (*onclose)(void *arg); ++ void (*onerror)(void *arg); + } cwebsocket_subprotocol; + + char* cwebsocket_create_key_challenge_response(const char *seckey); + char* cwebsocket_base64_encode(const unsigned char *input, int length); + void cwebsocket_print_frame(cwebsocket_frame *frame); + ++void ws_thread_new( const char *pcName, void( *pxThread )( void *pvParameters ), void *pvArg, int iStackSize, int iPriority); ++ + #ifdef __cplusplus + } + #endif +-- +2.37.1 + diff --git a/netutils/cwebsocket/0002-Revert-dsp_message-and-app_message-to-original.patch b/netutils/cwebsocket/0002-Revert-dsp_message-and-app_message-to-original.patch new file mode 100644 index 000000000..4856b16a1 --- /dev/null +++ b/netutils/cwebsocket/0002-Revert-dsp_message-and-app_message-to-original.patch @@ -0,0 +1,186 @@ +From 73f37c25e822864d9a07d1c61c0372a3b432e524 Mon Sep 17 00:00:00 2001 +From: SPRESENSE <41312067+SPRESENSE@users.noreply.github.com> +Date: Fri, 1 May 2020 14:10:35 +0900 +Subject: [PATCH 2/2] Revert dsp_message and app_message to original + +--- + cwebsocket/src/cwebsocket/client.c | 39 +++++++----------------------- + cwebsocket/src/cwebsocket/client.h | 5 ++-- + cwebsocket/src/cwebsocket/common.h | 20 +++------------ + 3 files changed, 15 insertions(+), 49 deletions(-) + +diff --git a/cwebsocket/src/cwebsocket/client.c b/cwebsocket/src/cwebsocket/client.c +index 50747f0..082b451 100755 +--- a/cwebsocket/src/cwebsocket/client.c ++++ b/cwebsocket/src/cwebsocket/client.c +@@ -827,14 +827,14 @@ int cwebsocket_client_read_data(cwebsocket_client *websocket) { + if(websocket->subprotocol != NULL && websocket->subprotocol->onmessage != NULL) { + + #ifdef ENABLE_THREADS +- cwebsocket_dsp_message *message = malloc(sizeof(cwebsocket_dsp_message)); ++ cwebsocket_message *message = malloc(sizeof(cwebsocket_message)); + if(message == NULL) { + WS_DEBUG("client_read_data: text message out of memory"); + cwebsocket_client_close(websocket, 1009, "out of memory"); + free(payload); + return -1; + } +- memset(message, 0, sizeof(cwebsocket_dsp_message)); ++ memset(message, 0, sizeof(cwebsocket_message)); + message->opcode = frame.opcode; + message->payload_len = payload_length; + message->payload = payload; +@@ -859,7 +859,7 @@ int cwebsocket_client_read_data(cwebsocket_client *websocket) { + free(payload); + return bytes_read; + #else +- cwebsocket_dsp_message message = {0}; ++ cwebsocket_message message = {0}; + message.opcode = frame.opcode; + message.payload_len = payload_length; + message.payload = payload; +@@ -890,7 +890,7 @@ int cwebsocket_client_read_data(cwebsocket_client *websocket) { + if(websocket->subprotocol->onmessage != NULL) { + + #ifdef ENABLE_THREADS +- cwebsocket_dsp_message *message = malloc(sizeof(cwebsocket_dsp_message)); ++ cwebsocket_message *message = malloc(sizeof(cwebsocket_message)); + if(message == NULL) { + WS_DEBUG("client_read_data: binary message out of memory"); + cwebsocket_client_close(websocket, 1009, "out of memory"); +@@ -919,7 +919,7 @@ int cwebsocket_client_read_data(cwebsocket_client *websocket) { + free(payload); + return bytes_read; + #else +- cwebsocket_dsp_message message; ++ cwebsocket_message message; + message.opcode = frame.opcode; + message.payload_len = payload_length; + message.payload = payload; +@@ -1198,41 +1198,20 @@ void cwebsocket_client_onopen(cwebsocket_client *websocket) { + } + } + +-void cwebsocket_client_onmessage(cwebsocket_client *websocket, cwebsocket_dsp_message *message) { ++void cwebsocket_client_onmessage(cwebsocket_client *websocket, cwebsocket_message *message) { + if(websocket->subprotocol != NULL && websocket->subprotocol->onmessage != NULL) { +- uint64_t len; +- websocket->message.opcode = message->opcode; +- +- for (len = 0; len < message->payload_len; len += MAX_CHUNK_SIZE){ +- if (len + MAX_CHUNK_SIZE > message->payload_len){ +- websocket->message.chunk_len = (message->payload_len - len); +- memcpy(websocket->message.payload, &message->payload[len], (message->payload_len - len)); +- websocket->message.payload[(message->payload_len - len)] = '\0'; +- } else { +- websocket->message.chunk_len = MAX_CHUNK_SIZE; +- memcpy(websocket->message.payload, &message->payload[len], MAX_CHUNK_SIZE); +- websocket->message.payload[MAX_CHUNK_SIZE] = '\0'; +- } +- websocket->message.chunk_pos = len; +- websocket->message.payload_len = message->payload_len; +- websocket->subprotocol->onmessage(websocket); +- } ++ websocket->subprotocol->onmessage(websocket, message); + } + } + + void cwebsocket_client_onclose(cwebsocket_client *websocket, int code, const char *message) { + if(websocket->subprotocol != NULL && websocket->subprotocol->onclose != NULL) { +- strncpy(websocket->message.payload, message, MAX_CHUNK_SIZE); +- websocket->code = code; +- websocket->message.payload_len = strlen(message); +- websocket->subprotocol->onclose(websocket); ++ websocket->subprotocol->onclose(websocket, code, message); + } + } + + void cwebsocket_client_onerror(cwebsocket_client *websocket, const char *error) { + if(websocket->subprotocol != NULL && websocket->subprotocol->onerror != NULL) { +- strncpy(websocket->message.payload, error, MAX_CHUNK_SIZE); +- websocket->message.payload_len = strlen(error); +- websocket->subprotocol->onerror(websocket); ++ websocket->subprotocol->onerror(websocket, error); + } + } +diff --git a/cwebsocket/src/cwebsocket/client.h b/cwebsocket/src/cwebsocket/client.h +index d11dc0b..1bad957 100755 +--- a/cwebsocket/src/cwebsocket/client.h ++++ b/cwebsocket/src/cwebsocket/client.h +@@ -91,7 +91,6 @@ typedef struct _cwebsocket { + pthread_mutex_t lock; + pthread_mutex_t write_lock; + #endif +- cwebsocket_app_message message; + int code; + size_t subprotocol_len; + cwebsocket_subprotocol *subprotocol; +@@ -100,7 +99,7 @@ typedef struct _cwebsocket { + + typedef struct { + cwebsocket_client *socket; +- cwebsocket_dsp_message *message; ++ cwebsocket_message *message; + } cwebsocket_client_thread_args; + + // "public" +@@ -223,7 +222,7 @@ int cwebsocket_client_read(cwebsocket_client *websocket, void *buf, int len); + int cwebsocket_client_write(cwebsocket_client *websocket, void *buf, int len); + + void cwebsocket_client_onopen(cwebsocket_client *websocket); +-void cwebsocket_client_onmessage(cwebsocket_client *websocket, cwebsocket_dsp_message *message); ++void cwebsocket_client_onmessage(cwebsocket_client *websocket, cwebsocket_message *message); + void cwebsocket_client_onclose(cwebsocket_client *websocket, int code, const char *message); + void cwebsocket_client_onerror(cwebsocket_client *websocket, const char *error); + +diff --git a/cwebsocket/src/cwebsocket/common.h b/cwebsocket/src/cwebsocket/common.h +index faeb8ff..1141639 100644 +--- a/cwebsocket/src/cwebsocket/common.h ++++ b/cwebsocket/src/cwebsocket/common.h +@@ -108,8 +108,6 @@ + extern "C" { + #endif + +-#define MAX_CHUNK_SIZE 256 +- + typedef int ssize_t; + + typedef enum { +@@ -136,30 +134,20 @@ typedef struct { + uint32_t opcode; + uint64_t payload_len; + char *payload; +-} cwebsocket_dsp_message; +- +-typedef struct { +- uint32_t opcode; +- uint64_t payload_len; +- uint64_t chunk_len; +- uint64_t chunk_pos; +- char payload[MAX_CHUNK_SIZE + 1]; +-} cwebsocket_app_message; ++} cwebsocket_message; + + typedef struct { + char *name; + void (*onopen)(void *arg); +- void (*onmessage)(void *arg); +- void (*onclose)(void *arg); +- void (*onerror)(void *arg); ++ void (*onmessage)(void *arg, cwebsocket_message *message); ++ void (*onclose)(void *arg, int code, const char *message); ++ void (*onerror)(void *arg, const char *error); + } cwebsocket_subprotocol; + + char* cwebsocket_create_key_challenge_response(const char *seckey); + char* cwebsocket_base64_encode(const unsigned char *input, int length); + void cwebsocket_print_frame(cwebsocket_frame *frame); + +-void ws_thread_new( const char *pcName, void( *pxThread )( void *pvParameters ), void *pvArg, int iStackSize, int iPriority); +- + #ifdef __cplusplus + } + #endif +-- +2.37.1 + diff --git a/netutils/cwebsocket/Kconfig b/netutils/cwebsocket/Kconfig new file mode 100644 index 000000000..d5ec05f66 --- /dev/null +++ b/netutils/cwebsocket/Kconfig @@ -0,0 +1,15 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +config CWEBSOCKET + bool "WebSocket Client Library" + default n + depends on ALLOW_MIT_COMPONENTS + select LIBC_SCANSET + ---help--- + Enable WebSocket Client Library. + WebSocket Client Library is provided from https://github.com/jeremyhahn/cwebsocket + and licensed under MIT. + diff --git a/netutils/cwebsocket/Make.defs b/netutils/cwebsocket/Make.defs new file mode 100644 index 000000000..ca3e48e89 --- /dev/null +++ b/netutils/cwebsocket/Make.defs @@ -0,0 +1,26 @@ +############################################################################ +# apps/netutils/cwebsocket/Make.defs +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +ifneq ($(CONFIG_CWEBSOCKET),) +CONFIGURED_APPS += $(APPDIR)/netutils/cwebsocket + +CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(APPDIR)/netutils/cwebsocket/cwebsocket} +CXXFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(APPDIR)/netutils/cwebsocket/cwebsocket} +endif diff --git a/netutils/cwebsocket/Makefile b/netutils/cwebsocket/Makefile new file mode 100644 index 000000000..01ffd9fb2 --- /dev/null +++ b/netutils/cwebsocket/Makefile @@ -0,0 +1,48 @@ +############################################################################ +# apps/netutils/cwebsocket/Makefile +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +include $(APPDIR)/Make.defs + +SRC = cwebsocket/src/cwebsocket + +CSRCS += $(SRC)/client.c +CSRCS += $(SRC)/common.c +CSRCS += $(SRC)/utf8.c + +CFLAGS += -DENABLE_SSL +CFLAGS += -Wno-shadow -Wno-strict-prototypes -Wno-unknown-pragmas + +cwebsocket.zip: + $(Q) curl -L https://codeload.github.com/jeremyhahn/cwebsocket/zip/refs/heads/master -o cwebsocket.zip + $(Q) unzip cwebsocket.zip + $(Q) mv cwebsocket-master cwebsocket + $(Q) patch -Np1 < 0001-Porting-the-code-for-NuttX.patch + $(Q) patch -Np1 < 0002-Revert-dsp_message-and-app_message-to-original.patch + +# Download and unpack tarball if no git repo found +ifeq ($(wildcard cwebsocket/.git),) +context:: cwebsocket.zip + +distclean:: + $(call DELDIR, cwebsocket) + $(call DELFILE, cwebsocket.zip) +endif + +include $(APPDIR)/Application.mk