/*----------------------------------------------------------------------------*/
static
int
coap_receive(void)
{
    coap_error_code = NO_ERROR;

    PRINTF("handle_incoming_data(): received uip_datalen=%u \n",(uint16_t)uip_datalen());

    /* Static declaration reduces stack peaks and program code size. */
    static coap_packet_t message[1]; /* This way the packet can be treated as pointer as usual. */
    static coap_packet_t response[1];
    static coap_transaction_t *transaction = NULL;

    if (uip_newdata()) {

        PRINTF("receiving UDP datagram from: ");
        PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
        PRINTF(":%u\n  Length: %u\n  Data: ", uip_ntohs(UIP_UDP_BUF->srcport), uip_datalen() );
        PRINTBITS(uip_appdata, uip_datalen());
        PRINTF("\n");

        coap_error_code = coap_parse_message(message, uip_appdata, uip_datalen());

        if (coap_error_code==NO_ERROR)
        {

            /*TODO duplicates suppression, if required by application */

            PRINTF("  Parsed: v %u, t %u, oc %u, c %u, mid %u\n", message->version, message->type, message->option_count, message->code, message->mid);
            PRINTF("  URL: %.*s\n", message->uri_path_len, message->uri_path);
            PRINTF("  Payload: %.*s\n", message->payload_len, message->payload);

            /* Handle requests. */
            if (message->code >= COAP_GET && message->code <= COAP_DELETE)
            {
                /* Use transaction buffer for response to confirmable request. */
                if ( (transaction = coap_new_transaction(message->mid, &UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport)) )
                {
                    uint32_t block_num = 0;
                    uint16_t block_size = REST_MAX_CHUNK_SIZE;
                    uint32_t block_offset = 0;
                    int32_t new_offset = 0;

                    /* prepare response */
                    if (message->type==COAP_TYPE_CON)
                    {
                        /* Reliable CON requests are answered with an ACK. */
                        coap_init_message(response, COAP_TYPE_ACK, CONTENT_2_05, message->mid);
                    }
                    else
                    {
                        /* Unreliable NON requests are answered with a NON as well. */
                        coap_init_message(response, COAP_TYPE_NON, CONTENT_2_05, coap_get_mid());
                    }

                    /* resource handlers must take care of different handling (e.g., TOKEN_OPTION_REQUIRED_240) */
                    if (IS_OPTION(message, COAP_OPTION_TOKEN))
                    {
                        coap_set_header_token(response, message->token, message->token_len);
                        SET_OPTION(response, COAP_OPTION_TOKEN);
                    }

                    /* get offset for blockwise transfers */
                    if (coap_get_header_block2(message, &block_num, NULL, &block_size, &block_offset))
                    {
                        PRINTF("Blockwise: block request %lu (%u/%u) @ %lu bytes\n", block_num, block_size, REST_MAX_CHUNK_SIZE, block_offset);
                        block_size = MIN(block_size, REST_MAX_CHUNK_SIZE);
                        new_offset = block_offset;
                    }

                    /* Invoke resource handler. */
                    if (service_cbk)
                    {
                        /* Call REST framework and check if found and allowed. */
                        if (service_cbk(message, response, transaction->packet+COAP_MAX_HEADER_SIZE, block_size, &new_offset))
                        {
                            if (coap_error_code==NO_ERROR)
                            {
                                /* Apply blockwise transfers. */
                                if ( IS_OPTION(message, COAP_OPTION_BLOCK1) && response->code<BAD_REQUEST_4_00 && !IS_OPTION(response, COAP_OPTION_BLOCK1) )
                                {
                                    PRINTF("Block1 NOT IMPLEMENTED\n");

                                    coap_error_code = NOT_IMPLEMENTED_5_01;
                                    coap_error_message = "NoBlock1Support";
                                }
                                else if ( IS_OPTION(message, COAP_OPTION_BLOCK2) )
                                {
                                    /* unchanged new_offset indicates that resource is unaware of blockwise transfer */
                                    if (new_offset==block_offset)
                                    {
                                        PRINTF("Blockwise: unaware resource with payload length %u/%u\n", response->payload_len, block_size);
                                        if (block_offset >= response->payload_len)
                                        {
                                            PRINTF("handle_incoming_data(): block_offset >= response->payload_len\n");

                                            response->code = BAD_OPTION_4_02;
                                            coap_set_payload(response, "BlockOutOfScope", 15); /* a const char str[] and sizeof(str) produces larger code size */
                                        }
                                        else
                                        {
                                            coap_set_header_block2(response, block_num, response->payload_len - block_offset > block_size, block_size);
                                            coap_set_payload(response, response->payload+block_offset, MIN(response->payload_len - block_offset, block_size));
                                        } /* if (valid offset) */
                                    }
                                    else
                                    {
                                        /* resource provides chunk-wise data */
                                        PRINTF("Blockwise: blockwise resource, new offset %ld\n", new_offset);
                                        coap_set_header_block2(response, block_num, new_offset!=-1 || response->payload_len > block_size, block_size);
                                        if (response->payload_len > block_size) coap_set_payload(response, response->payload, block_size);
                                    } /* if (resource aware of blockwise) */
                                }
                                else if (new_offset!=0)
                                {
                                    PRINTF("Blockwise: no block option for blockwise resource, using block size %u\n", REST_MAX_CHUNK_SIZE);

                                    coap_set_header_block2(response, 0, new_offset!=-1, REST_MAX_CHUNK_SIZE);
                                    coap_set_payload(response, response->payload, MIN(response->payload_len, REST_MAX_CHUNK_SIZE));
                                } /* if (blockwise request) */
                            } /* no errors/hooks */
                        } /* successful service callback */

                        /* Serialize response. */
                        if (coap_error_code==NO_ERROR)
                        {
                            if ((transaction->packet_len = coap_serialize_message(response, transaction->packet))==0)
                            {
                                coap_error_code = PACKET_SERIALIZATION_ERROR;
                            }
                        }

                    }
                    else
                    {
                        coap_error_code = NOT_IMPLEMENTED_5_01;
                        coap_error_message = "NoServiceCallbck"; // no a to fit 16 bytes
                    } /* if (service callback) */

                } else {
                    coap_error_code = SERVICE_UNAVAILABLE_5_03;
                    coap_error_message = "NoFreeTraBuffer";
                } /* if (transaction buffer) */
            }
            else
            {
                /* Responses */

                if (message->type==COAP_TYPE_ACK)
                {
                    PRINTF("Received ACK\n");
                }
                else if (message->type==COAP_TYPE_RST)
                {
                    PRINTF("Received RST\n");
                    /* Cancel possible subscriptions. */
                    coap_remove_observer_by_mid(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, message->mid);
                }

                transaction = coap_get_transaction_by_mid(message->mid);
                if (message->type != COAP_TYPE_CON && transaction)
                {
                    /* Free transaction memory before callback, as it may create a new transaction. */
                    restful_response_handler callback = transaction->callback;
                    void *callback_data = transaction->callback_data;
                    coap_clear_transaction(transaction);

                    /* Check if someone registered for the response */
                    if (callback) {
                        callback(callback_data, message);
                    }
                } /* if (ACKed transaction) */
                /* Observe notification */
                if ((message->type == COAP_TYPE_CON || message->type == COAP_TYPE_NON) \
                        && IS_OPTION(message, COAP_OPTION_OBSERVE)) {
                    PRINTF("Observe [%u]\n", message->observe);
                    coap_handle_notification(&UIP_IP_BUF->srcipaddr,                     \
                                             UIP_UDP_BUF->srcport, message);
                }
                transaction = NULL;

            } /* Request or Response */

        } /* if (parsed correctly) */

        if (coap_error_code==NO_ERROR)
        {
            if (transaction) coap_send_transaction(transaction);
        }
        else if (coap_error_code==MANUAL_RESPONSE)
        {
            PRINTF("Clearing transaction for manual response");
            coap_clear_transaction(transaction);
        }
        else
        {
            PRINTF("ERROR %u: %s\n", coap_error_code, coap_error_message);
            coap_clear_transaction(transaction);

            /* Set to sendable error code. */
            if (coap_error_code >= 192)
            {
                coap_error_code = INTERNAL_SERVER_ERROR_5_00;
            }
            /* Reuse input buffer for error message. */
            coap_init_message(message, COAP_TYPE_ACK, coap_error_code, message->mid);
            coap_set_payload(message, coap_error_message, strlen(coap_error_message));
            coap_send_message(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, uip_appdata, coap_serialize_message(message, uip_appdata));
        }
    } /* if (new data) */

    return coap_error_code;
}
void
mirror_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset)
{
  /* The ETag and Token is copied to the header. */
  uint8_t opaque[] = {0x0A, 0xBC, 0xDE};

  /* Strings are not copied, so use static string buffers or strings in .text memory (char *str = "string in .text";). */
  static char location[] = {'/','f','/','a','?','k','&','e', 0};

  /* Getter for the header option Content-Type. If the option is not set, text/plain is returned by default. */
  unsigned int content_type = REST.get_header_content_type(request);

  /* The other getters copy the value (or string/array pointer) to the given pointers and return 1 for success or the length of strings/arrays. */
  uint32_t max_age_and_size = 0;
  const char *str = NULL;
  uint32_t observe = 0;
  const uint8_t *bytes = NULL;
  uint32_t block_num = 0;
  uint8_t block_more = 0;
  uint16_t block_size = 0;
  const char *query = "";
  int len = 0;

  /* Mirror the received header options in the response payload. Unsupported getters (e.g., rest_get_header_observe() with HTTP) will return 0. */

  int strpos = 0;
  /* snprintf() counts the terminating '\0' to the size parameter.
   * The additional byte is taken care of by allocating REST_MAX_CHUNK_SIZE+1 bytes in the REST framework.
   * Add +1 to fill the complete buffer, as the payload does not need a terminating '\0'. */
  if (content_type!=-1)
  {
    strpos += snprintf((char *)buffer, REST_MAX_CHUNK_SIZE+1, "CT %u\n", content_type);
  }
  
  /* Some getters such as for ETag or Location are omitted, as these options should not appear in a request.
   * Max-Age might appear in HTTP requests or used for special purposes in CoAP. */
  if (strpos<=REST_MAX_CHUNK_SIZE && REST.get_header_max_age(request, &max_age_and_size))
  {
    strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "MA %lu\n", max_age_and_size);
  }
  /* For HTTP this is the Length option, for CoAP it is the Size option. */
  if (strpos<=REST_MAX_CHUNK_SIZE && REST.get_header_length(request, &max_age_and_size))
  {
    strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "SZ %lu\n", max_age_and_size);
  }

  if (strpos<=REST_MAX_CHUNK_SIZE && (len = REST.get_header_host(request, &str)))
  {
    strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "UH %.*s\n", len, str);
  }

/* CoAP-specific example: actions not required for normal RESTful Web service. */
#if WITH_COAP > 1
  if (strpos<=REST_MAX_CHUNK_SIZE && coap_get_header_observe(request, &observe))
  {
    strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "Ob %lu\n", observe);
  }
  if (strpos<=REST_MAX_CHUNK_SIZE && (len = coap_get_header_token(request, &bytes)))
  {
    strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "To 0x");
    int index = 0;
    for (index = 0; index<len; ++index) {
        strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "%02X", bytes[index]);
    }
    strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "\n");
  }
  if (strpos<=REST_MAX_CHUNK_SIZE && (len = coap_get_header_etag(request, &bytes)))
  {
    strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "ET 0x");
    int index = 0;
    for (index = 0; index<len; ++index) {
        strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "%02X", bytes[index]);
    }
    strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "\n");
  }
  if (strpos<=REST_MAX_CHUNK_SIZE && (len = coap_get_header_uri_path(request, &str)))
  {
    strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "UP ");
    strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "%.*s\n", len, str);
  }
#if WITH_COAP == 3
  if (strpos<=REST_MAX_CHUNK_SIZE && (len = coap_get_header_location(request, &str)))
  {
    strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "Lo %.*s\n", len, str);
  }
  if (strpos<=REST_MAX_CHUNK_SIZE && coap_get_header_block(request, &block_num, &block_more, &block_size, NULL)) /* This getter allows NULL pointers to get only a subset of the block parameters. */
  {
    strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "Bl %lu%s (%u)\n", block_num, block_more ? "+" : "", block_size);
  }
#else
  if (strpos<=REST_MAX_CHUNK_SIZE && (len = coap_get_header_location_path(request, &str)))
  {
    strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "LP %.*s\n", len, str);
  }
  if (strpos<=REST_MAX_CHUNK_SIZE && (len = coap_get_header_location_query(request, &str)))
  {
    strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "LQ %.*s\n", len, str);
  }
  if (strpos<=REST_MAX_CHUNK_SIZE && coap_get_header_block2(request, &block_num, &block_more, &block_size, NULL)) /* This getter allows NULL pointers to get only a subset of the block parameters. */
  {
    strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "B2 %lu%s (%u)\n", block_num, block_more ? "+" : "", block_size);
  }
  /*
   * Critical Block1 option is currently rejected by engine.
   *
  if (strpos<=REST_MAX_CHUNK_SIZE && coap_get_header_block1(request, &block_num, &block_more, &block_size, NULL))
  {
    strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "B1 %lu%s (%u)\n", block_num, block_more ? "+" : "", block_size);
  }
  */
#endif /* CoAP > 03 */
#endif /* CoAP-specific example */

  if (strpos<=REST_MAX_CHUNK_SIZE && (len = REST.get_query(request, &query)))
  {
    strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "Qu %.*s\n", len, query);
  }
  if (strpos<=REST_MAX_CHUNK_SIZE && (len = REST.get_request_payload(request, &bytes)))
  {
    strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "%.*s", len, bytes);
  }

  if (strpos >= REST_MAX_CHUNK_SIZE)
  {
      buffer[REST_MAX_CHUNK_SIZE-1] = 0xBB; /* 'ยป' to indicate truncation */
  }

  REST.set_response_payload(response, buffer, strpos);

  PRINTF("/mirror options received: %s\n", buffer);

  /* Set dummy header options for response. Like getters, some setters are not implemented for HTTP and have no effect. */
  REST.set_header_content_type(response, REST.type.TEXT_PLAIN);
  REST.set_header_max_age(response, 17); /* For HTTP, browsers will not re-request the page for 17 seconds. */
  REST.set_header_etag(response, opaque, 2);
  REST.set_header_location(response, location); /* Initial slash is omitted by framework */
  REST.set_header_length(response, strpos); /* For HTTP, browsers will not re-request the page for 10 seconds. CoAP action depends on the client. */

/* CoAP-specific example: actions not required for normal RESTful Web service. */
#if WITH_COAP > 1
  coap_set_header_uri_host(response, "tiki");
  coap_set_header_observe(response, 10);
#if WITH_COAP == 3
  coap_set_header_block(response, 42, 0, 64); /* The block option might be overwritten by the framework when blockwise transfer is requested. */
#else
  coap_set_header_proxy_uri(response, "ftp://x");
  coap_set_header_block2(response, 42, 0, 64); /* The block option might be overwritten by the framework when blockwise transfer is requested. */
  coap_set_header_block1(response, 23, 0, 16);
  coap_set_header_accept(response, TEXT_PLAIN);
  coap_set_header_if_none_match(response);
#endif /* CoAP > 03 */
#endif /* CoAP-specific example */
}
Example #3
0
/* This function is an adaptation of function coap_receive() from Erbium's er-coap-13-engine.c.
 * Erbium is Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich
 * All rights reserved.
 */
void lwm2m_handle_packet(lwm2m_context_t * contextP,
                        uint8_t * buffer,
                        int length,
                        void * fromSessionH)
{
    coap_status_t coap_error_code = NO_ERROR;
    static coap_packet_t message[1];
    static coap_packet_t response[1];

    coap_error_code = coap_parse_message(message, buffer, (uint16_t)length);
    if (coap_error_code==NO_ERROR)
    {
        LOG("  Parsed: ver %u, type %u, tkl %u, code %u, mid %u\r\n", message->version, message->type, message->token_len, message->code, message->mid);
        LOG("  Payload: %.*s\r\n\n", message->payload_len, message->payload);

        if (message->code >= COAP_GET && message->code <= COAP_DELETE)
        {
            uint32_t block_num = 0;
            uint16_t block_size = REST_MAX_CHUNK_SIZE;
            uint32_t block_offset = 0;
            int32_t new_offset = 0;

            /* prepare response */
            if (message->type==COAP_TYPE_CON)
            {
                /* Reliable CON requests are answered with an ACK. */
                coap_init_message(response, COAP_TYPE_ACK, CONTENT_2_05, message->mid);
            }
            else
            {
                /* Unreliable NON requests are answered with a NON as well. */
                coap_init_message(response, COAP_TYPE_NON, CONTENT_2_05, coap_get_mid());
            }

            /* mirror token */
            if (message->token_len)
            {
                coap_set_header_token(response, message->token, message->token_len);
            }

            /* get offset for blockwise transfers */
            if (coap_get_header_block2(message, &block_num, NULL, &block_size, &block_offset))
            {
                LOG("Blockwise: block request %u (%u/%u) @ %u bytes\n", block_num, block_size, REST_MAX_CHUNK_SIZE, block_offset);
                block_size = MIN(block_size, REST_MAX_CHUNK_SIZE);
                new_offset = block_offset;
            }

            coap_error_code = handle_request(contextP, fromSessionH, message, response);
            if (coap_error_code==NO_ERROR)
            {
                /* Apply blockwise transfers. */
                if ( IS_OPTION(message, COAP_OPTION_BLOCK1) && response->code<BAD_REQUEST_4_00 && !IS_OPTION(response, COAP_OPTION_BLOCK1) )
                {
                    LOG("Block1 NOT IMPLEMENTED\n");

                    coap_error_code = NOT_IMPLEMENTED_5_01;
                    coap_error_message = "NoBlock1Support";
                }
                else if ( IS_OPTION(message, COAP_OPTION_BLOCK2) )
                {
                    /* unchanged new_offset indicates that resource is unaware of blockwise transfer */
                    if (new_offset==block_offset)
                    {
                        LOG("Blockwise: unaware resource with payload length %u/%u\n", response->payload_len, block_size);
                        if (block_offset >= response->payload_len)
                        {
                            LOG("handle_incoming_data(): block_offset >= response->payload_len\n");

                            response->code = BAD_OPTION_4_02;
                            coap_set_payload(response, "BlockOutOfScope", 15); /* a const char str[] and sizeof(str) produces larger code size */
                        }
                        else
                        {
                            coap_set_header_block2(response, block_num, response->payload_len - block_offset > block_size, block_size);
                            coap_set_payload(response, response->payload+block_offset, MIN(response->payload_len - block_offset, block_size));
                        } /* if (valid offset) */
                    }
                    else
                    {
                        /* resource provides chunk-wise data */
                        LOG("Blockwise: blockwise resource, new offset %d\n", new_offset);
                        coap_set_header_block2(response, block_num, new_offset!=-1 || response->payload_len > block_size, block_size);
                        if (response->payload_len > block_size) coap_set_payload(response, response->payload, block_size);
                    } /* if (resource aware of blockwise) */
                }
                else if (new_offset!=0)
                {
                    LOG("Blockwise: no block option for blockwise resource, using block size %u\n", REST_MAX_CHUNK_SIZE);

                    coap_set_header_block2(response, 0, new_offset!=-1, REST_MAX_CHUNK_SIZE);
                    coap_set_payload(response, response->payload, MIN(response->payload_len, REST_MAX_CHUNK_SIZE));
                } /* if (blockwise request) */

                coap_error_code = message_send(contextP, response, fromSessionH);

                lwm2m_free(response->payload);
                response->payload = NULL;
                response->payload_len = 0;
            }
            else
            {
            	coap_error_code = message_send(contextP, response, fromSessionH);
            }
        }
        else
        {
            /* Responses */
            lwm2m_transaction_t * transaction;

            if (message->type==COAP_TYPE_ACK)
            {
                LOG("Received ACK\n");
            }
            else if (message->type==COAP_TYPE_RST)
            {
                LOG("Received RST\n");
                /* Cancel possible subscriptions. */
                handle_reset(contextP, fromSessionH, message);
            }

#ifdef LWM2M_SERVER_MODE
            if (message->code == COAP_204_CHANGED
             && IS_OPTION(message, COAP_OPTION_OBSERVE))
            {
                handle_observe_notify(contextP, fromSessionH, message);
            }
            else
#endif
            {
                transaction_handle_response(contextP, fromSessionH, message);
            }
        } /* Request or Response */

        coap_free_header(message);

    } /* if (parsed correctly) */
    else
    {
        LOG("Message parsing failed %d\r\n", coap_error_code);
    }

    if (coap_error_code != NO_ERROR)
    {
        LOG("ERROR %u: %s\n", coap_error_code, coap_error_message);

        /* Set to sendable error code. */
        if (coap_error_code >= 192)
        {
            coap_error_code = INTERNAL_SERVER_ERROR_5_00;
        }
        /* Reuse input buffer for error message. */
        coap_init_message(message, COAP_TYPE_ACK, coap_error_code, message->mid);
        coap_set_payload(message, coap_error_message, strlen(coap_error_message));
        message_send(contextP, message, fromSessionH);
    }
}
Example #4
0
/*---------------------------------------------------------------------------*/
int
coap_engine_receive(coap_context_t *coap_ctx)
{
  erbium_status_code = NO_ERROR;
  coap_packet_t message[1]; /* this way the packet can be treated as pointer as usual */
  coap_packet_t response[1];
  coap_transaction_t *transaction = NULL;

  PRINTF("%s(): received data len %u\n", __FUNCTION__,
         (uint16_t)uip_appdatalen(coap_ctx->buf));

  if(uip_newdata(coap_ctx->buf)) {

    PRINTF("receiving UDP datagram from: ");
    PRINT6ADDR(&UIP_IP_BUF(coap_ctx->buf)->srcipaddr);
    PRINTF(":%u\n  Length: %u\n",
	   uip_ntohs(UIP_UDP_BUF(coap_ctx->buf)->srcport),
           uip_appdatalen(coap_ctx->buf));

    erbium_status_code =
    coap_parse_message(message, uip_appdata(coap_ctx->buf), uip_appdatalen(coap_ctx->buf));
    coap_set_context(message, coap_ctx);

    if(erbium_status_code == NO_ERROR) {

      NET_COAP_STAT(recv++);

      /*TODO duplicates suppression, if required by application */

      PRINTF("  Parsed: v %u, t %u, tkl %u, c %u, mid %u\n", message->version,
             message->type, message->token_len, message->code, message->mid);
      PRINTF("  URL[%d]: %.*s\n", message->uri_path_len, message->uri_path_len, message->uri_path);
      PRINTF("  Payload[%d]: %.*s\n", message->payload_len, message->payload_len, message->payload);

      /* handle requests */
      if(message->code >= COAP_GET && message->code <= COAP_DELETE) {

        /* use transaction buffer for response to confirmable request */
        if((transaction = coap_new_transaction(message->mid, coap_ctx,
                                               &UIP_IP_BUF(coap_ctx->buf)->srcipaddr,
                                               UIP_UDP_BUF(coap_ctx->buf)->srcport))) {
          uint32_t block_num = 0;
          uint16_t block_size = REST_MAX_CHUNK_SIZE;
          uint32_t block_offset = 0;
          int32_t new_offset = 0;

          /* prepare response */
          if(message->type == COAP_TYPE_CON) {
            /* reliable CON requests are answered with an ACK */
            coap_init_message(response, COAP_TYPE_ACK, CONTENT_2_05,
                              message->mid);
          } else {
            /* unreliable NON requests are answered with a NON as well */
            coap_init_message(response, COAP_TYPE_NON, CONTENT_2_05,
                              coap_get_mid());
            /* mirror token */
          } if(message->token_len) {
            coap_set_token(response, message->token, message->token_len);
            /* get offset for blockwise transfers */
          }
          if(coap_get_header_block2
               (message, &block_num, NULL, &block_size, &block_offset)) {
            PRINTF("Blockwise: block request %lu (%u/%u) @ %lu bytes\n",
                   (unsigned long)block_num, block_size, REST_MAX_CHUNK_SIZE, (unsigned long)block_offset);
            block_size = MIN(block_size, REST_MAX_CHUNK_SIZE);
            new_offset = block_offset;
          }

          /* invoke resource handler */
          if(service_cbk) {

            /* call REST framework and check if found and allowed */
            if(service_cbk
                 (message, response, transaction->packet + COAP_MAX_HEADER_SIZE,
                 block_size, &new_offset)) {

              if(erbium_status_code == NO_ERROR) {

                /* TODO coap_handle_blockwise(request, response, start_offset, end_offset); */

                /* resource is unaware of Block1 */
                if(IS_OPTION(message, COAP_OPTION_BLOCK1)
                   && response->code < BAD_REQUEST_4_00
                   && !IS_OPTION(response, COAP_OPTION_BLOCK1)) {
                  PRINTF("Block1 NOT IMPLEMENTED\n");

                  erbium_status_code = NOT_IMPLEMENTED_5_01;
                  coap_error_message = "NoBlock1Support";

                  /* client requested Block2 transfer */
                } else if(IS_OPTION(message, COAP_OPTION_BLOCK2)) {

                  /* unchanged new_offset indicates that resource is unaware of blockwise transfer */
                  if(new_offset == block_offset) {
                    PRINTF
                      ("Blockwise: unaware resource with payload length %u/%u\n",
                      response->payload_len, block_size);
                    if(block_offset >= response->payload_len) {
                      PRINTF
                        ("handle_incoming_data(): block_offset >= response->payload_len\n");

                      response->code = BAD_OPTION_4_02;
                      coap_set_payload(response, "BlockOutOfScope", 15); /* a const char str[] and sizeof(str) produces larger code size */
                    } else {
                      coap_set_header_block2(response, block_num,
                                             response->payload_len -
                                             block_offset > block_size,
                                             block_size);
                      coap_set_payload(response,
                                       response->payload + block_offset,
                                       MIN(response->payload_len -
                                           block_offset, block_size));
                    } /* if(valid offset) */

                    /* resource provides chunk-wise data */
                  } else {
                    PRINTF("Blockwise: blockwise resource, new offset %ld\n",
                           (long)new_offset);
                    coap_set_header_block2(response, block_num,
                                           new_offset != -1
                                           || response->payload_len >
                                           block_size, block_size);

                    if(response->payload_len > block_size) {
                      coap_set_payload(response, response->payload,
                                       block_size);
                    }
                  } /* if(resource aware of blockwise) */

                  /* Resource requested Block2 transfer */
                } else if(new_offset != 0) {
                  PRINTF
                    ("Blockwise: no block option for blockwise resource, using block size %u\n",
                    COAP_MAX_BLOCK_SIZE);

                  coap_set_header_block2(response, 0, new_offset != -1,
                                         COAP_MAX_BLOCK_SIZE);
                  coap_set_payload(response, response->payload,
                                   MIN(response->payload_len,
                                       COAP_MAX_BLOCK_SIZE));
                } /* blockwise transfer handling */
              } /* no errors/hooks */
                /* successful service callback */
                /* serialize response */
            }
            if(erbium_status_code == NO_ERROR) {
              if((transaction->packet_len = coap_serialize_message(response,
                                                                   transaction->
                                                                   packet)) ==
                 0) {
                erbium_status_code = PACKET_SERIALIZATION_ERROR;
              }
            }
          } else {
            erbium_status_code = NOT_IMPLEMENTED_5_01;
            coap_error_message = "NoServiceCallbck"; /* no 'a' to fit into 16 bytes */
          } /* if(service callback) */
        } else {
          erbium_status_code = SERVICE_UNAVAILABLE_5_03;
          coap_error_message = "NoFreeTraBuffer";
        } /* if(transaction buffer) */

        /* handle responses */
      } else {

        if(message->type == COAP_TYPE_CON && message->code == 0) {
          PRINTF("Received Ping\n");
          erbium_status_code = PING_RESPONSE;
        } else if(message->type == COAP_TYPE_ACK) {
          /* transactions are closed through lookup below */
          PRINTF("Received ACK\n");
        } else if(message->type == COAP_TYPE_RST) {
          PRINTF("Received RST\n");
          /* cancel possible subscriptions */
          coap_remove_observer_by_mid(coap_ctx, &UIP_IP_BUF(coap_ctx->buf)->srcipaddr,
                                      UIP_UDP_BUF(coap_ctx->buf)->srcport, message->mid);
        }

        if((transaction = coap_get_transaction_by_mid(message->mid))) {
          /* free transaction memory before callback, as it may create a new transaction */
          restful_response_handler callback = transaction->callback;
          void *callback_data = transaction->callback_data;

          coap_clear_transaction(transaction);

          /* check if someone registered for the response */
          if(callback) {
            callback(callback_data, message);
          }
        }
        /* if(ACKed transaction) */
        transaction = NULL;

#if COAP_OBSERVE_CLIENT
	/* if observe notification */
        if((message->type == COAP_TYPE_CON || message->type == COAP_TYPE_NON)
              && IS_OPTION(message, COAP_OPTION_OBSERVE)) {
          PRINTF("Observe [%u]\n", message->observe);
          coap_handle_notification(coap_ctx, &UIP_IP_BUF(coap_ctx->buf)->srcipaddr,
                                   UIP_UDP_BUF(coap_ctx->buf)->srcport, message);
        }
#endif /* COAP_OBSERVE_CLIENT */
      } /* request or response */
    } else { /* parsed correctly */
      NET_COAP_STAT(recv_err++);
    }

    /* if(parsed correctly) */
    if(erbium_status_code == NO_ERROR) {
      if(transaction) {
        coap_send_transaction(transaction);
      }
    } else if(erbium_status_code == MANUAL_RESPONSE) {
      PRINTF("Clearing transaction for manual response");
      coap_clear_transaction(transaction);
    } else {
      coap_message_type_t reply_type = COAP_TYPE_ACK;

      PRINTF("ERROR %u: %s\n", erbium_status_code, coap_error_message);
      coap_clear_transaction(transaction);

      if(erbium_status_code == PING_RESPONSE) {
        erbium_status_code = 0;
        reply_type = COAP_TYPE_RST;
      } else if(erbium_status_code >= 192) {
        /* set to sendable error code */
        erbium_status_code = INTERNAL_SERVER_ERROR_5_00;
        /* reuse input buffer for error message */
      }
      coap_init_message(message, reply_type, erbium_status_code,
                        message->mid);
      coap_set_payload(message, coap_error_message,
                       strlen(coap_error_message));
      coap_send_message(coap_ctx, &UIP_IP_BUF(coap_ctx->buf)->srcipaddr,
			UIP_UDP_BUF(coap_ctx->buf)->srcport,
                        uip_appdata(coap_ctx->buf),
			coap_serialize_message(message,
					       uip_appdata(coap_ctx->buf)));
    }
  }

  /* if(new data) */
  return erbium_status_code;
}
Example #5
0
/* This function is an adaptation of function coap_receive() from Erbium's er-coap-13-engine.c.
 * Erbium is Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich
 * All rights reserved.
 */
void lwm2m_handle_packet(lwm2m_context_t * contextP,
                         uint8_t * buffer,
                         int length,
                         void * fromSessionH)
{
    uint8_t coap_error_code = NO_ERROR;
    static coap_packet_t message[1];
    static coap_packet_t response[1];

    LOG("Entering");
    coap_error_code = coap_parse_message(message, buffer, (uint16_t)length);
    if (coap_error_code == NO_ERROR)
    {
        LOG_ARG("Parsed: ver %u, type %u, tkl %u, code %u.%.2u, mid %u, Content type: %d",
                message->version, message->type, message->token_len, message->code >> 5, message->code & 0x1F, message->mid, message->content_type);
        LOG_ARG("Payload: %.*s", message->payload_len, message->payload);
        if (message->code >= COAP_GET && message->code <= COAP_DELETE)
        {
            uint32_t block_num = 0;
            uint16_t block_size = REST_MAX_CHUNK_SIZE;
            uint32_t block_offset = 0;
            int64_t new_offset = 0;

            /* prepare response */
            if (message->type == COAP_TYPE_CON)
            {
                /* Reliable CON requests are answered with an ACK. */
                coap_init_message(response, COAP_TYPE_ACK, COAP_205_CONTENT, message->mid);
            }
            else
            {
                /* Unreliable NON requests are answered with a NON as well. */
                coap_init_message(response, COAP_TYPE_NON, COAP_205_CONTENT, contextP->nextMID++);
            }

            /* mirror token */
            if (message->token_len)
            {
                coap_set_header_token(response, message->token, message->token_len);
            }

            /* get offset for blockwise transfers */
            if (coap_get_header_block2(message, &block_num, NULL, &block_size, &block_offset))
            {
                LOG_ARG("Blockwise: block request %u (%u/%u) @ %u bytes", block_num, block_size, REST_MAX_CHUNK_SIZE, block_offset);
                block_size = MIN(block_size, REST_MAX_CHUNK_SIZE);
                new_offset = block_offset;
            }

            /* handle block1 option */
            if (IS_OPTION(message, COAP_OPTION_BLOCK1))
            {
#ifdef LWM2M_CLIENT_MODE
                // get server
                lwm2m_server_t * serverP;
                serverP = utils_findServer(contextP, fromSessionH);
#ifdef LWM2M_BOOTSTRAP
                if (serverP == NULL)
                {
                    serverP = utils_findBootstrapServer(contextP, fromSessionH);
                }
#endif
                if (serverP == NULL)
                {
                    coap_error_code = COAP_500_INTERNAL_SERVER_ERROR;
                }
                else
                {
                    uint32_t block1_num;
                    uint8_t  block1_more;
                    uint16_t block1_size;
                    uint8_t * complete_buffer = NULL;
                    size_t complete_buffer_size;

                    // parse block1 header
                    coap_get_header_block1(message, &block1_num, &block1_more, &block1_size, NULL);
                    LOG_ARG("Blockwise: block1 request NUM %u (SZX %u/ SZX Max%u) MORE %u", block1_num, block1_size, REST_MAX_CHUNK_SIZE, block1_more);

                    // handle block 1
                    coap_error_code = coap_block1_handler(&serverP->block1Data, message->mid, message->payload, message->payload_len, block1_size, block1_num, block1_more, &complete_buffer, &complete_buffer_size);

                    // if payload is complete, replace it in the coap message.
                    if (coap_error_code == NO_ERROR)
                    {
                        message->payload = complete_buffer;
                        message->payload_len = complete_buffer_size;
                    }
                    else if (coap_error_code == COAP_231_CONTINUE)
                    {
                        block1_size = MIN(block1_size, REST_MAX_CHUNK_SIZE);
                        coap_set_header_block1(response,block1_num, block1_more,block1_size);
                    }
                }
#else
                coap_error_code = COAP_501_NOT_IMPLEMENTED;
#endif
            }
            if (coap_error_code == NO_ERROR)
            {
                coap_error_code = handle_request(contextP, fromSessionH, message, response);
            }
            if (coap_error_code==NO_ERROR)
            {
                /* Save original payload pointer for later freeing. Payload in response may be updated. */
                uint8_t *payload = response->payload;
                if ( IS_OPTION(message, COAP_OPTION_BLOCK2) )
                {
                    /* unchanged new_offset indicates that resource is unaware of blockwise transfer */
                    if (new_offset==block_offset)
                    {
                        LOG_ARG("Blockwise: unaware resource with payload length %u/%u", response->payload_len, block_size);
                        if (block_offset >= response->payload_len)
                        {
                            LOG("handle_incoming_data(): block_offset >= response->payload_len");

                            response->code = COAP_402_BAD_OPTION;
                            coap_set_payload(response, "BlockOutOfScope", 15); /* a const char str[] and sizeof(str) produces larger code size */
                        }
                        else
                        {
                            coap_set_header_block2(response, block_num, response->payload_len - block_offset > block_size, block_size);
                            coap_set_payload(response, response->payload+block_offset, MIN(response->payload_len - block_offset, block_size));
                        } /* if (valid offset) */
                    }
                    else
                    {
                        /* resource provides chunk-wise data */
                        LOG_ARG("Blockwise: blockwise resource, new offset %d", (int) new_offset);
                        coap_set_header_block2(response, block_num, new_offset!=-1 || response->payload_len > block_size, block_size);
                        if (response->payload_len > block_size) coap_set_payload(response, response->payload, block_size);
                    } /* if (resource aware of blockwise) */
                }
                else if (new_offset!=0)
                {
                    LOG_ARG("Blockwise: no block option for blockwise resource, using block size %u", REST_MAX_CHUNK_SIZE);

                    coap_set_header_block2(response, 0, new_offset!=-1, REST_MAX_CHUNK_SIZE);
                    coap_set_payload(response, response->payload, MIN(response->payload_len, REST_MAX_CHUNK_SIZE));
                } /* if (blockwise request) */

                coap_error_code = message_send(contextP, response, fromSessionH);

                lwm2m_free(payload);
                response->payload = NULL;
                response->payload_len = 0;
            }
            else if (coap_error_code != COAP_IGNORE)
            {
                if (1 == coap_set_status_code(response, coap_error_code))
                {
                    coap_error_code = message_send(contextP, response, fromSessionH);
                }
            }
        }
        else
        {
            /* Responses */
            switch (message->type)
            {
            case COAP_TYPE_NON:
            case COAP_TYPE_CON:
                {
                    bool done = transaction_handleResponse(contextP, fromSessionH, message, response);

#ifdef LWM2M_SERVER_MODE
                    if (!done && IS_OPTION(message, COAP_OPTION_OBSERVE) &&
                        ((message->code == COAP_204_CHANGED) || (message->code == COAP_205_CONTENT)))
                    {
                        done = observe_handleNotify(contextP, fromSessionH, message, response);
                    }
#endif
                    if (!done && message->type == COAP_TYPE_CON )
                    {
                        coap_init_message(response, COAP_TYPE_ACK, 0, message->mid);
                        coap_error_code = message_send(contextP, response, fromSessionH);
                    }
                }
                break;

            case COAP_TYPE_RST:
                /* Cancel possible subscriptions. */
                handle_reset(contextP, fromSessionH, message);
                transaction_handleResponse(contextP, fromSessionH, message, NULL);
                break;

            case COAP_TYPE_ACK:
                transaction_handleResponse(contextP, fromSessionH, message, NULL);
                break;

            default:
                break;
            }
        } /* Request or Response */
        coap_free_header(message);
    } /* if (parsed correctly) */
Example #6
0
    // server CB
    int request1 (void* transaction_, void* data) {
#if COAP_CEU
        CEU_Transaction* transaction = (CEU_Transaction*) transaction_;
#else
        coap_transaction_t* transaction = (coap_transaction_t*) transaction_;
#endif
        /* Use transaction buffer for response to confirmable request. */
          uint32_t block_num = 0;
          uint16_t block_size = REST_MAX_CHUNK_SIZE;
          uint32_t block_offset = 0;
          int32_t new_offset = 0;

          /* prepare response */
          if (message->type==COAP_TYPE_CON)
          {
            /* Reliable CON requests are answered with an ACK. */
            coap_init_message(response, COAP_TYPE_ACK, CONTENT_2_05, message->mid);
          }
          else
          {
            /* Unreliable NON requests are answered with a NON as well. */
            coap_init_message(response, COAP_TYPE_NON, CONTENT_2_05, coap_get_mid());
          }

          /* mirror token */
          if (message->token_len)
          {
              coap_set_header_token(response, message->token, message->token_len);
          }

          /* get offset for blockwise transfers */
          if (coap_get_header_block2(message, &block_num, NULL, &block_size, &block_offset))
          {
              PRINTF("Blockwise: block request %lu (%u/%u) @ %lu bytes\n", block_num, block_size, REST_MAX_CHUNK_SIZE, block_offset);
              block_size = MIN(block_size, REST_MAX_CHUNK_SIZE);
              new_offset = block_offset;
          }

          /* Invoke resource handler. */
          if (service_cbk)
          {
            /* Call REST framework and check if found and allowed. */
            if (service_cbk(message, response, transaction->packet+COAP_MAX_HEADER_SIZE, block_size, &new_offset))
            {
              if (coap_error_code==NO_ERROR)
              {
                /* Apply blockwise transfers. */
                if ( IS_OPTION(message, COAP_OPTION_BLOCK1) && response->code<BAD_REQUEST_4_00 && !IS_OPTION(response, COAP_OPTION_BLOCK1) )
                {
                  PRINTF("Block1 NOT IMPLEMENTED\n");

                  coap_error_code = NOT_IMPLEMENTED_5_01;
                  coap_error_message = "NoBlock1Support";
                }
                else if ( IS_OPTION(message, COAP_OPTION_BLOCK2) )
                {
                  /* unchanged new_offset indicates that resource is unaware of blockwise transfer */
                  if (new_offset==block_offset)
                  {
                    PRINTF("Blockwise: unaware resource with payload length %u/%u\n", response->payload_len, block_size);
                    if (block_offset >= response->payload_len)
                    {
                      PRINTF("handle_incoming_data(): block_offset >= response->payload_len\n");

                      response->code = BAD_OPTION_4_02;
                      coap_set_payload(response, "BlockOutOfScope", 15); /* a const char str[] and sizeof(str) produces larger code size */
                    }
                    else
                    {
                      coap_set_header_block2(response, block_num, response->payload_len - block_offset > block_size, block_size);
                      coap_set_payload(response, response->payload+block_offset, MIN(response->payload_len - block_offset, block_size));
                    } /* if (valid offset) */
                  }
                  else
                  {
                    /* resource provides chunk-wise data */
                    PRINTF("Blockwise: blockwise resource, new offset %ld\n", new_offset);
                    coap_set_header_block2(response, block_num, new_offset!=-1 || response->payload_len > block_size, block_size);
                    if (response->payload_len > block_size) coap_set_payload(response, response->payload, block_size);
                  } /* if (resource aware of blockwise) */
                }
                else if (new_offset!=0)
                {
                  PRINTF("Blockwise: no block option for blockwise resource, using block size %u\n", REST_MAX_CHUNK_SIZE);

                  coap_set_header_block2(response, 0, new_offset!=-1, REST_MAX_CHUNK_SIZE);
                  coap_set_payload(response, response->payload, MIN(response->payload_len, REST_MAX_CHUNK_SIZE));
                } /* if (blockwise request) */
              } /* no errors/hooks */
            } /* successful service callback */

            /* Serialize response. */
            if (coap_error_code==NO_ERROR)
            {
              if ((transaction->packet_len = coap_serialize_message(response, transaction->packet))==0)
              {
                coap_error_code = PACKET_SERIALIZATION_ERROR;
              }
            }

          }
          else
          {
            coap_error_code = NOT_IMPLEMENTED_5_01;
            coap_error_message = "NoServiceCallbck"; // no a to fit 16 bytes
          } /* if (service callback) */

          return coap_error_code;
    }
Example #7
0
/*---------------------------------------------------------------------------*/
int
coap_receive(oc_message_t *msg)
{
  erbium_status_code = NO_ERROR;

  LOG("\n\nCoAP Engine: received datalen=%u \n", (unsigned int) msg->length);

  /* static declaration reduces stack peaks and program code size */
  static coap_packet_t
    message[1]; /* this way the packet can be treated as pointer as usual */
  static coap_packet_t response[1];
  static coap_transaction_t *transaction = NULL;

  erbium_status_code = coap_parse_message(message, msg->data, msg->length);

  if (erbium_status_code == NO_ERROR) {

/*TODO duplicates suppression, if required by application */

#if DEBUG
    LOG("  Parsed: CoAP version: %u, token: 0x%02X%02X, mid: %u\n",
        message->version, message->token[0], message->token[1], message->mid);
    switch (message->type) {
    case COAP_TYPE_CON:
      LOG("  type: CON\n");
      break;
    case COAP_TYPE_NON:
      LOG("  type: NON\n");
      break;
    case COAP_TYPE_ACK:
      LOG("  type: ACK\n");
      break;
    case COAP_TYPE_RST:
      LOG("  type: RST\n");
      break;
    default:
      break;
    }
#endif

    /* handle requests */
    if (message->code >= COAP_GET && message->code <= COAP_DELETE) {

#if DEBUG
      switch (message->code) {
      case COAP_GET:
        LOG("  method: GET\n");
        break;
      case COAP_PUT:
        LOG("  method: PUT\n");
        break;
      case COAP_POST:
        LOG("  method: POST\n");
        break;
      case COAP_DELETE:
        LOG("  method: DELETE\n");
        break;
      }
      LOG("  URL: %.*s\n", (int) message->uri_path_len, message->uri_path);
      LOG("  Payload: %.*s\n", (int) message->payload_len, message->payload);
#endif
      /* use transaction buffer for response to confirmable request */
      if ((transaction = coap_new_transaction(message->mid, &msg->endpoint))) {
        uint32_t block_num = 0;
        uint16_t block_size = COAP_MAX_BLOCK_SIZE;
        uint32_t block_offset = 0;
        int32_t new_offset = 0;

        /* prepare response */
        if (message->type == COAP_TYPE_CON) {
          /* reliable CON requests are answered with an ACK */
          coap_init_message(response, COAP_TYPE_ACK, CONTENT_2_05,
                            message->mid);
        } else {
          /* unreliable NON requests are answered with a NON as well */
          coap_init_message(response, COAP_TYPE_NON, CONTENT_2_05,
                            coap_get_mid());
          /* mirror token */
        }
        if (message->token_len) {
          coap_set_token(response, message->token, message->token_len);
          /* get offset for blockwise transfers */
        }
        if (coap_get_header_block2(message, &block_num, NULL, &block_size,
                                   &block_offset)) {
          LOG("\tBlockwise: block request %u (%u/%u) @ %u bytes\n", (unsigned int) block_num,
              block_size, COAP_MAX_BLOCK_SIZE, (unsigned int) block_offset);
          block_size = MIN(block_size, COAP_MAX_BLOCK_SIZE);
          new_offset = block_offset;
        }

        /* invoke resource handler in RI layer */
        if (oc_ri_invoke_coap_entity_handler(
              message, response,
              transaction->message->data + COAP_MAX_HEADER_SIZE, block_size,
              &new_offset, &msg->endpoint)) {

          if (erbium_status_code == NO_ERROR) {

            /* TODO coap_handle_blockwise(request, response, start_offset,
             * end_offset); */

            /* resource is unaware of Block1 */
            if (IS_OPTION(message, COAP_OPTION_BLOCK1) &&
                response->code < BAD_REQUEST_4_00 &&
                !IS_OPTION(response, COAP_OPTION_BLOCK1)) {
              LOG("\tBlock1 option NOT IMPLEMENTED\n");

              erbium_status_code = NOT_IMPLEMENTED_5_01;
              coap_error_message = "NoBlock1Support";

              /* client requested Block2 transfer */
            } else if (IS_OPTION(message, COAP_OPTION_BLOCK2)) {

              /* unchanged new_offset indicates that resource is unaware of
               * blockwise transfer */
              if (new_offset == block_offset) {
                LOG("\tBlockwise: unaware resource with payload length %u/%u\n",
                    response->payload_len, block_size);
                if (block_offset >= response->payload_len) {
                  LOG("\t\t: block_offset >= response->payload_len\n");

                  response->code = BAD_OPTION_4_02;
                  coap_set_payload(response, "BlockOutOfScope",
                                   15); /* a const char str[] and sizeof(str)
                                           produces larger code size */
                } else {
                  coap_set_header_block2(response, block_num,
                                         response->payload_len - block_offset >
                                           block_size,
                                         block_size);
                  coap_set_payload(
                    response, response->payload + block_offset,
                    MIN(response->payload_len - block_offset, block_size));
                } /* if(valid offset) */

                /* resource provides chunk-wise data */
              } else {
                LOG("\tBlockwise: blockwise resource, new offset %d\n",
                    (int) new_offset);
                coap_set_header_block2(response, block_num,
                                       new_offset != -1 ||
                                         response->payload_len > block_size,
                                       block_size);

                if (response->payload_len > block_size) {
                  coap_set_payload(response, response->payload, block_size);
                }
              } /* if(resource aware of blockwise) */

              /* Resource requested Block2 transfer */
            } else if (new_offset != 0) {
              LOG("\tBlockwise: no block option for blockwise resource, using "
                  "block size %u\n",
                  COAP_MAX_BLOCK_SIZE);

              coap_set_header_block2(response, 0, new_offset != -1,
                                     COAP_MAX_BLOCK_SIZE);
              coap_set_payload(response, response->payload,
                               MIN(response->payload_len, COAP_MAX_BLOCK_SIZE));
            } /* blockwise transfer handling */
          }   /* no errors/hooks */
          /* successful service callback */
          /* serialize response */
        }
        if (erbium_status_code == NO_ERROR) {
          if ((transaction->message->length = coap_serialize_message(
                 response, transaction->message->data)) == 0) {
            erbium_status_code = PACKET_SERIALIZATION_ERROR;
          }
        }
      } else {
        erbium_status_code = SERVICE_UNAVAILABLE_5_03;
        coap_error_message = "NoFreeTraBuffer";
      } /* if(transaction buffer) */

      /* handle responses */
    } else { // Fix this
      if (message->type == COAP_TYPE_CON) {
        erbium_status_code = EMPTY_ACK_RESPONSE;
      } else if (message->type == COAP_TYPE_ACK) {
        /* transactions are closed through lookup below */
      } else if (message->type == COAP_TYPE_RST) {
#ifdef OC_SERVER
        /* cancel possible subscriptions */
        coap_remove_observer_by_mid(&msg->endpoint, message->mid);
#endif
      }

      /* Open transaction now cleared for ACK since mid matches */
      if ((transaction = coap_get_transaction_by_mid(message->mid))) {
        coap_clear_transaction(transaction);
      }
      /* if(ACKed transaction) */
      transaction = NULL;

#ifdef OC_CLIENT // ACKs and RSTs sent to oc_ri.. RSTs cleared, ACKs sent to
                 // client
      oc_ri_invoke_client_cb(message, &msg->endpoint);
#endif

    } /* request or response */
  }   /* parsed correctly */

  /* if(parsed correctly) */
  if (erbium_status_code == NO_ERROR) {
    if (transaction) { // Server transactions sent from here
      coap_send_transaction(transaction);
    }
  } else if (erbium_status_code == CLEAR_TRANSACTION) {
    LOG("Clearing transaction for manual response");
    coap_clear_transaction(transaction); // used in server for separate response
  }
#ifdef OC_CLIENT
  else if (erbium_status_code == EMPTY_ACK_RESPONSE) {
    coap_init_message(message, COAP_TYPE_ACK, 0, message->mid);
    oc_message_t *response = oc_allocate_message();
    if (response) {
      memcpy(&response->endpoint, &msg->endpoint, sizeof(msg->endpoint));
      response->length = coap_serialize_message(message, response->data);
      coap_send_message(response);
    }
  }
#endif /* OC_CLIENT */
#ifdef OC_SERVER
  else { // framework errors handled here
    coap_message_type_t reply_type = COAP_TYPE_RST;

    coap_clear_transaction(transaction);

    coap_init_message(message, reply_type, SERVICE_UNAVAILABLE_5_03,
                      message->mid);

    oc_message_t *response = oc_allocate_message();
    if (response) {
      memcpy(&response->endpoint, &msg->endpoint, sizeof(msg->endpoint));
      response->length = coap_serialize_message(message, response->data);
      coap_send_message(response);
    }
  }
#endif /* OC_SERVER */

  /* if(new data) */
  return erbium_status_code;
}
Example #8
0
/* This function is an adaptation of function coap_receive() from Erbium's er-coap-13-engine.c.
 * Erbium is Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich
 * All rights reserved.
 */
void lwm2m_handle_packet(lwm2m_context_t * contextP,
                        uint8_t * buffer,
                        int length,
                        void * fromSessionH)
{
    coap_status_t coap_error_code = NO_ERROR;
    static coap_packet_t message[1];
    static coap_packet_t response[1];

    coap_error_code = coap_parse_message(message, buffer, (uint16_t)length);

    if (message[0].uri_path && message[0].uri_path->next &&
            (message[0].uri_path->next->is_static != 0 && message[0].uri_path->next->is_static != 1)) {
        printf("BLA\n");
    }

    if (coap_error_code == NO_ERROR)
    {
        LOG("  Parsed: ver %u, type %u, tkl %u, code %u.%.2u, mid %u\r\n", message->version, message->type, message->token_len, message->code >> 5, message->code & 0x1F, message->mid);
        LOG("  Content type: %d\r\n  Payload: %.*s\r\n\n", message->content_type, message->payload_len, message->payload);
        if (message->code >= COAP_GET && message->code <= COAP_DELETE)
        {
            uint32_t block_num = 0;
            uint16_t block_size = REST_MAX_CHUNK_SIZE;
            uint32_t block_offset = 0;
            int64_t new_offset = 0;

            /* prepare response */
            if (message->type == COAP_TYPE_CON)
            {
                /* Reliable CON requests are answered with an ACK. */
                coap_init_message(response, COAP_TYPE_ACK, COAP_205_CONTENT, message->mid);
            }
            else
            {
                /* Unreliable NON requests are answered with a NON as well. */
                coap_init_message(response, COAP_TYPE_NON, COAP_205_CONTENT, contextP->nextMID++);
            }

            /* mirror token */
            if (message->token_len)
            {
                coap_set_header_token(response, message->token, message->token_len);
            }

            /* get offset for blockwise transfers */
            if (coap_get_header_block2(message, &block_num, NULL, &block_size, &block_offset))
            {
                LOG("Blockwise: block request %u (%u/%u) @ %u bytes\n", block_num, block_size, REST_MAX_CHUNK_SIZE, block_offset);
                block_size = MIN(block_size, REST_MAX_CHUNK_SIZE);
                new_offset = block_offset;
            }

            coap_error_code = handle_request(contextP, fromSessionH, message, response);
            if (coap_error_code==NO_ERROR)
            {
                /* Apply blockwise transfers. */
                if ( IS_OPTION(message, COAP_OPTION_BLOCK1) && response->code<COAP_400_BAD_REQUEST && !IS_OPTION(response, COAP_OPTION_BLOCK1) )
                {
                    LOG("Block1 NOT IMPLEMENTED\n");

                    coap_error_code = COAP_501_NOT_IMPLEMENTED;
                    coap_error_message = "NoBlock1Support";
                }
                else if ( IS_OPTION(message, COAP_OPTION_BLOCK2) )
                {
                    /* unchanged new_offset indicates that resource is unaware of blockwise transfer */
                    if (new_offset==block_offset)
                    {
                        LOG("Blockwise: unaware resource with payload length %u/%u\n", response->payload_len, block_size);
                        if (block_offset >= response->payload_len)
                        {
                            LOG("handle_incoming_data(): block_offset >= response->payload_len\n");

                            response->code = COAP_402_BAD_OPTION;
                            coap_set_payload(response, "BlockOutOfScope", 15); /* a const char str[] and sizeof(str) produces larger code size */
                        }
                        else
                        {
                            coap_set_header_block2(response, block_num, response->payload_len - block_offset > block_size, block_size);
                            coap_set_payload(response, response->payload+block_offset, MIN(response->payload_len - block_offset, block_size));
                        } /* if (valid offset) */
                    }
                    else
                    {
                        /* resource provides chunk-wise data */
                        LOG("Blockwise: blockwise resource, new offset %d\n", (int) new_offset);
                        coap_set_header_block2(response, block_num, new_offset!=-1 || response->payload_len > block_size, block_size);
                        if (response->payload_len > block_size) coap_set_payload(response, response->payload, block_size);
                    } /* if (resource aware of blockwise) */
                }
                else if (new_offset!=0)
                {
                    LOG("Blockwise: no block option for blockwise resource, using block size %u\n", REST_MAX_CHUNK_SIZE);

                    coap_set_header_block2(response, 0, new_offset!=-1, REST_MAX_CHUNK_SIZE);
                    coap_set_payload(response, response->payload, MIN(response->payload_len, REST_MAX_CHUNK_SIZE));
                } /* if (blockwise request) */

                coap_error_code = message_send(contextP, response, fromSessionH);

                lwm2m_free(response->payload);
                response->payload = NULL;
                response->payload_len = 0;
            }
            else if (coap_error_code != COAP_IGNORE)
            {
                if (1 == coap_set_status_code(response, coap_error_code))
                {
                    coap_error_code = message_send(contextP, response, fromSessionH);
                }
            }
        }
        else
        {
            /* Responses */
            switch (message->type)
            {
            case COAP_TYPE_NON:
            case COAP_TYPE_CON:
                {
                    bool done = transaction_handleResponse(contextP, fromSessionH, message, response);

#ifdef LWM2M_SERVER_MODE
                    if (!done && IS_OPTION(message, COAP_OPTION_OBSERVE) &&
                        ((message->code == COAP_204_CHANGED) || (message->code == COAP_205_CONTENT)))
                    {
                        done = observe_handleNotify(contextP, fromSessionH, message, response);
                    }
#endif
                    if (!done && message->type == COAP_TYPE_CON )
                    {
                        coap_init_message(response, COAP_TYPE_ACK, 0, message->mid);
                        coap_error_code = message_send(contextP, response, fromSessionH);
                    }
                }
                break;

            case COAP_TYPE_RST:
                /* Cancel possible subscriptions. */
                handle_reset(contextP, fromSessionH, message);
                transaction_handleResponse(contextP, fromSessionH, message, NULL);
                break;

            case COAP_TYPE_ACK:
                transaction_handleResponse(contextP, fromSessionH, message, NULL);
                break;

            default:
                break;
            }
        } /* Request or Response */
        coap_free_header(message);
    } /* if (parsed correctly) */