mirror of
https://github.com/eclipse/wakaama.git
synced 2025-05-08 23:31:37 +08:00
New initial commit
This commit is contained in:
commit
b1691d28c5
26
.gitignore
vendored
Normal file
26
.gitignore
vendored
Normal 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
30
EDL-v1.0
Normal 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
224
EPL-v1.0
Normal 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
80
README
Normal 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
54
TODO
Normal 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
46
about.html
Normal 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 ("Content"). Unless otherwise
|
||||
indicated below, the Content is provided to you under the terms and conditions of the
|
||||
Eclipse Public License Version 1.0 ("EPL") and the Eclipse Distribution License Version 1.0 ("EDL").
|
||||
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, "Program" 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 ("Redistributor") 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
16
core/CMakeLists.txt
Normal 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
30
core/er-coap-13/LICENSE
Normal 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
1294
core/er-coap-13/er-coap-13.c
Normal file
File diff suppressed because it is too large
Load Diff
401
core/er-coap-13/er-coap-13.h
Normal file
401
core/er-coap-13/er-coap-13.h
Normal 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
147
core/internals.h
Normal 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
290
core/liblwm2m.c
Normal 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
490
core/liblwm2m.h
Normal 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
113
core/list.c
Normal 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
356
core/management.c
Normal 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
216
core/object_server.c
Normal 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
462
core/objects.c
Normal 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
503
core/observe.c
Normal 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
323
core/packet.c
Normal 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
480
core/registration.c
Normal 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
632
core/tlv.c
Normal 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
325
core/transaction.c
Normal 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
220
core/uri.c
Normal 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
178
core/utils.c
Normal 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
107
notice.html
Normal 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 "CONTENT"). 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
|
||||
("EPL"). 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, "Program" 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 ("Repository") in software modules ("Modules") and made available as downloadable archives ("Downloads").</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 ("Plug-ins"), plug-in fragments ("Fragments"), and features ("Features").</li>
|
||||
<li>Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java™ ARchive) in a directory named "plugins".</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 "features". Within a Feature, files named "feature.xml" 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 ("Included Features"). Within a Feature, files named "feature.xml" 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 "about.html" ("Abouts"). The terms and conditions governing Features and
|
||||
Included Features should be contained in files named "license.html" ("Feature Licenses"). 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 "src" 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 ("Feature Update License") 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 "license" property of files named "feature.properties" 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 ("Provisioning Technology") for the purpose of allowing users to install software, documentation, information and/or
|
||||
other materials (collectively "Installable Software"). 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>
|
||||
("Specification").</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 ("Provisioning Process") in which a user may execute the Provisioning Technology
|
||||
on a machine ("Target Machine") 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 ("Installable Software Agreement") 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
10
tests/TLV/CMakeLists.txt
Normal 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
244
tests/TLV/decode.c
Normal 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);
|
||||
}
|
||||
|
15
tests/client/CMakeLists.txt
Normal file
15
tests/client/CMakeLists.txt
Normal 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
483
tests/client/lwm2mclient.c
Normal 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;
|
||||
}
|
490
tests/client/object_device.c
Normal file
490
tests/client/object_device.c
Normal 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;
|
||||
}
|
271
tests/client/object_firmware.c
Normal file
271
tests/client/object_firmware.c
Normal 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
289
tests/client/test_object.c
Normal 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;
|
||||
}
|
15
tests/server/CMakeLists.txt
Normal file
15
tests/server/CMakeLists.txt
Normal 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
792
tests/server/lwm2mserver.c
Normal 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
127
tests/utils/commandline.c
Normal 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
33
tests/utils/commandline.h
Normal 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
219
tests/utils/connection.c
Normal 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
51
tests/utils/connection.h
Normal 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
|
Loading…
x
Reference in New Issue
Block a user