terence zhang / wakaama-core
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers packet.c Source File

packet.c

00001 /*******************************************************************************
00002  *
00003  * Copyright (c) 2013, 2014 Intel Corporation and others.
00004  * All rights reserved. This program and the accompanying materials
00005  * are made available under the terms of the Eclipse Public License v1.0
00006  * and Eclipse Distribution License v1.0 which accompany this distribution.
00007  *
00008  * The Eclipse Public License is available at
00009  *    http://www.eclipse.org/legal/epl-v10.html
00010  * The Eclipse Distribution License is available at
00011  *    http://www.eclipse.org/org/documents/edl-v10.php.
00012  *
00013  * Contributors:
00014  *    David Navarro, Intel Corporation - initial API and implementation
00015  *    domedambrosio - Please refer to git log
00016  *    Fabien Fleutot - Please refer to git log
00017  *    Fabien Fleutot - Please refer to git log
00018  *    Simon Bernard - Please refer to git log
00019  *    Toby Jaffey - Please refer to git log
00020  *    Pascal Rieux - Please refer to git log
00021  *    Bosch Software Innovations GmbH - Please refer to git log
00022  *
00023  *******************************************************************************/
00024 
00025 /*
00026  Copyright (c) 2013, 2014 Intel Corporation
00027 
00028  Redistribution and use in source and binary forms, with or without modification,
00029  are permitted provided that the following conditions are met:
00030 
00031      * Redistributions of source code must retain the above copyright notice,
00032        this list of conditions and the following disclaimer.
00033      * Redistributions in binary form must reproduce the above copyright notice,
00034        this list of conditions and the following disclaimer in the documentation
00035        and/or other materials provided with the distribution.
00036      * Neither the name of Intel Corporation nor the names of its contributors
00037        may be used to endorse or promote products derived from this software
00038        without specific prior written permission.
00039 
00040  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00041  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00042  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00043  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
00044  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00045  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00046  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00047  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
00048  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
00049  THE POSSIBILITY OF SUCH DAMAGE.
00050 
00051  David Navarro <david.navarro@intel.com>
00052 
00053 */
00054 
00055 /*
00056 Contains code snippets which are:
00057 
00058  * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich
00059  * All rights reserved.
00060  *
00061  * Redistribution and use in source and binary forms, with or without
00062  * modification, are permitted provided that the following conditions
00063  * are met:
00064  * 1. Redistributions of source code must retain the above copyright
00065  *    notice, this list of conditions and the following disclaimer.
00066  * 2. Redistributions in binary form must reproduce the above copyright
00067  *    notice, this list of conditions and the following disclaimer in the
00068  *    documentation and/or other materials provided with the distribution.
00069  * 3. Neither the name of the Institute nor the names of its contributors
00070  *    may be used to endorse or promote products derived from this software
00071  *    without specific prior written permission.
00072  *
00073  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
00074  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00075  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00076  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
00077  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00078  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00079  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00080  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00081  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00082  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00083  * SUCH DAMAGE.
00084 
00085 */
00086 
00087 
00088 #include "internals.h"
00089 
00090 #include <stdlib.h>
00091 #include <string.h>
00092 
00093 #include <stdio.h>
00094 
00095 
00096 static void handle_reset(lwm2m_context_t * contextP,
00097                          void * fromSessionH,
00098                          coap_packet_t * message)
00099 {
00100 #ifdef LWM2M_CLIENT_MODE
00101     LOG("Entering");
00102     observe_cancel(contextP, message->mid, fromSessionH);
00103 #endif
00104 }
00105 
00106 static coap_status_t handle_request(lwm2m_context_t * contextP,
00107                                     void * fromSessionH,
00108                                     coap_packet_t * message,
00109                                     coap_packet_t * response)
00110 {
00111     lwm2m_uri_t * uriP;
00112     coap_status_t result = COAP_IGNORE;
00113 
00114     LOG("Entering");
00115     
00116 #ifdef LWM2M_CLIENT_MODE
00117     uriP = uri_decode(contextP->altPath, message->uri_path);
00118 #else
00119     uriP = uri_decode(NULL, message->uri_path);
00120 #endif
00121 
00122     if (uriP == NULL) return COAP_400_BAD_REQUEST;
00123 
00124     switch(uriP->flag & LWM2M_URI_MASK_TYPE)
00125     {
00126 #ifdef LWM2M_CLIENT_MODE
00127     case LWM2M_URI_FLAG_DM:
00128     {
00129         lwm2m_server_t * serverP;
00130 
00131         serverP = utils_findServer(contextP, fromSessionH);
00132         if (serverP != NULL)
00133         {
00134             result = dm_handleRequest(contextP, uriP, serverP, message, response);
00135         }
00136 #ifdef LWM2M_BOOTSTRAP
00137         else
00138         {
00139             serverP = utils_findBootstrapServer(contextP, fromSessionH);
00140             if (serverP != NULL)
00141             {
00142                 result = bootstrap_handleCommand(contextP, uriP, serverP, message, response);
00143             }
00144         }
00145 #endif
00146     }
00147     break;
00148 
00149 #ifdef LWM2M_BOOTSTRAP
00150     case LWM2M_URI_FLAG_DELETE_ALL:
00151         if (COAP_DELETE != message->code)
00152         {
00153             result = COAP_400_BAD_REQUEST;
00154         }
00155         else
00156         {
00157             result = bootstrap_handleDeleteAll(contextP, fromSessionH);
00158         }
00159         break;
00160 
00161     case LWM2M_URI_FLAG_BOOTSTRAP:
00162         if (message->code == COAP_POST)
00163         {
00164             result = bootstrap_handleFinish(contextP, fromSessionH);
00165         }
00166         break;
00167 #endif
00168 #endif
00169 
00170 #ifdef LWM2M_SERVER_MODE
00171     case LWM2M_URI_FLAG_REGISTRATION:
00172         result = registration_handleRequest(contextP, uriP, fromSessionH, message, response);
00173         break;
00174 #endif
00175 #ifdef LWM2M_BOOTSTRAP_SERVER_MODE
00176     case LWM2M_URI_FLAG_BOOTSTRAP:
00177         result = bootstrap_handleRequest(contextP, uriP, fromSessionH, message, response);
00178         break;
00179 #endif
00180     default:
00181         result = COAP_IGNORE;
00182         break;
00183     }
00184 
00185     coap_set_status_code(response, result);
00186 
00187     if (COAP_IGNORE < result && result < COAP_400_BAD_REQUEST)
00188     {
00189         result = NO_ERROR;
00190     }
00191 
00192     lwm2m_free(uriP);
00193     return result;
00194 }
00195 
00196 /* This function is an adaptation of function coap_receive() from Erbium's er-coap-13-engine.c.
00197  * Erbium is Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich
00198  * All rights reserved.
00199  */
00200 void lwm2m_handle_packet(lwm2m_context_t * contextP,
00201                         uint8_t * buffer,
00202                         int length,
00203                         void * fromSessionH)
00204 {
00205     coap_status_t coap_error_code = NO_ERROR;
00206     static coap_packet_t message[1];
00207     static coap_packet_t response[1];
00208 
00209     LOG("Entering");
00210     coap_error_code = coap_parse_message(message, buffer, (uint16_t)length);
00211     if (coap_error_code == NO_ERROR)
00212     {
00213         LOG_ARG("Parsed: ver %u, type %u, tkl %u, code %u.%.2u, mid %u, Content type: %d",
00214                 message->version, message->type, message->token_len, message->code >> 5, message->code & 0x1F, message->mid, message->content_type);
00215         LOG_ARG("Payload: %.*s", message->payload_len, message->payload);
00216         if (message->code >= COAP_GET && message->code <= COAP_DELETE)
00217         {
00218             uint32_t block_num = 0;
00219             uint16_t block_size = REST_MAX_CHUNK_SIZE;
00220             uint32_t block_offset = 0;
00221             int64_t new_offset = 0;
00222 
00223             /* prepare response */
00224             if (message->type == COAP_TYPE_CON)
00225             {
00226                 /* Reliable CON requests are answered with an ACK. */
00227                 coap_init_message(response, COAP_TYPE_ACK, COAP_205_CONTENT, message->mid);
00228             }
00229             else
00230             {
00231                 /* Unreliable NON requests are answered with a NON as well. */
00232                 coap_init_message(response, COAP_TYPE_NON, COAP_205_CONTENT, contextP->nextMID++);
00233             }
00234 
00235             /* mirror token */
00236             if (message->token_len)
00237             {
00238                 coap_set_header_token(response, message->token, message->token_len);
00239             }
00240 
00241             /* get offset for blockwise transfers */
00242             if (coap_get_header_block2(message, &block_num, NULL, &block_size, &block_offset))
00243             {
00244                 LOG_ARG("Blockwise: block request %u (%u/%u) @ %u bytes", block_num, block_size, REST_MAX_CHUNK_SIZE, block_offset);
00245                 block_size = MIN(block_size, REST_MAX_CHUNK_SIZE);
00246                 new_offset = block_offset;
00247             }
00248 
00249             /* handle block1 option */
00250             if (IS_OPTION(message, COAP_OPTION_BLOCK1))
00251             {
00252 #ifdef LWM2M_CLIENT_MODE
00253                 // get server
00254                 lwm2m_server_t * serverP;
00255                 serverP = utils_findServer(contextP, fromSessionH);
00256 #ifdef LWM2M_BOOTSTRAP
00257                 if (serverP == NULL)
00258                 {
00259                     serverP = utils_findBootstrapServer(contextP, fromSessionH);
00260                 }
00261 #endif
00262                 if (serverP == NULL)
00263                 {
00264                     coap_error_code = COAP_500_INTERNAL_SERVER_ERROR;
00265                 }
00266                 else
00267                 {
00268                     uint32_t block1_num;
00269                     uint8_t  block1_more;
00270                     uint16_t block1_size;
00271                     uint8_t * complete_buffer = NULL;
00272                     size_t complete_buffer_size;
00273 
00274                     // parse block1 header
00275                     coap_get_header_block1(message, &block1_num, &block1_more, &block1_size, NULL);
00276                     LOG_ARG("Blockwise: block1 request NUM %u (SZX %u/ SZX Max%u) MORE %u", block1_num, block1_size, REST_MAX_CHUNK_SIZE, block1_more);
00277 
00278                     // handle block 1
00279                     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);
00280 
00281                     // if payload is complete, replace it in the coap message.
00282                     if (coap_error_code == NO_ERROR)
00283                     {
00284                         message->payload = complete_buffer;
00285                         message->payload_len = complete_buffer_size;
00286                     }
00287                     else if (coap_error_code == COAP_231_CONTINUE)
00288                     {
00289                         block1_size = MIN(block1_size, REST_MAX_CHUNK_SIZE);
00290                         coap_set_header_block1(response,block1_num, block1_more,block1_size);
00291                     }
00292                 }
00293 #else
00294                 coap_error_code = COAP_501_NOT_IMPLEMENTED;
00295 #endif
00296             }
00297             if (coap_error_code == NO_ERROR)
00298             {
00299                 coap_error_code = handle_request(contextP, fromSessionH, message, response);
00300             }
00301             if (coap_error_code==NO_ERROR)
00302             {
00303                 if ( IS_OPTION(message, COAP_OPTION_BLOCK2) )
00304                 {
00305                     /* unchanged new_offset indicates that resource is unaware of blockwise transfer */
00306                     if (new_offset==block_offset)
00307                     {
00308                         LOG_ARG("Blockwise: unaware resource with payload length %u/%u", response->payload_len, block_size);
00309                         if (block_offset >= response->payload_len)
00310                         {
00311                             LOG("handle_incoming_data(): block_offset >= response->payload_len");
00312 
00313                             response->code = COAP_402_BAD_OPTION;
00314                             coap_set_payload(response, "BlockOutOfScope", 15); /* a const char str[] and sizeof(str) produces larger code size */
00315                         }
00316                         else
00317                         {
00318                             coap_set_header_block2(response, block_num, response->payload_len - block_offset > block_size, block_size);
00319                             coap_set_payload(response, response->payload+block_offset, MIN(response->payload_len - block_offset, block_size));
00320                         } /* if (valid offset) */
00321                     }
00322                     else
00323                     {
00324                         /* resource provides chunk-wise data */
00325                         LOG_ARG("Blockwise: blockwise resource, new offset %d", (int) new_offset);
00326                         coap_set_header_block2(response, block_num, new_offset!=-1 || response->payload_len > block_size, block_size);
00327                         if (response->payload_len > block_size) coap_set_payload(response, response->payload, block_size);
00328                     } /* if (resource aware of blockwise) */
00329                 }
00330                 else if (new_offset!=0)
00331                 {
00332                     LOG_ARG("Blockwise: no block option for blockwise resource, using block size %u", REST_MAX_CHUNK_SIZE);
00333 
00334                     coap_set_header_block2(response, 0, new_offset!=-1, REST_MAX_CHUNK_SIZE);
00335                     coap_set_payload(response, response->payload, MIN(response->payload_len, REST_MAX_CHUNK_SIZE));
00336                 } /* if (blockwise request) */
00337 
00338                 coap_error_code = message_send(contextP, response, fromSessionH);
00339 
00340                 lwm2m_free(response->payload);
00341                 response->payload = NULL;
00342                 response->payload_len = 0;
00343             }
00344             else if (coap_error_code != COAP_IGNORE)
00345             {
00346                 if (1 == coap_set_status_code(response, coap_error_code))
00347                 {
00348                     coap_error_code = message_send(contextP, response, fromSessionH);
00349                 }
00350             }
00351         }
00352         else
00353         {
00354             /* Responses */
00355             switch (message->type)
00356             {
00357             case COAP_TYPE_NON:
00358             case COAP_TYPE_CON:
00359                 {
00360                     bool done = transaction_handleResponse(contextP, fromSessionH, message, response);
00361 
00362 #ifdef LWM2M_SERVER_MODE
00363                     if (!done && IS_OPTION(message, COAP_OPTION_OBSERVE) &&
00364                         ((message->code == COAP_204_CHANGED) || (message->code == COAP_205_CONTENT)))
00365                     {
00366                         done = observe_handleNotify(contextP, fromSessionH, message, response);
00367                     }
00368 #endif
00369                     if (!done && message->type == COAP_TYPE_CON )
00370                     {
00371                         coap_init_message(response, COAP_TYPE_ACK, 0, message->mid);
00372                         coap_error_code = message_send(contextP, response, fromSessionH);
00373                     }
00374                 }
00375                 break;
00376 
00377             case COAP_TYPE_RST:
00378                 /* Cancel possible subscriptions. */
00379                 handle_reset(contextP, fromSessionH, message);
00380                 transaction_handleResponse(contextP, fromSessionH, message, NULL);
00381                 break;
00382 
00383             case COAP_TYPE_ACK:
00384                 transaction_handleResponse(contextP, fromSessionH, message, NULL);
00385                 break;
00386 
00387             default:
00388                 break;
00389             }
00390         } /* Request or Response */
00391         coap_free_header(message);
00392     } /* if (parsed correctly) */
00393     else
00394     {
00395         LOG_ARG("Message parsing failed %u.%2u", coap_error_code >> 5, coap_error_code & 0x1F);
00396     }
00397 
00398     if (coap_error_code != NO_ERROR && coap_error_code != COAP_IGNORE)
00399     {
00400         LOG_ARG("ERROR %u: %s", coap_error_code, coap_error_message);
00401 
00402         /* Set to sendable error code. */
00403         if (coap_error_code >= 192)
00404         {
00405             coap_error_code = COAP_500_INTERNAL_SERVER_ERROR;
00406         }
00407         /* Reuse input buffer for error message. */
00408         coap_init_message(message, COAP_TYPE_ACK, coap_error_code, message->mid);
00409         coap_set_payload(message, coap_error_message, strlen(coap_error_message));
00410         message_send(contextP, message, fromSessionH);
00411     }
00412 }
00413 
00414 
00415 coap_status_t message_send(lwm2m_context_t * contextP,
00416                            coap_packet_t * message,
00417                            void * sessionH)
00418 {
00419     coap_status_t result = COAP_500_INTERNAL_SERVER_ERROR;
00420     uint8_t * pktBuffer;
00421     size_t pktBufferLen = 0;
00422     size_t allocLen;
00423 
00424     LOG("Entering");
00425     allocLen = coap_serialize_get_size(message);
00426     LOG_ARG("Size to allocate: %d", allocLen);
00427     if (allocLen == 0) return COAP_500_INTERNAL_SERVER_ERROR;
00428 
00429     pktBuffer = (uint8_t *)lwm2m_malloc(allocLen);
00430     if (pktBuffer != NULL)
00431     {
00432         pktBufferLen = coap_serialize_message(message, pktBuffer);
00433         LOG_ARG("coap_serialize_message() returned %d", pktBufferLen);
00434         if (0 != pktBufferLen)
00435         {
00436             result = lwm2m_buffer_send(sessionH, pktBuffer, pktBufferLen, contextP->userData);
00437         }
00438         lwm2m_free(pktBuffer);
00439     }
00440 
00441     return result;
00442 }
00443