New initial commit

This commit is contained in:
mward 2014-07-16 13:34:01 -04:00
commit b1691d28c5
38 changed files with 10082 additions and 0 deletions

26
.gitignore vendored Normal file
View File

@ -0,0 +1,26 @@
*.o
*.lo
*~
*.la
*.pc
*.tgz
*.gz
.dirstamp
Makefile
.cproject
.project
CMakeCache.txt
CMakeFiles
Debug
Release
cmake_install.cmake
core/CMakeCache.txt
core/CMakeFiles
core/Makefile
core/cmake_install.cmake
lwm2mclient
lwm2mserver
tlvdecode

30
EDL-v1.0 Normal file
View File

@ -0,0 +1,30 @@
*Eclipse Distribution License - v 1.0*
Copyright (c) 2007, Eclipse Foundation, Inc. and its licensors.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Eclipse Foundation, Inc. nor the names of
its contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

224
EPL-v1.0 Normal file
View File

@ -0,0 +1,224 @@
Eclipse Public License - v 1.0
THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE
PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF
THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
*1. DEFINITIONS*
"Contribution" means:
a) in the case of the initial Contributor, the initial code and
documentation distributed under this Agreement, and
b) in the case of each subsequent Contributor:
i) changes to the Program, and
ii) additions to the Program;
where such changes and/or additions to the Program originate from and
are distributed by that particular Contributor. A Contribution
'originates' from a Contributor if it was added to the Program by such
Contributor itself or anyone acting on such Contributor's behalf.
Contributions do not include additions to the Program which: (i) are
separate modules of software distributed in conjunction with the Program
under their own license agreement, and (ii) are not derivative works of
the Program.
"Contributor" means any person or entity that distributes the Program.
"Licensed Patents" mean patent claims licensable by a Contributor which
are necessarily infringed by the use or sale of its Contribution alone
or when combined with the Program.
"Program" means the Contributions distributed in accordance with this
Agreement.
"Recipient" means anyone who receives the Program under this Agreement,
including all Contributors.
*2. GRANT OF RIGHTS*
a) Subject to the terms of this Agreement, each Contributor hereby
grants Recipient a non-exclusive, worldwide, royalty-free copyright
license to reproduce, prepare derivative works of, publicly display,
publicly perform, distribute and sublicense the Contribution of such
Contributor, if any, and such derivative works, in source code and
object code form.
b) Subject to the terms of this Agreement, each Contributor hereby
grants Recipient a non-exclusive, worldwide, royalty-free patent license
under Licensed Patents to make, use, sell, offer to sell, import and
otherwise transfer the Contribution of such Contributor, if any, in
source code and object code form. This patent license shall apply to the
combination of the Contribution and the Program if, at the time the
Contribution is added by the Contributor, such addition of the
Contribution causes such combination to be covered by the Licensed
Patents. The patent license shall not apply to any other combinations
which include the Contribution. No hardware per se is licensed hereunder.
c) Recipient understands that although each Contributor grants the
licenses to its Contributions set forth herein, no assurances are
provided by any Contributor that the Program does not infringe the
patent or other intellectual property rights of any other entity. Each
Contributor disclaims any liability to Recipient for claims brought by
any other entity based on infringement of intellectual property rights
or otherwise. As a condition to exercising the rights and licenses
granted hereunder, each Recipient hereby assumes sole responsibility to
secure any other intellectual property rights needed, if any. For
example, if a third party patent license is required to allow Recipient
to distribute the Program, it is Recipient's responsibility to acquire
that license before distributing the Program.
d) Each Contributor represents that to its knowledge it has sufficient
copyright rights in its Contribution, if any, to grant the copyright
license set forth in this Agreement.
*3. REQUIREMENTS*
A Contributor may choose to distribute the Program in object code form
under its own license agreement, provided that:
a) it complies with the terms and conditions of this Agreement; and
b) its license agreement:
i) effectively disclaims on behalf of all Contributors all warranties
and conditions, express and implied, including warranties or conditions
of title and non-infringement, and implied warranties or conditions of
merchantability and fitness for a particular purpose;
ii) effectively excludes on behalf of all Contributors all liability for
damages, including direct, indirect, special, incidental and
consequential damages, such as lost profits;
iii) states that any provisions which differ from this Agreement are
offered by that Contributor alone and not by any other party; and
iv) states that source code for the Program is available from such
Contributor, and informs licensees how to obtain it in a reasonable
manner on or through a medium customarily used for software exchange.
When the Program is made available in source code form:
a) it must be made available under this Agreement; and
b) a copy of this Agreement must be included with each copy of the Program.
Contributors may not remove or alter any copyright notices contained
within the Program.
Each Contributor must identify itself as the originator of its
Contribution, if any, in a manner that reasonably allows subsequent
Recipients to identify the originator of the Contribution.
*4. COMMERCIAL DISTRIBUTION*
Commercial distributors of software may accept certain responsibilities
with respect to end users, business partners and the like. While this
license is intended to facilitate the commercial use of the Program, the
Contributor who includes the Program in a commercial product offering
should do so in a manner which does not create potential liability for
other Contributors. Therefore, if a Contributor includes the Program in
a commercial product offering, such Contributor ("Commercial
Contributor") hereby agrees to defend and indemnify every other
Contributor ("Indemnified Contributor") against any losses, damages and
costs (collectively "Losses") arising from claims, lawsuits and other
legal actions brought by a third party against the Indemnified
Contributor to the extent caused by the acts or omissions of such
Commercial Contributor in connection with its distribution of the
Program in a commercial product offering. The obligations in this
section do not apply to any claims or Losses relating to any actual or
alleged intellectual property infringement. In order to qualify, an
Indemnified Contributor must: a) promptly notify the Commercial
Contributor in writing of such claim, and b) allow the Commercial
Contributor to control, and cooperate with the Commercial Contributor
in, the defense and any related settlement negotiations. The Indemnified
Contributor may participate in any such claim at its own expense.
For example, a Contributor might include the Program in a commercial
product offering, Product X. That Contributor is then a Commercial
Contributor. If that Commercial Contributor then makes performance
claims, or offers warranties related to Product X, those performance
claims and warranties are such Commercial Contributor's responsibility
alone. Under this section, the Commercial Contributor would have to
defend claims against the other Contributors related to those
performance claims and warranties, and if a court requires any other
Contributor to pay any damages as a result, the Commercial Contributor
must pay those damages.
*5. NO WARRANTY*
EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED
ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES
OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR
A PARTICULAR PURPOSE. Each Recipient is solely responsible for
determining the appropriateness of using and distributing the Program
and assumes all risks associated with its exercise of rights under this
Agreement , including but not limited to the risks and costs of program
errors, compliance with applicable laws, damage to or loss of data,
programs or equipment, and unavailability or interruption of operations.
*6. DISCLAIMER OF LIABILITY*
EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR
ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING
WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR
DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*7. GENERAL*
If any provision of this Agreement is invalid or unenforceable under
applicable law, it shall not affect the validity or enforceability of
the remainder of the terms of this Agreement, and without further action
by the parties hereto, such provision shall be reformed to the minimum
extent necessary to make such provision valid and enforceable.
If Recipient institutes patent litigation against any entity (including
a cross-claim or counterclaim in a lawsuit) alleging that the Program
itself (excluding combinations of the Program with other software or
hardware) infringes such Recipient's patent(s), then such Recipient's
rights granted under Section 2(b) shall terminate as of the date such
litigation is filed.
All Recipient's rights under this Agreement shall terminate if it fails
to comply with any of the material terms or conditions of this Agreement
and does not cure such failure in a reasonable period of time after
becoming aware of such noncompliance. If all Recipient's rights under
this Agreement terminate, Recipient agrees to cease use and distribution
of the Program as soon as reasonably practicable. However, Recipient's
obligations under this Agreement and any licenses granted by Recipient
relating to the Program shall continue and survive.
Everyone is permitted to copy and distribute copies of this Agreement,
but in order to avoid inconsistency the Agreement is copyrighted and may
only be modified in the following manner. The Agreement Steward reserves
the right to publish new versions (including revisions) of this
Agreement from time to time. No one other than the Agreement Steward has
the right to modify this Agreement. The Eclipse Foundation is the
initial Agreement Steward. The Eclipse Foundation may assign the
responsibility to serve as the Agreement Steward to a suitable separate
entity. Each new version of the Agreement will be given a distinguishing
version number. The Program (including Contributions) may always be
distributed subject to the version of the Agreement under which it was
received. In addition, after a new version of the Agreement is
published, Contributor may elect to distribute the Program (including
its Contributions) under the new version. Except as expressly stated in
Sections 2(a) and 2(b) above, Recipient receives no rights or licenses
to the intellectual property of any Contributor under this Agreement,
whether expressly, by implication, estoppel or otherwise. All rights in
the Program not expressly granted under this Agreement are reserved.
This Agreement is governed by the laws of the State of New York and the
intellectual property laws of the United States of America. No party to
this Agreement will bring a legal action under this Agreement more than
one year after the cause of action arose. Each party waives its rights
to a jury trial in any resulting litigation.

80
README Normal file
View File

@ -0,0 +1,80 @@
Wakaama (formerly liblwm2m) is an implementation of the Open Mobile Alliance's LightWeight M2M
protocol (LWM2M).
Source Layout
-------------
-+- core (the LWM2M engine)
| |
| +- er-coap-13 (Erbium's CoAP engine from
| http://people.inf.ethz.ch/mkovatsc/erbium.php, modified
| to run on linux)
|
+- tests (example and test application)
|
+- client (a command-line LWM2M client with two test objects)
|
+- server (a command-line LWM2M server)
|
+- TLV (application decoding two hard-coded TLV buffers)
|
+- utils (utility functions for connection handling and command-
line interface)
Compiling
---------
Despite its name, liblwm2m is not a library but files to be built with an
application. liblwm2m uses CMake. Look at tests/server/CMakeLists.txt for an
example of how to include it.
Two compilation switches are used: LWM2M_CLIENT_MODE and LWM2M_SERVER_MODE.
Define LWM2M_CLIENT_MODE to enable LWM2M Client interfaces. Define
LWM2M_SERVER_MODE to enable LWM2M Server interfaces. Both can be defined at the
same time.
Testing
-------
To compile the test server
- - - - - - - - - - - - -
In the any directory, run the following commands:
cmake [liblwm2m directory]/tests/server
make
./lwm2mserver
The lwm2mserver listens on UDP port 5684. It features a basic command line
interface. Type 'help' for a list of supported commands.
To compile the test client
- - - - - - - - - - - - -
In the any directory, run the following commands:
cmake [liblwm2m directory]/tests/client
make
./lwm2mclient
The lwm2mclient features four LWM2M objects:
- Server Object (id: 1) provided by the core.
- Device Object (id: 3) containing hard-coded values from the Example LWM2M
Client of Appendix E of the LWM2M Technical Specification.
- FirmwareUpdate Object (id: 5) as a skeleton.
- a test object (id: 1024) with the following description:
Multiple
Object | ID | Instances | Mandatoty |
Test | 1024 | Yes | No |
Ressources:
Supported Multiple
Name | ID | Operations | Instances | Mandatory | Type | Range |
test | 1 | R/W | No | Yes | Integer | 0-255 |
exec | 2 | E | No | Yes | | |
The lwm2mclient opens udp port 5683 and tries to register to a LWM2M Server at
127.0.0.1:5684. It features a basic command line interface. Type 'help' for a
list of supported commands.

54
TODO Normal file
View File

@ -0,0 +1,54 @@
LWM2M Features
--------------
- LWM2M Security and LWM2M Server Objects:
Implement these two objects in core as interfaces to lwm2m_server_t instances.
Forbid clients to add objects with ID 0 or 1.
* dnav WORKING ON IT *
- Bootstrap interface:
Implements LWM2M Bootstap Server as a special instance of lwm2m_server_t.
- Access Control List
- JSON support
- Add token in every message
- Handle Observe parameters
- Keep-alive mechanism
Implementation Improvments
--------------------------
- Store lwm2m_transaction_t per peer
- bufferize all CoaP messages until all callbacks returned
Currently if a server sends a request from its monitoring callback upon client
registration, the client will receive the request before the ACK to its register
and it will discard it.
- Easy access to the lwm2m_context_t from objects callbacks
- Allow object callbacks to return static buffers
This can be done by a flag stating if the retruned buffer must be freed or not by the core.
- Simplify lwm2m_uri_t handling
Basically hide the flag member.
- Use an unified result callback
Add some parameter so that the same user callback can be used for all DM operations.
- Use lwm2m-*-t types in er-coap-13
To avoid multiple conversions.
- Switch to void* parameters in lwm2m_list_* APIs
- Change object interface to hide the whole TLV mechanism
Useful when the core will support JSON.
- Utility functions to easily implements objects
The utility will just use read and write individual resources. Either statically or
throught callbacks. See [https://github.com/01org/libdmclient]/tests/mgtobj/utils/static_mo_util.h

46
about.html Normal file
View File

@ -0,0 +1,46 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
<title>About</title>
</head>
<body lang="EN-US">
<h2>About This Content</h2>
<p>April 24, 2014</p>
<h3>License</h3>
<p>The Eclipse Foundation makes available all content in this plug-in (&quot;Content&quot;). Unless otherwise
indicated below, the Content is provided to you under the terms and conditions of the
Eclipse Public License Version 1.0 (&quot;EPL&quot;) and the Eclipse Distribution License Version 1.0 (&quot;EDL&quot;).
A copy of the EPL is available at
<a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
A copy of the EDL is available at
<a href="http://www.eclipse.org/org/documents/edl-v10.php">http://www.eclipse.org/org/documents/edl-v10.php</a>.
For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
being redistributed by another party (&quot;Redistributor&quot;) and different terms and conditions may
apply to your use of any object code in the Content. Check the Redistributor's license that was
provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
indicated below, the terms and conditions of the EPL still apply to any source code in the Content
and such source code may be obtained at <a href="http://www.eclipse.org/">http://www.eclipse.org</a>.</p>
<h3>Third Party Content</h3>
<p>The Content includes items that have been sourced from third parties as set out below. If you
did not receive this Content directly from the Eclipse Foundation, the following is provided
for informational purposes only, and you should look to the Redistributor's license for
terms and conditions of use.</p>
<p>
<strong>er-coap-13</strong> <br/><br/>
Erbium's CoAP engine from
<a href="http://people.inf.ethz.ch/mkovatsc/erbium.php">http://people.inf.ethz.ch/mkovatsc/erbium.php</a>
Your use of er-coap-13 is subject to the terms and conditions of the BSD license contained in the file LICENSE
in core/er-coap-13
</p>
</body>
</html>

16
core/CMakeLists.txt Normal file
View File

@ -0,0 +1,16 @@
SET(EXT_SOURCES ${CMAKE_CURRENT_LIST_DIR}/er-coap-13/er-coap-13.c)
SET(CORE_SOURCES
${CMAKE_CURRENT_LIST_DIR}/liblwm2m.c
${CMAKE_CURRENT_LIST_DIR}/uri.c
${CMAKE_CURRENT_LIST_DIR}/utils.c
${CMAKE_CURRENT_LIST_DIR}/objects.c
${CMAKE_CURRENT_LIST_DIR}/object_server.c
${CMAKE_CURRENT_LIST_DIR}/tlv.c
${CMAKE_CURRENT_LIST_DIR}/list.c
${CMAKE_CURRENT_LIST_DIR}/packet.c
${CMAKE_CURRENT_LIST_DIR}/transaction.c
${CMAKE_CURRENT_LIST_DIR}/registration.c
${CMAKE_CURRENT_LIST_DIR}/management.c
${CMAKE_CURRENT_LIST_DIR}/observe.c
${EXT_SOURCES}
PARENT_SCOPE)

30
core/er-coap-13/LICENSE Normal file
View File

@ -0,0 +1,30 @@
/*
* Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file is part of the Contiki operating system.
*/

1294
core/er-coap-13/er-coap-13.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,401 @@
/*
* Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file is part of the Contiki operating system.
*/
/**
* \file
* An implementation of the Constrained Application Protocol (draft 12)
* \author
* Matthias Kovatsch <kovatsch@inf.ethz.ch>
*/
/*******************************************************************************
*
* This file is made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* The Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* David Navarro, Intel Corporation - Adapt to usage in liblwm2m
*
*******************************************************************************/
#ifndef COAP_13_H_
#define COAP_13_H_
#include <stdint.h>
#include <stddef.h> /* for size_t */
#include <signal.h>
#include <time.h>
/*
* The maximum buffer size that is provided for resource responses and must be respected due to the limited IP buffer.
* Larger data must be handled by the resource and will be sent chunk-wise through a TCP stream or CoAP blocks.
*/
#ifndef REST_MAX_CHUNK_SIZE
#define REST_MAX_CHUNK_SIZE 128
#endif
#define COAP_DEFAULT_MAX_AGE 60
#define COAP_RESPONSE_TIMEOUT 2
#define COAP_MAX_RETRANSMIT 4
#define COAP_HEADER_LEN 4 /* | version:0x03 type:0x0C tkl:0xF0 | code | mid:0x00FF | mid:0xFF00 | */
#define COAP_ETAG_LEN 8 /* The maximum number of bytes for the ETag */
#define COAP_TOKEN_LEN 8 /* The maximum number of bytes for the Token */
#define COAP_MAX_ACCEPT_NUM 2 /* The maximum number of accept preferences to parse/store */
#define COAP_HEADER_VERSION_MASK 0xC0
#define COAP_HEADER_VERSION_POSITION 6
#define COAP_HEADER_TYPE_MASK 0x30
#define COAP_HEADER_TYPE_POSITION 4
#define COAP_HEADER_TOKEN_LEN_MASK 0x0F
#define COAP_HEADER_TOKEN_LEN_POSITION 0
#define COAP_HEADER_OPTION_DELTA_MASK 0xF0
#define COAP_HEADER_OPTION_SHORT_LENGTH_MASK 0x0F
/*
* Conservative size limit, as not all options have to be set at the same time.
*/
#ifndef COAP_MAX_HEADER_SIZE
/* Hdr CoT Age Tag Obs Tok Blo strings */
#define COAP_MAX_HEADER_SIZE (4 + 3 + 5 + 1+COAP_ETAG_LEN + 3 + 1+COAP_TOKEN_LEN + 4 + 30) /* 70 */
#endif /* COAP_MAX_HEADER_SIZE */
#define COAP_MAX_PACKET_SIZE (COAP_MAX_HEADER_SIZE + REST_MAX_CHUNK_SIZE)
/* 0/14 48 for IPv6 (28 for IPv4) */
#if COAP_MAX_PACKET_SIZE > (UIP_BUFSIZE - UIP_LLH_LEN - UIP_IPUDPH_LEN)
//#error "UIP_CONF_BUFFER_SIZE too small for REST_MAX_CHUNK_SIZE"
#endif
/* Bitmap for set options */
enum { OPTION_MAP_SIZE = sizeof(uint8_t) * 8 };
#define SET_OPTION(packet, opt) ((packet)->options[opt / OPTION_MAP_SIZE] |= 1 << (opt % OPTION_MAP_SIZE))
#define IS_OPTION(packet, opt) ((packet)->options[opt / OPTION_MAP_SIZE] & (1 << (opt % OPTION_MAP_SIZE)))
#ifndef MIN
#define MIN(a, b) ((a) < (b)? (a) : (b))
#endif /* MIN */
/* CoAP message types */
typedef enum {
COAP_TYPE_CON, /* confirmables */
COAP_TYPE_NON, /* non-confirmables */
COAP_TYPE_ACK, /* acknowledgements */
COAP_TYPE_RST /* reset */
} coap_message_type_t;
/* CoAP request method codes */
typedef enum {
COAP_GET = 1,
COAP_POST,
COAP_PUT,
COAP_DELETE
} coap_method_t;
/* CoAP response codes */
typedef enum {
NO_ERROR = 0,
CREATED_2_01 = 65, /* CREATED */
DELETED_2_02 = 66, /* DELETED */
VALID_2_03 = 67, /* NOT_MODIFIED */
CHANGED_2_04 = 68, /* CHANGED */
CONTENT_2_05 = 69, /* OK */
BAD_REQUEST_4_00 = 128, /* BAD_REQUEST */
UNAUTHORIZED_4_01 = 129, /* UNAUTHORIZED */
BAD_OPTION_4_02 = 130, /* BAD_OPTION */
FORBIDDEN_4_03 = 131, /* FORBIDDEN */
NOT_FOUND_4_04 = 132, /* NOT_FOUND */
METHOD_NOT_ALLOWED_4_05 = 133, /* METHOD_NOT_ALLOWED */
NOT_ACCEPTABLE_4_06 = 134, /* NOT_ACCEPTABLE */
PRECONDITION_FAILED_4_12 = 140, /* BAD_REQUEST */
REQUEST_ENTITY_TOO_LARGE_4_13 = 141, /* REQUEST_ENTITY_TOO_LARGE */
UNSUPPORTED_MEDIA_TYPE_4_15 = 143, /* UNSUPPORTED_MEDIA_TYPE */
INTERNAL_SERVER_ERROR_5_00 = 160, /* INTERNAL_SERVER_ERROR */
NOT_IMPLEMENTED_5_01 = 161, /* NOT_IMPLEMENTED */
BAD_GATEWAY_5_02 = 162, /* BAD_GATEWAY */
SERVICE_UNAVAILABLE_5_03 = 163, /* SERVICE_UNAVAILABLE */
GATEWAY_TIMEOUT_5_04 = 164, /* GATEWAY_TIMEOUT */
PROXYING_NOT_SUPPORTED_5_05 = 165, /* PROXYING_NOT_SUPPORTED */
/* Erbium errors */
MEMORY_ALLOCATION_ERROR = 192,
PACKET_SERIALIZATION_ERROR,
/* Erbium hooks */
MANUAL_RESPONSE
} coap_status_t;
/* CoAP header options */
typedef enum {
COAP_OPTION_IF_MATCH = 1, /* 0-8 B */
COAP_OPTION_URI_HOST = 3, /* 1-255 B */
COAP_OPTION_ETAG = 4, /* 1-8 B */
COAP_OPTION_IF_NONE_MATCH = 5, /* 0 B */
COAP_OPTION_OBSERVE = 6, /* 0-3 B */
COAP_OPTION_URI_PORT = 7, /* 0-2 B */
COAP_OPTION_LOCATION_PATH = 8, /* 0-255 B */
COAP_OPTION_URI_PATH = 11, /* 0-255 B */
COAP_OPTION_CONTENT_TYPE = 12, /* 0-2 B */
COAP_OPTION_MAX_AGE = 14, /* 0-4 B */
COAP_OPTION_URI_QUERY = 15, /* 0-270 B */
COAP_OPTION_ACCEPT = 16, /* 0-2 B */
COAP_OPTION_TOKEN = 19, /* 1-8 B */
COAP_OPTION_LOCATION_QUERY = 20, /* 1-270 B */
COAP_OPTION_BLOCK2 = 23, /* 1-3 B */
COAP_OPTION_BLOCK1 = 27, /* 1-3 B */
COAP_OPTION_SIZE = 28, /* 0-4 B */
COAP_OPTION_PROXY_URI = 35, /* 1-270 B */
} coap_option_t;
/* CoAP Content-Types */
typedef enum {
TEXT_PLAIN = 0,
TEXT_XML = 1, /* Indented types are not in the initial registry. */
TEXT_CSV = 2,
TEXT_HTML = 3,
IMAGE_GIF = 21,
IMAGE_JPEG = 22,
IMAGE_PNG = 23,
IMAGE_TIFF = 24,
AUDIO_RAW = 25,
VIDEO_RAW = 26,
APPLICATION_LINK_FORMAT = 40,
APPLICATION_XML = 41,
APPLICATION_OCTET_STREAM = 42,
APPLICATION_RDF_XML = 43,
APPLICATION_SOAP_XML = 44,
APPLICATION_ATOM_XML = 45,
APPLICATION_XMPP_XML = 46,
APPLICATION_EXI = 47,
APPLICATION_FASTINFOSET = 48,
APPLICATION_SOAP_FASTINFOSET = 49,
APPLICATION_JSON = 50,
APPLICATION_X_OBIX_BINARY = 51
} coap_content_type_t;
typedef struct _multi_option_t {
struct _multi_option_t *next;
uint8_t is_static;
uint8_t len;
char *data;
} multi_option_t;
/* Parsed message struct */
typedef struct {
uint8_t *buffer; /* pointer to CoAP header / incoming packet buffer / memory to serialize packet */
uint8_t version;
coap_message_type_t type;
uint8_t code;
uint16_t mid;
uint8_t options[COAP_OPTION_PROXY_URI / OPTION_MAP_SIZE + 1]; /* Bitmap to check if option is set */
coap_content_type_t content_type; /* Parse options once and store; allows setting options in random order */
uint32_t max_age;
size_t proxy_uri_len;
const char *proxy_uri;
uint8_t etag_len;
uint8_t etag[COAP_ETAG_LEN];
size_t uri_host_len;
const char *uri_host;
multi_option_t *location_path;
uint16_t uri_port;
size_t location_query_len;
const char *location_query;
multi_option_t *uri_path;
uint32_t observe;
uint8_t token_len;
uint8_t token[COAP_TOKEN_LEN];
uint8_t accept_num;
uint16_t accept[COAP_MAX_ACCEPT_NUM];
uint8_t if_match_len;
uint8_t if_match[COAP_ETAG_LEN];
uint32_t block2_num;
uint8_t block2_more;
uint16_t block2_size;
uint32_t block2_offset;
uint32_t block1_num;
uint8_t block1_more;
uint16_t block1_size;
uint32_t block1_offset;
uint32_t size;
multi_option_t *uri_query;
uint8_t if_none_match;
uint16_t payload_len;
uint8_t *payload;
} coap_packet_t;
/* Option format serialization*/
#define COAP_SERIALIZE_INT_OPTION(number, field, text) \
if (IS_OPTION(coap_pkt, number)) { \
PRINTF(text" [%u]\n", coap_pkt->field); \
option += coap_serialize_int_option(number, current_number, option, coap_pkt->field); \
current_number = number; \
}
#define COAP_SERIALIZE_BYTE_OPTION(number, field, text) \
if (IS_OPTION(coap_pkt, number)) { \
PRINTF(text" %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", coap_pkt->field##_len, \
coap_pkt->field[0], \
coap_pkt->field[1], \
coap_pkt->field[2], \
coap_pkt->field[3], \
coap_pkt->field[4], \
coap_pkt->field[5], \
coap_pkt->field[6], \
coap_pkt->field[7] \
); /*FIXME always prints 8 bytes */ \
option += coap_serialize_array_option(number, current_number, option, coap_pkt->field, coap_pkt->field##_len, '\0'); \
current_number = number; \
}
#define COAP_SERIALIZE_STRING_OPTION(number, field, splitter, text) \
if (IS_OPTION(coap_pkt, number)) { \
PRINTF(text" [%.*s]\n", coap_pkt->field##_len, coap_pkt->field); \
option += coap_serialize_array_option(number, current_number, option, (uint8_t *) coap_pkt->field, coap_pkt->field##_len, splitter); \
current_number = number; \
}
#define COAP_SERIALIZE_MULTI_OPTION(number, field, text) \
if (IS_OPTION(coap_pkt, number)) { \
PRINTF(text); \
option += coap_serialize_multi_option(number, current_number, option, coap_pkt->field); \
current_number = number; \
}
#define COAP_SERIALIZE_ACCEPT_OPTION(number, field, text) \
if (IS_OPTION(coap_pkt, number)) { \
int i; \
for (i=0; i<coap_pkt->field##_num; ++i) \
{ \
PRINTF(text" [%u]\n", coap_pkt->field[i]); \
option += coap_serialize_int_option(number, current_number, option, coap_pkt->field[i]); \
current_number = number; \
} \
}
#define COAP_SERIALIZE_BLOCK_OPTION(number, field, text) \
if (IS_OPTION(coap_pkt, number)) \
{ \
PRINTF(text" [%lu%s (%u B/blk)]\n", coap_pkt->field##_num, coap_pkt->field##_more ? "+" : "", coap_pkt->field##_size); \
uint32_t block = coap_pkt->field##_num << 4; \
if (coap_pkt->field##_more) block |= 0x8; \
block |= 0xF & coap_log_2(coap_pkt->field##_size/16); \
PRINTF(text" encoded: 0x%lX\n", block); \
option += coap_serialize_int_option(number, current_number, option, block); \
current_number = number; \
}
/* To store error code and human-readable payload */
extern coap_status_t coap_error_code;
extern char *coap_error_message;
uint16_t coap_get_mid(void);
void coap_init_message(void *packet, coap_message_type_t type, uint8_t code, uint16_t mid);
size_t coap_serialize_message(void *packet, uint8_t *buffer);
coap_status_t coap_parse_message(void *request, uint8_t *data, uint16_t data_len);
void coap_free_header(void *packet);
char * coap_get_multi_option_as_string(multi_option_t * option);
int coap_get_query_variable(void *packet, const char *name, const char **output);
int coap_get_post_variable(void *packet, const char *name, const char **output);
/*-----------------------------------------------------------------------------------*/
int coap_set_status_code(void *packet, unsigned int code);
unsigned int coap_get_header_content_type(void *packet);
int coap_set_header_content_type(void *packet, unsigned int content_type);
int coap_get_header_accept(void *packet, const uint16_t **accept);
int coap_set_header_accept(void *packet, uint16_t accept);
int coap_get_header_max_age(void *packet, uint32_t *age);
int coap_set_header_max_age(void *packet, uint32_t age);
int coap_get_header_etag(void *packet, const uint8_t **etag);
int coap_set_header_etag(void *packet, const uint8_t *etag, size_t etag_len);
int coap_get_header_if_match(void *packet, const uint8_t **etag);
int coap_set_header_if_match(void *packet, const uint8_t *etag, size_t etag_len);
int coap_get_header_if_none_match(void *packet);
int coap_set_header_if_none_match(void *packet);
int coap_get_header_token(void *packet, const uint8_t **token);
int coap_set_header_token(void *packet, const uint8_t *token, size_t token_len);
int coap_get_header_proxy_uri(void *packet, const char **uri); /* In-place string might not be 0-terminated. */
int coap_set_header_proxy_uri(void *packet, const char *uri);
int coap_get_header_uri_host(void *packet, const char **host); /* In-place string might not be 0-terminated. */
int coap_set_header_uri_host(void *packet, const char *host);
int coap_get_header_uri_path(void *packet, const char **path); /* In-place string might not be 0-terminated. */
int coap_set_header_uri_path(void *packet, const char *path);
int coap_set_header_uri_path_segment(void *packet, const char *path);
int coap_get_header_uri_query(void *packet, const char **query); /* In-place string might not be 0-terminated. */
int coap_set_header_uri_query(void *packet, const char *query);
int coap_get_header_location_path(void *packet, const char **path); /* In-place string might not be 0-terminated. */
int coap_set_header_location_path(void *packet, const char *path); /* Also splits optional query into Location-Query option. */
int coap_get_header_location_query(void *packet, const char **query); /* In-place string might not be 0-terminated. */
int coap_set_header_location_query(void *packet, const char *query);
int coap_get_header_observe(void *packet, uint32_t *observe);
int coap_set_header_observe(void *packet, uint32_t observe);
int coap_get_header_block2(void *packet, uint32_t *num, uint8_t *more, uint16_t *size, uint32_t *offset);
int coap_set_header_block2(void *packet, uint32_t num, uint8_t more, uint16_t size);
int coap_get_header_block1(void *packet, uint32_t *num, uint8_t *more, uint16_t *size, uint32_t *offset);
int coap_set_header_block1(void *packet, uint32_t num, uint8_t more, uint16_t size);
int coap_get_header_size(void *packet, uint32_t *size);
int coap_set_header_size(void *packet, uint32_t size);
int coap_get_payload(void *packet, const uint8_t **payload);
int coap_set_payload(void *packet, const void *payload, size_t length);
#endif /* COAP_13_H_ */

147
core/internals.h Normal file
View File

@ -0,0 +1,147 @@
/*******************************************************************************
*
* Copyright (c) 2013, 2014 Intel Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* The Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* David Navarro, Intel Corporation - initial API and implementation
* Fabien Fleutot - Please refer to git log
* Toby Jaffey - Please refer to git log
*
*******************************************************************************/
/*
Copyright (c) 2013, 2014 Intel Corporation
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of Intel Corporation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
David Navarro <david.navarro@intel.com>
*/
#ifndef _LWM2M_INTERNALS_H_
#define _LWM2M_INTERNALS_H_
#include "liblwm2m.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include "er-coap-13/er-coap-13.h"
#ifdef WITH_LOGS
#define LOG(...) fprintf(stderr, __VA_ARGS__)
#else
#define LOG(...)
#endif
#define LWM2M_MAX_PACKET_SIZE 198
#define LWM2M_SECURITY_OBJECT_ID 0
#define LWM2M_SERVER_OBJECT_ID 1
#define LWM2M_ACL_OBJECT_ID 2
#define URI_REGISTRATION_SEGMENT "rd"
#define URI_REGISTRATION_SEGMENT_LEN 2
#define URI_BOOTSTRAP_SEGMENT "bs"
#define URI_BOOTSTRAP_SEGMENT_LEN 2
#define LWM2M_URI_FLAG_DM (uint8_t)0x00
#define LWM2M_URI_FLAG_REGISTRATION (uint8_t)0x20
#define LWM2M_URI_FLAG_BOOTSTRAP (uint8_t)0x40
#define LWM2M_URI_MASK_TYPE (uint8_t)0x70
#define LWM2M_URI_MASK_ID (uint8_t)0x07
typedef struct
{
lwm2m_uri_t uri;
lwm2m_result_callback_t callback;
void * userData;
} dm_data_t;
typedef struct _obs_list_
{
struct _obs_list_ * next;
lwm2m_observed_t * item;
} obs_list_t;
// defined in uri.c
int prv_get_number(const char * uriString, size_t uriLength);
lwm2m_uri_t * lwm2m_decode_uri(multi_option_t *uriPath);
// defined in objects.c
coap_status_t object_read(lwm2m_context_t * contextP, lwm2m_uri_t * uriP, char ** bufferP, int * lengthP);
coap_status_t object_write(lwm2m_context_t * contextP, lwm2m_uri_t * uriP, char * buffer, int length);
coap_status_t object_create(lwm2m_context_t * contextP, lwm2m_uri_t * uriP, char * buffer, int length);
coap_status_t object_execute(lwm2m_context_t * contextP, lwm2m_uri_t * uriP, char * buffer, int length);
coap_status_t object_delete(lwm2m_context_t * contextP, lwm2m_uri_t * uriP);
bool object_isInstanceNew(lwm2m_context_t * contextP, uint16_t objectId, uint16_t instanceId);
int prv_getRegisterPayload(lwm2m_context_t * contextP, char * buffer, size_t length);
// defined in object_server.c
coap_status_t object_server_read(lwm2m_context_t * contextP, lwm2m_uri_t * uriP, char ** bufferP, int * lengthP);
coap_status_t object_server_write(lwm2m_context_t * contextP, lwm2m_uri_t * uriP, char * buffer, int length);
coap_status_t object_server_execute(lwm2m_context_t * contextP, lwm2m_uri_t * uriP, char * buffer, int length);
coap_status_t object_server_create(lwm2m_context_t * contextP, lwm2m_uri_t * uriP, char * buffer, int length);
coap_status_t object_server_delete(lwm2m_context_t * contextP, lwm2m_uri_t * uriP);
coap_status_t object_security_create(lwm2m_context_t * contextP, lwm2m_uri_t * uriP, char * buffer, int length);
coap_status_t object_security_delete(lwm2m_context_t * contextP, lwm2m_uri_t * uriP);
// defined in transaction.c
lwm2m_transaction_t * transaction_new(coap_method_t method, lwm2m_uri_t * uriP, uint16_t mID, lwm2m_endpoint_type_t peerType, void * peerP);
int transaction_send(lwm2m_context_t * contextP, lwm2m_transaction_t * transacP);
void transaction_free(lwm2m_transaction_t * transacP);
void transaction_remove(lwm2m_context_t * contextP, lwm2m_transaction_t * transacP);
void transaction_handle_response(lwm2m_context_t * contextP, void * fromSessionH, coap_packet_t * message);
// defined in management.c
coap_status_t handle_dm_request(lwm2m_context_t * contextP, lwm2m_uri_t * uriP, void * fromSessionH, coap_packet_t * message, coap_packet_t * response);
// defined in observe.c
coap_status_t handle_observe_request(lwm2m_context_t * contextP, lwm2m_uri_t * uriP, void * fromSessionH, coap_packet_t * message, coap_packet_t * response);
void cancel_observe(lwm2m_context_t * contextP, uint16_t mid, void * fromSessionH);
// defined in registration.c
coap_status_t handle_registration_request(lwm2m_context_t * contextP, lwm2m_uri_t * uriP, void * fromSessionH, coap_packet_t * message, coap_packet_t * response);
void registration_deregister(lwm2m_context_t * contextP, lwm2m_server_t * serverP);
void prv_freeClient(lwm2m_client_t * clientP);
// defined in packet.c
coap_status_t message_send(lwm2m_context_t * contextP, coap_packet_t * message, void * sessionH);
// defined in observe.c
void handle_observe_notify(lwm2m_context_t * contextP, void * fromSessionH, coap_packet_t * message);
#endif

290
core/liblwm2m.c Normal file
View File

@ -0,0 +1,290 @@
/*******************************************************************************
*
* Copyright (c) 2013, 2014 Intel Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* The Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* David Navarro, Intel Corporation - initial API and implementation
* Fabien Fleutot - Please refer to git log
* Simon Bernard - Please refer to git log
* Toby Jaffey - Please refer to git log
*
*******************************************************************************/
/*
Copyright (c) 2013, 2014 Intel Corporation
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of Intel Corporation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
David Navarro <david.navarro@intel.com>
*/
#include "internals.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
lwm2m_context_t * lwm2m_init(char * endpointName,
uint16_t numObject,
lwm2m_object_t * objectList[],
lwm2m_buffer_send_callback_t bufferSendCallback,
void * bufferSendUserData)
{
lwm2m_context_t * contextP;
if (NULL == bufferSendCallback)
return NULL;
#ifdef LWM2M_CLIENT_MODE
if (numObject != 0)
{
int i;
for (i = 0 ; i < numObject ; i++)
{
if (objectList[i]->objID <= LWM2M_ACL_OBJECT_ID)
{
// Use of a reserved object ID
return NULL;
}
}
}
#endif
contextP = (lwm2m_context_t *)lwm2m_malloc(sizeof(lwm2m_context_t));
if (NULL != contextP)
{
memset(contextP, 0, sizeof(lwm2m_context_t));
contextP->bufferSendCallback = bufferSendCallback;
contextP->bufferSendUserData = bufferSendUserData;
#ifdef LWM2M_CLIENT_MODE
contextP->endpointName = strdup(endpointName);
if (contextP->endpointName == NULL)
{
lwm2m_free(contextP);
return NULL;
}
if (numObject != 0)
{
contextP->objectList = (lwm2m_object_t **)lwm2m_malloc(numObject * sizeof(lwm2m_object_t *));
if (NULL != contextP->objectList)
{
memcpy(contextP->objectList, objectList, numObject * sizeof(lwm2m_object_t *));
contextP->numObject = numObject;
}
else
{
lwm2m_free(contextP->endpointName);
lwm2m_free(contextP);
return NULL;
}
}
#endif
}
return contextP;
}
void lwm2m_close(lwm2m_context_t * contextP)
{
int i;
#ifdef LWM2M_CLIENT_MODE
for (i = 0 ; i < contextP->numObject ; i++)
{
if (NULL != contextP->objectList[i]->closeFunc)
{
contextP->objectList[i]->closeFunc(contextP->objectList[i]);
}
lwm2m_free(contextP->objectList[i]);
}
if (NULL != contextP->bootstrapServer)
{
if (NULL != contextP->bootstrapServer->uri) lwm2m_free (contextP->bootstrapServer->uri);
if (NULL != contextP->bootstrapServer->security.privateKey) lwm2m_free (contextP->bootstrapServer->security.privateKey);
if (NULL != contextP->bootstrapServer->security.publicKey) lwm2m_free (contextP->bootstrapServer->security.publicKey);
lwm2m_free(contextP->bootstrapServer);
}
while (NULL != contextP->serverList)
{
lwm2m_server_t * targetP;
targetP = contextP->serverList;
contextP->serverList = contextP->serverList->next;
registration_deregister(contextP, targetP);
if (NULL != targetP->location) lwm2m_free(targetP->location);
if (NULL != targetP->security.privateKey) lwm2m_free (targetP->security.privateKey);
if (NULL != targetP->security.publicKey) lwm2m_free (targetP->security.publicKey);
lwm2m_free(targetP);
}
while (NULL != contextP->observedList)
{
lwm2m_observed_t * targetP;
targetP = contextP->observedList;
contextP->observedList = contextP->observedList->next;
while (NULL != targetP->watcherList)
{
lwm2m_watcher_t * watcherP;
watcherP = targetP->watcherList;
targetP->watcherList = targetP->watcherList->next;
lwm2m_free(watcherP);
}
lwm2m_free(targetP);
}
if (NULL != contextP->objectList)
{
lwm2m_free(contextP->objectList);
}
lwm2m_free(contextP->endpointName);
#endif
#ifdef LWM2M_SERVER_MODE
while (NULL != contextP->clientList)
{
lwm2m_client_t * clientP;
clientP = contextP->clientList;
contextP->clientList = contextP->clientList->next;
prv_freeClient(clientP);
}
#endif
while (NULL != contextP->transactionList)
{
lwm2m_transaction_t * transacP;
transacP = contextP->transactionList;
contextP->transactionList = contextP->transactionList->next;
transaction_free(transacP);
}
lwm2m_free(contextP);
}
#ifdef LWM2M_CLIENT_MODE
void lwm2m_set_bootstrap_server(lwm2m_context_t * contextP,
lwm2m_bootstrap_server_t * serverP)
{
if (NULL != contextP->bootstrapServer)
{
if (NULL != contextP->bootstrapServer->uri) lwm2m_free (contextP->bootstrapServer->uri);
if (NULL != contextP->bootstrapServer->security.privateKey) lwm2m_free (contextP->bootstrapServer->security.privateKey);
if (NULL != contextP->bootstrapServer->security.publicKey) lwm2m_free (contextP->bootstrapServer->security.publicKey);
lwm2m_free(contextP->bootstrapServer);
}
contextP->bootstrapServer = serverP;
}
int lwm2m_add_server(lwm2m_context_t * contextP,
uint16_t shortID,
void * sessionH,
lwm2m_security_t * securityP)
{
lwm2m_server_t * serverP;
int status = COAP_500_INTERNAL_SERVER_ERROR;
serverP = (lwm2m_server_t *)lwm2m_malloc(sizeof(lwm2m_server_t));
if (serverP != NULL)
{
memset(serverP, 0, sizeof(lwm2m_server_t));
memcpy(&(serverP->security), securityP, sizeof(lwm2m_security_t));
serverP->shortID = shortID;
serverP->sessionH = sessionH;
contextP->serverList = (lwm2m_server_t*)LWM2M_LIST_ADD(contextP->serverList, serverP);
status = COAP_NO_ERROR;
}
return status;
}
#endif
int lwm2m_step(lwm2m_context_t * contextP,
struct timeval * timeoutP)
{
lwm2m_transaction_t * transacP;
struct timeval tv;
if (0 != lwm2m_gettimeofday(&tv, NULL)) return COAP_500_INTERNAL_SERVER_ERROR;
transacP = contextP->transactionList;
while (transacP != NULL)
{
// transaction_send() may remove transaction from the linked list
lwm2m_transaction_t * nextP = transacP->next;
int removed = 0;
if (transacP->retrans_time <= tv.tv_sec)
{
removed = transaction_send(contextP, transacP);
}
if (0 == removed)
{
time_t interval;
if (transacP->retrans_time > tv.tv_sec)
{
interval = transacP->retrans_time - tv.tv_sec;
}
else
{
interval = 1;
}
if (timeoutP->tv_sec > interval)
{
timeoutP->tv_sec = interval;
}
}
transacP = nextP;
}
return 0;
}

490
core/liblwm2m.h Normal file
View File

@ -0,0 +1,490 @@
/*******************************************************************************
*
* Copyright (c) 2013, 2014 Intel Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* The Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* David Navarro, Intel Corporation - initial API and implementation
* Fabien Fleutot - Please refer to git log
* Simon Bernard - Please refer to git log
* Toby Jaffey - Please refer to git log
*
*******************************************************************************/
/*
Copyright (c) 2013, 2014 Intel Corporation
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of Intel Corporation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
David Navarro <david.navarro@intel.com>
*/
#ifndef _LWM2M_CLIENT_H_
#define _LWM2M_CLIENT_H_
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <sys/time.h>
#ifndef LWM2M_EMBEDDED_MODE
#define lwm2m_gettimeofday gettimeofday
#define lwm2m_malloc malloc
#define lwm2m_free free
#else
int lwm2m_gettimeofday(struct timeval *tv, void *p);
void *lwm2m_malloc(size_t s);
void lwm2m_free(void *p);
#endif
/*
* Error code
*/
#define COAP_NO_ERROR (uint8_t)0x00
#define COAP_201_CREATED (uint8_t)0x41
#define COAP_202_DELETED (uint8_t)0x42
#define COAP_204_CHANGED (uint8_t)0x44
#define COAP_205_CONTENT (uint8_t)0x45
#define COAP_400_BAD_REQUEST (uint8_t)0x80
#define COAP_401_UNAUTHORIZED (uint8_t)0x81
#define COAP_404_NOT_FOUND (uint8_t)0x84
#define COAP_405_METHOD_NOT_ALLOWED (uint8_t)0x85
#define COAP_406_NOT_ACCEPTABLE (uint8_t)0x86
#define COAP_500_INTERNAL_SERVER_ERROR (uint8_t)0xA0
#define COAP_501_NOT_IMPLEMENTED (uint8_t)0xA1
#define COAP_503_SERVICE_UNAVAILABLE (uint8_t)0xA3
/*
* Utility functions for sorted linked list
*/
typedef struct _lwm2m_list_t
{
struct _lwm2m_list_t * next;
uint16_t id;
} lwm2m_list_t;
// defined in list.c
// Add 'node' to the list 'head' and return the new list
lwm2m_list_t * lwm2m_list_add(lwm2m_list_t * head, lwm2m_list_t * node);
// Return the node with ID 'id' from the list 'head' or NULL if not found
lwm2m_list_t * lwm2m_list_find(lwm2m_list_t * head, uint16_t id);
// Remove the node with ID 'id' from the list 'head' and return the new list
lwm2m_list_t * lwm2m_list_remove(lwm2m_list_t * head, uint16_t id, lwm2m_list_t ** nodeP);
// Return the lowest unused ID in the list 'head'
uint16_t lwm2m_list_newId(lwm2m_list_t * head);
#define LWM2M_LIST_ADD(H,N) lwm2m_list_add((lwm2m_list_t *)H, (lwm2m_list_t *)N);
#define LWM2M_LIST_RM(H,I,N) lwm2m_list_remove((lwm2m_list_t *)H, I, (lwm2m_list_t **)N);
/*
* Resource values
*/
// defined in utils.c
int lwm2m_PlainTextToInt64(char * buffer, int length, int64_t * dataP);
/*
* These utility functions allocate a new buffer storing the plain text
* representation of data. They return the size in bytes of the buffer
* or 0 in case of error.
* There is no trailing '\0' character in the buffer.
*/
int lwm2m_int8ToPlainText(int8_t data, char ** bufferP);
int lwm2m_int16ToPlainText(int16_t data, char ** bufferP);
int lwm2m_int32ToPlainText(int32_t data, char ** bufferP);
int lwm2m_int64ToPlainText(int64_t data, char ** bufferP);
int lwm2m_float32ToPlainText(float data, char ** bufferP);
int lwm2m_float64ToPlainText(double data, char ** bufferP);
int lwm2m_boolToPlainText(bool data, char ** bufferP);
/*
* TLV
*/
#define LWM2M_TLV_HEADER_MAX_LENGTH 6
#define LWM2M_TYPE_RESSOURCE 0x00
#define LWM2M_TYPE_MULTIPLE_RESSOURCE 0x01
#define LWM2M_TYPE_RESSOURCE_INSTANCE 0x02
#define LWM2M_TYPE_OBJECT_INSTANCE 0x03
/*
* Bitmask for the lwm2m_tlv_t::flag
* LWM2M_TLV_FLAG_STATIC_DATA specifies that lwm2m_tlv_t::value
* points to static memory and must no be freeed by the caller.
* LWM2M_TLV_FLAG_TEXT_FORMAT specifies that lwm2m_tlv_t::value
* is expressed or requested in plain text format.
*/
#define LWM2M_TLV_FLAG_STATIC_DATA 0x01
#define LWM2M_TLV_FLAG_TEXT_FORMAT 0x02
typedef enum
{
TLV_OBJECT_INSTANCE = LWM2M_TYPE_OBJECT_INSTANCE,
TLV_RESSOURCE_INSTANCE = LWM2M_TYPE_RESSOURCE_INSTANCE,
TLV_MULTIPLE_INSTANCE = LWM2M_TYPE_MULTIPLE_RESSOURCE,
TLV_RESSOURCE = LWM2M_TYPE_RESSOURCE
} lwm2m_tlv_type_t;
typedef struct
{
uint8_t flags;
uint8_t type;
uint16_t id;
size_t length;
uint8_t * value;
} lwm2m_tlv_t;
lwm2m_tlv_t * lwm2m_tlv_new(int size);
int lwm2m_tlv_parse(char * buffer, size_t bufferLen, lwm2m_tlv_t ** dataP);
int lwm2m_tlv_serialize(int size, lwm2m_tlv_t * tlvP, char ** bufferP);
void lwm2m_tlv_free(int size, lwm2m_tlv_t * tlvP);
void lwm2m_tlv_encode_int(int64_t data, lwm2m_tlv_t * tlvP);
int lwm2m_tlv_decode_int(lwm2m_tlv_t * tlvP, int64_t * dataP);
/*
* These utility functions fill the buffer with a TLV record containing
* the data. They return the size in bytes of the TLV record, 0 in case
* of error.
*/
int lwm2m_intToTLV(lwm2m_tlv_type_t type, int64_t data, uint16_t id, char * buffer, size_t buffer_len);
int lwm2m_boolToTLV(lwm2m_tlv_type_t type, bool value, uint16_t id, char * buffer, size_t buffer_len);
int lwm2m_opaqueToTLV(lwm2m_tlv_type_t type, uint8_t * dataP, size_t data_len, uint16_t id, char * buffer, size_t buffer_len);
int lwm2m_decodeTLV(char * buffer, size_t buffer_len, lwm2m_tlv_type_t * oType, uint16_t * oID, size_t * oDataIndex, size_t * oDataLen);
int lwm2m_opaqueToInt(char * buffer, size_t buffer_len, int64_t * dataP);
/*
* URI
*
* objectId is always set
* if instanceId or resourceId is greater than LWM2M_URI_MAX_ID, it means it is not specified
*
*/
#define LWM2M_MAX_ID ((uint16_t)0xFFFF)
#define LWM2M_URI_FLAG_OBJECT_ID (uint8_t)0x04
#define LWM2M_URI_FLAG_INSTANCE_ID (uint8_t)0x02
#define LWM2M_URI_FLAG_RESOURCE_ID (uint8_t)0x01
#define LWM2M_URI_IS_SET_INSTANCE(uri) ((uri->flag & LWM2M_URI_FLAG_INSTANCE_ID) != 0)
#define LWM2M_URI_IS_SET_RESOURCE(uri) ((uri->flag & LWM2M_URI_FLAG_RESOURCE_ID) != 0)
typedef struct
{
uint8_t flag; // indicates which segments are set
uint16_t objectId;
uint16_t instanceId;
uint16_t resourceId;
} lwm2m_uri_t;
#define LWM2M_STRING_ID_MAX_LEN 6
// Parse an URI in LWM2M format and fill the lwm2m_uri_t.
// Return the number of characters read from buffer or 0 in case of error.
// Valid URIs: /1, /1/, /1/2, /1/2/, /1/2/3
// Invalid URIs: /, //, //2, /1//, /1//3, /1/2/3/, /1/2/3/4
int lwm2m_stringToUri(char * buffer, size_t buffer_len, lwm2m_uri_t * uriP);
/*
* LWM2M Objects
*
* For the read callback, if *numDataP is not zero, *dataArrayP is pre-allocated
* and contains the list of resources to read.
*
*/
typedef struct _lwm2m_object_t lwm2m_object_t;
typedef uint8_t (*lwm2m_read_callback_t) (uint16_t instanceId, int * numDataP, lwm2m_tlv_t ** dataArrayP, lwm2m_object_t * objectP);
typedef uint8_t (*lwm2m_write_callback_t) (uint16_t instanceId, int numData, lwm2m_tlv_t * dataArray, lwm2m_object_t * objectP);
typedef uint8_t (*lwm2m_execute_callback_t) (uint16_t instanceId, uint16_t resourceId, char * buffer, int length, lwm2m_object_t * objectP);
typedef uint8_t (*lwm2m_create_callback_t) (uint16_t instanceId, int numData, lwm2m_tlv_t * dataArray, lwm2m_object_t * objectP);
typedef uint8_t (*lwm2m_delete_callback_t) (uint16_t instanceId, lwm2m_object_t * objectP);
typedef void (*lwm2m_close_callback_t) (lwm2m_object_t * objectP);
struct _lwm2m_object_t
{
uint16_t objID;
lwm2m_list_t * instanceList;
lwm2m_read_callback_t readFunc;
lwm2m_write_callback_t writeFunc;
lwm2m_execute_callback_t executeFunc;
lwm2m_create_callback_t createFunc;
lwm2m_delete_callback_t deleteFunc;
lwm2m_close_callback_t closeFunc;
void * userData;
};
/*
* LWM2M Servers
*
* Since LWM2M Server Object instances are not accessible to LWM2M servers,
* there is no need to store them as lwm2m_objects_t
*/
typedef enum
{
SEC_NONE = 0,
SEC_PRE_SHARED_KEY,
SEC_RAW_PUBLIC_KEY,
SEC_CERTIFICATE
} lwm2m_security_mode_t;
typedef struct
{
lwm2m_security_mode_t mode;
size_t publicKeyLength;
uint8_t * publicKey;
size_t privateKeyLength;
uint8_t * privateKey;
} lwm2m_security_t;
typedef enum
{
STATE_UNKNOWN = 0,
STATE_REG_PENDING,
STATE_REGISTERED
} lwm2m_status_t;
typedef struct _lwm2m_server_
{
struct _lwm2m_server_ * next; // matches lwm2m_list_t::next
uint16_t shortID; // matches lwm2m_list_t::id
lwm2m_security_t security;
void * sessionH;
lwm2m_status_t status;
char * location;
uint16_t mid;
} lwm2m_server_t;
typedef struct
{
char * uri;
lwm2m_security_t security;
uint32_t holdOffTime;
} lwm2m_bootstrap_server_t;
/*
* LWM2M result callback
*
* When used with an observe, if 'data' is not nil, 'status' holds the observe counter.
*/
typedef void (*lwm2m_result_callback_t) (uint16_t clientID, lwm2m_uri_t * uriP, int status, uint8_t * data, int dataLength, void * userData);
/*
* LWM2M Observations
*
* Used to store observation of remote clients resources.
* status STATE_REG_PENDING means the observe request was sent to the client but not yet answered.
* status STATE_REGISTERED means the client acknowledged the observe request.
*/
typedef struct _lwm2m_observation_
{
struct _lwm2m_observation_ * next; // matches lwm2m_list_t::next
uint16_t id; // matches lwm2m_list_t::id
struct _lwm2m_client_ * clientP;
lwm2m_uri_t uri;
lwm2m_result_callback_t callback;
void * userData;
} lwm2m_observation_t;
/*
* LWM2M Clients
*
* Be careful not to mix lwm2m_client_object_t used to store list of objects of remote clients
* and lwm2m_object_t describing objects exposed to remote servers.
*
*/
typedef struct _lwm2m_client_object_
{
struct _lwm2m_client_object_ * next; // matches lwm2m_list_t::next
uint16_t id; // matches lwm2m_list_t::id
lwm2m_list_t * instanceList;
} lwm2m_client_object_t;
typedef struct _lwm2m_client_
{
struct _lwm2m_client_ * next; // matches lwm2m_list_t::next
uint16_t internalID; // matches lwm2m_list_t::id
char * name;
void * sessionH;
lwm2m_client_object_t * objectList;
lwm2m_observation_t * observationList;
} lwm2m_client_t;
/*
* LWM2M transaction
*
* Adaptation of Erbium's coap_transaction_t
*/
typedef enum
{
ENDPOINT_UNKNOWN = 0,
ENDPOINT_CLIENT,
ENDPOINT_SERVER,
ENDPOINT_BOOTSTRAP
} lwm2m_endpoint_type_t;
typedef struct _lwm2m_transaction_ lwm2m_transaction_t;
typedef void (*lwm2m_transaction_callback_t) (lwm2m_transaction_t * transacP, void * message);
struct _lwm2m_transaction_
{
lwm2m_transaction_t * next; // matches lwm2m_list_t::next
uint16_t mID; // matches lwm2m_list_t::id
lwm2m_endpoint_type_t peerType;
void * peerP;
uint8_t retrans_counter;
time_t retrans_time;
char objStringID[LWM2M_STRING_ID_MAX_LEN];
char instanceStringID[LWM2M_STRING_ID_MAX_LEN];
char resourceStringID[LWM2M_STRING_ID_MAX_LEN];
void * message;
uint16_t buffer_len;
uint8_t * buffer;
lwm2m_transaction_callback_t callback;
void * userData;
};
/*
* LWM2M observed resources
*/
typedef struct _lwm2m_watcher_
{
struct _lwm2m_watcher_ * next;
lwm2m_server_t * server;
uint8_t token[8];
size_t tokenLen;
uint32_t counter;
uint16_t lastMid;
} lwm2m_watcher_t;
typedef struct _lwm2m_observed_
{
struct _lwm2m_observed_ * next;
lwm2m_uri_t uri;
lwm2m_watcher_t * watcherList;
} lwm2m_observed_t;
/*
* LWM2M Context
*/
// The session handle MUST uniquely identify a peer.
typedef uint8_t (*lwm2m_buffer_send_callback_t)(void * sessionH, uint8_t * buffer, size_t length, void * userData);
typedef struct
{
int socket;
#ifdef LWM2M_CLIENT_MODE
char * endpointName;
lwm2m_bootstrap_server_t * bootstrapServer;
lwm2m_server_t * serverList;
lwm2m_object_t ** objectList;
uint16_t numObject;
lwm2m_observed_t * observedList;
#endif
#ifdef LWM2M_SERVER_MODE
lwm2m_client_t * clientList;
lwm2m_result_callback_t monitorCallback;
void * monitorUserData;
#endif
uint16_t nextMID;
lwm2m_transaction_t * transactionList;
// buffer send callback
lwm2m_buffer_send_callback_t bufferSendCallback;
void * bufferSendUserData;
} lwm2m_context_t;
// initialize a liblwm2m context. endpointName, numObject and objectList are ignored for pure servers.
lwm2m_context_t * lwm2m_init(char * endpointName, uint16_t numObject, lwm2m_object_t * objectList[], lwm2m_buffer_send_callback_t bufferSendCallback, void * bufferSendUserData);
// close a liblwm2m context.
void lwm2m_close(lwm2m_context_t * contextP);
// perform any required pending operation and adjust timeoutP to the maximal time interval to wait.
int lwm2m_step(lwm2m_context_t * contextP, struct timeval * timeoutP);
// dispatch received data to liblwm2m
void lwm2m_handle_packet(lwm2m_context_t * contextP, uint8_t * buffer, int length, void * fromSessionH);
#ifdef LWM2M_CLIENT_MODE
void lwm2m_set_bootstrap_server(lwm2m_context_t * contextP, lwm2m_bootstrap_server_t * serverP);
int lwm2m_add_server(lwm2m_context_t * contextP, uint16_t shortID, void * sessionH, lwm2m_security_t * securityP);
// send registration message to all known LWM2M Servers.
int lwm2m_register(lwm2m_context_t * contextP);
// inform liblwm2m that a resource value has changed.
void lwm2m_resource_value_changed(lwm2m_context_t * contextP, lwm2m_uri_t * uriP);
#endif
#ifdef LWM2M_SERVER_MODE
// Clients registration/deregistration monitoring API.
// When a LWM2M client registers, the callback is called with status CREATED_2_01.
// When a LWM2M client deregisters, the callback is called with status DELETED_2_02.
// clientID is the internal ID of the LWM2M Client.
// The callback's parameters uri, data, dataLength are always NULL.
// The lwm2m_client_t is present in the lwm2m_context_t's clientList when the callback is called. On a deregistration, it deleted when the callback returns.
void lwm2m_set_monitoring_callback(lwm2m_context_t * contextP, lwm2m_result_callback_t callback, void * userData);
// Device Management APIs
int lwm2m_dm_read(lwm2m_context_t * contextP, uint16_t clientID, lwm2m_uri_t * uriP, lwm2m_result_callback_t callback, void * userData);
int lwm2m_dm_write(lwm2m_context_t * contextP, uint16_t clientID, lwm2m_uri_t * uriP, char * buffer, int length, lwm2m_result_callback_t callback, void * userData);
int lwm2m_dm_execute(lwm2m_context_t * contextP, uint16_t clientID, lwm2m_uri_t * uriP, char * buffer, int length, lwm2m_result_callback_t callback, void * userData);
int lwm2m_dm_create(lwm2m_context_t * contextP, uint16_t clientID, lwm2m_uri_t * uriP, char * buffer, int length, lwm2m_result_callback_t callback, void * userData);
int lwm2m_dm_delete(lwm2m_context_t * contextP, uint16_t clientID, lwm2m_uri_t * uriP, lwm2m_result_callback_t callback, void * userData);
// Information Reporting APIs
int lwm2m_observe(lwm2m_context_t * contextP, uint16_t clientID, lwm2m_uri_t * uriP, lwm2m_result_callback_t callback, void * userData);
int lwm2m_observe_cancel(lwm2m_context_t * contextP, uint16_t clientID, lwm2m_uri_t * uriP, lwm2m_result_callback_t callback, void * userData);
#endif
#endif

113
core/list.c Normal file
View File

@ -0,0 +1,113 @@
/*******************************************************************************
*
* Copyright (c) 2013 Intel Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* The Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* David Navarro, Intel Corporation - initial API and implementation
*
*******************************************************************************/
#include "internals.h"
lwm2m_list_t * lwm2m_list_add(lwm2m_list_t * head,
lwm2m_list_t * node)
{
lwm2m_list_t * target;
if (NULL == head) return node;
if (head->id > node->id)
{
node->next = head;
return node;
}
target = head;
while (NULL != target->next && target->next->id < node->id)
{
target = target->next;
}
node->next = target->next;
target->next = node;
return head;
}
lwm2m_list_t * lwm2m_list_find(lwm2m_list_t * head,
uint16_t id)
{
while (NULL != head && head->id < id)
{
head = head->next;
}
if (NULL != head && head->id == id) return head;
return NULL;
}
lwm2m_list_t * lwm2m_list_remove(lwm2m_list_t * head,
uint16_t id,
lwm2m_list_t ** nodeP)
{
lwm2m_list_t * target;
if (head == NULL)
{
*nodeP = NULL;
return NULL;
}
if (head->id == id)
{
*nodeP = head;
return head->next;
}
target = head;
while (NULL != target->next && target->next->id < id)
{
target = target->next;
}
if (NULL != target->next && target->next->id == id)
{
*nodeP = target->next;
target->next = target->next->next;
}
else
{
*nodeP = NULL;
}
return head;
}
uint16_t lwm2m_list_newId(lwm2m_list_t * head)
{
uint16_t id;
lwm2m_list_t * target;
id = 0;
target = head;
while (target != NULL && id == target->id)
{
id = target->id + 1;
target = target->next;
}
return id;
}

356
core/management.c Normal file
View File

@ -0,0 +1,356 @@
/*******************************************************************************
*
* Copyright (c) 2013, 2014 Intel Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* The Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* David Navarro, Intel Corporation - initial API and implementation
* domedambrosio - Please refer to git log
* Toby Jaffey - Please refer to git log
*
*******************************************************************************/
/*
Copyright (c) 2013, 2014 Intel Corporation
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of Intel Corporation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
David Navarro <david.navarro@intel.com>
*/
#include "internals.h"
#include <stdio.h>
#ifdef LWM2M_CLIENT_MODE
coap_status_t handle_dm_request(lwm2m_context_t * contextP,
lwm2m_uri_t * uriP,
void * fromSessionH,
coap_packet_t * message,
coap_packet_t * response)
{
coap_status_t result;
switch (message->code)
{
case COAP_GET:
{
char * buffer = NULL;
int length = 0;
result = object_read(contextP, uriP, &buffer, &length);
if (result == COAP_205_CONTENT)
{
if (IS_OPTION(message, COAP_OPTION_OBSERVE))
{
result = handle_observe_request(contextP, uriP, fromSessionH, message, response);
}
if (result == COAP_205_CONTENT)
{
coap_set_payload(response, buffer, length);
// lwm2m_handle_packet will free buffer
}
}
}
break;
case COAP_POST:
{
if (!LWM2M_URI_IS_SET_INSTANCE(uriP))
{
result = object_create(contextP, uriP, message->payload, message->payload_len);
if (result == COAP_201_CREATED)
{
//longest uri is /65535/65535 = 12 + 1 (null) chars
char location_path[13] = "";
//instanceId expected
if ((uriP->flag & LWM2M_URI_FLAG_INSTANCE_ID) == 0)
{
result = COAP_500_INTERNAL_SERVER_ERROR;
break;
}
if (sprintf(location_path, "/%d/%d", uriP->objectId, uriP->instanceId) < 0)
{
result = COAP_500_INTERNAL_SERVER_ERROR;
break;
}
coap_set_header_location_path(response, location_path);
}
}
else if (!LWM2M_URI_IS_SET_RESOURCE(uriP))
{
if (object_isInstanceNew(contextP, uriP->objectId, uriP->instanceId))
{
result = object_create(contextP, uriP, message->payload, message->payload_len);
}
else
{
result = object_write(contextP, uriP, message->payload, message->payload_len);
}
}
else
{
result = object_execute(contextP, uriP, message->payload, message->payload_len);
}
}
break;
case COAP_PUT:
{
if (LWM2M_URI_IS_SET_INSTANCE(uriP) && LWM2M_URI_IS_SET_RESOURCE(uriP))
{
result = object_write(contextP, uriP, message->payload, message->payload_len);
}
else
{
result = BAD_REQUEST_4_00;
}
}
break;
case COAP_DELETE:
{
if (LWM2M_URI_IS_SET_INSTANCE(uriP) && !LWM2M_URI_IS_SET_RESOURCE(uriP))
{
result = object_delete(contextP, uriP);
}
else
{
result = BAD_REQUEST_4_00;
}
}
break;
default:
result = BAD_REQUEST_4_00;
break;
}
return result;
}
#endif
#ifdef LWM2M_SERVER_MODE
#define ID_AS_STRING_MAX_LEN 8
static void dm_result_callback(lwm2m_transaction_t * transacP,
void * message)
{
dm_data_t * dataP = (dm_data_t *)transacP->userData;
if (message == NULL)
{
dataP->callback(((lwm2m_client_t*)transacP->peerP)->internalID,
&dataP->uri,
COAP_503_SERVICE_UNAVAILABLE,
NULL, 0,
dataP->userData);
}
else
{
coap_packet_t * packet = (coap_packet_t *)message;
//if packet is a CREATE response and the instanceId was assigned by the client
if (packet->code == COAP_201_CREATED
&& packet->location_path != NULL)
{
char * locationString = NULL;
int result = 0;
lwm2m_uri_t locationUri;
locationString = coap_get_multi_option_as_string(packet->location_path);
if (locationString == NULL)
{
fprintf(stderr, "Error: coap_get_multi_option_as_string() failed for Location_path option in dm_result_callback()\n");
return;
}
result = lwm2m_stringToUri(locationString, strlen(locationString), &locationUri);
if (result == 0)
{
fprintf(stderr, "Error: lwm2m_stringToUri() failed for Location_path option in dm_result_callback()\n");
lwm2m_free(locationString);
return;
}
((dm_data_t*)transacP->userData)->uri.instanceId = locationUri.instanceId;
((dm_data_t*)transacP->userData)->uri.flag = locationUri.flag;
lwm2m_free(locationString);
}
dataP->callback(((lwm2m_client_t*)transacP->peerP)->internalID,
&dataP->uri,
packet->code,
packet->payload,
packet->payload_len,
dataP->userData);
}
lwm2m_free(dataP);
}
static int prv_make_operation(lwm2m_context_t * contextP,
uint16_t clientID,
lwm2m_uri_t * uriP,
coap_method_t method,
char * buffer,
int length,
lwm2m_result_callback_t callback,
void * userData)
{
lwm2m_client_t * clientP;
lwm2m_transaction_t * transaction;
dm_data_t * dataP;
clientP = (lwm2m_client_t *)lwm2m_list_find((lwm2m_list_t *)contextP->clientList, clientID);
if (clientP == NULL) return COAP_404_NOT_FOUND;
transaction = transaction_new(method, uriP, contextP->nextMID++, ENDPOINT_CLIENT, (void *)clientP);
if (transaction == NULL) return INTERNAL_SERVER_ERROR_5_00;
if (buffer != NULL)
{
// TODO: Take care of fragmentation
coap_set_payload(transaction->message, buffer, length);
}
if (callback != NULL)
{
dataP = (dm_data_t *)lwm2m_malloc(sizeof(dm_data_t));
if (dataP == NULL)
{
transaction_free(transaction);
return COAP_500_INTERNAL_SERVER_ERROR;
}
memcpy(&dataP->uri, uriP, sizeof(lwm2m_uri_t));
dataP->callback = callback;
dataP->userData = userData;
transaction->callback = dm_result_callback;
transaction->userData = (void *)dataP;
}
contextP->transactionList = (lwm2m_transaction_t *)LWM2M_LIST_ADD(contextP->transactionList, transaction);
return transaction_send(contextP, transaction);
}
int lwm2m_dm_read(lwm2m_context_t * contextP,
uint16_t clientID,
lwm2m_uri_t * uriP,
lwm2m_result_callback_t callback,
void * userData)
{
return prv_make_operation(contextP, clientID, uriP,
COAP_GET, NULL, 0,
callback, userData);
}
int lwm2m_dm_write(lwm2m_context_t * contextP,
uint16_t clientID,
lwm2m_uri_t * uriP,
char * buffer,
int length,
lwm2m_result_callback_t callback,
void * userData)
{
if (!LWM2M_URI_IS_SET_INSTANCE(uriP)
|| length == 0)
{
return COAP_400_BAD_REQUEST;
}
if (LWM2M_URI_IS_SET_RESOURCE(uriP))
{
return prv_make_operation(contextP, clientID, uriP,
COAP_PUT, buffer, length,
callback, userData);
}
else
{
return prv_make_operation(contextP, clientID, uriP,
COAP_POST, buffer, length,
callback, userData);
}
}
int lwm2m_dm_execute(lwm2m_context_t * contextP,
uint16_t clientID,
lwm2m_uri_t * uriP,
char * buffer,
int length,
lwm2m_result_callback_t callback,
void * userData)
{
if (!LWM2M_URI_IS_SET_RESOURCE(uriP))
{
return COAP_400_BAD_REQUEST;
}
return prv_make_operation(contextP, clientID, uriP,
COAP_POST, buffer, length,
callback, userData);
}
int lwm2m_dm_create(lwm2m_context_t * contextP,
uint16_t clientID,
lwm2m_uri_t * uriP,
char * buffer,
int length,
lwm2m_result_callback_t callback,
void * userData)
{
if (LWM2M_URI_IS_SET_RESOURCE(uriP)
|| length == 0)
{
return COAP_400_BAD_REQUEST;
}
return prv_make_operation(contextP, clientID, uriP,
COAP_POST, buffer, length,
callback, userData);
}
int lwm2m_dm_delete(lwm2m_context_t * contextP,
uint16_t clientID,
lwm2m_uri_t * uriP,
lwm2m_result_callback_t callback,
void * userData)
{
if (!LWM2M_URI_IS_SET_INSTANCE(uriP)
|| LWM2M_URI_IS_SET_RESOURCE(uriP))
{
return COAP_400_BAD_REQUEST;
}
return prv_make_operation(contextP, clientID, uriP,
COAP_DELETE, NULL, 0,
callback, userData);
}
#endif

216
core/object_server.c Normal file
View File

@ -0,0 +1,216 @@
/*******************************************************************************
*
* Copyright (c) 2013, 2014 Intel Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* The Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* David Navarro, Intel Corporation - initial API and implementation
*
*******************************************************************************/
/*
* Resources:
*
* Name | ID | Operations | Instances | Mandatory | Type | Range | Units |
* Short ID | 0 | R | Single | Yes | Integer | 1-65535 | |
* Lifetime | 1 | R/W | Single | Yes | Integer | | s |
* Default Min Period | 2 | R/W | Single | No | Integer | | s |
* Default Max Period | 3 | R/W | Single | No | Integer | | s |
* Disable | 4 | E | Single | No | | | |
* Disable Timeout | 5 | R/W | Single | No | Integer | | s |
* Notification Storing | 6 | R/W | Single | Yes | String | | |
* Binding | 7 | R/W | Single | Yes | | | |
* Registration Update | 8 | E | Single | Yes | | | |
*
*/
#ifdef LWM2M_CLIENT_MODE
#include "internals.h"
#define RESOURCE_SHORTID_ID 0
#define RESOURCE_LIFETIME_ID 1
#define RESOURCE_MINPERIOD_ID 2
#define RESOURCE_MAXPERIOD_ID 3
#define RESOURCE_DISABLE_ID 4
#define RESOURCE_TIMEOUT_ID 5
#define RESOURCE_STORING_ID 6
#define RESOURCE_BINDING_ID 7
#define RESOURCE_UPDATE_ID 8
coap_status_t object_server_read(lwm2m_context_t * contextP,
lwm2m_uri_t * uriP,
char ** bufferP,
int * lengthP)
{
if (!LWM2M_URI_IS_SET_INSTANCE(uriP))
{
return COAP_501_NOT_IMPLEMENTED;
}
else
{
lwm2m_server_t * serverP;
serverP = (lwm2m_server_t *)lwm2m_list_find((lwm2m_list_t *)contextP->serverList, uriP->instanceId);
if (serverP == NULL) return COAP_404_NOT_FOUND;
if (!LWM2M_URI_IS_SET_RESOURCE(uriP))
{
return COAP_501_NOT_IMPLEMENTED;
}
else
{
switch (uriP->resourceId)
{
case RESOURCE_SHORTID_ID:
*lengthP = lwm2m_int32ToPlainText(serverP->shortID, bufferP);
if (0 != *lengthP)
{
return COAP_205_CONTENT;
}
else
{
return COAP_500_INTERNAL_SERVER_ERROR;
}
break;
case RESOURCE_LIFETIME_ID:
return COAP_501_NOT_IMPLEMENTED;
case RESOURCE_MINPERIOD_ID:
return COAP_404_NOT_FOUND;
case RESOURCE_MAXPERIOD_ID:
return COAP_404_NOT_FOUND;
case RESOURCE_TIMEOUT_ID:
return COAP_404_NOT_FOUND;
case RESOURCE_STORING_ID:
return COAP_501_NOT_IMPLEMENTED;
case RESOURCE_BINDING_ID:
return COAP_501_NOT_IMPLEMENTED;
default:
return COAP_405_METHOD_NOT_ALLOWED;
}
}
}
}
coap_status_t object_server_write(lwm2m_context_t * contextP,
lwm2m_uri_t * uriP,
char * buffer,
int length)
{
if (!LWM2M_URI_IS_SET_INSTANCE(uriP))
{
return COAP_501_NOT_IMPLEMENTED;
}
else
{
lwm2m_server_t * serverP;
serverP = (lwm2m_server_t *)lwm2m_list_find((lwm2m_list_t *)contextP->serverList, uriP->instanceId);
if (serverP == NULL) return COAP_404_NOT_FOUND;
if (!LWM2M_URI_IS_SET_RESOURCE(uriP))
{
return COAP_501_NOT_IMPLEMENTED;
}
else
{
switch (uriP->resourceId)
{
case RESOURCE_LIFETIME_ID:
return COAP_501_NOT_IMPLEMENTED;
case RESOURCE_MINPERIOD_ID:
return COAP_404_NOT_FOUND;
case RESOURCE_MAXPERIOD_ID:
return COAP_404_NOT_FOUND;
case RESOURCE_TIMEOUT_ID:
return COAP_404_NOT_FOUND;
case RESOURCE_STORING_ID:
return COAP_501_NOT_IMPLEMENTED;
case RESOURCE_BINDING_ID:
return COAP_501_NOT_IMPLEMENTED;
default:
return COAP_405_METHOD_NOT_ALLOWED;
}
}
}
}
coap_status_t object_server_execute(lwm2m_context_t * contextP,
lwm2m_uri_t * uriP,
char * buffer,
int length)
{
lwm2m_server_t * serverP;
serverP = (lwm2m_server_t *)lwm2m_list_find((lwm2m_list_t *)contextP->serverList, uriP->instanceId);
if (serverP == NULL) return COAP_404_NOT_FOUND;
switch (uriP->resourceId)
{
case RESOURCE_DISABLE_ID:
return COAP_404_NOT_FOUND;
case RESOURCE_UPDATE_ID:
return COAP_501_NOT_IMPLEMENTED;
default:
return COAP_405_METHOD_NOT_ALLOWED;
}
}
coap_status_t object_server_create(lwm2m_context_t * contextP,
lwm2m_uri_t * uriP,
char * buffer,
int length)
{
lwm2m_server_t * serverP;
serverP = (lwm2m_server_t *)lwm2m_list_find((lwm2m_list_t *)contextP->serverList, uriP->instanceId);
if (serverP == NULL) return COAP_404_NOT_FOUND;
return COAP_501_NOT_IMPLEMENTED;
}
coap_status_t object_server_delete(lwm2m_context_t * contextP,
lwm2m_uri_t * uriP)
{
lwm2m_server_t * serverP;
serverP = (lwm2m_server_t *)lwm2m_list_find((lwm2m_list_t *)contextP->serverList, uriP->instanceId);
if (serverP == NULL) return COAP_404_NOT_FOUND;
return COAP_501_NOT_IMPLEMENTED;
}
coap_status_t object_security_create(lwm2m_context_t * contextP,
lwm2m_uri_t * uriP,
char * buffer,
int length)
{
lwm2m_server_t * serverP;
serverP = (lwm2m_server_t *)lwm2m_list_find((lwm2m_list_t *)contextP->serverList, uriP->instanceId);
if (serverP == NULL) return COAP_404_NOT_FOUND;
return COAP_501_NOT_IMPLEMENTED;
}
coap_status_t object_security_delete(lwm2m_context_t * contextP,
lwm2m_uri_t * uriP)
{
lwm2m_server_t * serverP;
serverP = (lwm2m_server_t *)lwm2m_list_find((lwm2m_list_t *)contextP->serverList, uriP->instanceId);
if (serverP == NULL) return COAP_404_NOT_FOUND;
return COAP_501_NOT_IMPLEMENTED;
}
#endif

462
core/objects.c Normal file
View File

@ -0,0 +1,462 @@
/*******************************************************************************
*
* Copyright (c) 2013, 2014 Intel Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* The Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* David Navarro, Intel Corporation - initial API and implementation
* Fabien Fleutot - Please refer to git log
* Toby Jaffey - Please refer to git log
* Benjamin Cabé - Please refer to git log
*
*******************************************************************************/
/*
Copyright (c) 2013, 2014 Intel Corporation
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of Intel Corporation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
David Navarro <david.navarro@intel.com>
*/
#ifdef LWM2M_CLIENT_MODE
#include "internals.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
static lwm2m_object_t * prv_find_object(lwm2m_context_t * contextP,
uint16_t Id)
{
int i;
for (i = 0 ; i < contextP->numObject ; i++)
{
if (contextP->objectList[i]->objID == Id)
{
return contextP->objectList[i];
}
}
return NULL;
}
coap_status_t object_read(lwm2m_context_t * contextP,
lwm2m_uri_t * uriP,
char ** bufferP,
int * lengthP)
{
coap_status_t result;
switch (uriP->objectId)
{
case LWM2M_SECURITY_OBJECT_ID:
result = NOT_FOUND_4_04;
break;
case LWM2M_SERVER_OBJECT_ID:
result = object_server_read(contextP, uriP, bufferP, lengthP);
break;
default:
{
lwm2m_object_t * targetP;
lwm2m_tlv_t * tlvP = NULL;
int size = 0;
targetP = prv_find_object(contextP, uriP->objectId);
if (NULL == targetP) return NOT_FOUND_4_04;
if (NULL == targetP->readFunc) return METHOD_NOT_ALLOWED_4_05;
if (targetP->instanceList == NULL)
{
// this is a single instance object
if (LWM2M_URI_IS_SET_INSTANCE(uriP) && (uriP->instanceId != 0))
{
return COAP_404_NOT_FOUND;
}
}
else
{
if (LWM2M_URI_IS_SET_INSTANCE(uriP))
{
if (NULL == lwm2m_list_find(targetP->instanceList, uriP->instanceId))
{
return COAP_404_NOT_FOUND;
}
}
else
{
// multiple object instances read
lwm2m_list_t * instanceP;
int i;
size = 0;
for (instanceP = targetP->instanceList; instanceP != NULL ; instanceP = instanceP->next)
{
size++;
}
tlvP = lwm2m_tlv_new(size);
if (tlvP == NULL) return COAP_500_INTERNAL_SERVER_ERROR;
result = COAP_205_CONTENT;
instanceP = targetP->instanceList;
i = 0;
while (instanceP != NULL && result == COAP_205_CONTENT)
{
result = targetP->readFunc(instanceP->id, (int*)&(tlvP[i].length), (lwm2m_tlv_t **)&(tlvP[i].value), targetP);
tlvP[i].type = LWM2M_TYPE_OBJECT_INSTANCE;
tlvP[i].id = instanceP->id;
i++;
instanceP = instanceP->next;
}
if (result == COAP_205_CONTENT)
{
*lengthP = lwm2m_tlv_serialize(size, tlvP, bufferP);
if (*lengthP == 0) result = COAP_500_INTERNAL_SERVER_ERROR;
}
lwm2m_tlv_free(size, tlvP);
return result;
}
}
// single instance read
if (LWM2M_URI_IS_SET_RESOURCE(uriP))
{
size = 1;
tlvP = lwm2m_tlv_new(size);
if (tlvP == NULL) return COAP_500_INTERNAL_SERVER_ERROR;
tlvP->type = LWM2M_TYPE_RESSOURCE;
tlvP->flags = LWM2M_TLV_FLAG_TEXT_FORMAT;
tlvP->id = uriP->resourceId;
}
result = targetP->readFunc(uriP->instanceId, &size, &tlvP, targetP);
if (result == COAP_205_CONTENT)
{
if (size == 1
&& tlvP->type == LWM2M_TYPE_RESSOURCE
&& (tlvP->flags && LWM2M_TLV_FLAG_TEXT_FORMAT) != 0 )
{
*bufferP = (char *)malloc(tlvP->length);
if (*bufferP == NULL)
{
result = COAP_500_INTERNAL_SERVER_ERROR;
}
else
{
memcpy(*bufferP, tlvP->value, tlvP->length);
*lengthP = tlvP->length;
}
}
else
{
*lengthP = lwm2m_tlv_serialize(size, tlvP, bufferP);
if (*lengthP == 0) result = COAP_500_INTERNAL_SERVER_ERROR;
}
}
lwm2m_tlv_free(size, tlvP);
}
}
return result;
}
coap_status_t object_write(lwm2m_context_t * contextP,
lwm2m_uri_t * uriP,
char * buffer,
int length)
{
coap_status_t result;
switch (uriP->objectId)
{
case LWM2M_SECURITY_OBJECT_ID:
result = NOT_FOUND_4_04;
break;
case LWM2M_SERVER_OBJECT_ID:
result = object_server_write(contextP, uriP, buffer, length);
break;
default:
{
lwm2m_object_t * targetP;
lwm2m_tlv_t * tlvP = NULL;
int size = 0;
targetP = prv_find_object(contextP, uriP->objectId);
if (NULL == targetP) return NOT_FOUND_4_04;
if (NULL == targetP->writeFunc) return METHOD_NOT_ALLOWED_4_05;
if (LWM2M_URI_IS_SET_RESOURCE(uriP))
{
size = 1;
tlvP = lwm2m_tlv_new(size);
if (tlvP == NULL) return COAP_500_INTERNAL_SERVER_ERROR;
tlvP->flags = LWM2M_TLV_FLAG_TEXT_FORMAT | LWM2M_TLV_FLAG_STATIC_DATA;
tlvP->type = LWM2M_TYPE_RESSOURCE;
tlvP->id = uriP->resourceId;
tlvP->length = length;
tlvP->value = buffer;
}
else
{
size = lwm2m_tlv_parse(buffer, length, &tlvP);
if (size = 0) return COAP_500_INTERNAL_SERVER_ERROR;
}
result = targetP->writeFunc(uriP->instanceId, size, tlvP, targetP);
lwm2m_tlv_free(size, tlvP);
}
}
return result;
}
coap_status_t object_execute(lwm2m_context_t * contextP,
lwm2m_uri_t * uriP,
char * buffer,
int length)
{
switch (uriP->objectId)
{
case LWM2M_SECURITY_OBJECT_ID:
return NOT_FOUND_4_04;
case LWM2M_SERVER_OBJECT_ID:
return object_server_execute(contextP, uriP, buffer, length);
default:
{
lwm2m_object_t * targetP;
targetP = prv_find_object(contextP, uriP->objectId);
if (NULL == targetP) return NOT_FOUND_4_04;
if (NULL == targetP->executeFunc) return METHOD_NOT_ALLOWED_4_05;
return targetP->executeFunc(uriP->instanceId, uriP->resourceId, buffer, length, targetP);
}
}
}
coap_status_t object_create(lwm2m_context_t * contextP,
lwm2m_uri_t * uriP,
char * buffer,
int length)
{
if (length == 0 || buffer == 0)
{
return BAD_REQUEST_4_00;
}
switch (uriP->objectId)
{
case LWM2M_SECURITY_OBJECT_ID:
return object_security_create(contextP, uriP, buffer, length);
case LWM2M_SERVER_OBJECT_ID:
return object_server_create(contextP, uriP, buffer, length);
default:
{
lwm2m_object_t * targetP;
lwm2m_tlv_t * tlvP = NULL;
int size = 0;
uint8_t result;
targetP = prv_find_object(contextP, uriP->objectId);
if (NULL == targetP) return NOT_FOUND_4_04;
if (NULL == targetP->createFunc) return METHOD_NOT_ALLOWED_4_05;
if (LWM2M_URI_IS_SET_INSTANCE(uriP))
{
if (NULL != lwm2m_list_find(targetP->instanceList, uriP->instanceId))
{
// Instance already exists
return COAP_406_NOT_ACCEPTABLE;
}
}
else
{
uriP->instanceId = lwm2m_list_newId(targetP->instanceList);
uriP->flag |= LWM2M_URI_FLAG_INSTANCE_ID;
}
targetP = prv_find_object(contextP, uriP->objectId);
if (NULL == targetP) return NOT_FOUND_4_04;
if (NULL == targetP->writeFunc) return METHOD_NOT_ALLOWED_4_05;
size = lwm2m_tlv_parse(buffer, length, &tlvP);
if (size == 0) return COAP_500_INTERNAL_SERVER_ERROR;
result = targetP->createFunc(uriP->instanceId, size, tlvP, targetP);
lwm2m_tlv_free(size, tlvP);
return result;
}
}
}
coap_status_t object_delete(lwm2m_context_t * contextP,
lwm2m_uri_t * uriP)
{
switch (uriP->objectId)
{
case LWM2M_SECURITY_OBJECT_ID:
return object_security_delete(contextP, uriP);
case LWM2M_SERVER_OBJECT_ID:
return object_server_delete(contextP, uriP);
default:
{
lwm2m_object_t * targetP;
targetP = prv_find_object(contextP, uriP->objectId);
if (NULL == targetP) return NOT_FOUND_4_04;
if (NULL == targetP->deleteFunc) return METHOD_NOT_ALLOWED_4_05;
return targetP->deleteFunc(uriP->instanceId, targetP);
}
}
}
bool object_isInstanceNew(lwm2m_context_t * contextP,
uint16_t objectId,
uint16_t instanceId)
{
switch (objectId)
{
case LWM2M_SECURITY_OBJECT_ID:
case LWM2M_SERVER_OBJECT_ID:
if (NULL != lwm2m_list_find((lwm2m_list_t *)contextP->serverList, instanceId))
{
return false;
}
break;
default:
{
lwm2m_object_t * targetP;
targetP = prv_find_object(contextP, objectId);
if (targetP != NULL)
{
if (NULL != lwm2m_list_find(targetP->instanceList, instanceId))
{
return false;
}
}
}
break;
}
return true;
}
int prv_getRegisterPayload(lwm2m_context_t * contextP,
char * buffer,
size_t length)
{
int index;
int i;
int result;
lwm2m_server_t * serverP;
// index can not be greater than length
index = 0;
for (serverP = contextP->serverList;
serverP != NULL;
serverP = serverP->next)
{
result = snprintf(buffer + index, length - index, "</%hu/%hu>,", LWM2M_SERVER_OBJECT_ID, serverP->shortID);
if (result > 0 && result <= length - index)
{
index += result;
}
else
{
return 0;
}
}
for (i = 0 ; i < contextP->numObject ; i++)
{
if (contextP->objectList[i]->instanceList == NULL)
{
result = snprintf(buffer + index, length - index, "</%hu>,", contextP->objectList[i]->objID);
if (result > 0 && result <= length - index)
{
index += result;
}
else
{
return 0;
}
}
else
{
lwm2m_list_t * targetP;
for (targetP = contextP->objectList[i]->instanceList ; targetP != NULL ; targetP = targetP->next)
{
int result;
result = snprintf(buffer + index, length - index, "</%hu/%hu>,", contextP->objectList[i]->objID, targetP->id);
if (result > 0 && result <= length - index)
{
index += result;
}
else
{
return 0;
}
}
}
}
if (index > 0)
{
index = index - 1; // remove trailing ','
}
buffer[index] = 0;
return index;
}
#endif

503
core/observe.c Normal file
View File

@ -0,0 +1,503 @@
/*******************************************************************************
*
* Copyright (c) 2013, 2014 Intel Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* The Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* David Navarro, Intel Corporation - initial API and implementation
* Toby Jaffey - Please refer to git log
*
*******************************************************************************/
/*
Copyright (c) 2013, 2014 Intel Corporation
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of Intel Corporation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
David Navarro <david.navarro@intel.com>
*/
#include "internals.h"
#include <stdio.h>
#ifdef LWM2M_CLIENT_MODE
static lwm2m_observed_t * prv_findObserved(lwm2m_context_t * contextP,
lwm2m_uri_t * uriP)
{
lwm2m_observed_t * targetP;
targetP = contextP->observedList;
while (targetP != NULL
&& (targetP->uri.objectId != uriP->objectId
|| targetP->uri.flag != uriP->flag
|| (LWM2M_URI_IS_SET_INSTANCE(uriP) && targetP->uri.instanceId != uriP->instanceId)
|| (LWM2M_URI_IS_SET_RESOURCE(uriP) && targetP->uri.resourceId != uriP->resourceId)))
{
targetP = targetP->next;
}
return targetP;
}
static obs_list_t * prv_getObservedList(lwm2m_context_t * contextP,
lwm2m_uri_t * uriP)
{
obs_list_t * resultP;
lwm2m_observed_t * targetP;
resultP = NULL;
targetP = contextP->observedList;
while (targetP != NULL)
{
if (targetP->uri.objectId == uriP->objectId)
{
if (!LWM2M_URI_IS_SET_INSTANCE(uriP)
|| (targetP->uri.flag & LWM2M_URI_FLAG_INSTANCE_ID) == 0
|| uriP->instanceId == targetP->uri.instanceId)
{
if (!LWM2M_URI_IS_SET_RESOURCE(uriP)
|| (targetP->uri.flag & LWM2M_URI_FLAG_RESOURCE_ID) == 0
|| uriP->resourceId == targetP->uri.resourceId)
{
obs_list_t * newP;
newP = (obs_list_t *)lwm2m_malloc(sizeof(obs_list_t));
if (newP != NULL)
{
newP->item = targetP;
newP->next = resultP;
resultP = newP;
}
}
}
}
targetP = targetP->next;
}
return resultP;
}
static void prv_unlinkObserved(lwm2m_context_t * contextP,
lwm2m_observed_t * observedP)
{
if (contextP->observedList == observedP)
{
contextP->observedList = contextP->observedList->next;
}
else
{
lwm2m_observed_t * parentP;
parentP = contextP->observedList;
while (parentP->next != NULL
&& parentP->next != observedP)
{
parentP = parentP->next;
}
if (parentP->next != NULL)
{
parentP->next = parentP->next->next;
}
}
}
static lwm2m_server_t * prv_findServer(lwm2m_context_t * contextP,
void * fromSessionH)
{
lwm2m_server_t * targetP;
targetP = contextP->serverList;
while (targetP != NULL
&& targetP->sessionH != fromSessionH)
{
targetP = targetP->next;
}
return targetP;
}
static lwm2m_watcher_t * prv_findWatcher(lwm2m_observed_t * observedP,
lwm2m_server_t * serverP)
{
lwm2m_watcher_t * targetP;
targetP = observedP->watcherList;
while (targetP != NULL
&& targetP->server != serverP)
{
targetP = targetP->next;
}
return targetP;
}
coap_status_t handle_observe_request(lwm2m_context_t * contextP,
lwm2m_uri_t * uriP,
void * fromSessionH,
coap_packet_t * message,
coap_packet_t * response)
{
lwm2m_observed_t * observedP;
lwm2m_watcher_t * watcherP;
lwm2m_server_t * serverP;
LOG("handle_observe_request()\r\n");
if (!LWM2M_URI_IS_SET_INSTANCE(uriP) && LWM2M_URI_IS_SET_RESOURCE(uriP)) return COAP_400_BAD_REQUEST;
if (message->token_len == 0) return COAP_400_BAD_REQUEST;
serverP = prv_findServer(contextP, fromSessionH);
if (serverP == NULL || serverP->status != STATE_REGISTERED) return COAP_401_UNAUTHORIZED;
observedP = prv_findObserved(contextP, uriP);
if (observedP == NULL)
{
observedP = (lwm2m_observed_t *)lwm2m_malloc(sizeof(lwm2m_observed_t));
if (observedP == NULL) return COAP_500_INTERNAL_SERVER_ERROR;
memset(observedP, 0, sizeof(lwm2m_observed_t));
memcpy(&(observedP->uri), uriP, sizeof(lwm2m_uri_t));
observedP->next = contextP->observedList;
contextP->observedList = observedP;
}
watcherP = prv_findWatcher(observedP, serverP);
if (watcherP == NULL)
{
watcherP = (lwm2m_watcher_t *)lwm2m_malloc(sizeof(lwm2m_watcher_t));
if (watcherP == NULL) return COAP_500_INTERNAL_SERVER_ERROR;
memset(watcherP, 0, sizeof(lwm2m_watcher_t));
watcherP->server = serverP;
watcherP->tokenLen = message->token_len;
memcpy(watcherP->token, message->token, message->token_len);
watcherP->next = observedP->watcherList;
observedP->watcherList = watcherP;
}
coap_set_header_observe(response, watcherP->counter++);
return COAP_205_CONTENT;
}
void cancel_observe(lwm2m_context_t * contextP,
uint16_t mid,
void * fromSessionH)
{
lwm2m_observed_t * observedP;
LOG("cancel_observe()\r\n");
for (observedP = contextP->observedList;
observedP != NULL;
observedP = observedP->next)
{
lwm2m_watcher_t * targetP = NULL;
if (observedP->watcherList->lastMid == mid
&& observedP->watcherList->server->sessionH == fromSessionH)
{
targetP = observedP->watcherList;
observedP->watcherList = observedP->watcherList->next;
}
else
{
lwm2m_watcher_t * parentP;
parentP = observedP->watcherList;
while (parentP->next != NULL
&& (parentP->next->lastMid != mid
|| parentP->next->server->sessionH != fromSessionH))
{
parentP = parentP->next;
}
if (parentP->next != NULL)
{
targetP = parentP->next;
parentP->next = parentP->next->next;
}
}
if (targetP != NULL)
{
lwm2m_free(targetP);
if (observedP->watcherList == NULL)
{
prv_unlinkObserved(contextP, observedP);
lwm2m_free(observedP);
}
return;
}
}
}
void lwm2m_resource_value_changed(lwm2m_context_t * contextP,
lwm2m_uri_t * uriP)
{
int result;
obs_list_t * listP;
lwm2m_watcher_t * watcherP;
listP = prv_getObservedList(contextP, uriP);
while (listP != NULL)
{
obs_list_t * targetP;
char * buffer = NULL;
int length = 0;
result = object_read(contextP, &listP->item->uri, &buffer, &length);
if (result == COAP_205_CONTENT)
{
coap_packet_t message[1];
coap_init_message(message, COAP_TYPE_NON, COAP_204_CHANGED, 0);
coap_set_payload(message, buffer, length);
for (watcherP = listP->item->watcherList ; watcherP != NULL ; watcherP = watcherP->next)
{
watcherP->lastMid = contextP->nextMID++;
message->mid = watcherP->lastMid;
coap_set_header_token(message, watcherP->token, watcherP->tokenLen);
coap_set_header_observe(message, watcherP->counter++);
(void)message_send(contextP, message, watcherP->server->sessionH);
}
}
targetP = listP;
listP = listP->next;
lwm2m_free(targetP);
}
}
#endif
#ifdef LWM2M_SERVER_MODE
static lwm2m_observation_t * prv_findObservationByURI(lwm2m_client_t * clientP,
lwm2m_uri_t * uriP)
{
lwm2m_observation_t * targetP;
targetP = clientP->observationList;
while (targetP != NULL)
{
if (targetP->uri.objectId == uriP->objectId
&& targetP->uri.flag == uriP->flag
&& targetP->uri.instanceId == uriP->instanceId
&& targetP->uri.resourceId == uriP->resourceId)
{
return targetP;
}
targetP = targetP->next;
}
return targetP;
}
static void prv_observationRemove(lwm2m_client_t * clientP,
lwm2m_observation_t * observationP)
{
if (clientP->observationList == observationP)
{
clientP->observationList = clientP->observationList->next;
}
else if (clientP->observationList != NULL)
{
lwm2m_observation_t * parentP;
parentP = clientP->observationList;
while (parentP->next != NULL
&& parentP->next != observationP)
{
parentP = parentP->next;
}
if (parentP->next != NULL)
{
parentP->next = parentP->next->next;
}
}
lwm2m_free(observationP);
}
static void prv_obsRequestCallback(lwm2m_transaction_t * transacP,
void * message)
{
lwm2m_observation_t * observationP = (lwm2m_observation_t *)transacP->userData;
coap_packet_t * packet = (coap_packet_t *)message;
uint8_t code;
if (message == NULL)
{
code = COAP_503_SERVICE_UNAVAILABLE;
}
else if (packet->code == COAP_205_CONTENT
&& !IS_OPTION(packet, COAP_OPTION_OBSERVE))
{
code = COAP_405_METHOD_NOT_ALLOWED;
}
else
{
code = packet->code;
}
if (code != COAP_205_CONTENT)
{
observationP->callback(((lwm2m_client_t*)transacP->peerP)->internalID,
&observationP->uri,
code,
NULL, 0,
observationP->userData);
prv_observationRemove(((lwm2m_client_t*)transacP->peerP), observationP);
}
else
{
observationP->clientP->observationList = (lwm2m_observation_t *)LWM2M_LIST_ADD(observationP->clientP->observationList, observationP);
observationP->callback(((lwm2m_client_t*)transacP->peerP)->internalID,
&observationP->uri,
0,
packet->payload, packet->payload_len,
observationP->userData);
}
}
int lwm2m_observe(lwm2m_context_t * contextP,
uint16_t clientID,
lwm2m_uri_t * uriP,
lwm2m_result_callback_t callback,
void * userData)
{
lwm2m_client_t * clientP;
lwm2m_transaction_t * transactionP;
lwm2m_observation_t * observationP;
uint8_t token[4];
if (!LWM2M_URI_IS_SET_INSTANCE(uriP) && LWM2M_URI_IS_SET_RESOURCE(uriP)) return COAP_400_BAD_REQUEST;
clientP = (lwm2m_client_t *)lwm2m_list_find((lwm2m_list_t *)contextP->clientList, clientID);
if (clientP == NULL) return COAP_404_NOT_FOUND;
observationP = (lwm2m_observation_t *)lwm2m_malloc(sizeof(lwm2m_observation_t));
if (observationP == NULL) return COAP_500_INTERNAL_SERVER_ERROR;
memset(observationP, 0, sizeof(lwm2m_observation_t));
transactionP = transaction_new(COAP_GET, uriP, contextP->nextMID++, ENDPOINT_CLIENT, (void *)clientP);
if (transactionP == NULL)
{
lwm2m_free(observationP);
return COAP_500_INTERNAL_SERVER_ERROR;
}
observationP->id = lwm2m_list_newId((lwm2m_list_t *)clientP->observationList);
memcpy(&observationP->uri, uriP, sizeof(lwm2m_uri_t));
observationP->clientP = clientP;
observationP->callback = callback;
observationP->userData = userData;
token[0] = clientP->internalID >> 8;
token[1] = clientP->internalID & 0xFF;
token[2] = observationP->id >> 8;
token[3] = observationP->id & 0xFF;
coap_set_header_observe(transactionP->message, 0);
coap_set_header_token(transactionP->message, token, sizeof(token));
transactionP->callback = prv_obsRequestCallback;
transactionP->userData = (void *)observationP;
contextP->transactionList = (lwm2m_transaction_t *)LWM2M_LIST_ADD(contextP->transactionList, transactionP);
return transaction_send(contextP, transactionP);
}
int lwm2m_observe_cancel(lwm2m_context_t * contextP,
uint16_t clientID,
lwm2m_uri_t * uriP,
lwm2m_result_callback_t callback,
void * userData)
{
lwm2m_client_t * clientP;
lwm2m_observation_t * observationP;
clientP = (lwm2m_client_t *)lwm2m_list_find((lwm2m_list_t *)contextP->clientList, clientID);
if (clientP == NULL) return COAP_404_NOT_FOUND;
observationP = prv_findObservationByURI(clientP, uriP);
if (observationP == NULL) return COAP_404_NOT_FOUND;
prv_observationRemove(clientP, observationP);
return 0;
}
void handle_observe_notify(lwm2m_context_t * contextP,
void * fromSessionH,
coap_packet_t * message)
{
uint8_t * tokenP;
int token_len;
uint16_t clientID;
uint16_t obsID;
lwm2m_client_t * clientP;
lwm2m_observation_t * observationP;
uint32_t count;
token_len = coap_get_header_token(message, (const uint8_t **)&tokenP);
if (token_len != sizeof(uint32_t)) return;
if (1 != coap_get_header_observe(message, &count)) return;
clientID = (tokenP[0] << 8) | tokenP[1];
obsID = (tokenP[2] << 8) | tokenP[3];
clientP = (lwm2m_client_t *)lwm2m_list_find((lwm2m_list_t *)contextP->clientList, clientID);
if (clientP == NULL) return;
observationP = (lwm2m_observation_t *)lwm2m_list_find((lwm2m_list_t *)clientP->observationList, obsID);
if (observationP == NULL)
{
coap_packet_t resetMsg;
coap_init_message(&resetMsg, COAP_TYPE_RST, 0, message->mid);
message_send(contextP, &resetMsg, fromSessionH);
}
else
{
observationP->callback(clientID,
&observationP->uri,
(int)count,
message->payload, message->payload_len,
observationP->userData);
}
}
#endif

323
core/packet.c Normal file
View File

@ -0,0 +1,323 @@
/*******************************************************************************
*
* Copyright (c) 2013, 2014 Intel Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* The Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* David Navarro, Intel Corporation - initial API and implementation
* domedambrosio - Please refer to git log
* Fabien Fleutot - Please refer to git log
* Fabien Fleutot - Please refer to git log
* Simon Bernard - Please refer to git log
* Toby Jaffey - Please refer to git log
*
*******************************************************************************/
/*
Copyright (c) 2013, 2014 Intel Corporation
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of Intel Corporation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
David Navarro <david.navarro@intel.com>
*/
/*
Contains code snippets which are:
* Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "internals.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
static void handle_reset(lwm2m_context_t * contextP,
void * fromSessionH,
coap_packet_t * message)
{
#ifdef LWM2M_CLIENT_MODE
cancel_observe(contextP, message->mid, fromSessionH);
#endif
}
static coap_status_t handle_request(lwm2m_context_t * contextP,
void * fromSessionH,
coap_packet_t * message,
coap_packet_t * response)
{
lwm2m_uri_t * uriP;
coap_status_t result = NOT_FOUND_4_04;
uriP = lwm2m_decode_uri(message->uri_path);
if (uriP == NULL) return BAD_REQUEST_4_00;
switch(uriP->flag & LWM2M_URI_MASK_TYPE)
{
#ifdef LWM2M_CLIENT_MODE
case LWM2M_URI_FLAG_DM:
// TODO: Authentify server
result = handle_dm_request(contextP, uriP, fromSessionH, message, response);
break;
case LWM2M_URI_FLAG_BOOTSTRAP:
result = NOT_IMPLEMENTED_5_01;
break;
#endif
#ifdef LWM2M_SERVER_MODE
case LWM2M_URI_FLAG_REGISTRATION:
result = handle_registration_request(contextP, uriP, fromSessionH, message, response);
break;
#endif
default:
result = BAD_REQUEST_4_00;
break;
}
coap_set_status_code(response, result);
if (result < BAD_REQUEST_4_00)
{
result = NO_ERROR;
}
lwm2m_free( uriP);
return result;
}
/* 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
{
/* 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);
}
}
coap_status_t message_send(lwm2m_context_t * contextP,
coap_packet_t * message,
void * sessionH)
{
coap_status_t result = INTERNAL_SERVER_ERROR_5_00;
uint8_t pktBuffer[COAP_MAX_PACKET_SIZE+1];
size_t pktBufferLen = 0;
pktBufferLen = coap_serialize_message(message, pktBuffer);
if (0 != pktBufferLen)
{
result = contextP->bufferSendCallback(sessionH, pktBuffer, pktBufferLen, contextP->bufferSendUserData);
}
return result;
}

480
core/registration.c Normal file
View File

@ -0,0 +1,480 @@
/*******************************************************************************
*
* Copyright (c) 2013, 2014 Intel Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* The Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* David Navarro, Intel Corporation - initial API and implementation
* domedambrosio - Please refer to git log
* Fabien Fleutot - Please refer to git log
* Simon Bernard - Please refer to git log
* Toby Jaffey - Please refer to git log
* Manuel Sangoi - Please refer to git log
*
*******************************************************************************/
/*
Copyright (c) 2013, 2014 Intel Corporation
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of Intel Corporation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
David Navarro <david.navarro@intel.com>
*/
#include "internals.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define QUERY_TEMPLATE "ep="
#define QUERY_LENGTH 3
#define QUERY_DELIMITER '&'
#define MAX_LOCATION_LENGTH 10 // strlen("/rd/65534") + 1
#ifdef LWM2M_CLIENT_MODE
static void prv_handleRegistrationReply(lwm2m_transaction_t * transacP,
void * message)
{
lwm2m_server_t * targetP;
coap_packet_t * packet = (coap_packet_t *)message;
targetP = (lwm2m_server_t *)(transacP->peerP);
switch(targetP->status)
{
case STATE_REG_PENDING:
{
if (packet == NULL)
{
targetP->status = STATE_UNKNOWN;
targetP->mid = 0;
}
else if (packet->mid == targetP->mid
&& packet->type == COAP_TYPE_ACK
&& packet->location_path != NULL)
{
if (packet->code == CREATED_2_01)
{
targetP->status = STATE_REGISTERED;
targetP->location = coap_get_multi_option_as_string(packet->location_path);
}
else if (packet->code == BAD_REQUEST_4_00)
{
targetP->status = STATE_UNKNOWN;
targetP->mid = 0;
}
}
}
break;
default:
break;
}
}
int lwm2m_register(lwm2m_context_t * contextP)
{
char * query;
char payload[512];
int payload_length;
lwm2m_server_t * targetP;
payload_length = prv_getRegisterPayload(contextP, payload, sizeof(payload));
if (payload_length == 0) return INTERNAL_SERVER_ERROR_5_00;
query = (char*)lwm2m_malloc(QUERY_LENGTH + strlen(contextP->endpointName) + 1);
if (query == NULL) return INTERNAL_SERVER_ERROR_5_00;
strcpy(query, QUERY_TEMPLATE);
strcpy(query + QUERY_LENGTH, contextP->endpointName);
targetP = contextP->serverList;
while (targetP != NULL)
{
lwm2m_transaction_t * transaction;
transaction = transaction_new(COAP_POST, NULL, contextP->nextMID++, ENDPOINT_SERVER, (void *)targetP);
if (transaction == NULL) return INTERNAL_SERVER_ERROR_5_00;
coap_set_header_uri_path(transaction->message, "/"URI_REGISTRATION_SEGMENT);
coap_set_header_uri_query(transaction->message, query);
coap_set_payload(transaction->message, payload, payload_length);
transaction->callback = prv_handleRegistrationReply;
transaction->userData = (void *) contextP;
contextP->transactionList = (lwm2m_transaction_t *)LWM2M_LIST_ADD(contextP->transactionList, transaction);
if (transaction_send(contextP, transaction) == 0)
{
targetP->status = STATE_REG_PENDING;
targetP->mid = transaction->mID;
}
targetP = targetP->next;
}
lwm2m_free(query);
return 0;
}
void registration_deregister(lwm2m_context_t * contextP,
lwm2m_server_t * serverP)
{
coap_packet_t message[1];
uint8_t pktBuffer[COAP_MAX_PACKET_SIZE+1];
size_t pktBufferLen = 0;
if (serverP->status != STATE_REGISTERED) return;
coap_init_message(message, COAP_TYPE_CON, COAP_DELETE, contextP->nextMID++);
coap_set_header_uri_path(message, serverP->location);
pktBufferLen = coap_serialize_message(message, pktBuffer);
if (0 != pktBufferLen)
{
contextP->bufferSendCallback(serverP->sessionH, pktBuffer, pktBufferLen, contextP->bufferSendUserData);
}
serverP->status = STATE_UNKNOWN;
}
#endif
#ifdef LWM2M_SERVER_MODE
static void prv_getParameters(multi_option_t * query,
char ** nameP)
{
const char * start;
int length;
*nameP = NULL;
while (query != NULL)
{
if (query->len > QUERY_LENGTH)
{
if (strncmp(query->data, QUERY_TEMPLATE, QUERY_LENGTH) == 0)
{
*nameP = (char *)lwm2m_malloc(query->len - QUERY_LENGTH + 1);
if (*nameP != NULL)
{
memcpy(*nameP, query->data + QUERY_LENGTH, query->len - QUERY_LENGTH);
(*nameP)[query->len - QUERY_LENGTH] = 0;
}
break;
}
}
query = query->next;
}
}
static int prv_getId(uint8_t * data,
uint16_t length,
uint16_t * objId,
uint16_t * instanceId)
{
int value;
uint16_t limit;
uint16_t end;
// Expecting application/link-format (RFC6690)
// strip open and close tags
if (length >= 1 && data[0] == '<' && data[length-1] == '>')
{
data++;
length-=2;
}
else
{
return 0;
}
// If there is a preceding /, remove it
if (length >= 1 && data[0] == '/')
{
data++;
length-=1;
}
limit = 0;
while (limit < length && data[limit] != '/' && data[limit] != ' ') limit++;
value = prv_get_number(data, limit);
if (value < 0 || value >= LWM2M_MAX_ID) return 0;
*objId = value;
if (limit != length)
{
limit += 1;
end = limit;
while (end < length && data[end] != ' ') end++;
if (end != limit)
{
value = prv_get_number(data + limit, end - limit);
if (value >= 0 && value < LWM2M_MAX_ID)
{
*instanceId = value;
return 2;
}
}
}
return 1;
}
static lwm2m_client_object_t * prv_decodeRegisterPayload(uint8_t * payload,
uint16_t payloadLength)
{
lwm2m_client_object_t * objList;
uint16_t id;
uint16_t instance;
uint16_t start;
uint16_t end;
int result;
objList = NULL;
start = 0;
while (start < payloadLength)
{
while (start < payloadLength && payload[start] == ' ') start++;
if (start == payloadLength) return objList;
end = start;
while (end < payloadLength && payload[end] != ',') end++;
result = prv_getId(payload + start, end - start, &id, &instance);
if (result != 0)
{
lwm2m_client_object_t * objectP;
objectP = (lwm2m_client_object_t *)lwm2m_list_find((lwm2m_list_t *)objList, id);
if (objectP == NULL)
{
objectP = (lwm2m_client_object_t *)lwm2m_malloc(sizeof(lwm2m_client_object_t));
memset(objectP, 0, sizeof(lwm2m_client_object_t));
if (objectP == NULL) return objList;
objectP->id = id;
objList = (lwm2m_client_object_t *)LWM2M_LIST_ADD(objList, objectP);
}
if (result == 2)
{
lwm2m_list_t * instanceP;
instanceP = lwm2m_list_find(objectP->instanceList, instance);
if (instanceP == NULL)
{
instanceP = (lwm2m_list_t *)lwm2m_malloc(sizeof(lwm2m_list_t));
memset(instanceP, 0, sizeof(lwm2m_list_t));
instanceP->id = instance;
objectP->instanceList = LWM2M_LIST_ADD(objectP->instanceList, instanceP);
}
}
}
start = end + 1;
}
return objList;
}
static lwm2m_client_t * prv_getClientByName(lwm2m_context_t * contextP,
char * name)
{
lwm2m_client_t * targetP;
targetP = contextP->clientList;
while (targetP != NULL && strcmp(name, targetP->name) != 0)
{
targetP = targetP->next;
}
return targetP;
}
static void prv_freeClientObjectList(lwm2m_client_object_t * objects)
{
while (objects != NULL)
{
lwm2m_client_object_t * objP;
while (objects->instanceList != NULL)
{
lwm2m_list_t * target;
target = objects->instanceList;
objects->instanceList = objects->instanceList->next;
lwm2m_free(target);
}
objP = objects;
objects = objects->next;
lwm2m_free(objP);
}
}
void prv_freeClient(lwm2m_client_t * clientP)
{
if (clientP->name != NULL) lwm2m_free(clientP->name);
prv_freeClientObjectList(clientP->objectList);
while(clientP->observationList != NULL)
{
lwm2m_observation_t * targetP;
targetP = clientP->observationList;
clientP->observationList = clientP->observationList->next;
lwm2m_free(targetP);
}
lwm2m_free(clientP);
}
static int prv_getLocationString(uint16_t id,
char location[MAX_LOCATION_LENGTH])
{
int result;
memset(location, 0, MAX_LOCATION_LENGTH);
result = snprintf(location, MAX_LOCATION_LENGTH, "/"URI_REGISTRATION_SEGMENT"/%hu", id);
if (result <= 0 || result > MAX_LOCATION_LENGTH)
{
return 0;
}
return result;
}
coap_status_t handle_registration_request(lwm2m_context_t * contextP,
lwm2m_uri_t * uriP,
void * fromSessionH,
coap_packet_t * message,
coap_packet_t * response)
{
coap_status_t result;
switch(message->code)
{
case COAP_POST:
{
char * name = NULL;
lwm2m_client_object_t * objects;
lwm2m_client_t * clientP;
char location[MAX_LOCATION_LENGTH];
if ((uriP->flag & LWM2M_URI_MASK_ID) != 0) return COAP_400_BAD_REQUEST;
prv_getParameters(message->uri_query, &name);
if (name == NULL) return COAP_400_BAD_REQUEST;
objects = prv_decodeRegisterPayload(message->payload, message->payload_len);
if (objects == NULL)
{
lwm2m_free(name);
return COAP_400_BAD_REQUEST;
}
clientP = prv_getClientByName(contextP, name);
if (clientP != NULL)
{
// we reset this registration
lwm2m_free(clientP->name);
prv_freeClientObjectList(clientP->objectList);
clientP->objectList = NULL;
}
else
{
clientP = (lwm2m_client_t *)lwm2m_malloc(sizeof(lwm2m_client_t));
if (clientP == NULL)
{
lwm2m_free(name);
prv_freeClientObjectList(objects);
return COAP_500_INTERNAL_SERVER_ERROR;
}
memset(clientP, 0, sizeof(lwm2m_client_t));
clientP->internalID = lwm2m_list_newId((lwm2m_list_t *)contextP->clientList);
contextP->clientList = (lwm2m_client_t *)LWM2M_LIST_ADD(contextP->clientList, clientP);
}
clientP->name = name;
clientP->objectList = objects;
clientP->sessionH = fromSessionH;
if (prv_getLocationString(clientP->internalID, location) == 0)
{
prv_freeClient(clientP);
return COAP_500_INTERNAL_SERVER_ERROR;
}
if (coap_set_header_location_path(response, location) == 0)
{
prv_freeClient(clientP);
return COAP_500_INTERNAL_SERVER_ERROR;
}
if (contextP->monitorCallback != NULL)
{
contextP->monitorCallback(clientP->internalID, NULL, CREATED_2_01, NULL, 0, contextP->monitorUserData);
}
result = CREATED_2_01;
}
break;
case COAP_PUT:
result = COAP_501_NOT_IMPLEMENTED;
break;
case COAP_DELETE:
{
lwm2m_client_t * clientP;
if ((uriP->flag & LWM2M_URI_MASK_ID) != LWM2M_URI_FLAG_OBJECT_ID) return COAP_400_BAD_REQUEST;
contextP->clientList = (lwm2m_client_t *)LWM2M_LIST_RM(contextP->clientList, uriP->objectId, &clientP);
if (clientP == NULL) return COAP_400_BAD_REQUEST;
if (contextP->monitorCallback != NULL)
{
contextP->monitorCallback(clientP->internalID, NULL, DELETED_2_02, NULL, 0, contextP->monitorUserData);
}
prv_freeClient(clientP);
result = DELETED_2_02;
}
break;
default:
return COAP_400_BAD_REQUEST;
}
return result;
}
void lwm2m_set_monitoring_callback(lwm2m_context_t * contextP,
lwm2m_result_callback_t callback,
void * userData)
{
contextP->monitorCallback = callback;
contextP->monitorUserData = userData;
}
#endif

632
core/tlv.c Normal file
View File

@ -0,0 +1,632 @@
/*******************************************************************************
*
* Copyright (c) 2013, 2014 Intel Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* The Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* David Navarro, Intel Corporation - initial API and implementation
* Fabien Fleutot - Please refer to git log
*
*******************************************************************************/
#include "internals.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <inttypes.h>
#define _PRV_64BIT_BUFFER_SIZE 8
static int prv_getHeaderLength(uint16_t id,
size_t dataLen)
{
int length;
length = 2;
if (id > 0xFF)
{
length += 1;
}
if (dataLen > 0xFFFF)
{
length += 3;
}
else if (dataLen > 0xFF)
{
length += 2;
}
else if (dataLen > 7)
{
length += 1;
}
return length;
}
static int prv_create_header(uint8_t * header,
lwm2m_tlv_type_t type,
uint16_t id,
size_t data_len)
{
int header_len;
header_len = prv_getHeaderLength(id, data_len);
header[0] = 0;
switch (type)
{
case TLV_OBJECT_INSTANCE:
// do nothing
break;
case TLV_RESSOURCE_INSTANCE:
header[0] |= 0x40;
break;
case TLV_MULTIPLE_INSTANCE:
header[0] |= 0x80;
break;
case TLV_RESSOURCE:
header[0] |= 0xC0;
break;
default:
return 0;
}
if (id > 0xFF)
{
header[0] |= 0x20;
header[1] = (id >> 8) & 0XFF;
header[2] = id & 0XFF;
}
else
{
header[1] = id;
}
if (data_len <= 7)
{
header[0] += data_len;
}
else if (data_len <= 0xFF)
{
header[0] |= 0x08;
header[2] = data_len;
}
else if (data_len <= 0xFFFF)
{
header[0] |= 0x10;
header[2] = (data_len >> 8) & 0XFF;
header[3] = data_len & 0XFF;
}
else if (data_len <= 0xFFFFFF)
{
header[0] |= 0x18;
header[2] = (data_len >> 16) & 0XFF;
header[3] = (data_len >> 8) & 0XFF;
header[4] = data_len & 0XFF;
}
return header_len;
}
int lwm2m_opaqueToTLV(lwm2m_tlv_type_t type,
uint8_t* dataP,
size_t data_len,
uint16_t id,
char * buffer,
size_t buffer_len)
{
uint8_t header[LWM2M_TLV_HEADER_MAX_LENGTH];
size_t header_len;
header_len = prv_create_header(header, type, id, data_len);
if (buffer_len < data_len + header_len) return 0;
memmove(buffer, header, header_len);
memmove(buffer + header_len, dataP, data_len);
return header_len + data_len;
}
int lwm2m_boolToTLV(lwm2m_tlv_type_t type,
bool value,
uint16_t id,
char * buffer,
size_t buffer_len)
{
return lwm2m_intToTLV(type, value?1:0, id, buffer, buffer_len);
}
int lwm2m_intToTLV(lwm2m_tlv_type_t type,
int64_t data,
uint16_t id,
char * buffer,
size_t buffer_len)
{
uint8_t data_buffer[_PRV_64BIT_BUFFER_SIZE];
size_t length = 0;
uint64_t value;
int negative = 0;
if (type != TLV_RESSOURCE_INSTANCE && type != TLV_RESSOURCE)
return 0;
memset(data_buffer, 0, 8);
if (data < 0)
{
negative = 1;
value = 0 - data;
}
else
{
value = data;
}
do
{
length++;
data_buffer[_PRV_64BIT_BUFFER_SIZE - length] = (value >> (8*(length-1))) & 0xFF;
} while (value > (((uint64_t)1 << ((8 * length)-1)) - 1));
if (1 == negative)
{
data_buffer[_PRV_64BIT_BUFFER_SIZE - length] |= 0x80;
}
return lwm2m_opaqueToTLV(type, data_buffer + (_PRV_64BIT_BUFFER_SIZE - length), length, id, buffer, buffer_len);
}
int lwm2m_decodeTLV(char * buffer,
size_t buffer_len,
lwm2m_tlv_type_t * oType,
uint16_t * oID,
size_t * oDataIndex,
size_t * oDataLen)
{
if (buffer_len < 2) return 0;
*oDataIndex = 2;
switch (buffer[0]&0xC0)
{
case 0x00:
*oType = TLV_OBJECT_INSTANCE;
break;
case 0x40:
*oType = TLV_RESSOURCE_INSTANCE;
break;
case 0x80:
*oType = TLV_MULTIPLE_INSTANCE;
break;
case 0xC0:
*oType = TLV_RESSOURCE;
break;
default:
// can't happen
return 0;
}
if ((uint8_t)(buffer[0]&0x20) == 0x20)
{
// id is 16 bits long
if (buffer_len < 3) return 0;
*oDataIndex += 1;
*oID = (buffer[1]<<8) + buffer[2];
}
else
{
// id is 8 bits long
*oID = buffer[1];
}
switch (buffer[0]&0x18)
{
case 0x00:
// no length field
*oDataLen = buffer[0]&0x07;
break;
case 0x08:
// length field is 8 bits long
if (buffer_len < *oDataIndex + 1) return 0;
*oDataLen = buffer[*oDataIndex];
*oDataIndex += 1;
break;
case 0x10:
// length field is 16 bits long
if (buffer_len < *oDataIndex + 2) return 0;
*oDataLen = (buffer[*oDataIndex]<<8) + buffer[*oDataIndex+1];
*oDataIndex += 2;
break;
case 0x18:
// length field is 24 bits long
if (buffer_len < *oDataIndex + 3) return 0;
*oDataLen = (buffer[*oDataIndex]<<16) + (buffer[*oDataIndex+1]<<8) + buffer[*oDataIndex+2];
*oDataIndex += 3;
break;
default:
// can't happen
return 0;
}
if (*oDataIndex + *oDataLen > buffer_len) return 0;
return *oDataIndex + *oDataLen;
}
int lwm2m_opaqueToInt(char * buffer,
size_t buffer_len,
int64_t * dataP)
{
int i;
if (buffer_len == 0 || buffer_len > 8) return 0;
// first bit is the sign
*dataP = buffer[0]&0x7F;
for (i = 1 ; i < buffer_len ; i++)
{
*dataP = (*dataP << 8) + buffer[i];
}
// first bit is the sign
if ((uint8_t)(buffer[0]&0x80) == 0x80)
{
*dataP = 0 - *dataP;
}
return i;
}
lwm2m_tlv_t * lwm2m_tlv_new(int size)
{
lwm2m_tlv_t * tlvP;
if (size <= 0) return NULL;
tlvP = (lwm2m_tlv_t *)lwm2m_malloc(size * sizeof(lwm2m_tlv_t));
if (tlvP != NULL)
{
memset(tlvP, 0, size * sizeof(lwm2m_tlv_t));
}
return tlvP;
}
int lwm2m_tlv_parse(char * buffer,
size_t bufferLen,
lwm2m_tlv_t ** dataP)
{
lwm2m_tlv_type_t type;
uint16_t id;
size_t dataIndex;
size_t dataLen;
int length = 0;
int result;
int size = 0;
*dataP = NULL;
while (0 != (result = lwm2m_decodeTLV(buffer + length, bufferLen - length, &type, &id, &dataIndex, &dataLen)))
{
lwm2m_tlv_t * newTlvP;
newTlvP = lwm2m_tlv_new(size + 1);
if (size >= 1)
{
if (newTlvP == NULL)
{
lwm2m_tlv_free(size, *dataP);
return 0;
}
else
{
memcpy(newTlvP, *dataP, size * sizeof(lwm2m_tlv_t));
lwm2m_free(*dataP);
}
}
*dataP = newTlvP;
switch (type)
{
case TLV_OBJECT_INSTANCE:
(*dataP)[size].type = LWM2M_TYPE_OBJECT_INSTANCE;
break;
case TLV_RESSOURCE_INSTANCE:
(*dataP)[size].type = LWM2M_TYPE_RESSOURCE_INSTANCE;
break;
case TLV_MULTIPLE_INSTANCE:
(*dataP)[size].type = LWM2M_TYPE_MULTIPLE_RESSOURCE;
break;
case TLV_RESSOURCE:
(*dataP)[size].type = LWM2M_TYPE_RESSOURCE;
break;
default:
lwm2m_tlv_free(size, *dataP);
return 0;
}
(*dataP)[size].id = id;
if (type == TLV_OBJECT_INSTANCE || type == TLV_MULTIPLE_INSTANCE)
{
(*dataP)[size].length = lwm2m_tlv_parse(buffer + length + dataIndex,
dataLen,
(lwm2m_tlv_t **)&((*dataP)[size].value));
if ((*dataP)[size].length == 0)
{
lwm2m_tlv_free(size + 1, *dataP);
return 0;
}
}
else
{
(*dataP)[size].flags = LWM2M_TLV_FLAG_STATIC_DATA;
(*dataP)[size].length = dataLen;
(*dataP)[size].value = buffer + length + dataIndex;
}
size++;
length += result;
}
return size;
}
static int prv_getLength(int size,
lwm2m_tlv_t * tlvP)
{
int length;
int i;
length = 0;
for (i = 0 ; i < size && length != -1 ; i++)
{
switch (tlvP[i].type)
{
case LWM2M_TYPE_OBJECT_INSTANCE:
case LWM2M_TYPE_MULTIPLE_RESSOURCE:
{
int subLength;
subLength = prv_getLength(tlvP[i].length, (lwm2m_tlv_t *)(tlvP[i].value));
if (subLength == -1)
{
length = -1;
}
else
{
length += prv_getHeaderLength(tlvP[i].id, subLength) + subLength;
}
}
break;
case LWM2M_TYPE_RESSOURCE_INSTANCE:
case LWM2M_TYPE_RESSOURCE:
length += prv_getHeaderLength(tlvP[i].id, tlvP[i].length) + tlvP[i].length;
break;
default:
length = -1;
break;
}
}
return length;
}
int lwm2m_tlv_serialize(int size,
lwm2m_tlv_t * tlvP,
char ** bufferP)
{
int length;
int index;
int i;
*bufferP = NULL;
length = prv_getLength(size, tlvP);
if (length <= 0) return length;
*bufferP = (char *)lwm2m_malloc(length);
if (*bufferP == NULL) return 0;
index = 0;
for (i = 0 ; i < size && length != 0 ; i++)
{
int headerLen;
switch (tlvP[i].type)
{
case LWM2M_TYPE_OBJECT_INSTANCE:
case LWM2M_TYPE_MULTIPLE_RESSOURCE:
{
char * tmpBuffer;
int tmpLength;
tmpLength = lwm2m_tlv_serialize(tlvP[i].length, (lwm2m_tlv_t *)tlvP[i].value, &tmpBuffer);
if (tmpLength == 0)
{
length = 0;
}
else
{
headerLen = prv_create_header(*bufferP + index, tlvP[i].type, tlvP[i].id, tmpLength);
index += headerLen;
memcpy(*bufferP + index, tmpBuffer, tmpLength);
index += tmpLength;
lwm2m_free(tmpBuffer);
}
}
break;
case LWM2M_TYPE_RESSOURCE_INSTANCE:
case LWM2M_TYPE_RESSOURCE:
{
headerLen = prv_create_header(*bufferP + index, tlvP[i].type, tlvP[i].id, tlvP[i].length);
if (headerLen == 0)
{
length = 0;
}
else
{
index += headerLen;
memcpy(*bufferP + index, tlvP[i].value, tlvP[i].length);
index += tlvP[i].length;
}
}
break;
default:
length = 0;
break;
}
}
if (length == 0)
{
lwm2m_free(*bufferP);
}
return length;
}
void lwm2m_tlv_free(int size,
lwm2m_tlv_t * tlvP)
{
int i;
if (size == 0 || tlvP == NULL) return;
for (i = 0 ; i < size ; i++)
{
if ((tlvP[i].flags & LWM2M_TLV_FLAG_STATIC_DATA) == 0)
{
if (tlvP[i].type == LWM2M_TYPE_MULTIPLE_RESSOURCE
|| tlvP[i].type == TLV_OBJECT_INSTANCE)
{
lwm2m_tlv_free(tlvP[i].length, (lwm2m_tlv_t *)(tlvP[i].value));
}
else
{
lwm2m_free(tlvP[i].value);
}
}
}
lwm2m_free(tlvP);
}
void lwm2m_tlv_encode_int(int64_t data,
lwm2m_tlv_t * tlvP)
{
tlvP->length = 0;
if ((tlvP->flags & LWM2M_TLV_FLAG_TEXT_FORMAT) != 0)
{
char string[32];
int length;
length = snprintf(string, 32, "%" PRId64, data);
if (length > 0)
{
tlvP->value = (uint8_t *)malloc(length);
if (tlvP->value != NULL)
{
strncpy(tlvP->value, string, length);
tlvP->flags &= ~LWM2M_TLV_FLAG_STATIC_DATA;
tlvP->length = length;
}
}
}
else
{
uint8_t buffer[_PRV_64BIT_BUFFER_SIZE];
size_t length = 0;
uint64_t value;
int negative = 0;
memset(buffer, 0, _PRV_64BIT_BUFFER_SIZE);
if (data < 0)
{
negative = 1;
value = 0 - data;
}
else
{
value = data;
}
do
{
length++;
buffer[_PRV_64BIT_BUFFER_SIZE - length] = (value >> (8*(length-1))) & 0xFF;
} while (value > (((uint64_t)1 << ((8 * length)-1)) - 1));
if (1 == negative)
{
buffer[_PRV_64BIT_BUFFER_SIZE - length] |= 0x80;
}
tlvP->value = (uint8_t *)malloc(length);
if (tlvP->value != NULL)
{
memcpy(tlvP->value,
buffer + (_PRV_64BIT_BUFFER_SIZE - length),
length);
tlvP->flags &= ~LWM2M_TLV_FLAG_STATIC_DATA;
tlvP->length = length;
}
}
}
int lwm2m_tlv_decode_int(lwm2m_tlv_t * tlvP,
int64_t * dataP)
{
int i;
if (tlvP->length == 0) return 0;
if ((tlvP->flags & LWM2M_TLV_FLAG_TEXT_FORMAT) != 0)
{
char string[32];
int result;
// int64 is 20 digit max
if (tlvP->length > 32) return 0;
memcpy(string, tlvP->value, tlvP->length);
string[tlvP->length] = 0;
result = sscanf(string, "%" PRId64, dataP);
if (result != 1) return 0;
}
else
{
if (tlvP->length > 8) return 0;
// first bit is the sign
*dataP = tlvP->value[0]&0x7F;
for (i = 1 ; i < tlvP->length ; i++)
{
*dataP = (*dataP << 8) + tlvP->value[i];
}
// first bit is the sign
if ((tlvP->value[0]&0x80) == 0x80)
{
*dataP = 0 - *dataP;
}
}
return 1;
}

325
core/transaction.c Normal file
View File

@ -0,0 +1,325 @@
/*******************************************************************************
*
* Copyright (c) 2013, 2014 Intel Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* The Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* David Navarro, Intel Corporation - initial API and implementation
* Simon Bernard - Please refer to git log
* Toby Jaffey - Please refer to git log
*
*******************************************************************************/
/*
Copyright (c) 2013, 2014 Intel Corporation
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of Intel Corporation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
David Navarro <david.navarro@intel.com>
*/
/*
Contains code snippets which are:
* Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "internals.h"
/*
* Modulo mask (+1 and +0.5 for rounding) for a random number to get the tick number for the random
* retransmission time between COAP_RESPONSE_TIMEOUT and COAP_RESPONSE_TIMEOUT*COAP_RESPONSE_RANDOM_FACTOR.
*/
#define COAP_RESPONSE_TIMEOUT_TICKS (CLOCK_SECOND * COAP_RESPONSE_TIMEOUT)
#define COAP_RESPONSE_TIMEOUT_BACKOFF_MASK ((CLOCK_SECOND * COAP_RESPONSE_TIMEOUT * (COAP_RESPONSE_RANDOM_FACTOR - 1)) + 1.5)
static int prv_check_addr(void * leftSessionH,
void * rightSessionH)
{
if ((leftSessionH == NULL)
|| (rightSessionH == NULL)
|| (leftSessionH != rightSessionH))
{
return 0;
}
return 1;
}
lwm2m_transaction_t * transaction_new(coap_method_t method,
lwm2m_uri_t * uriP,
uint16_t mID,
lwm2m_endpoint_type_t peerType,
void * peerP)
{
lwm2m_transaction_t * transacP;
int result;
transacP = (lwm2m_transaction_t *)lwm2m_malloc(sizeof(lwm2m_transaction_t));
if (transacP == NULL) return NULL;
memset(transacP, 0, sizeof(lwm2m_transaction_t));
transacP->message = lwm2m_malloc(sizeof(coap_packet_t));
if (transacP->message == NULL) goto error;
coap_init_message(transacP->message, COAP_TYPE_CON, method, mID);
transacP->mID = mID;
transacP->peerType = peerType;
transacP->peerP = peerP;
if (uriP != NULL)
{
result = snprintf(transacP->objStringID, LWM2M_STRING_ID_MAX_LEN, "%hu", uriP->objectId);
if (result < 0 || result > LWM2M_STRING_ID_MAX_LEN) goto error;
coap_set_header_uri_path_segment(transacP->message, transacP->objStringID);
if (LWM2M_URI_IS_SET_INSTANCE(uriP))
{
result = snprintf(transacP->instanceStringID, LWM2M_STRING_ID_MAX_LEN, "%hu", uriP->instanceId);
if (result < 0 || result > LWM2M_STRING_ID_MAX_LEN) goto error;
coap_set_header_uri_path_segment(transacP->message, transacP->instanceStringID);
}
else
{
if (LWM2M_URI_IS_SET_RESOURCE(uriP))
{
coap_set_header_uri_path_segment(transacP->message, NULL);
}
}
if (LWM2M_URI_IS_SET_RESOURCE(uriP))
{
result = snprintf(transacP->resourceStringID, LWM2M_STRING_ID_MAX_LEN, "%hu", uriP->resourceId);
if (result < 0 || result > LWM2M_STRING_ID_MAX_LEN) goto error;
coap_set_header_uri_path_segment(transacP->message, transacP->resourceStringID);
}
}
return transacP;
error:
lwm2m_free(transacP);
return NULL;
}
void transaction_free(lwm2m_transaction_t * transacP)
{
if (transacP->message) lwm2m_free(transacP->message);
if (transacP->buffer) lwm2m_free(transacP->buffer);
lwm2m_free(transacP);
}
void transaction_remove(lwm2m_context_t * contextP,
lwm2m_transaction_t * transacP)
{
if (NULL != contextP->transactionList)
{
if (transacP == contextP->transactionList)
{
contextP->transactionList = contextP->transactionList->next;
}
else
{
lwm2m_transaction_t *previous = contextP->transactionList;
while (previous->next && previous->next != transacP)
{
previous = previous->next;
}
if (NULL != previous->next)
{
previous->next = previous->next->next;
}
}
}
transaction_free(transacP);
}
void transaction_handle_response(lwm2m_context_t * contextP,
void * fromSessionH,
coap_packet_t * message)
{
lwm2m_transaction_t * transacP;
transacP = contextP->transactionList;
while (transacP != NULL)
{
void * targetSessionH;
targetSessionH = NULL;
switch (transacP->peerType)
{
#ifdef LWM2M_SERVER_MODE
case ENDPOINT_CLIENT:
targetSessionH = ((lwm2m_client_t *)transacP->peerP)->sessionH;
break;
#endif
#ifdef LWM2M_CLIENT_MODE
case ENDPOINT_SERVER:
targetSessionH = ((lwm2m_server_t *)transacP->peerP)->sessionH;
break;
#endif
default:
break;
}
if (prv_check_addr(fromSessionH, targetSessionH))
{
if (transacP->mID == message->mid)
{
// HACK: If a message is sent from the monitor callback,
// it will arrive before the registration ACK.
// So we resend transaction that were denied for authentication reason.
if (message->code != COAP_401_UNAUTHORIZED || transacP->retrans_counter >= COAP_MAX_RETRANSMIT)
{
if (transacP->callback != NULL)
{
transacP->callback(transacP, message);
}
transaction_remove(contextP, transacP);
}
// we found our guy, exit
return;
}
}
transacP = transacP->next;
}
}
int transaction_send(lwm2m_context_t * contextP,
lwm2m_transaction_t * transacP)
{
if (transacP->buffer == NULL)
{
uint8_t tempBuffer[LWM2M_MAX_PACKET_SIZE];
int length;
length = coap_serialize_message(transacP->message, tempBuffer);
if (length <= 0) return COAP_500_INTERNAL_SERVER_ERROR;
transacP->buffer = (uint8_t*)lwm2m_malloc(length);
if (transacP->buffer == NULL) return COAP_500_INTERNAL_SERVER_ERROR;
memcpy(transacP->buffer, tempBuffer, length);
transacP->buffer_len = length;
}
switch(transacP->peerType)
{
case ENDPOINT_CLIENT:
LOG("Sending %d bytes\r\n", transacP->buffer_len);
contextP->bufferSendCallback(((lwm2m_client_t*)transacP->peerP)->sessionH,
transacP->buffer, transacP->buffer_len, contextP->bufferSendUserData);
break;
case ENDPOINT_SERVER:
LOG("Sending %d bytes\r\n", transacP->buffer_len);
contextP->bufferSendCallback(((lwm2m_server_t*)transacP->peerP)->sessionH,
transacP->buffer, transacP->buffer_len, contextP->bufferSendUserData);
break;
case ENDPOINT_BOOTSTRAP:
// not implemented yet
break;
default:
return 0;
}
if (transacP->retrans_counter == 0)
{
struct timeval tv;
if (0 == lwm2m_gettimeofday(&tv, NULL))
{
transacP->retrans_time = tv.tv_sec;
transacP->retrans_counter = 1;
}
else
{
// crude error handling
transacP->retrans_counter = COAP_MAX_RETRANSMIT;
}
}
if (transacP->retrans_counter < COAP_MAX_RETRANSMIT)
{
transacP->retrans_time += COAP_RESPONSE_TIMEOUT * transacP->retrans_counter;
transacP->retrans_counter++;
}
else
{
if (transacP->callback)
{
transacP->callback(transacP, NULL);
}
transaction_remove(contextP, transacP);
return -1;
}
return 0;
}

220
core/uri.c Normal file
View File

@ -0,0 +1,220 @@
/*******************************************************************************
*
* Copyright (c) 2013, 2014 Intel Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* The Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* David Navarro, Intel Corporation - initial API and implementation
* Fabien Fleutot - Please refer to git log
* Toby Jaffey - Please refer to git log
*
*******************************************************************************/
/*
Copyright (c) 2013, 2014 Intel Corporation
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of Intel Corporation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
David Navarro <david.navarro@intel.com>
*/
#include "internals.h"
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
static int prv_parse_number(const char * uriString,
size_t uriLength,
int * headP)
{
int result = 0;
if (uriString[*headP] == '/')
{
// empty Object Instance ID with resource ID is not allowed
return -1;
}
while (*headP < uriLength && uriString[*headP] != '/')
{
if ('0' <= uriString[*headP] && uriString[*headP] <= '9')
{
result += uriString[*headP] - '0';
result *= 10;
}
else
{
return -1;
}
*headP += 1;
}
result /= 10;
return result;
}
int prv_get_number(const char * uriString,
size_t uriLength)
{
int index = 0;
return prv_parse_number(uriString, uriLength, &index);
}
lwm2m_uri_t * lwm2m_decode_uri(multi_option_t *uriPath)
{
lwm2m_uri_t * uriP;
int readNum;
if (NULL == uriPath) return NULL;
uriP = (lwm2m_uri_t *)lwm2m_malloc(sizeof(lwm2m_uri_t));
if (NULL == uriP) return NULL;
memset(uriP, 0, sizeof(lwm2m_uri_t));
// Read object ID
if (URI_REGISTRATION_SEGMENT_LEN == uriPath->len
&& 0 == strncmp(URI_REGISTRATION_SEGMENT, uriPath->data, uriPath->len))
{
uriP->flag |= LWM2M_URI_FLAG_REGISTRATION;
uriPath = uriPath->next;
if (uriPath == NULL) return uriP;
}
else if (URI_BOOTSTRAP_SEGMENT_LEN == uriPath->len
&& 0 == strncmp(URI_BOOTSTRAP_SEGMENT, uriPath->data, uriPath->len))
{
uriP->flag |= LWM2M_URI_FLAG_BOOTSTRAP;
uriPath = uriPath->next;
if (uriPath != NULL) goto error;
return uriP;
}
readNum = prv_get_number(uriPath->data, uriPath->len);
if (readNum < 0 || readNum > LWM2M_MAX_ID) goto error;
uriP->objectId = (uint16_t)readNum;
uriP->flag |= LWM2M_URI_FLAG_OBJECT_ID;
uriPath = uriPath->next;
if ((uriP->flag & LWM2M_URI_MASK_TYPE) == LWM2M_URI_FLAG_REGISTRATION)
{
if (uriPath != NULL) goto error;
return uriP;
}
uriP->flag |= LWM2M_URI_FLAG_DM;
if (uriPath == NULL) return uriP;
// Read object instance
if (uriPath->len != 0)
{
readNum = prv_get_number(uriPath->data, uriPath->len);
if (readNum < 0 || readNum >= LWM2M_MAX_ID) goto error;
uriP->instanceId = (uint16_t)readNum;
uriP->flag |= LWM2M_URI_FLAG_INSTANCE_ID;
}
uriPath = uriPath->next;
if (uriPath == NULL) return uriP;
// Read resource ID
if (uriPath->len != 0)
{
// resource ID without an instance ID is not allowed
if ((uriP->flag & LWM2M_URI_FLAG_INSTANCE_ID) == 0) goto error;
readNum = prv_get_number(uriPath->data, uriPath->len);
if (readNum < 0 || readNum > LWM2M_MAX_ID) goto error;
uriP->resourceId = (uint16_t)readNum;
uriP->flag |= LWM2M_URI_FLAG_RESOURCE_ID;
}
// must be the last segment
if (NULL == uriPath->next) return uriP;
error:
lwm2m_free(uriP);
return NULL;
}
int lwm2m_stringToUri(char * buffer,
size_t buffer_len,
lwm2m_uri_t * uriP)
{
int head;
int readNum;
if (buffer == NULL || buffer_len == 0 || uriP == NULL) return 0;
memset(uriP, 0, sizeof(lwm2m_uri_t));
// Skip any white space
head = 0;
while (head < buffer_len && isspace(buffer[head]))
{
head++;
}
if (head == buffer_len) return 0;
// Check the URI start with a '/'
if (buffer[head] != '/') return 0;
head++;
if (head == buffer_len) return 0;
// Read object ID
readNum = prv_parse_number(buffer, buffer_len, &head);
if (readNum < 0 || readNum > LWM2M_MAX_ID) return 0;
uriP->objectId = (uint16_t)readNum;
if (buffer[head] == '/') head += 1;
if (head >= buffer_len) return head;
readNum = prv_parse_number(buffer, buffer_len, &head);
if (readNum < 0 || readNum >= LWM2M_MAX_ID) return 0;
uriP->instanceId = (uint16_t)readNum;
uriP->flag |= LWM2M_URI_FLAG_INSTANCE_ID;
if (buffer[head] == '/') head += 1;
if (head >= buffer_len) return head;
readNum = prv_parse_number(buffer, buffer_len, &head);
if (readNum < 0 || readNum >= LWM2M_MAX_ID) return 0;
uriP->resourceId = (uint16_t)readNum;
uriP->flag |= LWM2M_URI_FLAG_RESOURCE_ID;
if (head != buffer_len) return 0;
return head;
}

178
core/utils.c Normal file
View File

@ -0,0 +1,178 @@
/*******************************************************************************
*
* Copyright (c) 2013, 2014 Intel Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* The Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* David Navarro, Intel Corporation - initial API and implementation
* Toby Jaffey - Please refer to git log
*
*******************************************************************************/
/*
Copyright (c) 2013, 2014 Intel Corporation
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of Intel Corporation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
David Navarro <david.navarro@intel.com>
*/
#include "internals.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <inttypes.h>
int lwm2m_PlainTextToInt64(char * buffer,
int length,
int64_t * dataP)
{
uint64_t result = 0;
int sign = 1;
int mul = 0;
int i = 0;
if (0 == length) return 0;
if (buffer[0] == '-')
{
sign = -1;
i = 1;
}
while (i < length)
{
if ('0' <= buffer[i] && buffer[i] <= '9')
{
if (0 == mul)
{
mul = 10;
}
else
{
result *= mul;
}
result += buffer[i] - '0';
}
else
{
return 0;
}
i++;
}
*dataP = result * sign;
return 1;
}
int lwm2m_int8ToPlainText(int8_t data,
char ** bufferP)
{
return lwm2m_int64ToPlainText((int64_t)data, bufferP);
}
int lwm2m_int16ToPlainText(int16_t data,
char ** bufferP)
{
return lwm2m_int64ToPlainText((int64_t)data, bufferP);
}
int lwm2m_int32ToPlainText(int32_t data,
char ** bufferP)
{
return lwm2m_int64ToPlainText((int64_t)data, bufferP);
}
int lwm2m_int64ToPlainText(int64_t data,
char ** bufferP)
{
char string[32];
int len;
len = snprintf(string, 32, "%" PRId64, data);
if (len > 0)
{
*bufferP = (char *)lwm2m_malloc(len);
if (NULL != *bufferP)
{
strncpy(*bufferP, string, len);
}
else
{
len = 0;
}
}
return len;
}
int lwm2m_float32ToPlainText(float data,
char ** bufferP)
{
return lwm2m_float64ToPlainText((double)data, bufferP);
}
int lwm2m_float64ToPlainText(double data,
char ** bufferP)
{
char string[64];
int len;
len = snprintf(string, 64, "%lf", data);
if (len > 0)
{
*bufferP = (char *)lwm2m_malloc(len);
if (NULL != *bufferP)
{
strncpy(*bufferP, string, len);
}
else
{
len = 0;
}
}
return len;
}
int lwm2m_boolToPlainText(bool data,
char ** bufferP)
{
return lwm2m_int64ToPlainText((int64_t)(data?1:0), bufferP);
}

107
notice.html Normal file
View File

@ -0,0 +1,107 @@
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<title>Eclipse Foundation Software User Agreement</title>
</head>
<body lang="EN-US">
<h2>Eclipse Foundation Software User Agreement</h2>
<p>April 9, 2014</p>
<h3>Usage Of Content</h3>
<p>THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS
(COLLECTIVELY &quot;CONTENT&quot;). USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE TERMS AND
CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW. BY USING THE CONTENT, YOU AGREE THAT YOUR USE
OF THE CONTENT IS GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR
NOTICES INDICATED OR REFERENCED BELOW. IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND
CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT USE THE CONTENT.</p>
<h3>Applicable Licenses</h3>
<p>Unless otherwise indicated, all Content made available by the Eclipse Foundation is provided to you under the terms and conditions of the Eclipse Public License Version 1.0
(&quot;EPL&quot;). A copy of the EPL is provided with this Content and is also available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
<p>Content includes, but is not limited to, source code, object code, documentation and other files maintained in the Eclipse Foundation source code
repository (&quot;Repository&quot;) in software modules (&quot;Modules&quot;) and made available as downloadable archives (&quot;Downloads&quot;).</p>
<ul>
<li>Content may be structured and packaged into modules to facilitate delivering, extending, and upgrading the Content. Typical modules may include plug-ins (&quot;Plug-ins&quot;), plug-in fragments (&quot;Fragments&quot;), and features (&quot;Features&quot;).</li>
<li>Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java&trade; ARchive) in a directory named &quot;plugins&quot;.</li>
<li>A Feature is a bundle of one or more Plug-ins and/or Fragments and associated material. Each Feature may be packaged as a sub-directory in a directory named &quot;features&quot;. Within a Feature, files named &quot;feature.xml&quot; may contain a list of the names and version numbers of the Plug-ins
and/or Fragments associated with that Feature.</li>
<li>Features may also include other Features (&quot;Included Features&quot;). Within a Feature, files named &quot;feature.xml&quot; may contain a list of the names and version numbers of Included Features.</li>
</ul>
<p>The terms and conditions governing Plug-ins and Fragments should be contained in files named &quot;about.html&quot; (&quot;Abouts&quot;). The terms and conditions governing Features and
Included Features should be contained in files named &quot;license.html&quot; (&quot;Feature Licenses&quot;). Abouts and Feature Licenses may be located in any directory of a Download or Module
including, but not limited to the following locations:</p>
<ul>
<li>The top-level (root) directory</li>
<li>Plug-in and Fragment directories</li>
<li>Inside Plug-ins and Fragments packaged as JARs</li>
<li>Sub-directories of the directory named &quot;src&quot; of certain Plug-ins</li>
<li>Feature directories</li>
</ul>
<p>Note: if a Feature made available by the Eclipse Foundation is installed using the Provisioning Technology (as defined below), you must agree to a license (&quot;Feature Update License&quot;) during the
installation process. If the Feature contains Included Features, the Feature Update License should either provide you with the terms and conditions governing the Included Features or
inform you where you can locate them. Feature Update Licenses may be found in the &quot;license&quot; property of files named &quot;feature.properties&quot; found within a Feature.
Such Abouts, Feature Licenses, and Feature Update Licenses contain the terms and conditions (or references to such terms and conditions) that govern your use of the associated Content in
that directory.</p>
<p>THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS. SOME OF THESE
OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):</p>
<ul>
<li>Eclipse Distribution License Version 1.0 (available at <a href="http://www.eclipse.org/licenses/edl-v10.html">http://www.eclipse.org/licenses/edl-v1.0.html</a>)</li>
<li>Common Public License Version 1.0 (available at <a href="http://www.eclipse.org/legal/cpl-v10.html">http://www.eclipse.org/legal/cpl-v10.html</a>)</li>
<li>Apache Software License 1.1 (available at <a href="http://www.apache.org/licenses/LICENSE">http://www.apache.org/licenses/LICENSE</a>)</li>
<li>Apache Software License 2.0 (available at <a href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a>)</li>
<li>Mozilla Public License Version 1.1 (available at <a href="http://www.mozilla.org/MPL/MPL-1.1.html">http://www.mozilla.org/MPL/MPL-1.1.html</a>)</li>
</ul>
<p>IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR TO USE OF THE CONTENT. If no About, Feature License, or Feature Update License is provided, please
contact the Eclipse Foundation to determine what terms and conditions govern that particular Content.</p>
<h3>Use of Provisioning Technology</h3>
<p>The Eclipse Foundation makes available provisioning software, examples of which include, but are not limited to, p2 and the Eclipse
Update Manager (&quot;Provisioning Technology&quot;) for the purpose of allowing users to install software, documentation, information and/or
other materials (collectively &quot;Installable Software&quot;). This capability is provided with the intent of allowing such users to
install, extend and update Eclipse-based products. Information about packaging Installable Software is available at <a
href="http://eclipse.org/equinox/p2/repository_packaging.html">http://eclipse.org/equinox/p2/repository_packaging.html</a>
(&quot;Specification&quot;).</p>
<p>You may use Provisioning Technology to allow other parties to install Installable Software. You shall be responsible for enabling the
applicable license agreements relating to the Installable Software to be presented to, and accepted by, the users of the Provisioning Technology
in accordance with the Specification. By using Provisioning Technology in such a manner and making it available in accordance with the
Specification, you further acknowledge your agreement to, and the acquisition of all necessary rights to permit the following:</p>
<ol>
<li>A series of actions may occur (&quot;Provisioning Process&quot;) in which a user may execute the Provisioning Technology
on a machine (&quot;Target Machine&quot;) with the intent of installing, extending or updating the functionality of an Eclipse-based
product.</li>
<li>During the Provisioning Process, the Provisioning Technology may cause third party Installable Software or a portion thereof to be
accessed and copied to the Target Machine.</li>
<li>Pursuant to the Specification, you will provide to the user the terms and conditions that govern the use of the Installable
Software (&quot;Installable Software Agreement&quot;) and such Installable Software Agreement shall be accessed from the Target
Machine in accordance with the Specification. Such Installable Software Agreement must inform the user of the terms and conditions that govern
the Installable Software and must solicit acceptance by the end user in the manner prescribed in such Installable Software Agreement. Upon such
indication of agreement by the user, the provisioning Technology will complete installation of the Installable Software.</li>
</ol>
<h3>Cryptography</h3>
<p>Content may contain encryption software. The country in which you are currently may have restrictions on the import, possession, and use, and/or re-export to
another country, of encryption software. BEFORE using any encryption software, please check the country's laws, regulations and policies concerning the import,
possession, or use, and re-export of encryption software, to see if this is permitted.</p>
<p><small>Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.</small></p>
</body>
</html>

10
tests/TLV/CMakeLists.txt Normal file
View File

@ -0,0 +1,10 @@
cmake_minimum_required (VERSION 2.6)
project (tlvdecode)
include_directories ("${PROJECT_SOURCE_DIR}/../..")
SET(SOURCES decode.c)
SET(CORE_SOURCES ${PROJECT_SOURCE_DIR}/../../core/tlv.c)
add_executable(tlvdecode ${SOURCES} ${CORE_SOURCES})

244
tests/TLV/decode.c Normal file
View File

@ -0,0 +1,244 @@
/*******************************************************************************
*
* Copyright (c) 2013, 2014 Intel Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* The Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* David Navarro, Intel Corporation - initial API and implementation
*
*******************************************************************************/
#include "core/liblwm2m.h"
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
static void prv_output_buffer(uint8_t * buffer,
int length)
{
int i;
uint8_t array[16];
if (length == 0 || length > 16) printf("\n");
i = 0;
while (i < length)
{
int j;
printf(" ");
memcpy(array, buffer+i, 16);
for (j = 0 ; j < 16 && i+j < length; j++)
{
printf("%02X ", array[j]);
}
if (length > 16)
{
while (j < 16)
{
printf(" ");
j++;
}
}
printf(" ");
for (j = 0 ; j < 16 && i+j < length; j++)
{
if (isprint(array[j]))
printf("%c ", array[j]);
else
printf(". ");
}
printf("\n");
i += 16;
}
}
void print_indent(int num)
{
int i;
for ( i = 0 ; i< num ; i++)
printf("\t");
}
void dump_tlv(int size,
lwm2m_tlv_t * tlvP,
int indent)
{
int i;
for(i= 0 ; i < size ; i++)
{
print_indent(indent);
printf("type: ");
switch (tlvP[i].type)
{
case LWM2M_TYPE_OBJECT_INSTANCE:
printf("TLV_OBJECT_INSTANCE\r\n");
break;
case LWM2M_TYPE_RESSOURCE_INSTANCE:
printf("TLV_RESSOURCE_INSTANCE\r\n");
break;
case LWM2M_TYPE_MULTIPLE_RESSOURCE:
printf("TLV_MULTIPLE_INSTANCE\r\n");
break;
case LWM2M_TYPE_RESSOURCE:
printf("TLV_RESSOURCE\r\n");
break;
default:
printf("unknown (%d)\r\n", (int)tlvP[i].type);
break;
}
print_indent(indent);
printf("id: %d\r\n", tlvP[i].id);
print_indent(indent);
printf("data (%d bytes): ", tlvP[i].length);
prv_output_buffer(tlvP[i].value, tlvP[i].length);
if (tlvP[i].type == LWM2M_TYPE_OBJECT_INSTANCE
|| tlvP[i].type == LWM2M_TYPE_MULTIPLE_RESSOURCE)
{
dump_tlv(tlvP[i].length, (lwm2m_tlv_t *)(tlvP[i].value), indent+1);
}
else if (tlvP[i].length <= 8)
{
int64_t value;
if (0 != lwm2m_opaqueToInt(tlvP[i].value, tlvP[i].length, &value))
{
print_indent(indent);
printf(" as int: %ld\r\n", value);
}
}
}
}
void decode(char * buffer,
size_t buffer_len,
int indent)
{
lwm2m_tlv_type_t type;
uint16_t id;
size_t dataIndex;
size_t dataLen;
int length = 0;
int result;
while (0 != (result = lwm2m_decodeTLV(buffer + length, buffer_len - length, &type, &id, &dataIndex, &dataLen)))
{
print_indent(indent);
printf("type: ");
switch (type)
{
case TLV_OBJECT_INSTANCE:
printf("TLV_OBJECT_INSTANCE\r\n");
break;
case TLV_RESSOURCE_INSTANCE:
printf("TLV_RESSOURCE_INSTANCE\r\n");
break;
case TLV_MULTIPLE_INSTANCE:
printf("TLV_MULTIPLE_INSTANCE\r\n");
break;
case TLV_RESSOURCE:
printf("TLV_RESSOURCE\r\n");
break;
default:
printf("unknown (%d)\r\n", (int)type);
break;
}
print_indent(indent);
printf("id: %d\r\n", id);
print_indent(indent);
printf("data (%d bytes): ", dataLen);
prv_output_buffer(buffer + length + dataIndex, dataLen);
if (type == TLV_OBJECT_INSTANCE || type == TLV_MULTIPLE_INSTANCE)
{
decode(buffer + length + dataIndex, dataLen, indent+1);
}
else if (dataLen <= 8)
{
int64_t value;
if (0 != lwm2m_opaqueToInt(buffer + length + dataIndex, dataLen, &value))
{
print_indent(indent);
printf(" as int: %ld\r\n", value);
}
}
length += result;
}
}
int main(int argc, char *argv[])
{
lwm2m_tlv_t * tlvP;
int size;
int length;
char * buffer;
char buffer1[] = {0x03, 0x0A, 0xC1, 0x01, 0x14, 0x03, 0x0B, 0xC1, 0x01, 0x15, 0x03, 0x0C, 0xC1, 0x01, 0x16};
char buffer2[] = {0xC8, 0x00, 0x14, 0x4F, 0x70, 0x65, 0x6E, 0x20, 0x4D, 0x6F, 0x62, 0x69, 0x6C, 0x65, 0x20,
0x41, 0x6C, 0x6C, 0x69, 0x61, 0x6E, 0x63, 0x65, 0xC8, 0x01, 0x16, 0x4C, 0x69, 0x67, 0x68,
0x74, 0x77 , 0x65, 0x69, 0x67, 0x68, 0x74, 0x20, 0x4D, 0x32, 0x4D, 0x20, 0x43, 0x6C, 0x69,
0x65, 0x6E, 0x74 , 0xC8, 0x02, 0x09, 0x33, 0x34, 0x35, 0x30, 0x30, 0x30, 0x31, 0x32, 0x33,
0xC3, 0x03, 0x31, 0x2E , 0x30, 0x86, 0x06, 0x41, 0x00, 0x01, 0x41, 0x01, 0x05, 0x88, 0x07,
0x08, 0x42, 0x00, 0x0E, 0xD8 , 0x42, 0x01, 0x13, 0x88, 0x87, 0x08, 0x41, 0x00, 0x7D, 0x42,
0x01, 0x03, 0x84, 0xC1, 0x09, 0x64 , 0xC1, 0x0A, 0x0F, 0x83, 0x0B, 0x41, 0x00, 0x00, 0xC4,
0x0D, 0x51, 0x82, 0x42, 0x8F, 0xC6, 0x0E, 0x2B, 0x30, 0x32, 0x3A, 0x30, 0x30, 0xC1, 0x0F, 0x55};
printf("Buffer 1:\n");
decode(buffer1, sizeof(buffer1), 0);
printf("\n\nBuffer 1 using lwm2m_tlv_t:\n");
size = lwm2m_tlv_parse(buffer1, sizeof(buffer1), &tlvP);
dump_tlv(size, tlvP, 0);
length = lwm2m_tlv_serialize(size, tlvP, &buffer);
if (length != sizeof(buffer1))
{
printf("\n\nSerialize Buffer 1 failed: %d bytes instead of %d\n", length, sizeof(buffer1));
}
else if (memcmp(buffer, buffer1, length) != 0)
{
printf("\n\nSerialize Buffer 1 failed:\n");
prv_output_buffer(buffer, length);
printf("\ninstead of:\n");
prv_output_buffer(buffer1, length);
}
else
{
printf("\n\nSerialize Buffer 1 OK\n");
}
lwm2m_tlv_free(size, tlvP);
printf("\n\n============\n\nBuffer 2: \r\r\n");
decode(buffer2, sizeof(buffer2), 0);
printf("\n\nBuffer 2 using lwm2m_tlv_t: \r\r\n");
size = lwm2m_tlv_parse(buffer2, sizeof(buffer2), &tlvP);
dump_tlv(size, tlvP, 0);
length = lwm2m_tlv_serialize(size, tlvP, &buffer);
if (length != sizeof(buffer2))
{
printf("\n\nSerialize Buffer 2 failed: %d bytes instead of %d\n", length, sizeof(buffer2));
}
else if (memcmp(buffer, buffer2, length) != 0)
{
printf("\n\nSerialize Buffer 2 failed:\n");
prv_output_buffer(buffer, length);
printf("\ninstead of:\n");
prv_output_buffer(buffer2, length);
}
else
{
printf("\n\nSerialize Buffer 2 OK\n\n");
}
lwm2m_tlv_free(size, tlvP);
}

View File

@ -0,0 +1,15 @@
cmake_minimum_required (VERSION 2.8.3)
project (lwm2mclient)
SET(LIBLWM2M_DIR ${PROJECT_SOURCE_DIR}/../../core)
add_definitions(-DLWM2M_CLIENT_MODE)
include_directories (${LIBLWM2M_DIR} ${PROJECT_SOURCE_DIR}/../utils)
add_subdirectory(${LIBLWM2M_DIR} ${CMAKE_CURRENT_BINARY_DIR}/core)
SET(SOURCES lwm2mclient.c ../utils/commandline.c ../utils/connection.c object_device.c object_firmware.c test_object.c)
add_executable(lwm2mclient ${SOURCES} ${CORE_SOURCES})

483
tests/client/lwm2mclient.c Normal file
View File

@ -0,0 +1,483 @@
/*******************************************************************************
*
* Copyright (c) 2013, 2014 Intel Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* The Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* David Navarro, Intel Corporation - initial API and implementation
* Benjamin Cabé - Please refer to git log
* Fabien Fleutot - Please refer to git log
* Simon Bernard - Please refer to git log
* Julien Vermillard - Please refer to git log
* Axel Lorente - Please refer to git log
* Toby Jaffey - Please refer to git log
*
*******************************************************************************/
/*
Copyright (c) 2013, 2014 Intel Corporation
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of Intel Corporation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
David Navarro <david.navarro@intel.com>
*/
#include "liblwm2m.h"
#include "commandline.h"
#include "connection.h"
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <ctype.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/stat.h>
#include <errno.h>
#include <signal.h>
#define MAX_PACKET_SIZE 128
static int g_quit = 0;
extern lwm2m_object_t * get_object_device();
extern lwm2m_object_t * get_object_firmware();
extern lwm2m_object_t * get_test_object();
static void prv_quit(char * buffer,
void * user_data)
{
g_quit = 1;
}
void handle_sigint(int signum)
{
g_quit = 2;
}
void print_usage(void)
{
fprintf(stderr, "Usage: lwm2mclient\r\n");
fprintf(stderr, "Launch a LWM2M client.\r\n\n");
}
static uint8_t prv_buffer_send(void * sessionH,
uint8_t * buffer,
size_t length,
void * userdata)
{
connection_t * connP = (connection_t*) sessionH;
if (-1 == connection_send(connP, buffer, length))
{
return COAP_500_INTERNAL_SERVER_ERROR;
}
return COAP_NO_ERROR;
}
static void prv_output_servers(char * buffer,
void * user_data)
{
lwm2m_context_t * lwm2mH = (lwm2m_context_t *) user_data;
lwm2m_server_t * targetP;
targetP = lwm2mH->serverList;
if (targetP == NULL)
{
fprintf(stdout, "No server.\r\n");
return;
}
for (targetP = lwm2mH->serverList ; targetP != NULL ; targetP = targetP->next)
{
fprintf(stdout, "Server ID %d:\r\n", targetP->shortID);
fprintf(stdout, "\tstatus: ");
switch(targetP->status)
{
case STATE_UNKNOWN:
fprintf(stdout, "UNKNOWN\r\n");
break;
case STATE_REG_PENDING:
fprintf(stdout, "REGISTRATION PENDING\r\n");
break;
case STATE_REGISTERED:
fprintf(stdout, "REGISTERED location: \"%s\"\r\n", targetP->location);
break;
}
fprintf(stdout, "\r\n");
}
}
static void prv_change(char * buffer,
void * user_data)
{
lwm2m_context_t * lwm2mH = (lwm2m_context_t *) user_data;
lwm2m_uri_t uri;
int result;
size_t length;
if (buffer[0] == 0) goto syntax_error;
length = 0;
// remove white space
while (length < strlen(buffer) && isspace(buffer[length]))
{
length++;
}
// find end of URI
while (length < strlen(buffer) && !isspace(buffer[length]))
{
length++;
}
result = lwm2m_stringToUri(buffer, length, &uri);
if (result == 0) goto syntax_error;
buffer += length;
while (buffer[0] != 0 && isspace(buffer[0])) buffer++;
if (buffer[0] == 0)
{
lwm2m_resource_value_changed(lwm2mH, &uri);
}
else
{
int i;
i = 0;
while (i < lwm2mH->numObject)
{
if (uri.objectId == lwm2mH->objectList[i]->objID)
{
if (lwm2mH->objectList[i]->writeFunc != NULL)
{
lwm2m_tlv_t * tlvP;
tlvP = lwm2m_tlv_new(1);
if (tlvP == NULL)
{
fprintf(stdout, "Internal allocation failure !\n");
return;
}
tlvP->flags = LWM2M_TLV_FLAG_STATIC_DATA | LWM2M_TLV_FLAG_TEXT_FORMAT;
tlvP->id = uri.resourceId;
tlvP->length = strlen(buffer);
tlvP->value = buffer;
if (COAP_204_CHANGED != lwm2mH->objectList[i]->writeFunc(uri.instanceId,
1, tlvP,
lwm2mH->objectList[i]))
{
fprintf(stdout, "Failed to change value !\n");
}
else
{
lwm2m_resource_value_changed(lwm2mH, &uri);
}
lwm2m_tlv_free(1, tlvP);
return;
}
return;
}
i++;
}
fprintf(stdout, "Object not found !\n");
}
return;
syntax_error:
fprintf(stdout, "Syntax error !\n");
}
int main(int argc, char *argv[])
{
int sock;
int result;
lwm2m_context_t * lwm2mH = NULL;
lwm2m_object_t * objArray[3];
lwm2m_security_t security;
int i;
connection_t * connList;
connList = NULL;
/*
* The function start by setting up the command line interface (which may or not be useful depending on your project)
*
* This is an array of commands describes as { name, description, long description, callback, userdata }.
* The firsts tree are easy to understand, the callback is the function that will be called when this command is typed
* and in the last one will be stored the lwm2m context (allowing access to the server settings and the objects).
*/
command_desc_t commands[] =
{
{"list", "List known servers.", NULL, prv_output_servers, NULL},
{"change", "Change the value of resource.", " change URI [DATA]\r\n"
" URI: uri of the resource such as /3/0, /3/0/2\r\n"
" DATA: (optional) new value\r\n", prv_change, NULL},
{"quit", "Quit the client gracefully.", NULL, prv_quit, NULL},
{"^C", "Quit the client abruptly (without sending a de-register message).", NULL, NULL, NULL},
COMMAND_END_LIST
};
/*
*This call an internal function that create an IPV6 socket on the port 5683.
*/
sock = create_socket("5683");
if (sock < 0)
{
fprintf(stderr, "Failed to open socket: %d\r\n", errno);
return -1;
}
/*
* Now the main function fill an array with each object, this list will be later passed to liblwm2m.
* Those functions are located in their respective object file.
*/
objArray[0] = get_object_device();
if (NULL == objArray[0])
{
fprintf(stderr, "Failed to create Device object\r\n");
return -1;
}
objArray[1] = get_object_firmware();
if (NULL == objArray[1])
{
fprintf(stderr, "Failed to create Firmware object\r\n");
return -1;
}
objArray[2] = get_test_object();
if (NULL == objArray[2])
{
fprintf(stderr, "Failed to create test object\r\n");
return -1;
}
/*
* The liblwm2m library is now initialized with the name of the client - which shall be unique for each client -
* the number of objects we will be passing through, the object constructor array and the function that will be in
* charge to send the buffer (containing the LWM2M packets) to the network
*/
lwm2mH = lwm2m_init("testlwm2mclient", 3, objArray, prv_buffer_send, NULL);
if (NULL == lwm2mH)
{
fprintf(stderr, "lwm2m_init() failed\r\n");
return -1;
}
signal(SIGINT, handle_sigint);
connList = connection_create(connList, sock, "localhost", LWM2M_STANDARD_PORT);
if (connList == NULL)
{
fprintf(stderr, "Connection creation failed.\r\n");
return -1;
}
memset(&security, 0, sizeof(lwm2m_security_t));
/*
* This function add a server to the lwm2m context by passing an identifier, an opaque connection handler and a security
* context.
* You can add as many server as your application need and there will be thereby allowed to interact with your object
*/
result = lwm2m_add_server(lwm2mH, 123, (void *)connList, &security);
if (result != 0)
{
fprintf(stderr, "lwm2m_add_server() failed: 0x%X\r\n", result);
return -1;
}
/*
* This function register your client to all the servers you added with the precedent one
*/
result = lwm2m_register(lwm2mH);
if (result != 0)
{
fprintf(stderr, "lwm2m_register() failed: 0x%X\r\n", result);
return -1;
}
/*
* As you now have your lwm2m context complete you can pass it as an argument to all the command line functions
* precedently viewed (first point)
*/
for (i = 0 ; commands[i].name != NULL ; i++)
{
commands[i].userData = (void *)lwm2mH;
}
fprintf(stdout, "> "); fflush(stdout);
/*
* We now enter in a while loop that will handle the communications from the server
*/
while (0 == g_quit)
{
struct timeval tv;
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(sock, &readfds);
FD_SET(STDIN_FILENO, &readfds);
tv.tv_sec = 60;
tv.tv_usec = 0;
/*
* This function does two things:
* - first it does the work needed by liblwm2m (eg. (re)sending some packets).
* - Secondly it adjust the timeout value (default 60s) depending on the state of the transaction
* (eg. retransmission) and the time between the next operation
*/
result = lwm2m_step(lwm2mH, &tv);
if (result != 0)
{
fprintf(stderr, "lwm2m_step() failed: 0x%X\r\n", result);
return -1;
}
/*
* This part will set up an interruption until an event happen on SDTIN or the socket until "tv" timed out (set
* with the precedent function)
*/
result = select(FD_SETSIZE, &readfds, NULL, NULL, &tv);
if ( result < 0 )
{
if (errno != EINTR)
{
fprintf(stderr, "Error in select(): %d\r\n", errno);
}
}
else if (result > 0)
{
uint8_t buffer[MAX_PACKET_SIZE];
int numBytes;
/*
* If an event happen on the socket
*/
if (FD_ISSET(sock, &readfds))
{
struct sockaddr_storage addr;
socklen_t addrLen;
addrLen = sizeof(addr);
/*
* We retrieve the data received
*/
numBytes = recvfrom(sock, buffer, MAX_PACKET_SIZE, 0, (struct sockaddr *)&addr, &addrLen);
if (numBytes == -1)
{
fprintf(stderr, "Error in recvfrom(): %d\r\n", errno);
}
else
{
char s[INET6_ADDRSTRLEN];
connection_t * connP;
fprintf(stderr, "%d bytes received from [%s]:%hu\r\n",
numBytes,
inet_ntop(addr.ss_family,
&(((struct sockaddr_in6*)&addr)->sin6_addr),
s,
INET6_ADDRSTRLEN),
ntohs(((struct sockaddr_in6*)&addr)->sin6_port));
/*
* Display it in the STDERR
*/
output_buffer(stderr, buffer, numBytes);
connP = connection_find(connList, &addr, addrLen);
if (connP != NULL)
{
/*
* Let liblwm2m respond to the query depending on the context
*/
lwm2m_handle_packet(lwm2mH, buffer, numBytes, connP);
}
}
}
/*
* If the event happened on the SDTIN
*/
else if (FD_ISSET(STDIN_FILENO, &readfds))
{
numBytes = read(STDIN_FILENO, buffer, MAX_PACKET_SIZE);
if (numBytes > 1)
{
buffer[numBytes - 1] = 0;
/*
* We call the corresponding callback of the typed command passing it the buffer for further arguments
*/
handle_command(commands, buffer);
}
if (g_quit == 0)
{
fprintf(stdout, "\r\n> ");
fflush(stdout);
}
else
{
fprintf(stdout, "\r\n");
}
}
}
}
/*
* Finally when the loop is left smoothly - asked by user in the command line interface - we unregister our client from it
*/
if (g_quit == 1)
{
lwm2m_close(lwm2mH);
}
close(sock);
connection_free(connList);
return 0;
}

View File

@ -0,0 +1,490 @@
/*******************************************************************************
*
* Copyright (c) 2013, 2014 Intel Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* The Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* David Navarro, Intel Corporation - initial API and implementation
* domedambrosio - Please refer to git log
* Fabien Fleutot - Please refer to git log
* Axel Lorente - Please refer to git log
*
*******************************************************************************/
/*
Copyright (c) 2013, 2014 Intel Corporation
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of Intel Corporation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
David Navarro <david.navarro@intel.com>
*/
/*
* This object is single instance only, and is mandatory to all LWM2M device as it describe the object such as its
* manufacturer, model, etc...
*/
#include "liblwm2m.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define PRV_MANUFACTURER "Open Mobile Alliance"
#define PRV_MODEL_NUMBER "Lightweight M2M Client"
#define PRV_SERIAL_NUMBER "345000123"
#define PRV_FIRMWARE_VERSION "1.0"
#define PRV_POWER_SOURCE_1 1
#define PRV_POWER_SOURCE_2 5
#define PRV_POWER_VOLTAGE_1 3800
#define PRV_POWER_VOLTAGE_2 5000
#define PRV_POWER_CURRENT_1 125
#define PRV_POWER_CURRENT_2 900
#define PRV_BATTERY_LEVEL 100
#define PRV_MEMORY_FREE 15
#define PRV_ERROR_CODE 0
#define PRV_BINDING_MODE "U"
#define PRV_OFFSET_MAXLEN 7 //+HH:MM\0 at max
#define PRV_TLV_BUFFER_SIZE 128
typedef struct
{
int64_t time;
char time_offset[PRV_OFFSET_MAXLEN];
} device_data_t;
// basic check that the time offset value is at ISO 8601 format
// bug: +12:30 is considered a valid value by this function
static int prv_check_time_offset(char * buffer,
int length)
{
int min_index;
if (length != 3 && length != 5 && length != 6) return 0;
if (buffer[0] != '-' && buffer[0] != '+') return 0;
switch (buffer[1])
{
case '0':
if (buffer[2] < '0' || buffer[2] > '9') return 0;
break;
case '1':
if (buffer[2] < '0' || buffer[2] > '2') return 0;
break;
default:
return 0;
}
switch (length)
{
case 3:
return 1;
case 5:
min_index = 3;
break;
case 6:
if (buffer[3] != ':') return 0;
min_index = 4;
break;
default:
// never happen
return 0;
}
if (buffer[min_index] < '0' || buffer[min_index] > '5') return 0;
if (buffer[min_index+1] < '0' || buffer[min_index+1] > '9') return 0;
return 1;
}
static uint8_t prv_set_value(lwm2m_tlv_t * tlvP,
device_data_t * devDataP)
{
// a simple switch structure is used to respond at the specified resource asked
switch (tlvP->id)
{
case 0:
tlvP->value = PRV_MANUFACTURER;
tlvP->length = strlen(PRV_MANUFACTURER);
tlvP->flags = LWM2M_TLV_FLAG_STATIC_DATA;
tlvP->type = LWM2M_TYPE_RESSOURCE;
return COAP_205_CONTENT;
case 1:
tlvP->value = PRV_MODEL_NUMBER;
tlvP->length = strlen(PRV_MODEL_NUMBER);
tlvP->flags = LWM2M_TLV_FLAG_STATIC_DATA;
tlvP->type = LWM2M_TYPE_RESSOURCE;
return COAP_205_CONTENT;
case 2:
tlvP->value = PRV_SERIAL_NUMBER;
tlvP->length = strlen(PRV_SERIAL_NUMBER);
tlvP->flags = LWM2M_TLV_FLAG_STATIC_DATA;
tlvP->type = LWM2M_TYPE_RESSOURCE;
return COAP_205_CONTENT;
case 3:
tlvP->value = PRV_FIRMWARE_VERSION;
tlvP->length = strlen(PRV_FIRMWARE_VERSION);
tlvP->flags = LWM2M_TLV_FLAG_STATIC_DATA;
tlvP->type = LWM2M_TYPE_RESSOURCE;
return COAP_205_CONTENT;
case 4:
return COAP_405_METHOD_NOT_ALLOWED;
case 5:
return COAP_405_METHOD_NOT_ALLOWED;
case 6:
{
lwm2m_tlv_t * subTlvP;
subTlvP = lwm2m_tlv_new(2);
subTlvP[0].flags = 0;
subTlvP[0].id = 0;
subTlvP[0].type = LWM2M_TYPE_RESSOURCE_INSTANCE;
lwm2m_tlv_encode_int(PRV_POWER_SOURCE_1, subTlvP);
if (0 == subTlvP[0].length)
{
lwm2m_tlv_free(2, subTlvP);
return COAP_500_INTERNAL_SERVER_ERROR;
}
subTlvP[1].flags = 0;
subTlvP[1].id = 1;
subTlvP[1].type = LWM2M_TYPE_RESSOURCE_INSTANCE;
lwm2m_tlv_encode_int(PRV_POWER_SOURCE_2, subTlvP + 1);
if (0 == subTlvP[1].length)
{
lwm2m_tlv_free(2, subTlvP);
return COAP_500_INTERNAL_SERVER_ERROR;
}
tlvP->flags = 0;
tlvP->type = LWM2M_TYPE_MULTIPLE_RESSOURCE;
tlvP->length = 2;
tlvP->value = (uint8_t *)subTlvP;
return COAP_205_CONTENT;
}
case 7:
{
lwm2m_tlv_t * subTlvP;
subTlvP = lwm2m_tlv_new(2);
subTlvP[0].flags = 0;
subTlvP[0].id = 0;
subTlvP[0].type = LWM2M_TYPE_RESSOURCE_INSTANCE;
lwm2m_tlv_encode_int(PRV_POWER_VOLTAGE_1, subTlvP);
if (0 == subTlvP[0].length)
{
lwm2m_tlv_free(2, subTlvP);
return COAP_500_INTERNAL_SERVER_ERROR;
}
subTlvP[1].flags = 0;
subTlvP[1].id = 1;
subTlvP[1].type = LWM2M_TYPE_RESSOURCE_INSTANCE;
lwm2m_tlv_encode_int(PRV_POWER_VOLTAGE_2, subTlvP + 1);
if (0 == subTlvP[1].length)
{
lwm2m_tlv_free(2, subTlvP);
return COAP_500_INTERNAL_SERVER_ERROR;
}
tlvP->flags = 0;
tlvP->type = LWM2M_TYPE_MULTIPLE_RESSOURCE;
tlvP->length = 2;
tlvP->value = (uint8_t *)subTlvP;
return COAP_205_CONTENT;
}
case 8:
{
lwm2m_tlv_t * subTlvP;
subTlvP = lwm2m_tlv_new(2);
subTlvP[0].flags = 0;
subTlvP[0].id = 0;
subTlvP[0].type = LWM2M_TYPE_RESSOURCE_INSTANCE;
lwm2m_tlv_encode_int(PRV_POWER_CURRENT_1, subTlvP);
if (0 == subTlvP[0].length)
{
lwm2m_tlv_free(2, subTlvP);
return COAP_500_INTERNAL_SERVER_ERROR;
}
subTlvP[1].flags = 0;
subTlvP[1].id = 1;
subTlvP[1].type = LWM2M_TYPE_RESSOURCE_INSTANCE;
lwm2m_tlv_encode_int(PRV_POWER_CURRENT_2, subTlvP + 1);
if (0 == subTlvP[1].length)
{
lwm2m_tlv_free(2, subTlvP);
return COAP_500_INTERNAL_SERVER_ERROR;
}
tlvP->flags = 0;
tlvP->type = LWM2M_TYPE_MULTIPLE_RESSOURCE;
tlvP->length = 2;
tlvP->value = (uint8_t *)subTlvP;
return COAP_205_CONTENT;
}
case 9:
lwm2m_tlv_encode_int(PRV_BATTERY_LEVEL, tlvP);
tlvP->type = LWM2M_TYPE_RESSOURCE;
if (0 != tlvP->length) return COAP_205_CONTENT;
else return COAP_500_INTERNAL_SERVER_ERROR;
case 10:
lwm2m_tlv_encode_int(PRV_MEMORY_FREE, tlvP);
tlvP->type = LWM2M_TYPE_RESSOURCE;
if (0 != tlvP->length) return COAP_205_CONTENT;
else return COAP_500_INTERNAL_SERVER_ERROR;
case 11:
lwm2m_tlv_encode_int(PRV_ERROR_CODE, tlvP);
tlvP->type = LWM2M_TYPE_RESSOURCE;
if (0 != tlvP->length) return COAP_205_CONTENT;
else return COAP_500_INTERNAL_SERVER_ERROR;
case 12:
return COAP_405_METHOD_NOT_ALLOWED;
case 13:
lwm2m_tlv_encode_int(devDataP->time, tlvP);
tlvP->type = LWM2M_TYPE_RESSOURCE;
if (0 != tlvP->length) return COAP_205_CONTENT;
else return COAP_500_INTERNAL_SERVER_ERROR;
case 14:
tlvP->value = devDataP->time_offset;
tlvP->length = strlen(devDataP->time_offset);
tlvP->flags = LWM2M_TLV_FLAG_STATIC_DATA;
tlvP->type = LWM2M_TYPE_RESSOURCE;
return COAP_205_CONTENT;
case 15:
tlvP->value = PRV_BINDING_MODE;
tlvP->length = strlen(PRV_BINDING_MODE);
tlvP->flags = LWM2M_TLV_FLAG_STATIC_DATA;
tlvP->type = LWM2M_TYPE_RESSOURCE;
return COAP_205_CONTENT;
default:
return COAP_404_NOT_FOUND;
}
}
static uint8_t prv_device_read(uint16_t instanceId,
int * numDataP,
lwm2m_tlv_t ** dataArrayP,
lwm2m_object_t * objectP)
{
uint8_t result;
int i;
// this is a single instance object
if (instanceId != 0)
{
return COAP_404_NOT_FOUND;
}
// is the server asking for the full object ?
if (*numDataP == 0)
{
uint16_t resList[] = {0, 1, 2, 3, 6, 7, 8, 9, 10, 11, 13, 14, 15};
int nbRes = sizeof(resList)/sizeof(uint16_t);
*dataArrayP = lwm2m_tlv_new(nbRes);
if (*dataArrayP == NULL) return COAP_500_INTERNAL_SERVER_ERROR;
*numDataP = nbRes;
for (i = 0 ; i < nbRes ; i++)
{
(*dataArrayP)[i].id = resList[i];
}
}
i = 0;
do
{
result = prv_set_value((*dataArrayP) + i, (device_data_t*)(objectP->userData));
i++;
} while (i < *numDataP && result == COAP_205_CONTENT);
return result;
}
static uint8_t prv_device_write(uint16_t instanceId,
int numData,
lwm2m_tlv_t * dataArray,
lwm2m_object_t * objectP)
{
int i;
uint8_t result;
// this is a single instance object
if (instanceId != 0)
{
return COAP_404_NOT_FOUND;
}
i = 0;
do
{
switch (dataArray[i].id)
{
case 13:
if (1 == lwm2m_tlv_decode_int(dataArray + i, &((device_data_t*)(objectP->userData))->time))
{
result = COAP_204_CHANGED;
}
else
{
result = COAP_400_BAD_REQUEST;
}
break;
case 14:
if (1 == prv_check_time_offset(dataArray[i].value, dataArray[i].length))
{
strncpy(((device_data_t*)(objectP->userData))->time_offset, dataArray[i].value, dataArray[i].length);
((device_data_t*)(objectP->userData))->time_offset[dataArray[i].length] = 0;
result = COAP_204_CHANGED;
}
else
{
result = COAP_400_BAD_REQUEST;
}
break;
default:
result = COAP_405_METHOD_NOT_ALLOWED;
}
i++;
} while (i < numData && result == COAP_204_CHANGED);
return result;
}
static uint8_t prv_device_execute(uint16_t instanceId,
uint16_t resourceId,
char * buffer,
int length,
lwm2m_object_t * objectP)
{
// this is a single instance object
if (instanceId != 0)
{
return COAP_404_NOT_FOUND;
}
if (length != 0) return COAP_400_BAD_REQUEST;
switch (resourceId)
{
case 4:
fprintf(stdout, "\n\t REBOOT\r\n\n");
return COAP_204_CHANGED;
case 5:
fprintf(stdout, "\n\t FACTORY RESET\r\n\n");
return COAP_204_CHANGED;
case 12:
fprintf(stdout, "\n\t RESET ERROR CODE\r\n\n");
return COAP_204_CHANGED;
default:
return COAP_405_METHOD_NOT_ALLOWED;
}
}
lwm2m_object_t * get_object_device()
{
/*
* The get_object_device function create the object itself and return a pointer to the structure that represent it.
*/
lwm2m_object_t * deviceObj;
deviceObj = (lwm2m_object_t *)malloc(sizeof(lwm2m_object_t));
if (NULL != deviceObj)
{
memset(deviceObj, 0, sizeof(lwm2m_object_t));
/*
* It assign his unique ID
* The 3 is the standard ID for the mandatory object "Object device".
*/
deviceObj->objID = 3;
/*
* And the private function that will access the object.
* Those function will be called when a read/write/execute query is made by the server. In fact the library don't need to
* know the resources of the object, only the server does.
*/
deviceObj->readFunc = prv_device_read;
deviceObj->writeFunc = prv_device_write;
deviceObj->executeFunc = prv_device_execute;
deviceObj->userData = malloc(sizeof(device_data_t));
/*
* Also some user data can be stored in the object with a private structure containing the needed variables
*/
if (NULL != deviceObj->userData)
{
((device_data_t*)deviceObj->userData)->time = 1367491215;
strcpy(((device_data_t*)deviceObj->userData)->time_offset, "+02:00");
}
else
{
free(deviceObj);
deviceObj = NULL;
}
}
return deviceObj;
}

View File

@ -0,0 +1,271 @@
/*******************************************************************************
*
* Copyright (c) 2013, 2014 Intel Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* The Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Julien Vermillard - initial implementation
* Fabien Fleutot - Please refer to git log
* David Navarro, Intel Corporation - Please refer to git log
*
*******************************************************************************/
/*
* This object is single instance only, and provide firmware upgrade functionality.
* Object ID is 5.
*/
/*
* resources:
* 0 package write
* 1 package url write
* 2 update exec
* 3 state read
* 4 update supported objects read/write
* 5 update result read
*/
#include "liblwm2m.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define PRV_TLV_BUFFER_SIZE 128
typedef struct
{
uint8_t state;
uint8_t supported;
uint8_t result;
} firmware_data_t;
static uint8_t prv_firmware_read(uint16_t instanceId,
int * numDataP,
lwm2m_tlv_t ** dataArrayP,
lwm2m_object_t * objectP)
{
int i;
uint8_t result;
firmware_data_t * data = (firmware_data_t*)(objectP->userData);
// this is a single instance object
if (instanceId != 0)
{
return COAP_404_NOT_FOUND;
}
// is the server asking for the full object ?
if (*numDataP == 0)
{
uint16_t resList[] = {0, 1, 2, 3, 6, 7, 8, 9, 10, 11, 13, 14, 15};
int nbRes = sizeof(resList)/sizeof(uint16_t);
*dataArrayP = lwm2m_tlv_new(3);
if (*dataArrayP == NULL) return COAP_500_INTERNAL_SERVER_ERROR;
*numDataP = 3;
(*dataArrayP)[0].id = 3;
(*dataArrayP)[1].id = 4;
(*dataArrayP)[2].id = 5;
}
i = 0;
do
{
switch ((*dataArrayP)[i].id)
{
case 0:
case 1:
case 2:
result = COAP_405_METHOD_NOT_ALLOWED;
break;
case 3:
// firmware update state (int)
lwm2m_tlv_encode_int(data->state, *dataArrayP + i);
(*dataArrayP)[i].type = LWM2M_TYPE_RESSOURCE;
if (0 != (*dataArrayP)[i].length) result = COAP_205_CONTENT;
else result = COAP_500_INTERNAL_SERVER_ERROR;
break;
case 4:
lwm2m_tlv_encode_int(data->supported, *dataArrayP + i);
(*dataArrayP)[i].type = LWM2M_TYPE_RESSOURCE;
if (0 != (*dataArrayP)[i].length) result = COAP_205_CONTENT;
else result = COAP_500_INTERNAL_SERVER_ERROR;
break;
case 5:
lwm2m_tlv_encode_int(data->result, *dataArrayP + i);
(*dataArrayP)[i].type = LWM2M_TYPE_RESSOURCE;
if (0 != (*dataArrayP)[i].length) result = COAP_205_CONTENT;
else result = COAP_500_INTERNAL_SERVER_ERROR;
break;
default:
result = COAP_404_NOT_FOUND;
}
i++;
} while (i < *numDataP && result == COAP_205_CONTENT);
return result;
}
static uint8_t prv_firmware_write(uint16_t instanceId,
int numData,
lwm2m_tlv_t * dataArray,
lwm2m_object_t * objectP)
{
int i;
uint8_t result;
firmware_data_t * data = (firmware_data_t*)(objectP->userData);
// this is a single instance object
if (instanceId != 0)
{
return COAP_404_NOT_FOUND;
}
i = 0;
do
{
switch (dataArray[i].id)
{
case 0:
// inline firmware binary
result = COAP_204_CHANGED;
break;
case 1:
// URL for download the firmware
result = COAP_204_CHANGED;
break;
case 4:
if (1 == dataArray[i].length && dataArray[i].value[0] == '0')
{
data->supported = 0;
result = COAP_204_CHANGED;
}
else if (1 == dataArray[i].length && dataArray[i].value[0] == '1')
{
data->supported = 1;
result = COAP_204_CHANGED;
}
else
{
result = COAP_400_BAD_REQUEST;
}
break;
default:
result = COAP_405_METHOD_NOT_ALLOWED;
}
i++;
} while (i < numData && result == COAP_204_CHANGED);
return result;
}
static uint8_t prv_firmware_execute(uint16_t instanceId,
uint16_t resourceId,
char * buffer,
int length,
lwm2m_object_t * objectP)
{
firmware_data_t * data = (firmware_data_t*)(objectP->userData);
// this is a single instance object
if (instanceId != 0)
{
return COAP_404_NOT_FOUND;
}
if (length != 0) return COAP_400_BAD_REQUEST;
// for execute callback, resId is always set.
switch (resourceId)
{
case 2:
if (data->state == 1)
{
fprintf(stdout, "\n\t FIRMWARE UPDATE\r\n\n");
// trigger your firmware download and update logic
data->state = 2;
return COAP_204_CHANGED;
} else {
// firmware update already running
return COAP_400_BAD_REQUEST;
}
default:
return COAP_405_METHOD_NOT_ALLOWED;
}
}
lwm2m_object_t * get_object_firmware()
{
/*
* The get_object_firmware function create the object itself and return a pointer to the structure that represent it.
*/
lwm2m_object_t * firmwareObj;
firmwareObj = (lwm2m_object_t *)malloc(sizeof(lwm2m_object_t));
if (NULL != firmwareObj)
{
memset(firmwareObj, 0, sizeof(lwm2m_object_t));
/*
* It assign his unique ID
* The 5 is the standard ID for the optional object "Object firmware".
*/
firmwareObj->objID = 5;
/*
* And the private function that will access the object.
* Those function will be called when a read/write/execute query is made by the server. In fact the library don't need to
* know the resources of the object, only the server does.
*/
firmwareObj->readFunc = prv_firmware_read;
firmwareObj->writeFunc = prv_firmware_write;
firmwareObj->executeFunc = prv_firmware_execute;
firmwareObj->userData = malloc(sizeof(firmware_data_t));
/*
* Also some user data can be stored in the object with a private structure containing the needed variables
*/
if (NULL != firmwareObj->userData)
{
((firmware_data_t*)firmwareObj->userData)->state = 1;
((firmware_data_t*)firmwareObj->userData)->supported = 0;
((firmware_data_t*)firmwareObj->userData)->result = 0;
}
else
{
free(firmwareObj);
firmwareObj = NULL;
}
}
return firmwareObj;
}

289
tests/client/test_object.c Normal file
View File

@ -0,0 +1,289 @@
/*******************************************************************************
*
* Copyright (c) 2013, 2014 Intel Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* The Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* David Navarro, Intel Corporation - initial API and implementation
* domedambrosio - Please refer to git log
* Fabien Fleutot - Please refer to git log
* Axel Lorente - Please refer to git log
*
*******************************************************************************/
/*
Copyright (c) 2013, 2014 Intel Corporation
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of Intel Corporation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
David Navarro <david.navarro@intel.com>
*/
/*
* Implements an object for testing purpose
*
* Multiple
* Object | ID | Instances | Mandatoty |
* Test | 1024 | Yes | No |
*
* Ressources:
* Supported Multiple
* Name | ID | Operations | Instances | Mandatory | Type | Range | Units | Description |
* test | 1 | R/W | No | Yes | Integer | 0-255 | | |
* exec | 2 | E | No | Yes | | | | |
*
*/
#include "liblwm2m.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define PRV_TLV_BUFFER_SIZE 64
/*
* Multiple instance objects can use userdata to store data that will be shared between the different instances.
* The lwm2m_object_t object structure - which represent every object of the liblwm2m as seen in the single instance
* object - contain a chained list called instanceList with the object specific structure prv_instance_t:
*/
typedef struct _prv_instance_
{
/*
* The first two are mandatories and represent the pointer to the next instance and the ID of this one. The rest
* is the instance scope user data (uint8_t test in this case)
*/
struct _prv_instance_ * next; // matches lwm2m_list_t::next
uint16_t shortID; // matches lwm2m_list_t::id
uint8_t test;
} prv_instance_t;
static void prv_output_buffer(uint8_t * buffer,
int length)
{
int i;
uint8_t array[16];
i = 0;
while (i < length)
{
int j;
fprintf(stderr, " ");
memcpy(array, buffer+i, 16);
for (j = 0 ; j < 16 && i+j < length; j++)
{
fprintf(stderr, "%02X ", array[j]);
}
while (j < 16)
{
fprintf(stderr, " ");
j++;
}
fprintf(stderr, " ");
for (j = 0 ; j < 16 && i+j < length; j++)
{
if (isprint(array[j]))
fprintf(stderr, "%c ", array[j]);
else
fprintf(stderr, ". ");
}
fprintf(stderr, "\n");
i += 16;
}
}
static uint8_t prv_read(uint16_t instanceId,
int * numDataP,
lwm2m_tlv_t ** dataArrayP,
lwm2m_object_t * objectP)
{
prv_instance_t * targetP;
int i;
targetP = (prv_instance_t *)lwm2m_list_find(objectP->instanceList, instanceId);
if (NULL == targetP) return COAP_404_NOT_FOUND;
if (*numDataP == 0)
{
*dataArrayP = lwm2m_tlv_new(1);
if (*dataArrayP == NULL) return COAP_500_INTERNAL_SERVER_ERROR;
*numDataP = 1;
(*dataArrayP)->id = 1;
}
if (*numDataP != 1) return COAP_404_NOT_FOUND;
if ((*dataArrayP)->id != 1) return COAP_404_NOT_FOUND;
(*dataArrayP)->type = LWM2M_TYPE_RESSOURCE;
lwm2m_tlv_encode_int(targetP->test, *dataArrayP);
if ((*dataArrayP)->length == 0) return COAP_500_INTERNAL_SERVER_ERROR;
return COAP_205_CONTENT;
}
static uint8_t prv_write(uint16_t instanceId,
int numData,
lwm2m_tlv_t * dataArray,
lwm2m_object_t * objectP)
{
prv_instance_t * targetP;
int64_t value;
targetP = (prv_instance_t *)lwm2m_list_find(objectP->instanceList, instanceId);
if (NULL == targetP) return COAP_404_NOT_FOUND;
if (numData != 1 || dataArray->id != 1) return COAP_404_NOT_FOUND;
if (1 != lwm2m_tlv_decode_int(dataArray, &value)
|| value < 0 || value > 0xFF)
{
return COAP_400_BAD_REQUEST;
}
targetP->test = (uint8_t)value;
return COAP_204_CHANGED;
}
static uint8_t prv_delete(uint16_t id,
lwm2m_object_t * objectP)
{
prv_instance_t * targetP;
objectP->instanceList = lwm2m_list_remove(objectP->instanceList, id, (lwm2m_list_t **)&targetP);
if (NULL == targetP) return COAP_404_NOT_FOUND;
free(targetP);
return COAP_202_DELETED;
}
static uint8_t prv_create(uint16_t instanceId,
int numData,
lwm2m_tlv_t * dataArray,
lwm2m_object_t * objectP)
{
prv_instance_t * targetP;
uint8_t result;
targetP = (prv_instance_t *)malloc(sizeof(prv_instance_t));
if (NULL == targetP) return COAP_500_INTERNAL_SERVER_ERROR;
memset(targetP, 0, sizeof(prv_instance_t));
targetP->shortID = instanceId;
objectP->instanceList = LWM2M_LIST_ADD(objectP->instanceList, targetP);
result = prv_write(instanceId, numData, dataArray, objectP);
if (result != COAP_204_CHANGED)
{
(void)prv_delete(instanceId, objectP);
}
else
{
result = COAP_201_CREATED;
}
return result;
}
static uint8_t prv_exec(uint16_t instanceId,
uint16_t resourceId,
char * buffer,
int length,
lwm2m_object_t * objectP)
{
if (NULL == lwm2m_list_find(objectP->instanceList, instanceId)) return COAP_404_NOT_FOUND;
switch (resourceId)
{
case 1:
return COAP_405_METHOD_NOT_ALLOWED;
case 2:
fprintf(stdout, "\r\n-----------------\r\n"
"Execute on %hu/%d/%d\r\n"
" Parameter (%d bytes):\r\n",
objectP->objID, instanceId, resourceId, length);
prv_output_buffer(buffer, length);
fprintf(stdout, "-----------------\r\n\r\n");
return COAP_204_CHANGED;
default:
return COAP_404_NOT_FOUND;
}
}
lwm2m_object_t * get_test_object()
{
lwm2m_object_t * testObj;
testObj = (lwm2m_object_t *)malloc(sizeof(lwm2m_object_t));
if (NULL != testObj)
{
int i;
prv_instance_t * targetP;
memset(testObj, 0, sizeof(lwm2m_object_t));
testObj->objID = 1024;
for (i=0 ; i < 3 ; i++)
{
targetP = (prv_instance_t *)malloc(sizeof(prv_instance_t));
if (NULL == targetP) return NULL;
memset(targetP, 0, sizeof(prv_instance_t));
targetP->shortID = 10 + i;
targetP->test = 20 + i;
testObj->instanceList = LWM2M_LIST_ADD(testObj->instanceList, targetP);
}
/*
* From a single instance object, two more functions are available.
* - The first one (createFunc) create a new instance and filled it with the provided informations. If an ID is
* provided a check is done for verifying his disponibility, or a new one is generated.
* - The other one (deleteFunc) delete an instance by removing it from the instance list (and freeing the memory
* allocated to it)
*/
testObj->readFunc = prv_read;
testObj->writeFunc = prv_write;
testObj->createFunc = prv_create;
testObj->deleteFunc = prv_delete;
testObj->executeFunc = prv_exec;
}
return testObj;
}

View File

@ -0,0 +1,15 @@
cmake_minimum_required (VERSION 2.8.3)
project (lwm2mserver)
SET(LIBLWM2M_DIR ${PROJECT_SOURCE_DIR}/../../core)
add_definitions(-DLWM2M_SERVER_MODE)
include_directories (${LIBLWM2M_DIR} ${PROJECT_SOURCE_DIR}/../utils)
add_subdirectory(${LIBLWM2M_DIR} ${CMAKE_CURRENT_BINARY_DIR}/core)
SET(SOURCES lwm2mserver.c ../utils/commandline.c ../utils/connection.c)
add_executable(lwm2mserver ${SOURCES} ${CORE_SOURCES})

792
tests/server/lwm2mserver.c Normal file
View File

@ -0,0 +1,792 @@
/*******************************************************************************
*
* Copyright (c) 2013, 2014 Intel Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* The Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* David Navarro, Intel Corporation - initial API and implementation
* domedambrosio - Please refer to git log
* Simon Bernard - Please refer to git log
* Toby Jaffey - Please refer to git log
* Julien Vermillard - Please refer to git log
*
*******************************************************************************/
/*
Copyright (c) 2013, 2014 Intel Corporation
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of Intel Corporation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
David Navarro <david.navarro@intel.com>
*/
#include "liblwm2m.h"
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <ctype.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/stat.h>
#include <errno.h>
#include <signal.h>
#include "commandline.h"
#include "connection.h"
#define MAX_PACKET_SIZE 128
static int g_quit = 0;
static uint8_t prv_buffer_send(void * sessionH,
uint8_t * buffer,
size_t length,
void * userdata)
{
connection_t * connP = (connection_t*) sessionH;
if (-1 == connection_send(connP, buffer, length))
{
return COAP_500_INTERNAL_SERVER_ERROR;
}
return COAP_NO_ERROR;
}
static void prv_dump_client(lwm2m_client_t * targetP)
{
lwm2m_client_object_t * objectP;
fprintf(stdout, "Client #%d:\r\n", targetP->internalID);
fprintf(stdout, "\tname: \"%s\"\r\n", targetP->name);
fprintf(stdout, "\tobjects: ");
for (objectP = targetP->objectList; objectP != NULL ; objectP = objectP->next)
{
if (objectP->instanceList == NULL)
{
fprintf(stdout, "%d, ", objectP->id);
}
else
{
lwm2m_list_t * instanceP;
for (instanceP = objectP->instanceList; instanceP != NULL ; instanceP = instanceP->next)
{
fprintf(stdout, "%d/%d, ", objectP->id, instanceP->id);
}
}
}
fprintf(stdout, "\r\n");
}
static void prv_output_clients(char * buffer,
void * user_data)
{
lwm2m_context_t * lwm2mH = (lwm2m_context_t *) user_data;
lwm2m_client_t * targetP;
targetP = lwm2mH->clientList;
if (targetP == NULL)
{
fprintf(stdout, "No client.\r\n");
return;
}
for (targetP = lwm2mH->clientList ; targetP != NULL ; targetP = targetP->next)
{
prv_dump_client(targetP);
}
}
static void print_indent(int num)
{
int i;
for ( i = 0 ; i< num ; i++)
fprintf(stdout, " ");
}
static void output_tlv(char * buffer,
size_t buffer_len,
int indent)
{
lwm2m_tlv_type_t type;
uint16_t id;
size_t dataIndex;
size_t dataLen;
int length = 0;
int result;
while (0 != (result = lwm2m_decodeTLV(buffer + length, buffer_len - length, &type, &id, &dataIndex, &dataLen)))
{
print_indent(indent);
fprintf(stdout, "ID: %d", id);
fprintf(stdout, " type: ");
switch (type)
{
case TLV_OBJECT_INSTANCE:
fprintf(stdout, "Object Instance");
break;
case TLV_RESSOURCE_INSTANCE:
fprintf(stdout, "Ressource Instance");
break;
case TLV_MULTIPLE_INSTANCE:
fprintf(stdout, "Multiple Instances");
break;
case TLV_RESSOURCE:
fprintf(stdout, "Ressource");
break;
default:
printf("unknown (%d)", (int)type);
break;
}
fprintf(stdout, "\n");
print_indent(indent);
fprintf(stdout, "{\n");
if (type == TLV_OBJECT_INSTANCE || type == TLV_MULTIPLE_INSTANCE)
{
output_tlv(buffer + length + dataIndex, dataLen, indent+2);
}
else
{
print_indent(indent+2);
fprintf(stdout, "data (%d bytes): ", dataLen);
if (dataLen >= 16) fprintf(stdout, "\n");
output_buffer(stdout, buffer + length + dataIndex, dataLen);
}
print_indent(indent);
fprintf(stdout, "}\n");
length += result;
}
}
static int prv_read_id(char * buffer,
uint16_t * idP)
{
int nb;
int value;
nb = sscanf(buffer, "%d", &value);
if (nb == 1)
{
if (value < 0 || value > LWM2M_MAX_ID)
{
nb = 0;
}
else
{
*idP = value;
}
}
return nb;
}
static void prv_result_callback(uint16_t clientID,
lwm2m_uri_t * uriP,
int status,
uint8_t * data,
int dataLength,
void * userData)
{
fprintf(stdout, "\r\nClient #%d %d", clientID, uriP->objectId);
if (LWM2M_URI_IS_SET_INSTANCE(uriP))
fprintf(stdout, "/%d", uriP->instanceId);
else if (LWM2M_URI_IS_SET_RESOURCE(uriP))
fprintf(stdout, "/");
if (LWM2M_URI_IS_SET_RESOURCE(uriP))
fprintf(stdout, "/%d", uriP->resourceId);
fprintf(stdout, " returned status %d.%2d\r\n", (status&0xE0)>>5, status&0x1F);
if (data != NULL)
{
fprintf(stdout, "%d bytes received:\r\n", dataLength);
if (LWM2M_URI_IS_SET_RESOURCE(uriP))
{
output_buffer(stdout, data, dataLength);
}
else
{
output_tlv(data, dataLength, 2);
}
}
fprintf(stdout, "\r\n> ");
fflush(stdout);
}
static void prv_notify_callback(uint16_t clientID,
lwm2m_uri_t * uriP,
int count,
uint8_t * data,
int dataLength,
void * userData)
{
fprintf(stdout, "\r\nNotify from client #%d %d", clientID, uriP->objectId);
if (LWM2M_URI_IS_SET_INSTANCE(uriP))
fprintf(stdout, "/%d", uriP->instanceId);
else if (LWM2M_URI_IS_SET_RESOURCE(uriP))
fprintf(stdout, "/");
if (LWM2M_URI_IS_SET_RESOURCE(uriP))
fprintf(stdout, "/%d", uriP->resourceId);
fprintf(stdout, " number %d\r\n", count);
if (data != NULL)
{
fprintf(stdout, "%d bytes received:\r\n", dataLength);
output_buffer(stdout, data, dataLength);
}
fprintf(stdout, "\r\n> ");
fflush(stdout);
}
static void prv_read_client(char * buffer,
void * user_data)
{
lwm2m_context_t * lwm2mH = (lwm2m_context_t *) user_data;
uint16_t clientId;
lwm2m_uri_t uri;
int result;
result = prv_read_id(buffer, &clientId);
if (result != 1) goto syntax_error;
buffer = get_next_arg(buffer);
if (buffer[0] == 0) goto syntax_error;
result = lwm2m_stringToUri(buffer, strlen(buffer), &uri);
if (result == 0) goto syntax_error;
result = lwm2m_dm_read(lwm2mH, clientId, &uri, prv_result_callback, NULL);
if (result == 0)
{
fprintf(stdout, "OK");
}
else
{
fprintf(stdout, "Error %d.%2d", (result&0xE0)>>5, result&0x1F);
}
return;
syntax_error:
fprintf(stdout, "Syntax error !");
}
static void prv_write_client(char * buffer,
void * user_data)
{
lwm2m_context_t * lwm2mH = (lwm2m_context_t *) user_data;
uint16_t clientId;
lwm2m_uri_t uri;
char * uriString;
int i;
int result;
result = prv_read_id(buffer, &clientId);
if (result != 1) goto syntax_error;
buffer = get_next_arg(buffer);
if (buffer[0] == 0) goto syntax_error;
uriString = buffer;
buffer = get_next_arg(buffer);
if (buffer[0] == 0) goto syntax_error;
i = 0;
while (uriString + i < buffer && !isspace(uriString[i]))
{
i++;
}
result = lwm2m_stringToUri(uriString, i, &uri);
if (result == 0) goto syntax_error;
result = lwm2m_dm_write(lwm2mH, clientId, &uri, buffer, strlen(buffer), prv_result_callback, NULL);
if (result == 0)
{
fprintf(stdout, "OK");
}
else
{
fprintf(stdout, "Error %d.%2d", (result&0xE0)>>5, result&0x1F);
}
return;
syntax_error:
fprintf(stdout, "Syntax error !");
}
static void prv_exec_client(char * buffer,
void * user_data)
{
lwm2m_context_t * lwm2mH = (lwm2m_context_t *) user_data;
uint16_t clientId;
lwm2m_uri_t uri;
char * uriString;
int i;
int result;
result = prv_read_id(buffer, &clientId);
if (result != 1) goto syntax_error;
buffer = get_next_arg(buffer);
if (buffer[0] == 0) goto syntax_error;
uriString = buffer;
buffer = get_next_arg(buffer);
i = 0;
while (uriString + i < buffer && !isspace(uriString[i]))
{
i++;
}
result = lwm2m_stringToUri(uriString, i, &uri);
if (result == 0) goto syntax_error;
if (buffer[0] == 0)
{
result = lwm2m_dm_execute(lwm2mH, clientId, &uri, NULL, 0, prv_result_callback, NULL);
}
else
{
result = lwm2m_dm_execute(lwm2mH, clientId, &uri, buffer, strlen(buffer), prv_result_callback, NULL);
}
if (result == 0)
{
fprintf(stdout, "OK");
}
else
{
fprintf(stdout, "Error %d.%2d", (result&0xE0)>>5, result&0x1F);
}
return;
syntax_error:
fprintf(stdout, "Syntax error !");
}
static void prv_create_client(char * buffer,
void * user_data)
{
lwm2m_context_t * lwm2mH = (lwm2m_context_t *) user_data;
uint16_t clientId;
lwm2m_uri_t uri;
char * uriString;
int i;
int result;
uint64_t value;
char temp_buffer[MAX_PACKET_SIZE];
int temp_length = 0;
//Get Client ID
result = prv_read_id(buffer, &clientId);
if (result != 1) goto syntax_error;
buffer = get_next_arg(buffer);
if (buffer[0] == 0) goto syntax_error;
//save Uri start address
uriString = buffer;
//Get Data to Post
buffer = get_next_arg(buffer);
if (buffer[0] == 0) goto syntax_error;
//Get Uri
i = 0;
while (uriString + i < buffer && !isspace(uriString[i]))
{
i++;
}
result = lwm2m_stringToUri(uriString, i, &uri);
if (result == 0) goto syntax_error;
// TLV
/* Client dependent part */
if (uri.objectId == 1024)
{
result = lwm2m_PlainTextToInt64(buffer, strlen(buffer), &value);
temp_length = lwm2m_intToTLV(TLV_RESSOURCE, value, (uint16_t) 1, temp_buffer, MAX_PACKET_SIZE);
}
/* End Client dependent part*/
//Create
result = lwm2m_dm_create(lwm2mH, clientId,&uri, temp_buffer, temp_length, prv_result_callback, NULL);
if (result == 0)
{
fprintf(stdout, "OK");
}
else
{
fprintf(stdout, "Error %d.%2d", (result&0xE0)>>5, result&0x1F);
}
return;
syntax_error:
fprintf(stdout, "Syntax error !");
}
static void prv_delete_client(char * buffer,
void * user_data)
{
lwm2m_context_t * lwm2mH = (lwm2m_context_t *) user_data;
uint16_t clientId;
lwm2m_uri_t uri;
int result;
result = prv_read_id(buffer, &clientId);
if (result != 1) goto syntax_error;
buffer = get_next_arg(buffer);
if (buffer[0] == 0) goto syntax_error;
result = lwm2m_stringToUri(buffer, strlen(buffer), &uri);
if (result == 0) goto syntax_error;
result = lwm2m_dm_delete(lwm2mH, clientId, &uri, prv_result_callback, NULL);
if (result == 0)
{
fprintf(stdout, "OK");
}
else
{
fprintf(stdout, "Error %d.%2d", (result&0xE0)>>5, result&0x1F);
}
return;
syntax_error:
fprintf(stdout, "Syntax error !");
}
static void prv_observe_client(char * buffer,
void * user_data)
{
lwm2m_context_t * lwm2mH = (lwm2m_context_t *) user_data;
uint16_t clientId;
lwm2m_uri_t uri;
int result;
result = prv_read_id(buffer, &clientId);
if (result != 1) goto syntax_error;
buffer = get_next_arg(buffer);
if (buffer[0] == 0) goto syntax_error;
result = lwm2m_stringToUri(buffer, strlen(buffer), &uri);
if (result == 0) goto syntax_error;
result = lwm2m_observe(lwm2mH, clientId, &uri, prv_notify_callback, NULL);
if (result == 0)
{
fprintf(stdout, "OK");
}
else
{
fprintf(stdout, "Error %d.%2d", (result&0xE0)>>5, result&0x1F);
}
return;
syntax_error:
fprintf(stdout, "Syntax error !");
}
static void prv_cancel_client(char * buffer,
void * user_data)
{
lwm2m_context_t * lwm2mH = (lwm2m_context_t *) user_data;
uint16_t clientId;
lwm2m_uri_t uri;
int result;
result = prv_read_id(buffer, &clientId);
if (result != 1) goto syntax_error;
buffer = get_next_arg(buffer);
if (buffer[0] == 0) goto syntax_error;
result = lwm2m_stringToUri(buffer, strlen(buffer), &uri);
if (result == 0) goto syntax_error;
result = lwm2m_observe_cancel(lwm2mH, clientId, &uri, prv_result_callback, NULL);
if (result == 0)
{
fprintf(stdout, "OK");
}
else
{
fprintf(stdout, "Error %d.%2d", (result&0xE0)>>5, result&0x1F);
}
return;
syntax_error:
fprintf(stdout, "Syntax error !");
}
static void prv_monitor_callback(uint16_t clientID,
lwm2m_uri_t * uriP,
int status,
uint8_t * data,
int dataLength,
void * userData)
{
lwm2m_context_t * lwm2mH = (lwm2m_context_t *) userData;
lwm2m_client_t * targetP;
lwm2m_client_object_t * objectP;
switch (status)
{
case COAP_201_CREATED:
fprintf(stdout, "\r\nNew client #%d registered.\r\n", clientID);
targetP = (lwm2m_client_t *)lwm2m_list_find((lwm2m_list_t *)lwm2mH->clientList, clientID);
prv_dump_client(targetP);
break;
case COAP_202_DELETED:
fprintf(stdout, "\r\nClient #%d unregistered.\r\n", clientID);
break;
default:
fprintf(stdout, "\r\nMonitor callback called with an unknown status: %d.\r\n", status);
break;
}
fprintf(stdout, "\r\n> ");
fflush(stdout);
}
static void prv_quit(char * buffer,
void * user_data)
{
g_quit = 1;
}
void handle_sigint(int signum)
{
prv_quit(NULL, NULL);
}
void print_usage(void)
{
fprintf(stderr, "Usage: lwm2mserver\r\n");
fprintf(stderr, "Launch a LWM2M server on localhost port "LWM2M_STANDARD_PORT_STR".\r\n\n");
}
int main(int argc, char *argv[])
{
int sock;
fd_set readfds;
struct timeval tv;
int result;
lwm2m_context_t * lwm2mH = NULL;
int i;
connection_t * connList = NULL;
command_desc_t commands[] =
{
{"list", "List registered clients.", NULL, prv_output_clients, NULL},
{"read", "Read from a client.", " read CLIENT# URI\r\n"
" CLIENT#: client number as returned by command 'list'\r\n"
" URI: uri to read such as /3, /3//2, /3/0/2, /1024/11, /1024//1\r\n"
"Result will be displayed asynchronously.", prv_read_client, NULL},
{"write", "Write to a client.", " write CLIENT# URI DATA\r\n"
" CLIENT#: client number as returned by command 'list'\r\n"
" URI: uri to write to such as /3, /3//2, /3/0/2, /1024/11, /1024//1\r\n"
" DATA: data to write\r\n"
"Result will be displayed asynchronously.", prv_write_client, NULL},
{"exec", "Execute a client resource.", " exec CLIENT# URI\r\n"
" CLIENT#: client number as returned by command 'list'\r\n"
" URI: uri of the resource to execute such as /3/0/2\r\n"
"Result will be displayed asynchronously.", prv_exec_client, NULL},
{"del", "Delete a client Object instance.", " del CLIENT# URI\r\n"
" CLIENT#: client number as returned by command 'list'\r\n"
" URI: uri of the instance to delete such as /1024/11\r\n"
"Result will be displayed asynchronously.", prv_delete_client, NULL},
{"create", "create an Object instance.", " create CLIENT# URI DATA\r\n"
" CLIENT#: client number as returned by command 'list'\r\n"
" URI: uri to which create the Object Instance such as /1024, /1024/45 \r\n"
" DATA: data to initialize the new Object Instance (0-255 for object 1024) \r\n"
"Result will be displayed asynchronously.", prv_create_client, NULL},
{"observe", "Observe from a client.", " observe CLIENT# URI\r\n"
" CLIENT#: client number as returned by command 'list'\r\n"
" URI: uri to observe such as /3, /3/0/2, /1024/11\r\n"
"Result will be displayed asynchronously.", prv_observe_client, NULL},
{"cancel", "Cancel an observe.", " cancel CLIENT# URI\r\n"
" CLIENT#: client number as returned by command 'list'\r\n"
" URI: uri on which to cancel an observe such as /3, /3/0/2, /1024/11\r\n"
"Result will be displayed asynchronously.", prv_cancel_client, NULL},
{"quit", "Quit the server.", NULL, prv_quit, NULL},
COMMAND_END_LIST
};
sock = create_socket(LWM2M_STANDARD_PORT_STR);
if (sock < 0)
{
fprintf(stderr, "Error opening socket: %d\r\n", errno);
return -1;
}
lwm2mH = lwm2m_init("testlwm2mserver", 0, NULL, prv_buffer_send, NULL);
if (NULL == lwm2mH)
{
fprintf(stderr, "lwm2m_init() failed\r\n");
return -1;
}
signal(SIGINT, handle_sigint);
for (i = 0 ; commands[i].name != NULL ; i++)
{
commands[i].userData = (void *)lwm2mH;
}
fprintf(stdout, "> "); fflush(stdout);
lwm2m_set_monitoring_callback(lwm2mH, prv_monitor_callback, lwm2mH);
while (0 == g_quit)
{
FD_ZERO(&readfds);
FD_SET(sock, &readfds);
FD_SET(STDIN_FILENO, &readfds);
tv.tv_sec = 60;
tv.tv_usec = 0;
result = lwm2m_step(lwm2mH, &tv);
if (result != 0)
{
fprintf(stderr, "lwm2m_step() failed: 0x%X\r\n", result);
return -1;
}
result = select(FD_SETSIZE, &readfds, 0, 0, &tv);
if ( result < 0 )
{
if (errno != EINTR)
{
fprintf(stderr, "Error in select(): %d\r\n", errno);
}
}
else if (result > 0)
{
uint8_t buffer[MAX_PACKET_SIZE];
int numBytes;
if (FD_ISSET(sock, &readfds))
{
struct sockaddr_storage addr;
socklen_t addrLen;
addrLen = sizeof(addr);
numBytes = recvfrom(sock, buffer, MAX_PACKET_SIZE, 0, (struct sockaddr *)&addr, &addrLen);
if (numBytes == -1)
{
fprintf(stderr, "Error in recvfrom(): %d\r\n", errno);
}
else
{
char s[INET6_ADDRSTRLEN];
connection_t * connP;
fprintf(stderr, "%d bytes received from [%s]:%hu\r\n",
numBytes,
inet_ntop(addr.ss_family,
&(((struct sockaddr_in6*)&addr)->sin6_addr),
s,
INET6_ADDRSTRLEN),
ntohs(((struct sockaddr_in6*)&addr)->sin6_port));
output_buffer(stderr, buffer, numBytes);
connP = connection_find(connList, &addr, addrLen);
if (connP == NULL)
{
connList = connection_new_incoming(connList, sock, (struct sockaddr *)&addr, addrLen);
connP = connList;
}
if (connP != NULL)
{
lwm2m_handle_packet(lwm2mH, buffer, numBytes, connP);
}
}
}
else if (FD_ISSET(STDIN_FILENO, &readfds))
{
numBytes = read(STDIN_FILENO, buffer, MAX_PACKET_SIZE);
if (numBytes > 1)
{
buffer[numBytes - 1] = 0;
handle_command(commands, buffer);
}
if (g_quit == 0)
{
fprintf(stdout, "\r\n> ");
fflush(stdout);
}
else
{
fprintf(stdout, "\r\n");
}
}
}
}
lwm2m_close(lwm2mH);
close(sock);
connection_free(connList);
return 0;
}

127
tests/utils/commandline.c Normal file
View File

@ -0,0 +1,127 @@
/*******************************************************************************
*
* Copyright (c) 2013, 2014 Intel Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* The Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* David Navarro, Intel Corporation - initial API and implementation
* Fabien Fleutot - Please refer to git log
*
*******************************************************************************/
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include "commandline.h"
#define HELP_COMMAND "help"
#define HELP_DESC "Type '"HELP_COMMAND" [COMMAND]' for more details on a command."
#define UNKNOWN_CMD_MSG "Unknown command. Type '"HELP_COMMAND"' for help."
static command_desc_t * prv_find_command(command_desc_t * commandArray,
char * buffer,
int length)
{
int i;
if (length == 0) return NULL;
i = 0;
while (commandArray[i].name != NULL
&& (strlen(commandArray[i].name) != length || strncmp(buffer, commandArray[i].name, length)))
{
i++;
}
if (commandArray[i].name == NULL)
{
return NULL;
}
else
{
return &commandArray[i];
}
}
static void prv_displayHelp(command_desc_t * commandArray,
char * buffer)
{
command_desc_t * cmdP;
int length;
// find end of first argument
length = 0;
while (buffer[length] != 0 && !isspace(buffer[length]))
length++;
cmdP = prv_find_command(commandArray, buffer, length);
if (cmdP == NULL)
{
int i;
fprintf(stdout, HELP_COMMAND"\t"HELP_DESC"\r\n");
for (i = 0 ; commandArray[i].name != NULL ; i++)
{
fprintf(stdout, "%s\t%s\r\n", commandArray[i].name, commandArray[i].shortDesc);
}
}
else
{
fprintf(stdout, "%s\r\n", cmdP->longDesc?cmdP->longDesc:cmdP->shortDesc);
}
}
void handle_command(command_desc_t * commandArray,
char * buffer)
{
command_desc_t * cmdP;
int length;
// find end of command name
length = 0;
while (buffer[length] != 0 && !isspace(buffer[length]))
length++;
cmdP = prv_find_command(commandArray, buffer, length);
if (cmdP != NULL)
{
while (buffer[length] != 0 && isspace(buffer[length]))
length++;
cmdP->callback(buffer + length, cmdP->userData);
}
else
{
if (!strncmp(buffer, HELP_COMMAND, length))
{
while (buffer[length] != 0 && isspace(buffer[length]))
length++;
prv_displayHelp(commandArray, buffer + length);
}
else
{
fprintf(stdout, UNKNOWN_CMD_MSG"\r\n");
}
}
}
char * get_next_arg(char * buffer)
{
while (buffer[0] != 0 && !isspace(buffer[0])) buffer++;
while (buffer[0] != 0 && isspace(buffer[0])) buffer++;
return buffer;
}

33
tests/utils/commandline.h Normal file
View File

@ -0,0 +1,33 @@
/*******************************************************************************
*
* Copyright (c) 2013 Intel Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* The Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* David Navarro, Intel Corporation - initial API and implementation
*
*******************************************************************************/
#define COMMAND_END_LIST {NULL, NULL, NULL, NULL, NULL}
typedef void (*command_handler_t) (char * args, void * user_data);
typedef struct
{
char * name;
char * shortDesc;
char * longDesc;
command_handler_t callback;
void * userData;
} command_desc_t;
void handle_command(command_desc_t * commandArray, char * buffer);
char * get_next_arg(char * buffer);

219
tests/utils/connection.c Normal file
View File

@ -0,0 +1,219 @@
/*******************************************************************************
*
* Copyright (c) 2013, 2014 Intel Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* The Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* David Navarro, Intel Corporation - initial API and implementation
*
*******************************************************************************/
#include <stdlib.h>
#include <string.h>
#include "connection.h"
int create_socket(char * portStr)
{
int s = -1;
struct addrinfo hints;
struct addrinfo *res;
struct addrinfo *p;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE;
if (0 != getaddrinfo(NULL, portStr, &hints, &res))
{
return -1;
}
for(p = res ; p != NULL && s == -1 ; p = p->ai_next)
{
s = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (s >= 0)
{
if (-1 == bind(s, p->ai_addr, p->ai_addrlen))
{
close(s);
s = -1;
}
}
}
freeaddrinfo(res);
return s;
}
connection_t * connection_find(connection_t * connList,
struct sockaddr_storage * addr,
size_t addrLen)
{
connection_t * connP;
connP = connList;
while (connP != NULL)
{
if ((connP->addrLen == addrLen)
&& (memcmp(&(connP->addr), addr, addrLen) == 0))
{
return connP;
}
connP = connP->next;
}
return connP;
}
connection_t * connection_new_incoming(connection_t * connList,
int sock,
struct sockaddr * addr,
size_t addrLen)
{
connection_t * connP;
connP = (connection_t *)malloc(sizeof(connection_t));
if (connP != NULL)
{
connP->sock = sock;
memcpy(&(connP->addr), addr, addrLen);
connP->addrLen = addrLen;
connP->next = connList;
}
return connP;
}
connection_t * connection_create(connection_t * connList,
int sock,
char * host,
uint16_t port)
{
char portStr[6];
struct addrinfo hints;
struct addrinfo *servinfo = NULL;
struct addrinfo *p;
int s;
struct sockaddr *sa;
socklen_t sl;
connection_t * connP = NULL;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
if (0 >= sprintf(portStr, "%hu", port)) return NULL;
if (0 != getaddrinfo(host, portStr, &hints, &servinfo) || servinfo == NULL) return NULL;
// we test the various addresses
s = -1;
for(p = servinfo ; p != NULL && s == -1 ; p = p->ai_next)
{
s = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (s >= 0)
{
sa = p->ai_addr;
sl = p->ai_addrlen;
if (-1 == connect(s, p->ai_addr, p->ai_addrlen))
{
close(s);
s = -1;
}
}
}
if (s >= 0)
{
connP = connection_new_incoming(connList, sock, sa, sl);
close(s);
}
return connP;
}
void connection_free(connection_t * connList)
{
if (connList != NULL)
{
connection_t * nextP;
nextP = connList->next;
free(connList);
connection_free(nextP);
}
}
int connection_send(connection_t *connP,
uint8_t * buffer,
size_t length)
{
size_t nbSent;
size_t offset;
offset = 0;
while (offset != length)
{
nbSent = sendto(connP->sock, buffer + offset, length - offset, 0, (struct sockaddr *)&(connP->addr), connP->addrLen);
if (nbSent == -1) return -1;
offset += nbSent;
}
return 0;
}
void output_buffer(FILE * stream,
uint8_t * buffer,
int length)
{
int i;
int j;
uint8_t array[16];
i = 0;
while (i < length)
{
fprintf(stream, " ");
memcpy(array, buffer+i, 16);
for (j = 0 ; j < 16 && i+j < length; j++)
{
fprintf(stream, "%02X ", array[j]);
}
if (i != 0)
{
while (j < 16)
{
fprintf(stream, " ");
j++;
}
}
fprintf(stream, " ");
for (j = 0 ; j < 16 && i+j < length; j++)
{
if (isprint(array[j]))
{
fprintf(stream, "%c ", array[j]);
}
else
{
fprintf(stream, ". ");
}
}
fprintf(stream, "\n");
i += 16;
}
}

51
tests/utils/connection.h Normal file
View File

@ -0,0 +1,51 @@
/*******************************************************************************
*
* Copyright (c) 2013, 2014 Intel Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* The Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* David Navarro, Intel Corporation - initial API and implementation
*
*******************************************************************************/
#ifndef CONNECTION_H_
#define CONNECTION_H_
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/stat.h>
#define LWM2M_STANDARD_PORT_STR "5684"
#define LWM2M_STANDARD_PORT 5684
typedef struct _connection_t
{
struct _connection_t * next;
int sock;
struct sockaddr_in6 addr;
size_t addrLen;
} connection_t;
int create_socket(char * portStr);
connection_t * connection_find(connection_t * connList, struct sockaddr_storage * addr, size_t addrLen);
connection_t * connection_new_incoming(connection_t * connList, int sock, struct sockaddr * addr, size_t addrLen);
connection_t * connection_create(connection_t * connList, int sock, char * host, uint16_t port);
void connection_free(connection_t * connList);
int connection_send(connection_t *connP, uint8_t * buffer, size_t length);
void output_buffer(FILE * stream, uint8_t * buffer, int length);
#endif