Commit 86fc5768 authored by Joonghwan Lee's avatar Joonghwan Lee Committed by Randeep

[IOT-1548] Fix to transfer a large size of data on CoAPs over TCP

Fixed sending/receiving for large size of data which is bigger than 16kbytes on TLS.

https://jira.iotivity.org/browse/IOT-1548

*Notice : This patchset necessarily requires https://gerrit.iotivity.org/gerrit/#/c/14325/.

Change-Id: I1921d1d2d9d18acb921f093136457120ac862a2c
Signed-off-by: default avatarJoonghwan Lee <jh05.lee@samsung.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/14351Reviewed-by: default avatarUze Choi <uzchoi@samsung.com>
Tested-by: default avatarjenkins-iotivity <jenkins-iotivity@opendaylight.org>
Reviewed-by: default avatarPhil Coval <philippe.coval@osg.samsung.com>
Reviewed-by: Randeep's avatarRandeep Singh <randeep.s@samsung.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/14827
parent 07876e79
......@@ -53,7 +53,9 @@ typedef struct
int fd; /**< file descriptor info */
unsigned char* data; /**< received data from remote device */
size_t len; /**< received data length */
size_t totalLen; /**< total data length required to receive */
size_t totalLen; /**< total coap data length required to receive */
unsigned char tlsdata[18437]; /**< tls data(rfc5246: TLSCiphertext max (2^14+2048+5)) */
size_t tlsLen; /**< received tls data length */
CAProtocol_t protocol; /**< application-level protocol */
} CATCPSessionInfo_t;
......
......@@ -232,6 +232,24 @@ CAResult_t CASearchAndDeleteTCPSession(const CAEndpoint_t *endpoint);
*/
size_t CACheckPayloadLengthFromHeader(const void *data, size_t dlen);
/**
* Construct CoAP header and payload from buffer
*
* @param[in] svritem - used socket, buffer, current received message length and protocol
* @param[in/out] data - data buffer, this value is updated as data is copied to svritem
* @param[in/out] dataLength - length of data, this value decreased as data is copied to svritem
* @return - CA_STATUS_OK or appropriate error code
*/
CAResult_t CAConstructCoAP(CATCPSessionInfo_t *svritem, unsigned char **data,
size_t *dataLength);
/**
* Clean socket state data
*
* @param[in/out] svritem - socket state data
*/
void CACleanData(CATCPSessionInfo_t *svritem);
#ifdef __cplusplus
}
#endif
......
......@@ -38,6 +38,7 @@
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/pkcs12.h"
#include "mbedtls/ssl_internal.h"
#include "mbedtls/net.h"
#ifdef __WITH_DTLS__
#include "mbedtls/timing.h"
#include "mbedtls/ssl_cookie.h"
......@@ -1536,15 +1537,29 @@ CAResult_t CAencryptSsl(const CAEndpoint_t *endpoint,
if (MBEDTLS_SSL_HANDSHAKE_OVER == tep->ssl.state)
{
ret = mbedtls_ssl_write(&tep->ssl, (unsigned char *) data, dataLen);
unsigned char *dataBuf = (unsigned char *)data;
size_t written = 0;
if(ret < 0)
do
{
OIC_LOG_V(ERROR, NET_SSL_TAG, "mbedTLS write returned %d", ret);
RemovePeerFromList(&tep->sep.endpoint);
oc_mutex_unlock(g_sslContextMutex);
return CA_STATUS_FAILED;
}
ret = mbedtls_ssl_write(&tep->ssl, dataBuf, dataLen - written);
if (ret < 0)
{
if (MBEDTLS_ERR_SSL_WANT_WRITE != ret)
{
OIC_LOG_V(ERROR, NET_SSL_TAG, "mbedTLS write failed! returned 0x%x", -ret);
RemovePeerFromList(&tep->sep.endpoint);
oc_mutex_unlock(g_sslContextMutex);
return CA_STATUS_FAILED;
}
continue;
}
OIC_LOG_V(DEBUG, NET_SSL_TAG, "mbedTLS write returned with sent bytes[%d]", ret);
dataBuf += ret;
written += ret;
} while (dataLen > written);
}
else
{
......@@ -1581,16 +1596,27 @@ static void SendCacheMessages(SslEndPoint_t * tep)
SslCacheMessage_t * msg = (SslCacheMessage_t *) u_arraylist_get(tep->cacheList, listIndex);
if (NULL != msg && NULL != msg->data && 0 != msg->len)
{
unsigned char *dataBuf = (unsigned char *)msg->data;
size_t written = 0;
do
{
ret = mbedtls_ssl_write(&tep->ssl, (unsigned char *) msg->data, msg->len);
}
while(MBEDTLS_ERR_SSL_WANT_WRITE == ret);
ret = mbedtls_ssl_write(&tep->ssl, dataBuf, msg->len - written);
if (ret < 0)
{
if (MBEDTLS_ERR_SSL_WANT_WRITE != ret)
{
OIC_LOG_V(ERROR, NET_SSL_TAG, "mbedTLS write failed! returned -0x%x", -ret);
break;
}
continue;
}
OIC_LOG_V(DEBUG, NET_SSL_TAG, "mbedTLS write returned with sent bytes[%d]", ret);
dataBuf += ret;
written += ret;
} while (msg->len > written);
if(ret < 0)
{
OIC_LOG_V(ERROR, NET_SSL_TAG,"mbedTLS write returned %d", ret );
}
if (u_arraylist_remove(tep->cacheList, listIndex))
{
DeleteCacheMessage(msg);
......@@ -1725,6 +1751,7 @@ CAResult_t CAdecryptSsl(const CASecureEndpoint_t *sep, uint8_t *data, uint32_t d
if (NULL != uuidPos)
{
memcpy(uuid, (char*) uuidPos + sizeof(UUID_PREFIX) - 1, UUID_LENGTH * 2 + 4);
OIC_LOG_V(DEBUG, NET_SSL_TAG, "certificate uuid string: %s" , uuid);
ret = OCConvertStringToUuid(uuid, peer->sep.identity.id);
SSL_CHECK_FAIL(peer, ret, "Failed to convert subject", 1,
CA_STATUS_FAILED, MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT);
......
......@@ -163,10 +163,55 @@ void CATCPPacketReceivedCB(const CASecureEndpoint_t *sep, const void *data,
OIC_LOG_V(DEBUG, TAG, "Address: %s, port:%d", sep->endpoint.addr, sep->endpoint.port);
#ifdef SINGLE_THREAD
if (g_networkPacketCallback)
{
g_networkPacketCallback(sep, data, dataLength);
}
#else
unsigned char *buffer = (unsigned char*)data;
size_t bufferLen = dataLength;
size_t index = 0;
//get remote device information from file descriptor.
CATCPSessionInfo_t *svritem = CAGetTCPSessionInfoFromEndpoint(&sep->endpoint, &index);
if (!svritem)
{
OIC_LOG(ERROR, TAG, "there is no connection information in list");
return;
}
if (UNKNOWN == svritem->protocol)
{
OIC_LOG(ERROR, TAG, "invalid protocol type");
return;
}
//totalLen filled only when header fully read and parsed
while (0 != bufferLen)
{
CAResult_t res = CAConstructCoAP(svritem, &buffer, &bufferLen);
if (CA_STATUS_OK != res)
{
OIC_LOG_V(ERROR, TAG, "CAConstructCoAP return error : %d", res);
return;
}
//when successfully read all required data - pass them to upper layer.
if (svritem->len == svritem->totalLen)
{
if (g_networkPacketCallback)
{
g_networkPacketCallback(sep, svritem->data, svritem->totalLen);
}
CACleanData(svritem);
}
else
{
OIC_LOG_V(DEBUG, TAG, "%u bytes required for complete CoAP",
svritem->totalLen - svritem->len);
}
}
#endif
}
#ifdef __WITH_TLS__
......
......@@ -400,18 +400,135 @@ static bool CAIsTlsMessage(const unsigned char* data, size_t length)
*
* @param[in/out] item - socket state data
*/
static void CACleanData(CATCPSessionInfo_t *svritem)
void CACleanData(CATCPSessionInfo_t *svritem)
{
if (svritem)
{
OICFree(svritem->data);
svritem->data = NULL;
svritem->len = 0;
svritem->tlsLen = 0;
svritem->totalLen = 0;
svritem->protocol = UNKNOWN;
}
}
/**
* Construct CoAP header and payload from buffer
*
* @param[in] svritem - used socket, buffer, current received message length and protocol
* @param[in/out] data - data buffer, this value is updated as data is copied to svritem
* @param[in/out] dataLength - length of data, this value decreased as data is copied to svritem
* @return - CA_STATUS_OK or appropriate error code
*/
CAResult_t CAConstructCoAP(CATCPSessionInfo_t *svritem, unsigned char **data,
size_t *dataLength)
{
OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
if (NULL == svritem || NULL == data || NULL == dataLength)
{
OIC_LOG(ERROR, TAG, "Invalid input parameter(NULL)");
return CA_STATUS_INVALID_PARAM;
}
unsigned char *inBuffer = *data;
size_t inLen = *dataLength;
OIC_LOG_V(DEBUG, TAG, "before-datalength : %u", *dataLength);
if (NULL == svritem->data && inLen > 0)
{
// allocate memory for message header (CoAP header size because it is bigger)
svritem->data = (unsigned char *) OICCalloc(1, COAP_MAX_HEADER_SIZE);
if (NULL == svritem->data)
{
OIC_LOG(ERROR, TAG, "OICCalloc - out of memory");
return CA_MEMORY_ALLOC_FAILED;
}
// copy 1 byte to parse coap header length
memcpy(svritem->data, inBuffer, 1);
svritem->len = 1;
inBuffer++;
inLen--;
}
//if not enough data received - read them on next CAFillHeader() call
if (0 == inLen)
{
return CA_STATUS_OK;
}
//if enough data received - parse header
svritem->protocol = COAP;
//seems CoAP data received. read full coap header.
coap_transport_t transport = coap_get_tcp_header_type_from_initbyte(svritem->data[0] >> 4);
size_t headerLen = coap_get_tcp_header_length_for_transport(transport);
size_t copyLen = 0;
// HEADER
if (svritem->len < headerLen)
{
copyLen = headerLen - svritem->len;
if (inLen < copyLen)
{
copyLen = inLen;
}
//read required bytes to have full CoAP header
memcpy(svritem->data + svritem->len, inBuffer, copyLen);
svritem->len += copyLen;
inBuffer += copyLen;
inLen -= copyLen;
//if not enough data received - read them on next CAFillHeader() call
if (svritem->len < headerLen)
{
*data = inBuffer;
*dataLength = inLen;
OIC_LOG(DEBUG, TAG, "CoAP header received partially. Wait for rest header data");
return CA_STATUS_OK;
}
//calculate CoAP message length
svritem->totalLen = CAGetTotalLengthFromHeader(svritem->data);
// allocate required memory
unsigned char *buffer = OICRealloc(svritem->data, svritem->totalLen);
if (NULL == buffer)
{
OIC_LOG(ERROR, TAG, "OICRealloc - out of memory");
return CA_MEMORY_ALLOC_FAILED;
}
svritem->data = buffer;
}
// PAYLOAD
if (inLen > 0)
{
// read required bytes to have full CoAP payload
copyLen = svritem->totalLen - svritem->len;
if (inLen < copyLen)
{
copyLen = inLen;
}
//read required bytes to have full CoAP header
memcpy(svritem->data + svritem->len, inBuffer, copyLen);
svritem->len += copyLen;
inBuffer += copyLen;
inLen -= copyLen;
}
*data = inBuffer;
*dataLength = inLen;
OIC_LOG_V(DEBUG, TAG, "after-datalength : %u", *dataLength);
OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
return CA_STATUS_OK;
}
/**
* Read message header from socket item->fd
*
......@@ -580,20 +697,87 @@ static void CAReceiveMessage(int fd)
return;
}
//totalLen filled only when header fully read and parsed
if (0 == svritem->totalLen)
// read data
int len = 0;
if (svritem->sep.endpoint.flags & CA_SECURE)
{
res = CAReadHeader(svritem);
svritem->protocol = TLS;
#ifdef __WITH_TLS__
size_t nbRead = 0;
size_t tlsLength = 0;
if (TLS_HEADER_SIZE > svritem->tlsLen)
{
nbRead = TLS_HEADER_SIZE - svritem->tlsLen;
}
else
{
//[3][4] bytes in tls header are tls payload length
tlsLength = TLS_HEADER_SIZE +
(size_t)((svritem->tlsdata[3] << 8) | svritem->tlsdata[4]);
OIC_LOG_V(DEBUG, TAG, "toal tls length = %u", tlsLength);
if (tlsLength > sizeof(svritem->tlsdata))
{
OIC_LOG_V(ERROR, TAG, "toal tls length is too big (buffer size : %u)",
sizeof(svritem->tlsdata));
return CA_STATUS_FAILED;
}
nbRead = tlsLength - svritem->tlsLen;
}
len = recv(fd, svritem->tlsdata + svritem->tlsLen, nbRead, 0);
if (len < 0)
{
OIC_LOG_V(ERROR, TAG, "recv failed %s", strerror(errno));
res = CA_RECEIVE_FAILED;
}
else if (0 == len)
{
OIC_LOG(INFO, TAG, "Received disconnect from peer. Close connection");
res = CA_DESTINATION_DISCONNECTED;
}
else
{
svritem->tlsLen += len;
OIC_LOG_V(DEBUG, TAG, "nb_read : %u bytes , recv() : %d bytes, svritem->tlsLen : %u bytes",
nbRead, len, svritem->tlsLen);
if (tlsLength > 0 && tlsLength == svritem->tlsLen)
{
//when successfully read data - pass them to callback.
res = CAdecryptSsl(&svritem->sep, (uint8_t *)svritem->tlsdata, svritem->tlsLen);
svritem->tlsLen = 0;
OIC_LOG_V(DEBUG, TAG, "%s: CAdecryptSsl returned %d", __func__, res);
}
}
#endif
}
else
{
res = CAReadPayload(svritem);
unsigned char buffer[65535] = {0,}; // 65535 is the maximum size of ip packet
svritem->protocol = COAP;
//when successfully read all required data - pass them to upper layer.
if (CA_STATUS_OK == res && svritem->len == svritem->totalLen)
len = recv(fd, buffer, sizeof(buffer), 0);
if (len < 0)
{
CAExecuteRequest(svritem);
CACleanData(svritem);
OIC_LOG_V(ERROR, TAG, "recv failed %s", strerror(errno));
res = CA_RECEIVE_FAILED;
}
else if (0 == len)
{
OIC_LOG(INFO, TAG, "Received disconnect from peer. Close connection");
res = CA_DESTINATION_DISCONNECTED;
}
else
{
OIC_LOG_V(DEBUG, TAG, "recv() : %d bytes", len);
//when successfully read data - pass them to callback.
if (g_packetReceivedCallback)
{
g_packetReceivedCallback(&svritem->sep, buffer, len);
}
}
}
......
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