Commit 086111f1 authored by Keith Holman's avatar Keith Holman

WebSocket: initial websocket support + utilities

closes: #166

This patch provides an initial implementation for websocket support for
paho. For the websocket specification see RFC 6455.  The purpose of this
patch is to allow connnecting to an MQTT broker listening on a websocket
port (typically 80 [HTTP] or 443 [HTTPS]) to be able to communicate with
a client using the paho library.  Using websockets to communicate increases
the packet overhead both sending and receiving as well as additional setup
and ping packets.  However, using websockets allows for communications on
standard HTTP/HTTPS ports which are generally already configured by
firewalls to allow outside communications.

To use websockets, prefix the connection URI with either: "ws://" or
"wss://" for either websockets or secure websockets, repectfully.
Signed-off-by: 's avatarKeith Holman <keith.holman@windriver.com>
parent af104622
This diff is collapsed.
/*******************************************************************************
* Copyright (c) 2018 Wind River Systems, Inc. All Rights Reserved.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Keith Holman - initial implementation and documentation
*******************************************************************************/
#if !defined(BASE64_H)
#define BASE64_H
/** type for size of a buffer, it saves passing around @p size_t (unsigned long long or unsigned long int) */
typedef unsigned int b64_size_t;
/** type for raw base64 data */
typedef unsigned char b64_data_t;
/**
* Decodes base64 data
*
* @param[out] out decoded data
* @param[in] out_len length of output buffer
* @param[in] in base64 string to decode
* @param[in] in_len length of input buffer
*
* @return the amount of data decoded
*
* @see Base64_decodeLength
* @see Base64_encode
*/
b64_size_t Base64_decode( b64_data_t *out, b64_size_t out_len,
const char *in, b64_size_t in_len );
/**
* Size of buffer required to decode base64 data
*
* @param[in] in base64 string to decode
* @param[in] in_len length of input buffer
*
* @return the size of buffer the decoded string would require
*
* @see Base64_decode
* @see Base64_encodeLength
*/
b64_size_t Base64_decodeLength( const char *in, b64_size_t in_len );
/**
* Encodes base64 data
*
* @param[out] out encode base64 string
* @param[in] out_len length of output buffer
* @param[in] in raw data to encode
* @param[in] in_len length of input buffer
*
* @return the amount of data encoded
*
* @see Base64_decode
* @see Base64_encodeLength
*/
b64_size_t Base64_encode( char *out, b64_size_t out_len,
const b64_data_t *in, b64_size_t in_len );
/**
* Size of buffer required to encode base64 data
*
* @param[in] in raw data to encode
* @param[in] in_len length of input buffer
*
* @return the size of buffer the encoded string would require
*
* @see Base64_decodeLength
* @see Base64_encode
*/
b64_size_t Base64_encodeLength( const b64_data_t *in, b64_size_t in_len );
#endif /* BASE64_H */
......@@ -46,6 +46,12 @@ SET(common_src
SocketBuffer.c
Heap.c
LinkedList.c
Base64.c
Base64.h
SHA1.c
SHA1.h
WebSocket.c
WebSocket.h
)
IF (WIN32)
......
......@@ -158,6 +158,8 @@ typedef struct
SSL* ssl;
SSL_CTX* ctx;
#endif
int websocket; /**< socket has been upgraded to use web sockets */
char *websocket_key;
} networkHandles;
......@@ -168,8 +170,10 @@ typedef struct
#define TCP_IN_PROGRESS 0x1
/** SSL connection in progress */
#define SSL_IN_PROGRESS 0x2
/** Websocket connection in progress */
#define WEBSOCKET_IN_PROGRESS 0x3
/** TCP completed, waiting for MQTT ACK */
#define WAIT_FOR_CONNACK 0x3
#define WAIT_FOR_CONNACK 0x4
/** Disconnecting */
#define DISCONNECTING -2
......
......@@ -62,8 +62,11 @@
#include "StackTrace.h"
#include "Heap.h"
#include "OsWrapper.h"
#include "WebSocket.h"
#define URI_TCP "tcp://"
#define URI_WS "ws://"
#define URI_WSS "wss://"
#include "VersionInfo.h"
......@@ -294,6 +297,7 @@ typedef struct MQTTAsync_struct
{
char* serverURI;
int ssl;
int websocket;
Clients* c;
/* "Global", to the client, callback definitions */
......@@ -507,12 +511,23 @@ int MQTTAsync_createWithOptions(MQTTAsync* handle, const char* serverURI, const
memset(m, '\0', sizeof(MQTTAsyncs));
if (strncmp(URI_TCP, serverURI, strlen(URI_TCP)) == 0)
serverURI += strlen(URI_TCP);
else if (strncmp(URI_WS, serverURI, strlen(URI_WS)) == 0)
{
serverURI += strlen(URI_WS);
m->websocket = 1;
}
#if defined(OPENSSL)
else if (strncmp(URI_SSL, serverURI, strlen(URI_SSL)) == 0)
{
serverURI += strlen(URI_SSL);
m->ssl = 1;
}
else if (strncmp(URI_WSS, serverURI, strlen(URI_WSS)) == 0)
{
serverURI += strlen(URI_WSS);
m->ssl = 1;
m->websocket = 1;
}
#endif
m->serverURI = MQTTStrdup(serverURI);
m->responses = ListInitialize();
......@@ -575,10 +590,7 @@ static void MQTTAsync_terminate(void)
MQTTAsync_freeCommand1((MQTTAsync_queuedCommand*)(elem->content));
ListFree(commands);
handles = NULL;
Socket_outTerminate();
#if defined(OPENSSL)
SSLSocket_terminate();
#endif
WebSocket_terminate();
#if defined(HEAP_H)
Heap_terminate();
#endif
......@@ -1256,9 +1268,9 @@ static int MQTTAsync_processCommand(void)
Log(TRACE_MIN, -1, "Connecting to serverURI %s with MQTT version %d", serverURI, command->command.details.conn.MQTTVersion);
#if defined(OPENSSL)
rc = MQTTProtocol_connect(serverURI, command->client->c, command->client->ssl, command->command.details.conn.MQTTVersion);
rc = MQTTProtocol_connect(serverURI, command->client->c, command->client->ssl, command->client->websocket, command->command.details.conn.MQTTVersion);
#else
rc = MQTTProtocol_connect(serverURI, command->client->c, command->command.details.conn.MQTTVersion);
rc = MQTTProtocol_connect(serverURI, command->client->c, command->client->websocket, command->command.details.conn.MQTTVersion);
#endif
if (command->client->c->connect_state == NOT_IN_PROGRESS)
rc = SOCKET_ERROR;
......@@ -2118,6 +2130,7 @@ static void MQTTAsync_closeOnly(Clients* client)
if (client->connected && Socket_noPendingWrites(client->net.socket))
MQTTPacket_send_disconnect(&client->net, client->clientID);
Thread_lock_mutex(socket_mutex);
WebSocket_close(&client->net, WebSocket_CLOSE_NORMAL, NULL);
#if defined(OPENSSL)
SSLSocket_close(&client->net);
#endif
......@@ -2924,13 +2937,12 @@ static int MQTTAsync_connecting(MQTTAsyncs* m)
if (m->ssl)
{
int port;
char* hostname;
size_t hostname_len;
int setSocketForSSLrc = 0;
hostname = MQTTProtocol_addressPort(m->serverURI, &port);
setSocketForSSLrc = SSLSocket_setSocketForSSL(&m->c->net, m->c->sslopts, hostname);
if (hostname != m->serverURI)
free(hostname);
hostname_len = MQTTProtocol_addressPort(m->serverURI, &port, NULL);
setSocketForSSLrc = SSLSocket_setSocketForSSL(&m->c->net, m->c->sslopts,
m->serverURI, hostname_len);
if (setSocketForSSLrc != MQTTASYNC_SUCCESS)
{
......@@ -2951,12 +2963,21 @@ static int MQTTAsync_connecting(MQTTAsyncs* m)
}
else if (rc == 1)
{
rc = MQTTCLIENT_SUCCESS;
m->c->connect_state = WAIT_FOR_CONNACK;
if (MQTTPacket_send_connect(m->c, m->connect.details.conn.MQTTVersion) == SOCKET_ERROR)
if ( m->websocket )
{
rc = SOCKET_ERROR;
goto exit;
m->c->connect_state = WEBSOCKET_IN_PROGRESS;
if ((rc = WebSocket_connect(&m->c->net, m->serverURI)) == SOCKET_ERROR )
goto exit;
}
else
{
rc = MQTTCLIENT_SUCCESS;
m->c->connect_state = WAIT_FOR_CONNACK;
if (MQTTPacket_send_connect(m->c, m->connect.details.conn.MQTTVersion) == SOCKET_ERROR)
{
rc = SOCKET_ERROR;
goto exit;
}
}
if (!m->c->cleansession && m->c->session == NULL)
m->c->session = SSL_get1_session(m->c->net.ssl);
......@@ -2971,9 +2992,18 @@ static int MQTTAsync_connecting(MQTTAsyncs* m)
else
{
#endif
m->c->connect_state = WAIT_FOR_CONNACK; /* TCP/SSL connect completed, in which case send the MQTT connect packet */
if ((rc = MQTTPacket_send_connect(m->c, m->connect.details.conn.MQTTVersion)) == SOCKET_ERROR)
goto exit;
if ( m->websocket )
{
m->c->connect_state = WEBSOCKET_IN_PROGRESS;
if ((rc = WebSocket_connect(&m->c->net, m->serverURI)) == SOCKET_ERROR )
goto exit;
}
else
{
m->c->connect_state = WAIT_FOR_CONNACK; /* TCP/SSL connect completed, in which case send the MQTT connect packet */
if ((rc = MQTTPacket_send_connect(m->c, m->connect.details.conn.MQTTVersion)) == SOCKET_ERROR)
goto exit;
}
#if defined(OPENSSL)
}
#endif
......@@ -2987,14 +3017,34 @@ static int MQTTAsync_connecting(MQTTAsyncs* m)
if(!m->c->cleansession && m->c->session == NULL)
m->c->session = SSL_get1_session(m->c->net.ssl);
m->c->connect_state = WAIT_FOR_CONNACK; /* SSL connect completed, in which case send the MQTT connect packet */
if ((rc = MQTTPacket_send_connect(m->c, m->connect.details.conn.MQTTVersion)) == SOCKET_ERROR)
goto exit;
if ( m->websocket )
{
m->c->connect_state = WEBSOCKET_IN_PROGRESS;
if ((rc = WebSocket_connect(&m->c->net, m->serverURI)) == SOCKET_ERROR )
goto exit;
}
else
{
m->c->connect_state = WAIT_FOR_CONNACK; /* SSL connect completed, in which case send the MQTT connect packet */
if ((rc = MQTTPacket_send_connect(m->c, m->connect.details.conn.MQTTVersion)) == SOCKET_ERROR)
goto exit;
}
}
#endif
else if (m->c->connect_state == WEBSOCKET_IN_PROGRESS) /* Websocket connect sent - wait for completion */
{
if ((rc = WebSocket_upgrade( &m->c->net ) ) == SOCKET_ERROR )
goto exit;
else
{
m->c->connect_state = WAIT_FOR_CONNACK; /* Websocket upgrade completed, in which case send the MQTT connect packet */
if ((rc = MQTTPacket_send_connect(m->c, m->connect.details.conn.MQTTVersion)) == SOCKET_ERROR)
goto exit;
}
}
exit:
if ((rc != 0 && rc != TCPSOCKET_INTERRUPTED && m->c->connect_state != SSL_IN_PROGRESS) || (rc == SSL_FATAL))
if ((rc != 0 && rc != TCPSOCKET_INTERRUPTED && (m->c->connect_state != SSL_IN_PROGRESS && m->c->connect_state != WEBSOCKET_IN_PROGRESS)) || (rc == SSL_FATAL))
nextOrClose(m, MQTTASYNC_FAILURE, "TCP/TLS connect failure");
FUNC_EXIT_RC(rc);
......@@ -3035,7 +3085,7 @@ static MQTTPacket* MQTTAsync_cycle(int* sock, unsigned long timeout, int* rc)
if (m != NULL)
{
Log(TRACE_MINIMUM, -1, "m->c->connect_state = %d",m->c->connect_state);
if (m->c->connect_state == TCP_IN_PROGRESS || m->c->connect_state == SSL_IN_PROGRESS)
if (m->c->connect_state == TCP_IN_PROGRESS || m->c->connect_state == SSL_IN_PROGRESS || m->c->connect_state == WEBSOCKET_IN_PROGRESS)
*rc = MQTTAsync_connecting(m);
else
pack = MQTTPacket_Factory(&m->c->net, rc);
......
......@@ -71,9 +71,11 @@
#include "OsWrapper.h"
#define URI_TCP "tcp://"
#define URI_WS "ws://"
#define URI_WSS "wss://"
#include "VersionInfo.h"
#include "WebSocket.h"
const char *client_timestamp_eye = "MQTTClientV3_Timestamp " BUILD_TIMESTAMP;
const char *client_version_eye = "MQTTClientV3_Version " CLIENT_VERSION;
......@@ -195,6 +197,7 @@ typedef struct
#if defined(OPENSSL)
int ssl;
#endif
int websocket;
Clients* c;
MQTTClient_connectionLost* cl;
MQTTClient_messageArrived* ma;
......@@ -350,19 +353,36 @@ int MQTTClient_create(MQTTClient* handle, const char* serverURI, const char* cli
#endif
initialized = 1;
}
m = malloc(sizeof(MQTTClients));
*handle = m;
memset(m, '\0', sizeof(MQTTClients));
if (strncmp(URI_TCP, serverURI, strlen(URI_TCP)) == 0)
serverURI += strlen(URI_TCP);
else if (strncmp(URI_WS, serverURI, strlen(URI_WS)) == 0)
{
serverURI += strlen(URI_WS);
m->websocket = 1;
}
else if (strncmp(URI_SSL, serverURI, strlen(URI_SSL)) == 0)
{
#if defined(OPENSSL)
serverURI += strlen(URI_SSL);
m->ssl = 1;
#else
rc = MQTTCLIENT_SSL_NOT_SUPPORTED;
goto exit;
rc = MQTTCLIENT_SSL_NOT_SUPPORTED;
goto exit;
#endif
}
else if (strncmp(URI_WSS, serverURI, strlen(URI_WSS)) == 0)
{
#if defined(OPENSSL)
serverURI += strlen(URI_WSS);
m->ssl = 1;
m->websocket = 1;
#else
rc = MQTTCLIENT_SSL_NOT_SUPPORTED;
goto exit;
#endif
}
m->serverURI = MQTTStrdup(serverURI);
......@@ -407,10 +427,7 @@ static void MQTTClient_terminate(void)
ListFree(bstate->clients);
ListFree(handles);
handles = NULL;
Socket_outTerminate();
#if defined(OPENSSL)
SSLSocket_terminate();
#endif
WebSocket_terminate();
#if defined(HEAP_H)
Heap_terminate();
#endif
......@@ -681,6 +698,12 @@ static thread_return_type WINAPI MQTTClient_run(void* n)
}
}
#endif
else if (m->c->connect_state == WEBSOCKET_IN_PROGRESS && !Thread_check_sem(m->connect_sem))
{
Log(TRACE_MIN, -1, "Posting websocket handshake for client %s rc %d", m->c->clientID, m->rc);
m->c->connect_state = WAIT_FOR_CONNACK;
Thread_post_sem(m->connect_sem);
}
}
}
run_id = 0;
......@@ -769,6 +792,8 @@ static void MQTTClient_closeSession(Clients* client)
if (client->connected)
MQTTPacket_send_disconnect(&client->net, client->clientID);
Thread_lock_mutex(socket_mutex);
WebSocket_close(&client->net, WebSocket_CLOSE_NORMAL, NULL);
#if defined(OPENSSL)
SSLSocket_close(&client->net);
#endif
......@@ -870,9 +895,9 @@ static int MQTTClient_connectURIVersion(MQTTClient handle, MQTTClient_connectOpt
Log(TRACE_MIN, -1, "Connecting to serverURI %s with MQTT version %d", serverURI, MQTTVersion);
#if defined(OPENSSL)
rc = MQTTProtocol_connect(serverURI, m->c, m->ssl, MQTTVersion);
rc = MQTTProtocol_connect(serverURI, m->c, m->ssl, m->websocket, MQTTVersion);
#else
rc = MQTTProtocol_connect(serverURI, m->c, MQTTVersion);
rc = MQTTProtocol_connect(serverURI, m->c, m->websocket, MQTTVersion);
#endif
if (rc == SOCKET_ERROR)
goto exit;
......@@ -893,18 +918,17 @@ static int MQTTClient_connectURIVersion(MQTTClient handle, MQTTClient_connectOpt
rc = SOCKET_ERROR;
goto exit;
}
#if defined(OPENSSL)
if (m->ssl)
{
int port;
char* hostname;
size_t hostname_len;
const char *topic;
int setSocketForSSLrc = 0;
hostname = MQTTProtocol_addressPort(m->serverURI, &port);
setSocketForSSLrc = SSLSocket_setSocketForSSL(&m->c->net, m->c->sslopts, hostname);
if (hostname != m->serverURI)
free(hostname);
hostname_len = MQTTProtocol_addressPort(m->serverURI, &port, &topic);
setSocketForSSLrc = SSLSocket_setSocketForSSL(&m->c->net, m->c->sslopts,
m->serverURI, hostname_len);
if (setSocketForSSLrc != MQTTCLIENT_SUCCESS)
{
......@@ -922,15 +946,25 @@ static int MQTTClient_connectURIVersion(MQTTClient handle, MQTTClient_connectOpt
}
else if (rc == 1)
{
rc = MQTTCLIENT_SUCCESS;
m->c->connect_state = WAIT_FOR_CONNACK;
if (MQTTPacket_send_connect(m->c, MQTTVersion) == SOCKET_ERROR)
if (m->websocket)
{
rc = SOCKET_ERROR;
goto exit;
m->c->connect_state = WEBSOCKET_IN_PROGRESS;
rc = WebSocket_connect(&m->c->net,m->serverURI);
if ( rc == SOCKET_ERROR )
goto exit;
}
else if ( rc == 1 )
{
rc = MQTTCLIENT_SUCCESS;
m->c->connect_state = WAIT_FOR_CONNACK;
if (MQTTPacket_send_connect(m->c, MQTTVersion) == SOCKET_ERROR)
{
rc = SOCKET_ERROR;
goto exit;
}
if (!m->c->cleansession && m->c->session == NULL)
m->c->session = SSL_get1_session(m->c->net.ssl);
}
if (!m->c->cleansession && m->c->session == NULL)
m->c->session = SSL_get1_session(m->c->net.ssl);
}
}
else
......@@ -939,18 +973,25 @@ static int MQTTClient_connectURIVersion(MQTTClient handle, MQTTClient_connectOpt
goto exit;
}
}
#endif
else if (m->websocket)
{
m->c->connect_state = WEBSOCKET_IN_PROGRESS;
if ( WebSocket_connect(&m->c->net, m->serverURI) == SOCKET_ERROR )
{
rc = SOCKET_ERROR;
goto exit;
}
}
else
{
#endif
m->c->connect_state = WAIT_FOR_CONNACK; /* TCP connect completed, in which case send the MQTT connect packet */
if (MQTTPacket_send_connect(m->c, MQTTVersion) == SOCKET_ERROR)
{
rc = SOCKET_ERROR;
goto exit;
}
#if defined(OPENSSL)
}
#endif
}
#if defined(OPENSSL)
......@@ -966,19 +1007,45 @@ static int MQTTClient_connectURIVersion(MQTTClient handle, MQTTClient_connectOpt
}
if(!m->c->cleansession && m->c->session == NULL)
m->c->session = SSL_get1_session(m->c->net.ssl);
m->c->connect_state = WAIT_FOR_CONNACK; /* TCP connect completed, in which case send the MQTT connect packet */
if ( m->websocket )
{
/* wait for websocket connect */
m->c->connect_state = WEBSOCKET_IN_PROGRESS;
rc = WebSocket_connect( &m->c->net, m->serverURI );
if ( rc != 1 )
{
rc = SOCKET_ERROR;
goto exit;
}
}
else
{
m->c->connect_state = WAIT_FOR_CONNACK; /* TCP connect completed, in which case send the MQTT connect packet */
if (MQTTPacket_send_connect(m->c, MQTTVersion) == SOCKET_ERROR)
{
rc = SOCKET_ERROR;
goto exit;
}
}
}
#endif
if (m->c->connect_state == WEBSOCKET_IN_PROGRESS) /* websocket request sent - wait for upgrade */
{
Thread_unlock_mutex(mqttclient_mutex);
MQTTClient_waitfor(handle, CONNECT, &rc, millisecsTimeout - MQTTClient_elapsed(start));
Thread_lock_mutex(mqttclient_mutex);
m->c->connect_state = WAIT_FOR_CONNACK; /* websocket upgrade complete */
if (MQTTPacket_send_connect(m->c, MQTTVersion) == SOCKET_ERROR)
{
rc = SOCKET_ERROR;
goto exit;
}
}
#endif
if (m->c->connect_state == WAIT_FOR_CONNACK) /* MQTT connect sent - wait for CONNACK */
{
MQTTPacket* pack = NULL;
Thread_unlock_mutex(mqttclient_mutex);
pack = MQTTClient_waitfor(handle, CONNACK, &rc, millisecsTimeout - MQTTClient_elapsed(start));
Thread_lock_mutex(mqttclient_mutex);
......@@ -1255,12 +1322,23 @@ int MQTTClient_connect(MQTTClient handle, MQTTClient_connectOptions* options)
if (strncmp(URI_TCP, serverURI, strlen(URI_TCP)) == 0)
serverURI += strlen(URI_TCP);
else if (strncmp(URI_WS, serverURI, strlen(URI_WS)) == 0)
{
serverURI += strlen(URI_WS);
m->websocket = 1;
}
#if defined(OPENSSL)
else if (strncmp(URI_SSL, serverURI, strlen(URI_SSL)) == 0)
{
serverURI += strlen(URI_SSL);
m->ssl = 1;
}
else if (strncmp(URI_WSS, serverURI, strlen(URI_WSS)) == 0)
{
serverURI += strlen(URI_WSS);
m->ssl = 1;
m->websocket = 1;
}
#endif
if ((rc = MQTTClient_connectURI(handle, options, serverURI)) == MQTTCLIENT_SUCCESS)
break;
......@@ -1743,6 +1821,8 @@ static MQTTPacket* MQTTClient_cycle(int* sock, unsigned long timeout, int* rc)
{
if (m->c->connect_state == TCP_IN_PROGRESS || m->c->connect_state == SSL_IN_PROGRESS)
*rc = 0; /* waiting for connect state to clear */
else if (m->c->connect_state == WEBSOCKET_IN_PROGRESS)
*rc = WebSocket_upgrade(&m->c->net);
else
{
pack = MQTTPacket_Factory(&m->c->net, rc);
......@@ -1857,7 +1937,8 @@ static MQTTPacket* MQTTClient_waitfor(MQTTClient handle, int packet_type, int* r
}
}
#endif
else if (m->c->connect_state == WAIT_FOR_CONNACK)
else if (m->c->connect_state == WEBSOCKET_IN_PROGRESS ||
m->c->connect_state == WAIT_FOR_CONNACK)
{
int error;
socklen_t len = sizeof(error);
......
......@@ -30,6 +30,7 @@
#endif
#include "Messages.h"
#include "StackTrace.h"
#include "WebSocket.h"
#include <stdlib.h>
#include <string.h>
......@@ -108,11 +109,7 @@ void* MQTTPacket_Factory(networkHandles* net, int* error)
*error = SOCKET_ERROR; /* indicate whether an error occurred, or not */
/* read the packet data from the socket */
#if defined(OPENSSL)
*error = (net->ssl) ? SSLSocket_getch(net->ssl, net->socket, &header.byte) : Socket_getch(net->socket, &header.byte);
#else
*error = Socket_getch(net->socket, &header.byte);
#endif
*error = WebSocket_getch(net, &header.byte);
if (*error != TCPSOCKET_COMPLETE) /* first byte is the header byte */
goto exit; /* packet not read, *error indicates whether SOCKET_ERROR occurred */
......@@ -121,12 +118,7 @@ void* MQTTPacket_Factory(networkHandles* net, int* error)
goto exit; /* packet not read, *error indicates whether SOCKET_ERROR occurred */
/* now read the rest, the variable header and payload */
#if defined(OPENSSL)
data = (net->ssl) ? SSLSocket_getdata(net->ssl, net->socket, remaining_length, &actual_len) :
Socket_getdata(net->socket, remaining_length, &actual_len);
#else
data = Socket_getdata(net->socket, remaining_length, &actual_len);
#endif
data = WebSocket_getdata(net, remaining_length, &actual_len);
if (data == NULL)
{
*error = SOCKET_ERROR;
......@@ -178,29 +170,28 @@ int MQTTPacket_send(networkHandles* net, Header header, char* buffer, size_t buf
{
int rc;
size_t buf0len;
size_t ws_header;
char *buf;
FUNC_ENTRY;
buf = malloc(10);
buf[0] = header.byte;
buf0len = 1 + MQTTPacket_encode(&buf[1], buflen);
ws_header = WebSocket_calculateFrameHeaderSize(net, buflen + 10);
buf = malloc(10 + ws_header);
if ( !buf ) return -1;
buf[ws_header] = header.byte;
buf0len = 1 + MQTTPacket_encode(&buf[ws_header + 1], buflen);
#if !defined(NO_PERSISTENCE)
if (header.bits.type == PUBREL)
{
char* ptraux = buffer;
int msgId = readInt(&ptraux);
rc = MQTTPersistence_put(net->socket, buf, buf0len, 1, &buffer, &buflen,
rc = MQTTPersistence_put(net->socket, &buf[ws_header], buf0len, 1, &buffer, &buflen,
header.bits.type, msgId, 0);
}
#endif
#if defined(OPENSSL)
if (net->ssl)
rc = SSLSocket_putdatas(net->ssl, net->socket, buf, buf0len, 1, &buffer, &buflen, &freeData);
else
#endif
rc = Socket_putdatas(net->socket, buf, buf0len, 1, &buffer, &buflen, &freeData);
rc = WebSocket_putdatas(net, &buf[ws_header], buf0len, 1, &buffer, &buflen, &freeData);
if (rc == TCPSOCKET_COMPLETE)
time(&(net->lastSent));
......@@ -225,30 +216,31 @@ int MQTTPacket_sends(networkHandles* net, Header header, int count, char** buffe
{
int i, rc;
size_t buf0len, total = 0;
size_t ws_header;
char *buf;
FUNC_ENTRY;
buf = malloc(10);
buf[0] = header.byte;
for (i = 0; i < count; i++)
total += buflens[i];
buf0len = 1 + MQTTPacket_encode(&buf[1], total);
ws_header = WebSocket_calculateFrameHeaderSize(net, total + 10);
buf = malloc(10 + ws_header);
if ( !buf ) return -1;
buf[ws_header] = header.byte;
buf0len = 1 + MQTTPacket_encode(&buf[ws_header + 1], total);
#if !defined(NO_PERSISTENCE)
if (header.bits.type == PUBLISH && header.bits.qos != 0)
{ /* persist PUBLISH QoS1 and Qo2 */
char *ptraux = buffers[2];
int msgId = readInt(&ptraux);
rc = MQTTPersistence_put(net->socket, buf, buf0len, count, buffers, buflens,
rc = MQTTPersistence_put(net->socket, &buf[ws_header], buf0len, count, buffers, buflens,
header.bits.type, msgId, 0);
}
#endif
#if defined(OPENSSL)
if (net->ssl)
rc = SSLSocket_putdatas(net->ssl, net->socket, buf, buf0len, count, buffers, buflens, frees);
else
#endif
rc = Socket_putdatas(net->socket, buf, buf0len, count, buffers, buflens, frees);
rc = WebSocket_putdatas(net, &buf[ws_header], buf0len, count, buffers, buflens, frees);
if (rc == TCPSOCKET_COMPLETE)
time(&(net->lastSent));
......@@ -307,11 +299,7 @@ int MQTTPacket_decode(networkHandles* net, size_t* value)
rc = SOCKET_ERROR; /* bad data */
goto exit;
}
#if defined(OPENSSL)
rc = (net->ssl) ? SSLSocket_getch(net->ssl, net->socket, &c) : Socket_getch(net->socket, &c);
#else
rc = Socket_getch(net->socket, &c);
#endif
rc = WebSocket_getch(net, &c);
if (rc != TCPSOCKET_COMPLETE)
goto exit;
*value += (c & 127) * multiplier;
......
......@@ -35,6 +35,7 @@
#include "MQTTProtocolOut.h"
#include "StackTrace.h"
#include "Heap.h"
#include "WebSocket.h"
extern ClientStates* bstate;
......@@ -42,11 +43,12 @@ extern ClientStates* bstate;
/**
* Separates an address:port into two separate values
* @param uri the input string - hostname:port
* @param port the returned port integer
* @param[in] uri the input string - hostname:port
* @param[out] port the returned port integer
* @param[out] topic optional topic portion of the address starting with '/'
* @return the address string
*/
char* MQTTProtocol_addressPort(const char* uri, int* port)
size_t MQTTProtocol_addressPort(const char* uri, int* port, const char **topic)
{
char* colon_pos = strrchr(uri, ':'); /* reverse find to allow for ':' in IPv6 addresses */
char* buf = (char*)uri;
......@@ -61,27 +63,31 @@ char* MQTTProtocol_addressPort(const char* uri, int* port)
if (colon_pos) /* have to strip off the port */
{
size_t addr_len = colon_pos - uri;
buf = malloc(addr_len + 1);
len = colon_pos - uri;
*port = atoi(colon_pos + 1);
MQTTStrncpy(buf, uri, addr_len+1);
}
else
{
len = strlen(buf);
*port = DEFAULT_PORT;
}
/* try and find topic portion */
if ( topic )
{
const char* addr_start = uri;
if ( colon_pos )
addr_start = colon_pos;
*topic = strchr( addr_start, '/' );
}
len = strlen(buf);
if (buf[len - 1] == ']')
{
if (buf == (char*)uri)
{
buf = malloc(len); /* we are stripping off the final ], so length is 1 shorter */
MQTTStrncpy(buf, uri, len);
}
else
buf[len - 1] = '\0';
/* we are stripping off the final ], so length is 1 shorter */
--len;
}
FUNC_EXIT;
return buf;
return len;
}
......@@ -94,19 +100,19 @@ char* MQTTProtocol_addressPort(const char* uri, int* port)
* @return return code
*/
#if defined(OPENSSL)
int MQTTProtocol_connect(const char* ip_address, Clients* aClient, int ssl, int MQTTVersion)
int MQTTProtocol_connect(const char* ip_address, Clients* aClient, int ssl, int websocket, int MQTTVersion)
#else
int MQTTProtocol_connect(const char* ip_address, Clients* aClient, int MQTTVersion)
int MQTTProtocol_connect(const char* ip_address, Clients* aClient, int websocket, int MQTTVersion)
#endif
{
int rc, port;
char* addr;
size_t addr_len;
FUNC_ENTRY;
aClient->good = 1;
addr = MQTTProtocol_addressPort(ip_address, &port);
rc = Socket_new(addr, port, &(aClient->net.socket));
addr_len = MQTTProtocol_addressPort(ip_address, &port, NULL);
rc = Socket_new(ip_address, addr_len, port, &(aClient->net.socket));
if (rc == EINPROGRESS || rc == EWOULDBLOCK)
aClient->connect_state = TCP_IN_PROGRESS; /* TCP connect called - wait for connect completion */
else if (rc == 0)
......@@ -114,10 +120,10 @@ int MQTTProtocol_connect(const char* ip_address, Clients* aClient, int MQTTVersi
#if defined(OPENSSL)
if (ssl)
{
if (SSLSocket_setSocketForSSL(&aClient->net, aClient->sslopts, addr) == 1)
if (SSLSocket_setSocketForSSL(&aClient->net, aClient->sslopts, ip_address, addr_len) == 1)
{
rc = SSLSocket_connect(aClient->net.ssl, aClient->net.socket,
addr, aClient->sslopts->verify);
ip_address, aClient->sslopts->verify);
if (rc == TCPSOCKET_INTERRUPTED)
aClient->connect_state = SSL_IN_PROGRESS; /* SSL connect called - wait for completion */
}
......@@ -125,6 +131,12 @@ int MQTTProtocol_connect(const char* ip_address, Clients* aClient, int MQTTVersi
rc = SOCKET_ERROR;
}
#endif
if ( websocket )
{
rc = WebSocket_connect( &aClient->net, ip_address );
if ( rc == TCPSOCKET_INTERRUPTED )
aClient->connect_state = WEBSOCKET_IN_PROGRESS; /* Websocket connect called - wait for completion */
}
if (rc == 0)
{
/* Now send the MQTT connect packet */
......@@ -134,8 +146,6 @@ int MQTTProtocol_connect(const char* ip_address, Clients* aClient, int MQTTVersi
aClient->connect_state = NOT_IN_PROGRESS;
}
}
if (addr != ip_address)
free(addr);
FUNC_EXIT_RC(rc);
return rc;
......
......@@ -30,12 +30,12 @@
#define DEFAULT_PORT 1883
char* MQTTProtocol_addressPort(const char* uri, int* port);
size_t MQTTProtocol_addressPort(const char* uri, int* port, const char **topic);
void MQTTProtocol_reconnect(const char* ip_address, Clients* client);
#if defined(OPENSSL)
int MQTTProtocol_connect(const char* ip_address, Clients* acClients, int ssl, int MQTTVersion);
int MQTTProtocol_connect(const char* ip_address, Clients* acClients, int ssl, int websocket, int MQTTVersion);
#else
int MQTTProtocol_connect(const char* ip_address, Clients* acClients, int MQTTVersion);
int MQTTProtocol_connect(const char* ip_address, Clients* acClients, int websocket, int MQTTVersion);
#endif
int MQTTProtocol_handlePingresps(void* pack, int sock);
int MQTTProtocol_subscribe(Clients* client, List* topics, List* qoss, int msgID);
......
/*******************************************************************************
* Copyright (c) 2018 Wind River Systems, Inc. All Rights Reserved.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Keith Holman - initial implementation and documentation
*******************************************************************************/
#include "SHA1.h"
#if !defined(OPENSSL)
#if defined(WIN32) || defined(WIN64)
#pragma comment(lib, "crypt32.lib")
int SHA1_Init(SHA_CTX *c)
{
if (!CryptAcquireContext(&c->hProv, NULL, NULL,
PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
return 0;
if (!CryptCreateHash(c->hProv, CALG_SHA1, 0, 0, &c->hHash))
{
CryptReleaseContext(c->hProv, 0);
return 0;
}
return 1;
}
int SHA1_Update(SHA_CTX *c, const void *data, size_t len)
{
int rv = 1;
if (!CryptHashData(c->hHash, data, len, 0))
rv = 0;
return rv;
}
int SHA1_Final(unsigned char *md, SHA_CTX *c)
{
int rv = 0;
DWORD md_len = SHA1_DIGEST_LENGTH;
if (CryptGetHashParam(c->hHash, HP_HASHVAL, md, &md_len, 0))
rv = 1;
CryptDestroyHash(c->hHash);
CryptReleaseContext(c->hProv, 0);
return rv;
}
#else /* if defined(WIN32) || defined(WIN64) */
#if defined(__linux__)
# include <endian.h>
#elif defined(__APPLE__)
# include <libkern/OSByteOrder.h>
# define htobe32(x) OSSwapHostToBigInt32(x)
# define be32toh(x) OSSwapBigToHostInt32(x)
#elif defined(__FreeBSD__) || defined(__NetBSD__)
# include <sys/endian.h>
#endif
#include <string.h>
static unsigned char pad[64] = {
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
int SHA1_Init(SHA_CTX *ctx)
{
int ret = 0;
if ( ctx )
{
ctx->h[0] = 0x67452301;
ctx->h[1] = 0xEFCDAB89;
ctx->h[2] = 0x98BADCFE;
ctx->h[3] = 0x10325476;
ctx->h[4] = 0xC3D2E1F0;
ctx->size = 0u;
ctx->total = 0u;
ret = 1;
}
return ret;
}
#define ROTATE_LEFT32(a, n) (((a) << (n)) | ((a) >> (32 - (n))))
static void SHA1_ProcessBlock(SHA_CTX *ctx)
{
uint32_t blks[5];
uint32_t *w;
int i;
/* initialize */
for ( i = 0; i < 5; ++i )
blks[i] = ctx->h[i];
w = ctx->w;
/* perform SHA-1 hash */
for ( i = 0; i < 16; ++i )
w[i] = be32toh(w[i]);
for( i = 0; i < 80; ++i )
{
int tmp;
if ( i >= 16 )
w[i & 0x0F] = ROTATE_LEFT32( w[(i+13) & 0x0F] ^ w[(i+8) & 0x0F] ^ w[(i+2) & 0x0F] ^ w[i & 0x0F], 1 );
if ( i < 20 )
tmp = ROTATE_LEFT32(blks[0], 5) + ((blks[1] & blks[2]) | (~(blks[1]) & blks[3])) + blks[4] + w[i & 0x0F] + 0x5A827999;
else if ( i < 40 )
tmp = ROTATE_LEFT32(blks[0], 5) + (blks[1]^blks[2]^blks[3]) + blks[4] + w[i & 0x0F] + 0x6ED9EBA1;
else if ( i < 60 )
tmp = ROTATE_LEFT32(blks[0], 5) + ((blks[1] & blks[2]) | (blks[1] & blks[3]) | (blks[2] & blks[3])) + blks[4] + w[i & 0x0F] + 0x8F1BBCDC;
else
tmp = ROTATE_LEFT32(blks[0], 5) + (blks[1]^blks[2]^blks[3]) + blks[4] + w[i & 0x0F] + 0xCA62C1D6;
/* update registers */
blks[4] = blks[3];
blks[3] = blks[2];
blks[2] = ROTATE_LEFT32(blks[1], 30);
blks[1] = blks[0];
blks[0] = tmp;
}
/* update of hash */
for ( i = 0; i < 5; ++i )
ctx->h[i] += blks[i];
}
int SHA1_Final(unsigned char *md, SHA_CTX *ctx)
{
int i;
int ret = 0;
size_t pad_amount;
uint64_t total;
/* length before pad */
total = ctx->total * 8;
if ( ctx->size < 56 )
pad_amount = 56 - ctx->size;
else
pad_amount = 64 + 56 - ctx->size;
SHA1_Update(ctx, pad, pad_amount);
ctx->w[14] = htobe32((uint32_t)(total >> 32));
ctx->w[15] = htobe32((uint32_t)total);
SHA1_ProcessBlock(ctx);
for ( i = 0; i < 5; ++i )
ctx->h[i] = htobe32(ctx->h[i]);
if ( md )
{
memcpy( md, &ctx->h[0], SHA1_DIGEST_LENGTH );
ret = 1;
}
return ret;
}
int SHA1_Update(SHA_CTX *ctx, const void *data, size_t len)
{
while ( len > 0 )
{
unsigned int n = 64 - ctx->size;
if ( len < n )
n = len;
memcpy(ctx->buffer + ctx->size, data, n);
ctx->size += n;
ctx->total += n;
data = (uint8_t *)data + n;
len -= n;
if ( ctx->size == 64 )
{
SHA1_ProcessBlock(ctx);
ctx->size = 0;
}
}
return 1;
}
#endif /* else if defined(WIN32) || defined(WIN64) */
#endif /* elif !defined(OPENSSL) */
#if defined(SHA1_TEST)
#include <stdio.h>
#include <string.h>
#define TEST_EXPECT(i,x) if (!(x)) {fprintf( stderr, "failed test: %s (for i == %d)\n", #x, i ); ++fails;}
int main(int argc, char *argv[])
{
struct _td
{
const char *in;
const char *out;
};
int i;
unsigned int fails = 0u;
struct _td test_data[] = {
{ "", "da39a3ee5e6b4b0d3255bfef95601890afd80709" },
{ "this string", "fda4e74bc7489a18b146abdf23346d166663dab8" },
{ NULL, NULL }
};
/* only 1 update */
i = 0;
while ( test_data[i].in != NULL )
{
int r[3] = { 1, 1, 1 };
unsigned char sha_out[SHA1_DIGEST_LENGTH];
char out[SHA1_DIGEST_LENGTH * 2 + 1];
SHA_CTX c;
int j;
r[0] = SHA1_Init( &c );
r[1] = SHA1_Update( &c, test_data[i].in, strlen(test_data[i].in));
r[2] = SHA1_Final( sha_out, &c );
for ( j = 0u; j < SHA1_DIGEST_LENGTH; ++j )
snprintf( &out[j*2], 3u, "%02x", sha_out[j] );
out[SHA1_DIGEST_LENGTH * 2] = '\0';
TEST_EXPECT( i, r[0] == 1 && r[1] == 1 && r[2] == 1 && strncmp(out, test_data[i].out, strlen(test_data[i].out)) == 0 );
++i;
}
if ( fails )
printf( "%u test failed!\n", fails );
else
printf( "all tests passed\n" );
return fails;
}
#endif /* if defined(SHA1_TEST) */
/*******************************************************************************
* Copyright (c) 2018 Wind River Systems, Inc. All Rights Reserved.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Keith Holman - initial implementation and documentation
*******************************************************************************/
#if !defined(SHA1_H)
#define SHA1_H
#if defined(OPENSSL)
#include <openssl/sha.h>
/** SHA-1 Digest Length */
#define SHA1_DIGEST_LENGTH SHA_DIGEST_LENGTH
#else /* if defined(OPENSSL) */
#if defined(WIN32) || defined(WIN64)
#include <Windows.h>
#include <WinCrypt.h>
typedef struct SHA_CTX_S
{
HCRYPTPROV hProv;
HCRYPTHASH hHash;
} SHA_CTX;
#else /* if defined(WIN32) || defined(WIN64) */
#include <stdint.h>
typedef struct SHA_CTX_S {
uint32_t h[5];
union {
uint32_t w[16];
uint8_t buffer[64];
};
unsigned int size;
unsigned int total;
} SHA_CTX;
#endif /* else if defined(WIN32) || defined(WIN64) */
#include <stddef.h>
/** SHA-1 Digest Length (number of bytes in SHA1) */
#define SHA1_DIGEST_LENGTH (160/8)
/**
* Initializes the SHA1 hashing algorithm
*
* @param[in,out] ctx hashing context structure
*
* @see SHA1_Update
* @see SHA1_Final
*/
int SHA1_Init(SHA_CTX *ctx);
/**
* Updates a block to the SHA1 hash
*
* @param[in,out] ctx hashing context structure
* @param[in] data block of data to hash
* @param[in] len length of block to hash
*
* @see SHA1_Init
* @see SHA1_Final
*/
int SHA1_Update(SHA_CTX *ctx, const void *data, size_t len);
/**
* Produce final SHA1 hash
*
* @param[out] md SHA1 hash produced (must be atleast
* @p SHA1_DIGEST_LENGTH in length)
* @param[in,out] ctx hashing context structure
*
* @see SHA1_Init
* @see SHA1_Final
*/
int SHA1_Final(unsigned char *md, SHA_CTX *ctx);
#endif /* if defined(OPENSSL) */
#endif /* SHA1_H */
......@@ -30,11 +30,11 @@
#include "SocketBuffer.h"
#include "MQTTClient.h"
#include "MQTTProtocolOut.h"
#include "SSLSocket.h"
#include "Log.h"
#include "StackTrace.h"
#include "Socket.h"
char* MQTTProtocol_addressPort(const char* uri, int* port);
#include "Heap.h"
......@@ -620,7 +620,8 @@ exit:
}
int SSLSocket_setSocketForSSL(networkHandles* net, MQTTClient_SSLOptions* opts, char* hostname)
int SSLSocket_setSocketForSSL(networkHandles* net, MQTTClient_SSLOptions* opts,
const char* hostname, size_t hostname_len)
{
int rc = 1;
......@@ -628,6 +629,7 @@ int SSLSocket_setSocketForSSL(networkHandles* net, MQTTClient_SSLOptions* opts,
if (net->ctx != NULL || (rc = SSLSocket_createContext(net, opts)) == 1)
{
char *hostname_plus_null;
int i;
SSL_CTX_set_info_callback(net->ctx, SSL_CTX_info_callback);
......@@ -648,8 +650,11 @@ int SSLSocket_setSocketForSSL(networkHandles* net, MQTTClient_SSLOptions* opts,
if ((rc = SSL_set_fd(net->ssl, net->socket)) != 1)
SSLSocket_error("SSL_set_fd", net->ssl, net->socket, rc);
if ((rc = SSL_set_tlsext_host_name(net->ssl, hostname)) != 1)
hostname_plus_null = malloc(hostname_len + 1u );
MQTTStrncpy(hostname_plus_null, hostname, hostname_len + 1u);
if ((rc = SSL_set_tlsext_host_name(net->ssl, hostname_plus_null)) != 1)
SSLSocket_error("SSL_set_tlsext_host_name", NULL, net->socket, rc);
free(hostname_plus_null);
}
FUNC_EXIT_RC(rc);
......@@ -659,7 +664,7 @@ int SSLSocket_setSocketForSSL(networkHandles* net, MQTTClient_SSLOptions* opts,
/*
* Return value: 1 - success, TCPSOCKET_INTERRUPTED - try again, anything else is failure
*/
int SSLSocket_connect(SSL* ssl, int sock, char* hostname, int verify)
int SSLSocket_connect(SSL* ssl, int sock, const char* hostname, int verify)
{
int rc = 0;
......@@ -680,12 +685,12 @@ int SSLSocket_connect(SSL* ssl, int sock, char* hostname, int verify)
{
char* peername = NULL;
int port;
char* addr = NULL;
size_t hostname_len;
X509* cert = SSL_get_peer_certificate(ssl);
addr = MQTTProtocol_addressPort(hostname, &port);
hostname_len = MQTTProtocol_addressPort(hostname, &port, NULL);
rc = X509_check_host(cert, addr, strlen(addr), 0, &peername);
rc = X509_check_host(cert, hostname, hostname_len, 0, &peername);
if (rc == 0)
rc = SOCKET_ERROR;
Log(TRACE_MIN, -1, "rc from X509_check_host is %d", rc);
......@@ -693,8 +698,6 @@ int SSLSocket_connect(SSL* ssl, int sock, char* hostname, int verify)
if (cert)
X509_free(cert);
if (addr != hostname)
free(addr);
}
#endif
......
......@@ -37,14 +37,14 @@ void SSLSocket_handleOpensslInit(int bool_value);
int SSLSocket_initialize(void);
void SSLSocket_terminate(void);
int SSLSocket_setSocketForSSL(networkHandles* net, MQTTClient_SSLOptions* opts, char* hostname);
int SSLSocket_setSocketForSSL(networkHandles* net, MQTTClient_SSLOptions* opts, const char* hostname, size_t hostname_len);
int SSLSocket_getch(SSL* ssl, int socket, char* c);
char *SSLSocket_getdata(SSL* ssl, int socket, size_t bytes, size_t* actual_len);
int SSLSocket_close(networkHandles* net);
int SSLSocket_putdatas(SSL* ssl, int socket, char* buf0, size_t buf0len, int count, char** buffers, size_t* buflens, int* frees);
int SSLSocket_connect(SSL* ssl, int sock, char* hostname, int verify);
int SSLSocket_connect(SSL* ssl, int sock, const char* hostname, int verify);
int SSLSocket_getPendingRead(void);
int SSLSocket_continueWrite(pending_writes* pw);
......
......@@ -650,9 +650,10 @@ void Socket_close(int socket)
* @param sock returns the new socket
* @return completion code
*/
int Socket_new(char* addr, int port, int* sock)
int Socket_new(const char* addr, size_t addr_len, int port, int* sock)
{
int type = SOCK_STREAM;
char *addr_mem;
struct sockaddr_in address;
#if defined(AF_INET6)
struct sockaddr_in6 address6;
......@@ -671,9 +672,16 @@ int Socket_new(char* addr, int port, int* sock)
memset(&address6, '\0', sizeof(address6));
if (addr[0] == '[')
++addr;
{
++addr;
--addr_len;
}
addr_mem = malloc( addr_len + 1u );
memcpy( addr_mem, addr, addr_len );
addr_mem[addr_len] = '\0';
if ((rc = getaddrinfo(addr, NULL, &hints, &result)) == 0)
if ((rc = getaddrinfo(addr_mem, NULL, &hints, &result)) == 0)
{
struct addrinfo* res = result;
......@@ -708,10 +716,10 @@ int Socket_new(char* addr, int port, int* sock)
freeaddrinfo(result);
}
else
Log(LOG_ERROR, -1, "getaddrinfo failed for addr %s with rc %d", addr, rc);
Log(LOG_ERROR, -1, "getaddrinfo failed for addr %s with rc %d", addr_mem, rc);
if (rc != 0)
Log(LOG_ERROR, -1, "%s is not a valid IP address", addr);
Log(LOG_ERROR, -1, "%s is not a valid IP address", addr_mem);
else
{
*sock = (int)socket(family, type, 0);
......@@ -771,6 +779,10 @@ int Socket_new(char* addr, int port, int* sock)
}
}
}
if (addr_mem)
free(addr_mem);
FUNC_EXIT_RC(rc);
return rc;
}
......
......@@ -131,7 +131,7 @@ int Socket_getch(int socket, char* c);
char *Socket_getdata(int socket, size_t bytes, size_t* actual_len);
int Socket_putdatas(int socket, char* buf0, size_t buf0len, int count, char** buffers, size_t* buflens, int* frees);
void Socket_close(int socket);
int Socket_new(char* addr, int port, int* socket);
int Socket_new(const char* addr, size_t addr_len, int port, int* socket);
int Socket_noPendingWrites(int socket);
char* Socket_getpeer(int sock);
......
This diff is collapsed.
/*******************************************************************************
* Copyright (c) 2018 Wind River Systems, Inc. All Rights Reserved.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Keith Holman - initial implementation and documentation
*******************************************************************************/
#if !defined(WEBSOCKET_H)
#define WEBSOCKET_H
#include "Clients.h"
/**
* WebSocket op codes
* @{
*/
#define WebSocket_OP_CONTINUE 0x0 /* 0000 - continue frame */
#define WebSocket_OP_TEXT 0x1 /* 0001 - text frame */
#define WebSocket_OP_BINARY 0x2 /* 0010 - binary frame */
#define WebSocket_OP_CLOSE 0x8 /* 1000 - close frame */
#define WebSocket_OP_PING 0x9 /* 1001 - ping frame */
#define WebSocket_OP_PONG 0xA /* 1010 - pong frame */
/** @} */
/**
* Various close status codes
* @{
*/
#define WebSocket_CLOSE_NORMAL 1000
#define WebSocket_CLOSE_GOING_AWAY 1001
#define WebSocket_CLOSE_PROTOCOL_ERROR 1002
#define WebSocket_CLOSE_UNKNOWN_DATA 1003
#define WebSocket_CLOSE_RESERVED 1004
#define WebSocket_CLOSE_NO_STATUS_CODE 1005 /* reserved: not to be used */
#define WebSocket_CLOSE_ABNORMAL 1006 /* reserved: not to be used */
#define WebSocket_CLOSE_BAD_DATA 1007
#define WebSocket_CLOSE_POLICY 1008
#define WebSocket_CLOSE_MSG_TOO_BIG 1009
#define WebSocket_CLOSE_NO_EXTENSION 1010
#define WebScoket_CLOSE_UNEXPECTED 1011
#define WebSocket_CLOSE_TLS_FAIL 1015 /* reserved: not be used */
/** @} */
/* closes a websocket connection */
void WebSocket_close(networkHandles *net, int status_code, const char *reason);
/* sends upgrade request */
int WebSocket_connect(networkHandles *net, const char *uri);
/* calculates the extra data required in a packet to hold a WebSocket frame header */
size_t WebSocket_calculateFrameHeaderSize(networkHandles *net, size_t data_len);
/* obtain data from network socket */
int WebSocket_getch(networkHandles *net, char* c);
char *WebSocket_getdata(networkHandles *net, size_t bytes, size_t* actual_len);
/* send data out, in websocket format only if required */
int WebSocket_putdatas(networkHandles* net, char* buf0, size_t buf0len,
int count, char** buffers, size_t* buflens, int* freeData);
/* releases any resources used by the websocket system */
void WebSocket_terminate(void);
/* handles websocket upgrade request */
int WebSocket_upgrade(networkHandles *net);
#endif /* WEBSOCKET_H */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment