<commit_before>/******************************************************************
 *
 * Copyright 2014 Samsung Electronics All Rights Reserved.
 *
 *
 *
 * Licensed 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.
 *
 ******************************************************************/

// Defining _BSD_SOURCE or _DEFAULT_SOURCE causes header files to expose
// definitions that may otherwise be skipped. Skipping can cause implicit
// declaration warnings and/or bugs and subtle problems in code execution.
// For glibc information on feature test macros,
// Refer http://www.gnu.org/software/libc/manual/html_node/Feature-Test-Macros.html
//
// For details on compatibility and glibc support,
// Refer http://www.gnu.org/software/libc/manual/html_node/BSD-Random.html
#define _DEFAULT_SOURCE

#include "iotivity_config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#ifdef HAVE_TIME_H
#include <time.h>
#endif

#include "caprotocolmessage.h"
#include "logger.h"
#include "oic_malloc.h"
#include "oic_string.h"
#include "ocrandom.h"
#include "cacommonutil.h"

#define TAG "OIC_CA_PRTCL_MSG"

#define CA_PDU_MIN_SIZE (4)
#define CA_ENCODE_BUFFER_SIZE (4)

static const char COAP_URI_HEADER[] = "coap://[::]/";

static char g_chproxyUri[CA_MAX_URI_LENGTH];

CAResult_t CASetProxyUri(const char *uri)
{
    VERIFY_NON_NULL(uri, TAG, "uri");
    OICStrcpy(g_chproxyUri, sizeof (g_chproxyUri), uri);
    return CA_STATUS_OK;
}

CAResult_t CAGetRequestInfoFromPDU(const coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
                                   CARequestInfo_t *outReqInfo)
{
    VERIFY_NON_NULL(pdu, TAG, "pdu");
    VERIFY_NON_NULL(outReqInfo, TAG, "outReqInfo");

    uint32_t code = CA_NOT_FOUND;
    CAResult_t ret = CAGetInfoFromPDU(pdu, endpoint, &code, &(outReqInfo->info));
    outReqInfo->method = code;

    return ret;
}

CAResult_t CAGetResponseInfoFromPDU(const coap_pdu_t *pdu, CAResponseInfo_t *outResInfo,
                                    const CAEndpoint_t *endpoint)
{
    VERIFY_NON_NULL(pdu, TAG, "pdu");
    VERIFY_NON_NULL(outResInfo, TAG, "outResInfo");

    uint32_t code = CA_NOT_FOUND;
    CAResult_t ret = CAGetInfoFromPDU(pdu, endpoint, &code, &(outResInfo->info));
    outResInfo->result = code;

    return ret;
}

CAResult_t CAGetErrorInfoFromPDU(const coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
                                 CAErrorInfo_t *errorInfo)
{
    VERIFY_NON_NULL(pdu, TAG, "pdu");

    uint32_t code = 0;
    CAResult_t ret = CAGetInfoFromPDU(pdu, endpoint, &code, &errorInfo->info);

    return ret;
}

coap_pdu_t *CAGeneratePDU(uint32_t code, const CAInfo_t *info, const CAEndpoint_t *endpoint,
                          coap_list_t **optlist, coap_transport_t *transport)
{
    VERIFY_NON_NULL_RET(info, TAG, "info", NULL);
    VERIFY_NON_NULL_RET(endpoint, TAG, "endpoint", NULL);
    VERIFY_NON_NULL_RET(optlist, TAG, "optlist", NULL);

    OIC_LOG_V(DEBUG, TAG, "generate pdu for [%d]adapter, [%d]flags",
              endpoint->adapter, endpoint->flags);

    coap_pdu_t *pdu = NULL;

    // RESET have to use only 4byte (empty message)
    // and ACKNOWLEDGE can use empty message when code is empty.
    if (CA_MSG_RESET == info->type || (CA_EMPTY == code && CA_MSG_ACKNOWLEDGE == info->type))
    {
        if (CA_EMPTY != code)
        {
            OIC_LOG(ERROR, TAG, "reset is not empty message");
            return NULL;
        }

        if (info->payloadSize > 0 || info->payload || info->token || info->tokenLength > 0)
        {
            OIC_LOG(ERROR, TAG, "Empty message has unnecessary data after messageID");
            return NULL;
        }

        OIC_LOG(DEBUG, TAG, "code is empty");
        if (!(pdu = CAGeneratePDUImpl((code_t) code, info, endpoint, NULL, transport)))
        {
            OIC_LOG(ERROR, TAG, "pdu NULL");
            return NULL;
        }
    }
    else
    {
        if (info->resourceUri)
        {
            OIC_LOG_V(DEBUG, TAG, "uri : %s", info->resourceUri);

            uint32_t length = strlen(info->resourceUri);
            if (CA_MAX_URI_LENGTH < length)
            {
                OIC_LOG(ERROR, TAG, "URI len err");
                return NULL;
            }

            uint32_t uriLength = length + sizeof(COAP_URI_HEADER);
            char *coapUri = (char *) OICCalloc(1, uriLength);
            if (NULL == coapUri)
            {
                OIC_LOG(ERROR, TAG, "out of memory");
                return NULL;
            }
            OICStrcat(coapUri, uriLength, COAP_URI_HEADER);
            OICStrcat(coapUri, uriLength, info->resourceUri);

            // parsing options in URI
            CAResult_t res = CAParseURI(coapUri, optlist);
            if (CA_STATUS_OK != res)
            {
                OICFree(coapUri);
                return NULL;
            }

            OICFree(coapUri);
        }
        // parsing options in HeadOption
        CAResult_t ret = CAParseHeadOption(code, info, optlist);
        if (CA_STATUS_OK != ret)
        {
            return NULL;
        }

        pdu = CAGeneratePDUImpl((code_t) code, info, endpoint, *optlist, transport);
        if (NULL == pdu)
        {
            OIC_LOG(ERROR, TAG, "pdu NULL");
            return NULL;
        }
    }

    // pdu print method : coap_show_pdu(pdu);
    return pdu;
}

coap_pdu_t *CAParsePDU(const char *data, size_t length, uint32_t *outCode,
                       const CAEndpoint_t *endpoint)
{
    VERIFY_NON_NULL_RET(data, TAG, "data", NULL);
    VERIFY_NON_NULL_RET(endpoint, TAG, "endpoint", NULL);

    coap_transport_t transport = COAP_UDP;
#ifdef WITH_TCP
    if (CAIsSupportedCoAPOverTCP(endpoint->adapter))
    {
        transport = coap_get_tcp_header_type_from_initbyte(((unsigned char *)data)[0] >> 4);
    }
#endif

    coap_pdu_t *outpdu =
        coap_pdu_init2(0, 0, ntohs(COAP_INVALID_TID), length, transport);
    if (NULL == outpdu)
    {
        OIC_LOG(ERROR, TAG, "outpdu is null");
        return NULL;
    }

    OIC_LOG_V(DEBUG, TAG, "pdu parse-transport type : %d", transport);

    int ret = coap_pdu_parse2((unsigned char *) data, length, outpdu, transport);
    OIC_LOG_V(DEBUG, TAG, "pdu parse ret: %d", ret);
    if (0 >= ret)
    {
        OIC_LOG(ERROR, TAG, "pdu parse failed");
        goto exit;
    }

#ifdef WITH_TCP
    if (CAIsSupportedCoAPOverTCP(endpoint->adapter))
    {
        OIC_LOG(INFO, TAG, "there is no version info in coap header");
    }
    else
#endif
    {
        if (outpdu->transport_hdr->udp.version != COAP_DEFAULT_VERSION)
        {
            OIC_LOG_V(ERROR, TAG, "coap version is not available : %d",
                      outpdu->transport_hdr->udp.version);
            goto exit;
        }
        if (outpdu->transport_hdr->udp.token_length > CA_MAX_TOKEN_LEN)
        {
            OIC_LOG_V(ERROR, TAG, "token length has been exceed : %d",
                      outpdu->transport_hdr->udp.token_length);
            goto exit;
        }
    }

    if (outCode)
    {
        (*outCode) = (uint32_t) CA_RESPONSE_CODE(coap_get_code(outpdu, transport));
    }

    return outpdu;

exit:
    coap_delete_pdu(outpdu);
    return NULL;
}

coap_pdu_t *CAGeneratePDUImpl(code_t code, const CAInfo_t *info,
                              const CAEndpoint_t *endpoint, coap_list_t *options,
                              coap_transport_t *transport)
{
    VERIFY_NON_NULL_RET(info, TAG, "info", NULL);
    VERIFY_NON_NULL_RET(endpoint, TAG, "endpoint", NULL);
    VERIFY_NON_NULL_RET(transport, TAG, "transport", NULL);

    unsigned int length = COAP_MAX_PDU_SIZE;
#ifdef WITH_TCP
    unsigned int msgLength = 0;
    if (CAIsSupportedCoAPOverTCP(endpoint->adapter))
    {
        if (options)
        {
            unsigned short prevOptNumber = 0;
            for (coap_list_t *opt = options; opt; opt = opt->next)
            {
                unsigned short curOptNumber = COAP_OPTION_KEY(*(coap_option *) opt->data);
                if (prevOptNumber > curOptNumber)
                {
                    OIC_LOG(ERROR, TAG, "option list is wrong");
                    return NULL;
                }

                size_t optValueLen = COAP_OPTION_LENGTH(*(coap_option *) opt->data);
                size_t optLength = coap_get_opt_header_length(curOptNumber - prevOptNumber, optValueLen);
                if (0 == optLength)
                {
                    OIC_LOG(ERROR, TAG, "Reserved for the Payload marker for the option");
                    return NULL;
                }
                msgLength += optLength;
                prevOptNumber = curOptNumber;
                OIC_LOG_V(DEBUG, TAG, "curOptNumber[%d], prevOptNumber[%d], optValueLen[%zu], "
                        "optLength[%zu], msgLength[%d]",
                          curOptNumber, prevOptNumber, optValueLen, optLength, msgLength);
            }
        }

        if (info->payloadSize > 0)
        {
            msgLength = msgLength + info->payloadSize + PAYLOAD_MARKER;
        }
        *transport = coap_get_tcp_header_type_from_size(msgLength);
        length = msgLength + coap_get_tcp_header_length_for_transport(*transport)
                + info->tokenLength;
    }
    else
#endif
    {
        *transport = COAP_UDP;
    }

    coap_pdu_t *pdu = coap_new_pdu2(*transport, length);

    if (NULL == pdu)
    {
        OIC_LOG(ERROR, TAG, "malloc failed");
        return NULL;
    }

    OIC_LOG_V(DEBUG, TAG, "transport type: %d, payload size: %zu",
              *transport, info->payloadSize);

#ifdef WITH_TCP
    if (CAIsSupportedCoAPOverTCP(endpoint->adapter))
    {
        coap_add_length(pdu, *transport, msgLength);
    }
    else
#endif
    {
        OIC_LOG_V(DEBUG, TAG, "msgID is %d", info->messageId);
        uint16_t message_id = 0;
        if (0 == info->messageId)
        {
            /* initialize message id */
            prng((uint8_t * ) &message_id, sizeof(message_id));

            OIC_LOG_V(DEBUG, TAG, "gen msg id=%d", message_id);
        }
        else
        {
            /* use saved message id */
            message_id = info->messageId;
        }
        pdu->transport_hdr->udp.id = message_id;
        OIC_LOG_V(DEBUG, TAG, "messageId in pdu is %d, %d", message_id, pdu->transport_hdr->udp.id);

        pdu->transport_hdr->udp.type = info->type;
    }

    coap_add_code(pdu, *transport, code);

    if (info->token && CA_EMPTY != code)
    {
        uint32_t tokenLength = info->tokenLength;
        OIC_LOG_V(DEBUG, TAG, "token info token length: %d, token :", tokenLength);
        OIC_LOG_BUFFER(DEBUG, TAG, (const uint8_t *)info->token, tokenLength);

        int32_t ret = coap_add_token2(pdu, tokenLength, (unsigned char *)info->token, *transport);
        if (0 == ret)
        {
            OIC_LOG(ERROR, TAG, "can't add token");
        }
    }

#ifdef WITH_BWT
    if (CA_ADAPTER_GATT_BTLE != endpoint->adapter
#ifdef WITH_TCP
            && !CAIsSupportedCoAPOverTCP(endpoint->adapter)
#endif
            )
    {
        // option list will be added in blockwise-transfer
        return pdu;
    }
#endif

    if (options)
    {
        for (coap_list_t *opt = options; opt; opt = opt->next)
        {
            OIC_LOG_V(DEBUG, TAG, "[%s] opt will be added.",
                      COAP_OPTION_DATA(*(coap_option *) opt->data));

            OIC_LOG_V(DEBUG, TAG, "[%d] pdu length", pdu->length);
            coap_add_option2(pdu, COAP_OPTION_KEY(*(coap_option *) opt->data),
                             COAP_OPTION_LENGTH(*(coap_option *) opt->data),
                             COAP_OPTION_DATA(*(coap_option *) opt->data), *transport);
        }<commit_msg>added fail case for coap_add_option2<commit_after>/******************************************************************
 *
 * Copyright 2014 Samsung Electronics All Rights Reserved.
 *
 *
 *
 * Licensed 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.
 *
 ******************************************************************/

// Defining _BSD_SOURCE or _DEFAULT_SOURCE causes header files to expose
// definitions that may otherwise be skipped. Skipping can cause implicit
// declaration warnings and/or bugs and subtle problems in code execution.
// For glibc information on feature test macros,
// Refer http://www.gnu.org/software/libc/manual/html_node/Feature-Test-Macros.html
//
// For details on compatibility and glibc support,
// Refer http://www.gnu.org/software/libc/manual/html_node/BSD-Random.html
#define _DEFAULT_SOURCE

#include "iotivity_config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#ifdef HAVE_TIME_H
#include <time.h>
#endif

#include "caprotocolmessage.h"
#include "logger.h"
#include "oic_malloc.h"
#include "oic_string.h"
#include "ocrandom.h"
#include "cacommonutil.h"

#define TAG "OIC_CA_PRTCL_MSG"

#define CA_PDU_MIN_SIZE (4)
#define CA_ENCODE_BUFFER_SIZE (4)

static const char COAP_URI_HEADER[] = "coap://[::]/";

static char g_chproxyUri[CA_MAX_URI_LENGTH];

CAResult_t CASetProxyUri(const char *uri)
{
    VERIFY_NON_NULL(uri, TAG, "uri");
    OICStrcpy(g_chproxyUri, sizeof (g_chproxyUri), uri);
    return CA_STATUS_OK;
}

CAResult_t CAGetRequestInfoFromPDU(const coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
                                   CARequestInfo_t *outReqInfo)
{
    VERIFY_NON_NULL(pdu, TAG, "pdu");
    VERIFY_NON_NULL(outReqInfo, TAG, "outReqInfo");

    uint32_t code = CA_NOT_FOUND;
    CAResult_t ret = CAGetInfoFromPDU(pdu, endpoint, &code, &(outReqInfo->info));
    outReqInfo->method = code;

    return ret;
}

CAResult_t CAGetResponseInfoFromPDU(const coap_pdu_t *pdu, CAResponseInfo_t *outResInfo,
                                    const CAEndpoint_t *endpoint)
{
    VERIFY_NON_NULL(pdu, TAG, "pdu");
    VERIFY_NON_NULL(outResInfo, TAG, "outResInfo");

    uint32_t code = CA_NOT_FOUND;
    CAResult_t ret = CAGetInfoFromPDU(pdu, endpoint, &code, &(outResInfo->info));
    outResInfo->result = code;

    return ret;
}

CAResult_t CAGetErrorInfoFromPDU(const coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
                                 CAErrorInfo_t *errorInfo)
{
    VERIFY_NON_NULL(pdu, TAG, "pdu");

    uint32_t code = 0;
    CAResult_t ret = CAGetInfoFromPDU(pdu, endpoint, &code, &errorInfo->info);

    return ret;
}

coap_pdu_t *CAGeneratePDU(uint32_t code, const CAInfo_t *info, const CAEndpoint_t *endpoint,
                          coap_list_t **optlist, coap_transport_t *transport)
{
    VERIFY_NON_NULL_RET(info, TAG, "info", NULL);
    VERIFY_NON_NULL_RET(endpoint, TAG, "endpoint", NULL);
    VERIFY_NON_NULL_RET(optlist, TAG, "optlist", NULL);

    OIC_LOG_V(DEBUG, TAG, "generate pdu for [%d]adapter, [%d]flags",
              endpoint->adapter, endpoint->flags);

    coap_pdu_t *pdu = NULL;

    // RESET have to use only 4byte (empty message)
    // and ACKNOWLEDGE can use empty message when code is empty.
    if (CA_MSG_RESET == info->type || (CA_EMPTY == code && CA_MSG_ACKNOWLEDGE == info->type))
    {
        if (CA_EMPTY != code)
        {
            OIC_LOG(ERROR, TAG, "reset is not empty message");
            return NULL;
        }

        if (info->payloadSize > 0 || info->payload || info->token || info->tokenLength > 0)
        {
            OIC_LOG(ERROR, TAG, "Empty message has unnecessary data after messageID");
            return NULL;
        }

        OIC_LOG(DEBUG, TAG, "code is empty");
        if (!(pdu = CAGeneratePDUImpl((code_t) code, info, endpoint, NULL, transport)))
        {
            OIC_LOG(ERROR, TAG, "pdu NULL");
            return NULL;
        }
    }
    else
    {
        if (info->resourceUri)
        {
            OIC_LOG_V(DEBUG, TAG, "uri : %s", info->resourceUri);

            uint32_t length = strlen(info->resourceUri);
            if (CA_MAX_URI_LENGTH < length)
            {
                OIC_LOG(ERROR, TAG, "URI len err");
                return NULL;
            }

            uint32_t uriLength = length + sizeof(COAP_URI_HEADER);
            char *coapUri = (char *) OICCalloc(1, uriLength);
            if (NULL == coapUri)
            {
                OIC_LOG(ERROR, TAG, "out of memory");
                return NULL;
            }
            OICStrcat(coapUri, uriLength, COAP_URI_HEADER);
            OICStrcat(coapUri, uriLength, info->resourceUri);

            // parsing options in URI
            CAResult_t res = CAParseURI(coapUri, optlist);
            if (CA_STATUS_OK != res)
            {
                OICFree(coapUri);
                return NULL;
            }

            OICFree(coapUri);
        }
        // parsing options in HeadOption
        CAResult_t ret = CAParseHeadOption(code, info, optlist);
        if (CA_STATUS_OK != ret)
        {
            return NULL;
        }

        pdu = CAGeneratePDUImpl((code_t) code, info, endpoint, *optlist, transport);
        if (NULL == pdu)
        {
            OIC_LOG(ERROR, TAG, "pdu NULL");
            return NULL;
        }
    }

    // pdu print method : coap_show_pdu(pdu);
    return pdu;
}

coap_pdu_t *CAParsePDU(const char *data, size_t length, uint32_t *outCode,
                       const CAEndpoint_t *endpoint)
{
    VERIFY_NON_NULL_RET(data, TAG, "data", NULL);
    VERIFY_NON_NULL_RET(endpoint, TAG, "endpoint", NULL);

    coap_transport_t transport = COAP_UDP;
#ifdef WITH_TCP
    if (CAIsSupportedCoAPOverTCP(endpoint->adapter))
    {
        transport = coap_get_tcp_header_type_from_initbyte(((unsigned char *)data)[0] >> 4);
    }
#endif

    coap_pdu_t *outpdu =
        coap_pdu_init2(0, 0, ntohs(COAP_INVALID_TID), length, transport);
    if (NULL == outpdu)
    {
        OIC_LOG(ERROR, TAG, "outpdu is null");
        return NULL;
    }

    OIC_LOG_V(DEBUG, TAG, "pdu parse-transport type : %d", transport);

    int ret = coap_pdu_parse2((unsigned char *) data, length, outpdu, transport);
    OIC_LOG_V(DEBUG, TAG, "pdu parse ret: %d", ret);
    if (0 >= ret)
    {
        OIC_LOG(ERROR, TAG, "pdu parse failed");
        goto exit;
    }

#ifdef WITH_TCP
    if (CAIsSupportedCoAPOverTCP(endpoint->adapter))
    {
        OIC_LOG(INFO, TAG, "there is no version info in coap header");
    }
    else
#endif
    {
        if (outpdu->transport_hdr->udp.version != COAP_DEFAULT_VERSION)
        {
            OIC_LOG_V(ERROR, TAG, "coap version is not available : %d",
                      outpdu->transport_hdr->udp.version);
            goto exit;
        }
        if (outpdu->transport_hdr->udp.token_length > CA_MAX_TOKEN_LEN)
        {
            OIC_LOG_V(ERROR, TAG, "token length has been exceed : %d",
                      outpdu->transport_hdr->udp.token_length);
            goto exit;
        }
    }

    if (outCode)
    {
        (*outCode) = (uint32_t) CA_RESPONSE_CODE(coap_get_code(outpdu, transport));
    }

    return outpdu;

exit:
    coap_delete_pdu(outpdu);
    return NULL;
}

coap_pdu_t *CAGeneratePDUImpl(code_t code, const CAInfo_t *info,
                              const CAEndpoint_t *endpoint, coap_list_t *options,
                              coap_transport_t *transport)
{
    VERIFY_NON_NULL_RET(info, TAG, "info", NULL);
    VERIFY_NON_NULL_RET(endpoint, TAG, "endpoint", NULL);
    VERIFY_NON_NULL_RET(transport, TAG, "transport", NULL);

    unsigned int length = COAP_MAX_PDU_SIZE;
#ifdef WITH_TCP
    unsigned int msgLength = 0;
    if (CAIsSupportedCoAPOverTCP(endpoint->adapter))
    {
        if (options)
        {
            unsigned short prevOptNumber = 0;
            for (coap_list_t *opt = options; opt; opt = opt->next)
            {
                unsigned short curOptNumber = COAP_OPTION_KEY(*(coap_option *) opt->data);
                if (prevOptNumber > curOptNumber)
                {
                    OIC_LOG(ERROR, TAG, "option list is wrong");
                    return NULL;
                }

                size_t optValueLen = COAP_OPTION_LENGTH(*(coap_option *) opt->data);
                size_t optLength = coap_get_opt_header_length(curOptNumber - prevOptNumber, optValueLen);
                if (0 == optLength)
                {
                    OIC_LOG(ERROR, TAG, "Reserved for the Payload marker for the option");
                    return NULL;
                }
                msgLength += optLength;
                prevOptNumber = curOptNumber;
                OIC_LOG_V(DEBUG, TAG, "curOptNumber[%d], prevOptNumber[%d], optValueLen[%zu], "
                        "optLength[%zu], msgLength[%d]",
                          curOptNumber, prevOptNumber, optValueLen, optLength, msgLength);
            }
        }

        if (info->payloadSize > 0)
        {
            msgLength = msgLength + info->payloadSize + PAYLOAD_MARKER;
        }
        *transport = coap_get_tcp_header_type_from_size(msgLength);
        length = msgLength + coap_get_tcp_header_length_for_transport(*transport)
                + info->tokenLength;
    }
    else
#endif
    {
        *transport = COAP_UDP;
    }

    coap_pdu_t *pdu = coap_new_pdu2(*transport, length);

    if (NULL == pdu)
    {
        OIC_LOG(ERROR, TAG, "malloc failed");
        return NULL;
    }

    OIC_LOG_V(DEBUG, TAG, "transport type: %d, payload size: %zu",
              *transport, info->payloadSize);

#ifdef WITH_TCP
    if (CAIsSupportedCoAPOverTCP(endpoint->adapter))
    {
        coap_add_length(pdu, *transport, msgLength);
    }
    else
#endif
    {
        OIC_LOG_V(DEBUG, TAG, "msgID is %d", info->messageId);
        uint16_t message_id = 0;
        if (0 == info->messageId)
        {
            /* initialize message id */
            prng((uint8_t * ) &message_id, sizeof(message_id));

            OIC_LOG_V(DEBUG, TAG, "gen msg id=%d", message_id);
        }
        else
        {
            /* use saved message id */
            message_id = info->messageId;
        }
        pdu->transport_hdr->udp.id = message_id;
        OIC_LOG_V(DEBUG, TAG, "messageId in pdu is %d, %d", message_id, pdu->transport_hdr->udp.id);

        pdu->transport_hdr->udp.type = info->type;
    }

    coap_add_code(pdu, *transport, code);

    if (info->token && CA_EMPTY != code)
    {
        uint32_t tokenLength = info->tokenLength;
        OIC_LOG_V(DEBUG, TAG, "token info token length: %d, token :", tokenLength);
        OIC_LOG_BUFFER(DEBUG, TAG, (const uint8_t *)info->token, tokenLength);

        int32_t ret = coap_add_token2(pdu, tokenLength, (unsigned char *)info->token, *transport);
        if (0 == ret)
        {
            OIC_LOG(ERROR, TAG, "can't add token");
        }
    }

#ifdef WITH_BWT
    if (CA_ADAPTER_GATT_BTLE != endpoint->adapter
#ifdef WITH_TCP
            && !CAIsSupportedCoAPOverTCP(endpoint->adapter)
#endif
            )
    {
        // option list will be added in blockwise-transfer
        return pdu;
    }
#endif

    if (options)
    {
        for (coap_list_t *opt = options; opt; opt = opt->next)
        {
            OIC_LOG_V(DEBUG, TAG, "[%s] opt will be added.",
                      COAP_OPTION_DATA(*(coap_option *) opt->data));

            OIC_LOG_V(DEBUG, TAG, "[%d] pdu length", pdu->length);
            if (0 == coap_add_option2(pdu, COAP_OPTION_KEY(*(coap_option *) opt->data),
                                      COAP_OPTION_LENGTH(*(coap_option *) opt->data),
                                      COAP_OPTION_DATA(*(coap_option *) opt->data), *transport))
            {
                OIC_LOG(ERROR, TAG, "coap_add_option2 has failed");
                coap_delete_pdu(pdu);
                return NULL;
            }
        }
{'fraction_non_alphanumeric': 0.12019720490567576, 'fraction_numerical': 0.004685653750560241, 'mean_word_length': 2.2998117773595053, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 145, 'https://': 0, 'lorem ipsum': 0, 'www.': 6, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2489168', 'n_tokens_mistral': 8231, 'n_tokens_neox': 7905, 'n_words': 1830}