text: /*
   * Copyright (c) 2014-2016 Alibaba Group. All rights reserved.
   * License-Identifier: Apache-2.0
   *
   * 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.
   *
   */
  
  
  #include <stdint.h>
  #include <stdio.h>
  #include <string.h>
  #include <errno.h>
  
  #include "iot_import.h"
  #include "CoAPExport.h"
  #include "iot_import_coap.h"
  #include "iot_import_dtls.h"
  #include "CoAPNetwork.h"
  
  #ifdef COAP_DTLS_SUPPORT
  static void CoAPNetworkDTLS_freeSession(void *p_session);
  
  unsigned int CoAPNetworkDTLS_read(void *p_session,
                                    unsigned char              *p_data,
                                    unsigned int               *p_datalen,
                                    unsigned int                timeout)
  {
      unsigned int           err_code  = DTLS_SUCCESS;
      const unsigned int     read_len  = *p_datalen;
      DTLSContext           *context   = NULL;
  
      COAP_TRC("<< secure_datagram_read, read buffer len %d, timeout %d", read_len, timeout);
      if (NULL != p_session) {
          /* read dtls application data*/
          context = (DTLSContext *)p_session;
          err_code = HAL_DTLSSession_read(context, p_data, p_datalen, timeout);
          if (DTLS_PEER_CLOSE_NOTIFY == err_code
              || DTLS_FATAL_ALERT_MESSAGE  == err_code) {
              COAP_INFO("dtls session read failed return (0x%04x)", err_code);
              CoAPNetworkDTLS_freeSession(context);
          }
          if (DTLS_SUCCESS == err_code) {
              return COAP_SUCCESS;
          } else {
              return COAP_ERROR_READ_FAILED;
          }
      }
  
      return COAP_ERROR_INVALID_PARAM;
  }
  
  unsigned int CoAPNetworkDTLS_write(void *p_session,
                                     const unsigned char        *p_data,
                                     unsigned int               *p_datalen)
  {
      unsigned int err_code = DTLS_SUCCESS;
      if (NULL != p_session) {
          err_code =  HAL_DTLSSession_write((DTLSContext *)p_session, p_data, p_datalen);
          if (DTLS_SUCCESS == err_code) {
              return COAP_SUCCESS;
          } else {
              return COAP_ERROR_WRITE_FAILED;
          }
      }
      return COAP_ERROR_INVALID_PARAM;
  }
  
  static  void CoAPNetworkDTLS_freeSession(void *p_session)
  {
      /* Free the session.*/
      HAL_DTLSSession_free((DTLSContext *)p_session);
  }
  
  void *CoAPNetworkDTLS_createSession(char *p_host,
                                      unsigned short         port,
                                      unsigned char         *p_ca_cert_pem)
  {
      DTLSContext *context = NULL;
      coap_dtls_options_t dtls_options;
  
      memset(&dtls_options, 0x00, sizeof(coap_dtls_options_t));
      dtls_options.p_ca_cert_pem     = p_ca_cert_pem;
      dtls_options.p_host            = p_host;
      dtls_options.port              = port;
  
      context = HAL_DTLSSession_create(&dtls_options);
      return (void *)context;
  }
  
  #endif
  
  unsigned int CoAPNetwork_write(coap_network_t *p_network,
                                 const unsigned char   *p_data,
                                 unsigned int           datalen)
  {
      int rc = COAP_ERROR_WRITE_FAILED;
  
  #ifdef COAP_DTLS_SUPPORT
      if (COAP_ENDPOINT_DTLS == p_network->ep_type) {
          rc = CoAPNetworkDTLS_write(p_network->context, p_data, &datalen);
      } else {
  #endif
          rc = HAL_UDP_write((void *)p_network->context, p_data, datalen);
          COAP_DEBUG("[CoAP-NWK]: Network write return %d", rc);
  
          if (-1 == rc) {
              rc = COAP_ERROR_WRITE_FAILED;
          } else {
              rc = COAP_SUCCESS;
          }
  #ifdef COAP_DTLS_SUPPORT
      }
  #endif
      return (unsigned int)rc;
  }
  
  int CoAPNetwork_read(coap_network_t *network, unsigned char  *data,
                       unsigned int datalen, unsigned int timeout)
  {
      unsigned int len = 0;
  
  #ifdef COAP_DTLS_SUPPORT
      if (COAP_ENDPOINT_DTLS == network->ep_type)  {
          len = datalen;
          memset(data, 0x00, datalen);
          CoAPNetworkDTLS_read(network->context, data, &len, timeout);
      } else {
  #endif
          memset(data, 0x00, datalen);
          len = HAL_UDP_readTimeout((void *)network->context,
                                    data, COAP_MSG_MAX_PDU_LEN, timeout);
  #ifdef COAP_DTLS_SUPPORT
      }
  #endif
      COAP_TRC("<< CoAP recv %d bytes data", len);
      return len;
  }
  
  unsigned int CoAPNetwork_init(const coap_network_init_t *p_param, coap_network_t *p_network)
  {
      unsigned int    err_code = COAP_SUCCESS;
  
      if (NULL == p_param || NULL == p_network) {
          return COAP_ERROR_INVALID_PARAM;
      }
  
      /* TODO : Parse the url here */
      p_network->ep_type = p_param->ep_type;
  
  #ifdef COAP_DTLS_SUPPORT
      if (COAP_ENDPOINT_DTLS == p_param->ep_type) {
          p_network->context = CoAPNetworkDTLS_createSession(p_param->p_host,
                               p_param->port, p_param->p_ca_cert_pem);
          if (NULL == p_network->context) {
              return COAP_ERROR_NET_INIT_FAILED;
          }
      }
  #endif
      if (COAP_ENDPOINT_NOSEC == p_param->ep_type) {
          /*Create udp socket*/
          p_network->context = HAL_UDP_create(p_param->p_host, p_param->port);
          if ((void *) - 1 == p_network->context) {
              return COAP_ERROR_NET_INIT_FAILED;
          }
      }
      return err_code;
  }
  
  
  unsigned int CoAPNetwork_deinit(coap_network_t *p_network)
  {
      unsigned int    err_code = COAP_SUCCESS;
  
  #ifdef COAP_DTLS_SUPPORT
      if (COAP_ENDPOINT_DTLS == p_network->ep_type) {
          CoAPNetworkDTLS_freeSession(p_network->context);
          p_network->context = NULL;
      }
  #endif
      if (COAP_ENDPOINT_NOSEC == p_network->ep_type) {
          HAL_UDP_close(p_network->context);
      }
  
      return err_code;
  }
  
  