ameba micropython sdk first commit

This commit is contained in:
xidameng 2020-07-31 22:16:12 +08:00
commit 8508ee6139
5619 changed files with 1874619 additions and 0 deletions

View file

@ -0,0 +1,738 @@
/*
* Copyright (c) 2014-2015 ARM Limited. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef NS_LIST_H_
#define NS_LIST_H_
#include "ns_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/** \file
* \brief Linked list support library
*
* The ns_list.h file provides a doubly-linked list/queue, providing O(1)
* performance for all insertion/removal operations, and access to either
* end of the list.
*
* Memory footprint is two pointers for the list head, and two pointers in each
* list entry. It is similar in concept to BSD's TAILQ.
*
* Although the API is symmetrical and O(1) in both directions, due to internal
* pointer design, it is *slightly* more efficient to insert at the end when
* used as a queue, and to iterate forwards rather than backwards.
*
* Example of an entry type that can be stored to this list.
* ~~~
* typedef struct example_entry
* {
* uint8_t *data;
* uint32_t data_count;
* ns_list_link_t link;
* }
* example_entry_t;
*
* static NS_LIST_HEAD(example_entry_t, link) my_list;
* ns_list_init(&my_list);
* ~~~
* OR
* ~~~
* NS_LIST_HEAD(example_entry_t, link) my_list = NS_LIST_INIT(my_list);
* ~~~
* OR
* ~~~
* static NS_LIST_DEFINE(my_list, example_entry_t, link);
* ~~~
* OR
* ~~~
* typedef NS_LIST_HEAD(example_entry_t, link) example_list_t;
* example_list_t NS_LIST_NAME_INIT(my_list);
* ~~~
* NOTE: the link field SHALL NOT be accessed by the user.
*
* An entry can exist on multiple lists by having multiple link fields.
*
* All the list operations are implemented as macros, most of which are backed
* by optionally-inline functions. The macros do not evaluate any arguments more
* than once, unless documented.
*
* In macro documentation, `list_t` refers to a list type defined using
* NS_LIST_HEAD(), and `entry_t` to the entry type that was passed to it.
*/
/** \brief Underlying generic linked list head.
*
* Users should not use this type directly, but use the NS_LIST_HEAD() macro.
*/
typedef struct ns_list {
void *first_entry; ///< Pointer to first entry, or NULL if list is empty
void **last_nextptr; ///< Pointer to last entry's `next` pointer, or
///< to head's `first_entry` pointer if list is empty
} ns_list_t;
/** \brief Declare a list head type
*
* This union stores the real list head, and also encodes as compile-time type
* information the offset of the link pointer, and the type of the entry.
*
* Note that type information is compiler-dependent; this means
* ns_list_get_first() could return either `void *`, or a pointer to the actual
* entry type. So `ns_list_get_first()->data` is not a portable construct -
* always assign returned entry pointers to a properly typed pointer variable.
* This assignment will be then type-checked where the compiler supports it, and
* will dereference correctly on compilers that don't support this extension.
* ~~~
* NS_LIST_HEAD(example_entry_t, link) my_list;
*
* example_entry_t *entry = ns_list_get_first(&my_list);
* do_something(entry->data);
* ~~~
* Each use of this macro generates a new anonymous union, so these two lists
* have different types:
* ~~~
* NS_LIST_HEAD(example_entry_t, link) my_list1;
* NS_LIST_HEAD(example_entry_t, link) my_list2;
* ~~~
* If you need to use a list type in multiple places, eg as a function
* parameter, use typedef:
* ~~~
* typedef NS_LIST_HEAD(example_entry_t, link) example_list_t;
*
* void example_function(example_list_t *);
* ~~~
*/
#define NS_LIST_HEAD(entry_type, field) \
NS_LIST_HEAD_BY_OFFSET_(entry_type, offsetof(entry_type, field))
/** \brief Declare a list head type for an incomplete entry type.
*
* This declares a list head, similarly to NS_LIST_HEAD(), but unlike that
* this can be used in contexts where the entry type may be incomplete.
*
* To use this, the link pointer must be the first member in the
* actual complete structure. This is NOT checked - the definition of the
* element should probably test NS_STATIC_ASSERT(offsetof(type, link) == 0)
* if outside users are known to be using NS_LIST_HEAD_INCOMPLETE().
* ~~~
* struct opaque;
* NS_LIST_HEAD_INCOMPLETE(struct opaque) opaque_list;
* ~~~
*/
#define NS_LIST_HEAD_INCOMPLETE(entry_type) \
NS_LIST_HEAD_BY_OFFSET_(entry_type, 0)
/// \privatesection
/** \brief Internal macro defining a list head, given the offset to the link pointer
* The +1 allows for link_offset being 0 - we can't declare a 0-size array
*/
#define NS_LIST_HEAD_BY_OFFSET_(entry_type, link_offset) \
union \
{ \
ns_list_t slist; \
NS_FUNNY_COMPARE_OK \
NS_STATIC_ASSERT(link_offset <= UINT_FAST8_MAX, "link offset too large") \
NS_FUNNY_COMPARE_RESTORE \
char (*offset)[link_offset + 1]; \
entry_type *type; \
}
/** \brief Get offset of link field in entry.
* \return `(ns_list_offset_t)` The offset of the link field for entries on the specified list
*/
#define NS_LIST_OFFSET_(list) ((ns_list_offset_t) (sizeof *(list)->offset - 1))
/** \brief Get the entry pointer type.
* \def NS_LIST_PTR_TYPE_
*
* \return An unqualified pointer type to an entry on the specified list.
*
* Only available if the compiler provides a "typeof" operator.
*/
#if defined __cplusplus && __cplusplus >= 201103L
#define NS_LIST_PTR_TYPE_(list) decltype((list)->type)
#elif defined __GNUC__
#define NS_LIST_PTR_TYPE_(list) __typeof__((list)->type)
#endif
/** \brief Check for compatible pointer types
*
* This test will produce a diagnostic about a pointer mismatch on
* the == inside the sizeof operator. For example ARM/Norcroft C gives the error:
*
* operand types are incompatible ("entry_t *" and "other_t *")
*/
#ifdef CPPCHECK
#define NS_PTR_MATCH_(a, b, str) ((void) 0)
#else
#define NS_PTR_MATCH_(a, b, str) ((void) sizeof ((a) == (b)))
#endif
/** \brief Internal macro to cast returned entry pointers to correct type.
*
* Not portable in C, alas. With GCC or C++11, the "get entry" macros return
* correctly-typed pointers. Otherwise, the macros return `void *`.
*
* The attempt at a portable version would work if the C `?:` operator wasn't
* broken - `x ? (t *) : (void *)` should really have type `(t *)` in C, but
* it has type `(void *)`, which only makes sense for C++. The `?:` is left in,
* in case some day it works. Some compilers may still warn if this is
* assigned to a different type.
*/
#ifdef NS_LIST_PTR_TYPE_
#define NS_LIST_TYPECAST_(list, val) ((NS_LIST_PTR_TYPE_(list)) (val))
#else
#define NS_LIST_TYPECAST_(list, val) (0 ? (list)->type : (val))
#endif
/** \brief Internal macro to check types of input entry pointer. */
#define NS_LIST_TYPECHECK_(list, entry) \
(NS_PTR_MATCH_((list)->type, (entry), "incorrect entry type for list"), (entry))
/** \brief Type used to pass link offset to underlying functions
*
* We could use size_t, but it would be unnecessarily large on 8-bit systems,
* where we can be (pretty) confident we won't have next pointers more than
* 256 bytes into a structure.
*/
typedef uint_fast8_t ns_list_offset_t;
/// \publicsection
/** \brief The type for the link member in the user's entry structure.
*
* Users should not access this member directly - just pass its name to the
* list head macros. The funny prev pointer simplifies common operations
* (eg insertion, removal), at the expense of complicating rare reverse iteration.
*
* NB - the list implementation relies on next being the first member.
*/
typedef struct ns_list_link {
void *next; ///< Pointer to next entry, or NULL if none
void **prev; ///< Pointer to previous entry's (or head's) next pointer
} ns_list_link_t;
/** \brief "Poison" value placed in unattached entries' link pointers.
* \internal What are good values for this? Platform dependent, maybe just NULL
*/
#define NS_LIST_POISON ((void *) 0xDEADBEEF)
/** \brief Initialiser for an entry's link member
*
* This initialiser is not required by the library, but a user may want an
* initialiser to include in their own entry initialiser. See
* ns_list_link_init() for more discussion.
*/
#define NS_LIST_LINK_INIT(name) \
NS_FUNNY_INTPTR_OK \
{ NS_LIST_POISON, NS_LIST_POISON } \
NS_FUNNY_INTPTR_RESTORE
/** \hideinitializer \brief Initialise an entry's list link
*
* This "initialises" an unattached entry's link by filling the fields with
* poison. This is optional, as unattached entries field pointers are not
* meaningful, and it is not valid to call ns_list_get_next or similar on
* an unattached entry.
*
* \param entry Pointer to an entry
* \param field The name of the link member to initialise
*/
#define ns_list_link_init(entry, field) ns_list_link_init_(&(entry)->field)
/** \hideinitializer \brief Initialise a list
*
* Initialise a list head before use. A list head must be initialised using this
* function or one of the NS_LIST_INIT()-type macros before use. A zero-initialised
* list head is *not* valid.
*
* If used on a list containing existing entries, those entries will
* become detached. (They are not modified, but their links are now effectively
* undefined).
*
* \param list Pointer to a NS_LIST_HEAD() structure.
*/
#define ns_list_init(list) ns_list_init_(&(list)->slist)
/** \brief Initialiser for an empty list
*
* Usage in an enclosing initialiser:
* ~~~
* static my_type_including_list_t x = {
* "Something",
* 23,
* NS_LIST_INIT(x),
* };
* ~~~
* NS_LIST_DEFINE() or NS_LIST_NAME_INIT() may provide a shorter alternative
* in simpler cases.
*/
#define NS_LIST_INIT(name) { { NULL, &(name).slist.first_entry } }
/** \brief Name and initialiser for an empty list
*
* Usage:
* ~~~
* list_t NS_LIST_NAME_INIT(foo);
* ~~~
* acts as
* ~~~
* list_t foo = { empty list };
* ~~~
* Also useful with designated initialisers:
* ~~~
* .NS_LIST_NAME_INIT(foo),
* ~~~
* acts as
* ~~~
* .foo = { empty list },
* ~~~
*/
#define NS_LIST_NAME_INIT(name) name = NS_LIST_INIT(name)
/** \brief Define a list, and initialise to empty.
*
* Usage:
* ~~~
* static NS_LIST_DEFINE(my_list, entry_t, link);
* ~~~
* acts as
* ~~~
* static list_type my_list = { empty list };
* ~~~
*/
#define NS_LIST_DEFINE(name, type, field) \
NS_LIST_HEAD(type, field) NS_LIST_NAME_INIT(name)
/** \hideinitializer \brief Add an entry to the start of the linked list.
*
* ns_list_add_to_end() is *slightly* more efficient than ns_list_add_to_start().
*
* \param list `(list_t *)` Pointer to list.
* \param entry `(entry_t * restrict)` Pointer to new entry to add.
*/
#define ns_list_add_to_start(list, entry) \
ns_list_add_to_start_(&(list)->slist, NS_LIST_OFFSET_(list), NS_LIST_TYPECHECK_(list, entry))
/** \hideinitializer \brief Add an entry to the end of the linked list.
*
* \param list `(list_t *)` Pointer to list.
* \param entry `(entry_t * restrict)` Pointer to new entry to add.
*/
#define ns_list_add_to_end(list, entry) \
ns_list_add_to_end_(&(list)->slist, NS_LIST_OFFSET_(list), NS_LIST_TYPECHECK_(list, entry))
/** \hideinitializer \brief Add an entry before a specified entry.
*
* \param list `(list_t *)` Pointer to list.
* \param before `(entry_t *)` Existing entry before which to place the new entry.
* \param entry `(entry_t * restrict)` Pointer to new entry to add.
*/
#define ns_list_add_before(list, before, entry) \
ns_list_add_before_(NS_LIST_OFFSET_(list), NS_LIST_TYPECHECK_(list, before), NS_LIST_TYPECHECK_(list, entry))
/** \hideinitializer \brief Add an entry after a specified entry.
*
* ns_list_add_before() is *slightly* more efficient than ns_list_add_after().
*
* \param list `(list_t *)` Pointer to list.
* \param after `(entry_t *)` Existing entry after which to place the new entry.
* \param entry `(entry_t * restrict)` Pointer to new entry to add.
*/
#define ns_list_add_after(list, after, entry) \
ns_list_add_after_(&(list)->slist, NS_LIST_OFFSET_(list), NS_LIST_TYPECHECK_(list, after), NS_LIST_TYPECHECK_(list, entry))
/** \brief Check if a list is empty.
*
* \param list `(const list_t *)` Pointer to list.
*
* \return `(bool)` true if the list is empty.
*/
#define ns_list_is_empty(list) ((bool) ((list)->slist.first_entry == NULL))
/** \brief Get the first entry.
*
* \param list `(const list_t *)` Pointer to list.
*
* \return `(entry_t *)` Pointer to first entry.
* \return NULL if list is empty.
*/
#define ns_list_get_first(list) NS_LIST_TYPECAST_(list, (list)->slist.first_entry)
/** \hideinitializer \brief Get the previous entry.
*
* \param list `(const list_t *)` Pointer to list.
* \param current `(const entry_t *)` Pointer to current entry.
*
* \return `(entry_t *)` Pointer to previous entry.
* \return NULL if current entry is first.
*/
#define ns_list_get_previous(list, current) \
NS_LIST_TYPECAST_(list, ns_list_get_previous_(&(list)->slist, NS_LIST_OFFSET_(list), NS_LIST_TYPECHECK_(list, current)))
/** \hideinitializer \brief Get the next entry.
*
* \param list `(const list_t *)` Pointer to list.
* \param current `(const entry_t *)` Pointer to current entry.
*
* \return `(entry_t *)` Pointer to next entry.
* \return NULL if current entry is last.
*/
#define ns_list_get_next(list, current) \
NS_LIST_TYPECAST_(list, ns_list_get_next_(NS_LIST_OFFSET_(list), NS_LIST_TYPECHECK_(list, current)))
/** \hideinitializer \brief Get the last entry.
*
* \param list `(const list_t *)` Pointer to list.
*
* \return `(entry_t *)` Pointer to last entry.
* \return NULL if list is empty.
*/
#define ns_list_get_last(list) \
NS_LIST_TYPECAST_(list, ns_list_get_last_(&(list)->slist, NS_LIST_OFFSET_(list)))
/** \hideinitializer \brief Remove an entry.
*
* \param list `(list_t *)` Pointer to list.
* \param entry `(entry_t *)` Entry on list to be removed.
*/
#define ns_list_remove(list, entry) \
ns_list_remove_(&(list)->slist, NS_LIST_OFFSET_(list), NS_LIST_TYPECHECK_(list, entry))
/** \hideinitializer \brief Replace an entry.
*
* \param list `(list_t *)` Pointer to list.
* \param current `(entry_t *)` Existing entry on list to be replaced.
* \param replacement `(entry_t * restrict)` New entry to be the replacement.
*/
#define ns_list_replace(list, current, replacement) \
ns_list_replace_(&(list)->slist, NS_LIST_OFFSET_(list), NS_LIST_TYPECHECK_(list, current), NS_LIST_TYPECHECK_(list, replacement))
/** \hideinitializer \brief Concatenate two lists.
*
* Attach the entries on the source list to the end of the destination
* list, leaving the source list empty.
*
* \param dst `(list_t *)` Pointer to destination list.
* \param src `(list_t *)` Pointer to source list.
*
*/
#define ns_list_concatenate(dst, src) \
(NS_PTR_MATCH_(dst, src, "concatenating different list types"), \
ns_list_concatenate_(&(dst)->slist, &(src)->slist, NS_LIST_OFFSET_(src)))
/** \brief Iterate forwards over a list.
*
* Example:
* ~~~
* ns_list_foreach(const my_entry_t, cur, &my_list)
* {
* printf("%s\n", cur->name);
* }
* ~~~
* Deletion of the current entry is not permitted as its next is checked after
* running user code.
*
* The iteration pointer is declared inside the loop, using C99/C++, so it
* is not accessible after the loop. This encourages good code style, and
* matches the semantics of C++11's "ranged for", which only provides the
* declaration form:
* ~~~
* for (const my_entry_t cur : my_list)
* ~~~
* If you need to see the value of the iteration pointer after a `break`,
* you will need to assign it to a variable declared outside the loop before
* breaking:
* ~~~
* my_entry_t *match = NULL;
* ns_list_foreach(my_entry_t, cur, &my_list)
* {
* if (cur->id == id)
* {
* match = cur;
* break;
* }
* }
* ~~~
*
* The user has to specify the entry type for the pointer definition, as type
* extraction from the list argument isn't portable. On the other hand, this
* also permits const qualifiers, as in the example above, and serves as
* documentation. The entry type will be checked against the list type where the
* compiler supports it.
*
* \param type Entry type `([const] entry_t)`.
* \param e Name for iteration pointer to be defined
* inside the loop.
* \param list `(const list_t *)` Pointer to list - evaluated multiple times.
*/
#define ns_list_foreach(type, e, list) \
for (type *e = ns_list_get_first(list); e; e = ns_list_get_next(list, e))
/** \brief Iterate forwards over a list, where user may delete.
*
* As ns_list_foreach(), but deletion of current entry is permitted as its
* next pointer is recorded before running user code.
*
* Example:
* ~~~
* ns_list_foreach_safe(my_entry_t, cur, &my_list)
* {
* ns_list_remove(cur);
* }
* ~~~
* \param type Entry type `(entry_t)`.
* \param e Name for iteration pointer to be defined
* inside the loop.
* \param list `(list_t *)` Pointer to list - evaluated multiple times.
*/
#define ns_list_foreach_safe(type, e, list) \
for (type *e = ns_list_get_first(list), *_next##e; \
e && (_next##e = ns_list_get_next(list, e), true); e = _next##e)
/** \brief Iterate backwards over a list.
*
* As ns_list_foreach(), but going backwards - see its documentation.
* Iterating forwards is *slightly* more efficient.
*/
#define ns_list_foreach_reverse(type, e, list) \
for (type *e = ns_list_get_last(list); e; e = ns_list_get_previous(list, e))
/** \brief Iterate backwards over a list, where user may delete.
*
* As ns_list_foreach_safe(), but going backwards - see its documentation.
* Iterating forwards is *slightly* more efficient.
*/
#define ns_list_foreach_reverse_safe(type, e, list) \
for (type *e = ns_list_get_last(list), *_next##e; \
e && (_next##e = ns_list_get_previous(list, e), true); e = _next##e)
/** \hideinitializer \brief Count entries on a list
*
* Unlike other operations, this is O(n). Note: if list might contain over
* 65535 entries, this function **must not** be used to get the entry count.
*
* \param list `(const list_t *)` Pointer to list.
* \return `(uint_fast16_t)` Number of entries that are stored in list.
*/
#define ns_list_count(list) ns_list_count_(&(list)->slist, NS_LIST_OFFSET_(list))
/** \privatesection
* Internal functions - designed to be accessed using corresponding macros above
*/
NS_INLINE void ns_list_init_(ns_list_t *list);
NS_INLINE void ns_list_link_init_(ns_list_link_t *link);
NS_INLINE void ns_list_add_to_start_(ns_list_t *list, ns_list_offset_t link_offset, void *restrict entry);
NS_INLINE void ns_list_add_to_end_(ns_list_t *list, ns_list_offset_t link_offset, void *restrict entry);
NS_INLINE void ns_list_add_before_(ns_list_offset_t link_offset, void *before, void *restrict entry);
NS_INLINE void ns_list_add_after_(ns_list_t *list, ns_list_offset_t link_offset, void *after, void *restrict entry);
NS_INLINE void *ns_list_get_next_(ns_list_offset_t link_offset, const void *current);
NS_INLINE void *ns_list_get_previous_(const ns_list_t *list, ns_list_offset_t link_offset, const void *current);
NS_INLINE void *ns_list_get_last_(const ns_list_t *list, ns_list_offset_t offset);
NS_INLINE void ns_list_remove_(ns_list_t *list, ns_list_offset_t link_offset, void *entry);
NS_INLINE void ns_list_replace_(ns_list_t *list, ns_list_offset_t link_offset, void *current, void *restrict replacement);
NS_INLINE void ns_list_concatenate_(ns_list_t *dst, ns_list_t *src, ns_list_offset_t offset);
NS_INLINE uint_fast16_t ns_list_count_(const ns_list_t *list, ns_list_offset_t link_offset);
/* Provide definitions, either for inlining, or for ns_list.c */
#if defined NS_ALLOW_INLINING || defined NS_LIST_FN
#ifndef NS_LIST_FN
#define NS_LIST_FN NS_INLINE
#endif
/* Pointer to the link member in entry e */
#define NS_LIST_LINK_(e, offset) ((ns_list_link_t *)((char *)(e) + offset))
/* Lvalue of the next link pointer in entry e */
#define NS_LIST_NEXT_(e, offset) (NS_LIST_LINK_(e, offset)->next)
/* Lvalue of the prev link pointer in entry e */
#define NS_LIST_PREV_(e, offset) (NS_LIST_LINK_(e, offset)->prev)
/* Convert a pointer to a link member back to the entry;
* works for linkptr either being a ns_list_link_t pointer, or its next pointer,
* as the next pointer is first in the ns_list_link_t */
#define NS_LIST_ENTRY_(linkptr, offset) ((void *)((char *)(linkptr) - offset))
NS_LIST_FN void ns_list_init_(ns_list_t *list)
{
list->first_entry = NULL;
list->last_nextptr = &list->first_entry;
}
NS_LIST_FN void ns_list_link_init_(ns_list_link_t *link)
{
NS_FUNNY_INTPTR_OK
link->next = NS_LIST_POISON;
link->prev = NS_LIST_POISON;
NS_FUNNY_INTPTR_RESTORE
}
NS_LIST_FN void ns_list_add_to_start_(ns_list_t *list, ns_list_offset_t offset, void *restrict entry)
{
void *next;
NS_LIST_PREV_(entry, offset) = &list->first_entry;
NS_LIST_NEXT_(entry, offset) = next = list->first_entry;
if (next) {
NS_LIST_PREV_(next, offset) = &NS_LIST_NEXT_(entry, offset);
} else {
list->last_nextptr = &NS_LIST_NEXT_(entry, offset);
}
list->first_entry = entry;
}
NS_LIST_FN void ns_list_add_after_(ns_list_t *list, ns_list_offset_t offset, void *current, void *restrict entry)
{
void *next;
NS_LIST_PREV_(entry, offset) = &NS_LIST_NEXT_(current, offset);
NS_LIST_NEXT_(entry, offset) = next = NS_LIST_NEXT_(current, offset);
if (next) {
NS_LIST_PREV_(next, offset) = &NS_LIST_NEXT_(entry, offset);
} else {
list->last_nextptr = &NS_LIST_NEXT_(entry, offset);
}
NS_LIST_NEXT_(current, offset) = entry;
}
NS_LIST_FN void ns_list_add_before_(ns_list_offset_t offset, void *current, void *restrict entry)
{
void **prev_nextptr;
NS_LIST_NEXT_(entry, offset) = current;
NS_LIST_PREV_(entry, offset) = prev_nextptr = NS_LIST_PREV_(current, offset);
*prev_nextptr = entry;
NS_LIST_PREV_(current, offset) = &NS_LIST_NEXT_(entry, offset);
}
NS_LIST_FN void ns_list_add_to_end_(ns_list_t *list, ns_list_offset_t offset, void *restrict entry)
{
void **prev_nextptr;
NS_LIST_NEXT_(entry, offset) = NULL;
NS_LIST_PREV_(entry, offset) = prev_nextptr = list->last_nextptr;
*prev_nextptr = entry;
list->last_nextptr = &NS_LIST_NEXT_(entry, offset);
}
NS_LIST_FN void *ns_list_get_next_(ns_list_offset_t offset, const void *current)
{
return NS_LIST_NEXT_(current, offset);
}
NS_LIST_FN void *ns_list_get_previous_(const ns_list_t *list, ns_list_offset_t offset, const void *current)
{
if (current == list->first_entry) {
return NULL;
}
// Tricky. We don't have a direct previous pointer, but a pointer to the
// pointer that points to us - ie &head->first_entry OR &{prev}->next.
// This makes life easier on insertion and removal, but this is where we
// pay the price.
// We have to check manually for being the first entry above, so we know it's
// a real link's next pointer. Then next is the first field of
// ns_list_link_t, so we can use the normal offset value.
return NS_LIST_ENTRY_(NS_LIST_PREV_(current, offset), offset);
}
NS_LIST_FN void *ns_list_get_last_(const ns_list_t *list, ns_list_offset_t offset)
{
if (!list->first_entry) {
return NULL;
}
// See comments in ns_list_get_previous_()
return NS_LIST_ENTRY_(list->last_nextptr, offset);
}
NS_LIST_FN void ns_list_remove_(ns_list_t *list, ns_list_offset_t offset, void *removed)
{
void *next;
void **prev_nextptr;
next = NS_LIST_NEXT_(removed, offset);
prev_nextptr = NS_LIST_PREV_(removed, offset);
if (next) {
NS_LIST_PREV_(next, offset) = prev_nextptr;
} else {
list->last_nextptr = prev_nextptr;
}
*prev_nextptr = next;
ns_list_link_init_(NS_LIST_LINK_(removed, offset));
}
NS_LIST_FN void ns_list_replace_(ns_list_t *list, ns_list_offset_t offset, void *current, void *restrict replacement)
{
void *next;
void **prev_nextptr;
NS_LIST_PREV_(replacement, offset) = prev_nextptr = NS_LIST_PREV_(current, offset);
NS_LIST_NEXT_(replacement, offset) = next = NS_LIST_NEXT_(current, offset);
if (next) {
NS_LIST_PREV_(next, offset) = &NS_LIST_NEXT_(replacement, offset);
} else {
list->last_nextptr = &NS_LIST_NEXT_(replacement, offset);
}
*prev_nextptr = replacement;
ns_list_link_init_(NS_LIST_LINK_(current, offset));
}
NS_LIST_FN void ns_list_concatenate_(ns_list_t *dst, ns_list_t *src, ns_list_offset_t offset)
{
ns_list_link_t *src_first;
src_first = src->first_entry;
if (!src_first) {
return;
}
*dst->last_nextptr = src_first;
NS_LIST_PREV_(src_first, offset) = dst->last_nextptr;
dst->last_nextptr = src->last_nextptr;
ns_list_init_(src);
}
NS_LIST_FN uint_fast16_t ns_list_count_(const ns_list_t *list, ns_list_offset_t offset)
{
uint_fast16_t count = 0;
for (void *p = list->first_entry; p; p = NS_LIST_NEXT_(p, offset)) {
count++;
}
return count;
}
#endif /* defined NS_ALLOW_INLINING || defined NS_LIST_FN */
#ifdef __cplusplus
}
#endif
#endif /* NS_LIST_H_ */

View file

@ -0,0 +1,403 @@
/*
* Copyright (c) 2014-2015 ARM Limited. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* ns_types.h - Basic compiler and type setup for Nanostack libraries.
*/
#ifndef NS_TYPES_H_
#define NS_TYPES_H_
/** \file
* \brief Basic compiler and type setup
*
* We currently assume C99 or later.
*
* C99 features being relied on:
*
* - <inttypes.h> and <stdbool.h>
* - inline (with C99 semantics, not C++ as per default GCC);
* - designated initialisers;
* - compound literals;
* - restrict;
* - [static N] in array parameters;
* - declarations in for statements;
* - mixing declarations and statements
*
* Compilers should be set to C99 or later mode when building Nanomesh source.
* For GCC this means "-std=gnu99" (C99 with usual GNU extensions).
*
* Also, a little extra care is required for public header files that could be
* included from C++, especially as C++ lacks some C99 features.
*
* (TODO: as this is exposed to API users, do we need a predefine to distinguish
* internal and external use, for finer control? Not yet, but maybe...)
*/
/* Make sure <stdint.h> defines its macros if C++ */
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
#endif
#ifndef __STDC_CONSTANT_MACROS
#define __STDC_CONSTANT_MACROS
#endif
#include <stddef.h>
#include <inttypes.h> // includes <stdint.h>; debugf() users need PRIu32 etc
#include <stdbool.h>
/*
* Create the optional <stdint.h> 24-bit types if they don't exist (worth trying
* to use them, as they could exist and be more efficient than 32-bit on 8-bit
* systems...)
*/
#ifndef UINT24_LEAST_MAX
typedef uint_least32_t uint_least24_t;
#define UINT_LEAST24_MAX UINT_LEAST32_MAX
#define UINT24_C(x) UINT32_C(x)
#define PRIoLEAST24 PRIoLEAST32
#define PRIuLEAST24 PRIuLEAST32
#define PRIxLEAST24 PRIxLEAST32
#define PRIXLEAST24 PRIXLEAST32
#endif
#ifndef INT24_LEAST_MAX
typedef int_least32_t int_least24_t;
#define INT24_LEAST_MIN INT_LEAST32_MIN
#define INT24_LEAST_MAX INT_LEAST32_MAX
#define INT24_C(x) INT32_C(x)
#define PRIdLEAST24 PRIdLEAST32
#define PRIiLEAST24 PRIiLEAST32
#endif
#ifndef UINT24_FAST_MAX
typedef uint_fast32_t uint_fast24_t;
#define UINT_FAST24_MAX UINT_FAST32_MAX
#define PRIoFAST24 PRIoFAST32
#define PRIuFAST24 PRIuFAST32
#define PRIxFAST24 PRIxFAST32
#define PRIXFAST24 PRIXFAST32
#endif
#ifndef INT24_FAST_MAX
typedef int_fast32_t int_fast24_t;
#define INT_FAST24_MIN INT_FAST32_MIN
#define INT_FAST24_MAX INT_FAST32_MAX
#define PRIdFAST24 PRIdFAST32
#define PRIiFAST24 PRIiFAST32
#endif
/* Function attribute - C11 "noreturn" or C++11 "[[noreturn]]" */
#ifndef NS_NORETURN
#if defined __cplusplus && __cplusplus >= 201103L
#define NS_NORETURN [[noreturn]]
#elif !defined __cplusplus && __STDC_VERSION__ >= 201112L
#define NS_NORETURN _Noreturn
#elif defined __GNUC__
#define NS_NORETURN __attribute__((__noreturn__))
#elif defined __CC_ARM
#define NS_NORETURN __declspec(noreturn)
#elif defined __IAR_SYSTEMS_ICC__
#define NS_NORETURN __noreturn
#else
#define NS_NORETURN
#endif
#endif
/* C11's "alignas" macro, emulated for integer expressions if necessary */
#ifndef __alignas_is_defined
#if defined __CC_ARM || defined __TASKING__
#define alignas(n) __align(n)
#define __alignas_is_defined 1
#elif (__STDC_VERSION__ >= 201112L) || (defined __cplusplus && __cplusplus >= 201103L)
#include <stdalign.h>
#elif defined __GNUC__
#define alignas(n) __attribute__((__aligned__(n)))
#define __alignas_is_defined 1
#elif defined __IAR_SYSTEMS_ICC__
/* Does this really just apply to the next variable? */
#define alignas(n) __Alignas(data_alignment=n)
#define __Alignas(x) _Pragma(#x)
#define __alignas_is_defined 1
#endif
#endif
/**
* Marker for functions or objects that may be unused, suppressing warnings.
* Place after the identifier:
* ~~~
* static int X MAYBE_UNUSED = 3;
* static int foo(void) MAYBE_UNUSED;
* ~~~
*/
#if defined __CC_ARM || defined __GNUC__
#define MAYBE_UNUSED __attribute__((unused))
#else
#define MAYBE_UNUSED
#endif
/*
* C++ (even C++11) doesn't provide restrict: define away or provide
* alternative.
*/
#ifdef __cplusplus
#ifdef __GNUC__
#define restrict __restrict
#else
#define restrict
#endif
#endif /* __cplusplus */
/**
* C++ doesn't allow "static" in function parameter types: ie
* ~~~
* entry_t *find_entry(const uint8_t address[static 16])
* ~~~
* If a header file may be included from C++, use this __static define instead.
*
* (Syntax introduced in C99 - `uint8_t address[16]` in a prototype was always
* equivalent to `uint8_t *address`, but the C99 addition of static tells the
* compiler that address is never NULL, and always points to at least 16
* elements. This adds no new type-checking, but the information could aid
* compiler optimisation, and it can serve as documentation).
*/
#ifdef __cplusplus
#define __static
#else
#define __static static
#endif
#ifdef __GNUC__
#define NS_GCC_VERSION (__GNUC__ * 10000 \
+ __GNUC_MINOR__ * 100 \
+ __GNUC_PATCHLEVEL__)
#endif
/** \brief Compile-time assertion
*
* C11 provides _Static_assert, as does GCC even in C99 mode (and
* as a freestanding implementation, we can't rely on <assert.h> to get
* the static_assert macro).
* C++11 provides static_assert as a keyword, as does G++ in C++0x mode.
*
* The assertion acts as a declaration that can be placed at file scope, in a
* code block (except after a label), or as a member of a struct/union. It
* produces a compiler error if "test" evaluates to 0.
*
* Note that this *includes* the required semicolon when defined, else it
* is totally empty, permitting use in structs. (If the user provided the `;`,
* it would leave an illegal stray `;` if unavailable).
*/
#ifdef __cplusplus
# if __cplusplus >= 201103L || __cpp_static_assert >= 200410
# define NS_STATIC_ASSERT(test, str) static_assert(test, str);
# elif defined __GXX_EXPERIMENTAL_CXX0X__ && NS_GCC_VERSION >= 40300
# define NS_STATIC_ASSERT(test, str) __extension__ static_assert(test, str);
# else
# define NS_STATIC_ASSERT(test, str)
# endif
#else /* C */
# if __STDC_VERSION__ >= 201112L
# define NS_STATIC_ASSERT(test, str) _Static_assert(test, str);
# elif defined __GNUC__ && NS_GCC_VERSION >= 40600 && !defined __CC_ARM
# ifdef _Static_assert
/*
* Some versions of glibc cdefs.h (which comes in via <stdint.h> above)
* attempt to define their own _Static_assert (if GCC < 4.6 or
* __STRICT_ANSI__) using an extern declaration, which doesn't work in a
* struct/union.
*
* For GCC >= 4.6 and __STRICT_ANSI__, we can do better - just use
* the built-in _Static_assert with __extension__. We have to do this, as
* ns_list.h needs to use it in a union. No way to get at it though, without
* overriding their define.
*/
# undef _Static_assert
# define _Static_assert(x, y) __extension__ _Static_assert(x, y)
# endif
# define NS_STATIC_ASSERT(test, str) __extension__ _Static_assert(test, str);
# else
# define NS_STATIC_ASSERT(test, str)
#endif
#endif
/** \brief Pragma to suppress warnings about unusual pointer values.
*
* Useful if using "poison" values.
*/
#ifdef __IAR_SYSTEMS_ICC__
#define NS_FUNNY_INTPTR_OK _Pragma("diag_suppress=Pe1053")
#define NS_FUNNY_INTPTR_RESTORE _Pragma("diag_default=Pe1053")
#else
#define NS_FUNNY_INTPTR_OK
#define NS_FUNNY_INTPTR_RESTORE
#endif
/** \brief Pragma to suppress warnings about always true/false comparisons
*/
#if defined __GNUC__ && NS_GCC_VERSION >= 40600 && !defined __CC_ARM
#define NS_FUNNY_COMPARE_OK _Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wtype-limits\"")
#define NS_FUNNY_COMPARE_RESTORE _Pragma("GCC diagnostic pop")
#else
#define NS_FUNNY_COMPARE_OK
#define NS_FUNNY_COMPARE_RESTORE
#endif
/** \brief Pragma to suppress warnings arising from dummy definitions.
*
* Useful when you have function-like macros that returning constants
* in cut-down builds. Can be fairly cavalier about disabling as we
* do not expect every build to use this macro. Generic builds of
* components should ensure this is not included by only using it in
* a ifdef blocks providing dummy definitions.
*/
#ifdef __CC_ARM
// statement is unreachable(111), controlling expression is constant(236), expression has no effect(174),
// function was declared but never referenced(177), variable was set but never used(550)
#define NS_DUMMY_DEFINITIONS_OK _Pragma("diag_suppress=111,236,174,177,550")
#elif defined __IAR_SYSTEMS_ICC__
// controlling expression is constant
#define NS_DUMMY_DEFINITIONS_OK _Pragma("diag_suppress=Pe236")
#else
#define NS_DUMMY_DEFINITIONS_OK
#endif
/** \brief Convert pointer to member to pointer to containing structure */
#define NS_CONTAINER_OF(ptr, type, member) \
((type *) ((char *) (ptr) - offsetof(type, member)))
/*
* Inlining could cause problems when mixing with C++; provide a mechanism to
* disable it. This could also be turned off for other reasons (although
* this can usually be done through a compiler flag, eg -O0 on gcc).
*/
#ifndef __cplusplus
#define NS_ALLOW_INLINING
#endif
/* There is inlining problem in GCC version 4.1.x and we know it works in 4.6.3 */
#if defined __GNUC__ && NS_GCC_VERSION < 40600
#undef NS_ALLOW_INLINING
#endif
/** \brief Mark a potentially-inlineable function.
*
* We follow C99 semantics, which requires precisely one external definition.
* To also allow inlining to be totally bypassed under control of
* NS_ALLOW_INLINING, code can be structured as per the example of ns_list:
*
* foo.h
* -----
* ~~~
* NS_INLINE int my_func(int);
*
* #if defined NS_ALLOW_INLINING || defined FOO_FN
* #ifndef FOO_FN
* #define FOO_FN NS_INLINE
* #endif
* FOO_FN int my_func(int a)
* {
* definition;
* }
* #endif
* ~~~
* foo.c
* -----
* ~~~
* #define FOO_FN extern
* #include "foo.h"
* ~~~
* Which generates:
* ~~~
* NS_ALLOW_INLINING set NS_ALLOW_INLINING unset
* ===================== =======================
* Include foo.h Include foo.h
* ------------- -------------
* inline int my_func(int); int my_func(int);
*
* // inline definition
* inline int my_func(int a)
* {
* definition;
* }
*
* Compile foo.c Compile foo.c
* ------------- -------------
* (from .h) inline int my_func(int); int my_func(int);
*
* // external definition
* // because of no "inline" // normal external definition
* extern int my_func(int a) extern int my_func(int a)
* { {
* definition; definition;
* } }
* ~~~
*
* Note that even with inline keywords, whether the compiler inlines or not is
* up to it. For example, gcc at "-O0" will not inline at all, and will always
* call the real functions in foo.o, just as if NS_ALLOW_INLINING was unset.
* At "-O2", gcc could potentially inline everything, meaning that foo.o is not
* referenced at all.
*
* Alternatively, you could use "static inline", which gives every caller its
* own internal definition. This is compatible with C++ inlining (which expects
* the linker to eliminate duplicates), but in C it's less efficient if the code
* ends up non-inlined, and it's harder to breakpoint. I don't recommend it
* except for the most trivial functions (which could then probably be macros).
*/
#ifdef NS_ALLOW_INLINING
#define NS_INLINE inline
#else
#define NS_INLINE
#endif
#if defined __SDCC_mcs51 || defined __ICC8051__ || defined __C51__
/* The 8051 environments: SDCC (historic), IAR (current), Keil (future?) */
#define NS_LARGE __xdata
#define NS_LARGE_PTR __xdata
#ifdef __ICC8051__
#define NS_REENTRANT
#define NS_REENTRANT_PREFIX __idata_reentrant
#else
#define NS_REENTRANT __reentrant
#define NS_REENTRANT_PREFIX
#endif
#define NS_NEAR_FUNC __near_func
#else
/* "Normal" systems. Define it all away. */
#define NS_LARGE
#define NS_LARGE_PTR
#define NS_REENTRANT
#define NS_REENTRANT_PREFIX
#define NS_NEAR_FUNC
#endif
/** \brief Scatter-gather descriptor
*
* Slightly optimised for small platforms - we assume we won't need any
* element bigger than 64K.
*/
typedef struct ns_iovec {
void *iov_base;
uint_fast16_t iov_len;
} ns_iovec_t;
#endif /* NS_TYPES_H */

View file

@ -0,0 +1,126 @@
#ifndef SN_COAP_AMEBA_PORT
#define SN_COAP_AMEBA_PORT
/** @addtogroup coap COAP
* @ingroup network
* @brief mbed CoAP APIs and Ameba wrappers
* @{
*/
#include "FreeRTOS.h"
#include "task.h"
#include "diag.h"
#include "platform_stdlib.h"
#include "osdep_service.h"
#include "wifi_constants.h"
#include "wifi_conf.h"
#include <lwip/sockets.h>
#include <lwip/netdb.h>
#include <stdint.h>
#include "sn_coap_protocol.h"
#define randLIB_seed_random() NULL /*!< Not used */
#define COAP_DBG_EN 0 /*!< Flag to enable / disable CoAP debug message in function **tr_debug()** */
#define COAP_DBG_DETAIL 0 /*!< Flage to enable / disable detialed log in CoAP debug message in function **tr_debug()** */
/**
* \brief print CoAP debug message
*/
#define tr_debug(fmat,...) \
do { \
if(COAP_DBG_EN){ \
printf(fmat "\n", ##__VA_ARGS__); \
if(COAP_DBG_DETAIL){\
printf("Function: %s :: Line: %d\n\n",__FUNCTION__,__LINE__);\
}\
} \
} while (0)
/**
* \brief This function is called in **sn_coap_protocol_init()** for ramdom message ID
* \return A random 16bit unsigned value
*/
uint16_t randLIB_get_16bit(void);
/**
* \brief Ameba **malloc()** function wrapper
* \param size: memory size to be allocated
* \return NULL = if memory allocation failed
* \return void* pointer to allocated memory = if allocation success
*/
void* coap_malloc(uint16_t size);
/**
* \brief Ameba **free()** function wrapper
* \param *addr: memory address to be freed
*/
void coap_free(void* addr);
/**
* \brief Ameba **calloc()** function wrapper, the effective result is the allocation of a zero-initialized memory block of *size* bytes
* \param size: memory size to be allocated
* \return NULL = if memory allocation failed
* \return void* pointer to the allocated memory = if memory allocation success
*/
void* coap_calloc(uint32_t size);
/**
* \brief Ameba **socket()** function wrapper, creates a **Datagrams type** i.e. *SOCK_DGRAM* socket
* \return Non-negative Integer (socket file descriptor) = if successfully completion
* \return -1 = if failed to create socket
*/
int coap_sock_open(void);
/**
* \brief Ameba **close()** function wrapper, closes a socket file descriptor
* \param sock_fd: the socket file descriptor is going to be closed.
* \return -1 = if close operation failed
* \return 0 = if close operation success
*/
int coap_sock_close(int socket_fd);
/**
* \brief Ameba **sn_coap_protocol_init()** function wrapper, initializes CoAP Protocol part.
* \param *coap_tx_callback : function callback pointer to tx function for sending coap messages
* \param *coap_rx_callback : function callback pointer to rx function, used to return CoAP header struct with status COAP_STATUS_BUILDER_MESSAGE_SENDING_FAILED
* when re-sendings exceeded. If set to NULL, no error message is returned.
* \return pointer to CoAP handle = if success
* \return NULL = if failed
*/
struct coap_s * coap_protocol_init(uint8_t (*coap_tx_callback)(uint8_t *, uint16_t, sn_nsdl_addr_s *, void *), int8_t (*coap_rx_callback)(sn_coap_hdr_s *, sn_nsdl_addr_s *, void *));
/**
* \brief Send the constructed CoAP message to designated host address on the specific port number
* \param *to_address : the host / domain / ip address that the message is targeted to
* \param port : port number that the host is used to receive the message
* \param socket : socket file descriptor used to send the message
* \param *coap_msg_hdr : constructed CoAP message pointer
* \return The number of bytes sent = if fuccess
* \return -1 = if failed
*/
int coap_send(char *to_address, uint16_t port, int socket, sn_coap_hdr_s *coap_msg_hdr);
/**
* \brief Receive the constructed CoAP message from host
* \param socket : socket file descriptor used to receive the message
* \param *from_address : an internet address pointer, which the sender address is to be stored into
* \param *buf : memory buffer that used to store the received message
* \param buf_size : specifies the length in bytes of the buffer pointed to by the *buf* argument.
* \return The length of the message in bytes : if successful completion
* \return 0 = If no messages are available to be received
* \return -1 = receive message failed
*/
int coap_recv(int socket, struct sockaddr_in *from_address, void *buf, uint32_t buf_size);
/**
* \brief Print CoAP message header (for debug use)
* \param *parsed_hdr : pointer to constructed CoAP message header
*/
void coap_print_hdr(sn_coap_hdr_s* parsed_hdr);
/*\@}*/
#endif //SN_COAP_AMEBA_PORT

View file

@ -0,0 +1,443 @@
/*
* Copyright (c) 2011-2015 ARM Limited. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file sn_coap_header.h
*
* \brief CoAP C-library User header interface header file
*/
#ifndef SN_COAP_HEADER_H_
#define SN_COAP_HEADER_H_
/** @addtogroup coap COAP
* @ingroup network
* @brief mbed CoAP APIs and Ameba wrappers
* @{
*/
#ifdef __cplusplus
extern "C" {
#endif
/* Handle structure */
struct coap_s;
/* * * * * * * * * * * * * * */
/* * * * ENUMERATIONS * * * */
/* * * * * * * * * * * * * * */
/**
* \brief Enumeration for CoAP Version
*/
typedef enum coap_version_ {
COAP_VERSION_1 = 0x40,
COAP_VERSION_UNKNOWN = 0xFF
} coap_version_e;
/**
* \brief Enumeration for CoAP Message type, used in CoAP Header
*/
typedef enum sn_coap_msg_type_ {
COAP_MSG_TYPE_CONFIRMABLE = 0x00, /**< Reliable Request messages */
COAP_MSG_TYPE_NON_CONFIRMABLE = 0x10, /**< Non-reliable Request and Response messages */
COAP_MSG_TYPE_ACKNOWLEDGEMENT = 0x20, /**< Response to a Confirmable Request */
COAP_MSG_TYPE_RESET = 0x30 /**< Answer a Bad Request */
} sn_coap_msg_type_e;
/**
* \brief Enumeration for CoAP Message code, used in CoAP Header
*/
typedef enum sn_coap_msg_code_ {
COAP_MSG_CODE_EMPTY = 0,
COAP_MSG_CODE_REQUEST_GET = 1,
COAP_MSG_CODE_REQUEST_POST = 2,
COAP_MSG_CODE_REQUEST_PUT = 3,
COAP_MSG_CODE_REQUEST_DELETE = 4,
COAP_MSG_CODE_RESPONSE_CREATED = 65,
COAP_MSG_CODE_RESPONSE_DELETED = 66,
COAP_MSG_CODE_RESPONSE_VALID = 67,
COAP_MSG_CODE_RESPONSE_CHANGED = 68,
COAP_MSG_CODE_RESPONSE_CONTENT = 69,
COAP_MSG_CODE_RESPONSE_CONTINUE = 95,
COAP_MSG_CODE_RESPONSE_BAD_REQUEST = 128,
COAP_MSG_CODE_RESPONSE_UNAUTHORIZED = 129,
COAP_MSG_CODE_RESPONSE_BAD_OPTION = 130,
COAP_MSG_CODE_RESPONSE_FORBIDDEN = 131,
COAP_MSG_CODE_RESPONSE_NOT_FOUND = 132,
COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED = 133,
COAP_MSG_CODE_RESPONSE_NOT_ACCEPTABLE = 134,
COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_INCOMPLETE = 136,
COAP_MSG_CODE_RESPONSE_PRECONDITION_FAILED = 140,
COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_TOO_LARGE = 141,
COAP_MSG_CODE_RESPONSE_UNSUPPORTED_CONTENT_FORMAT = 143,
COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR = 160,
COAP_MSG_CODE_RESPONSE_NOT_IMPLEMENTED = 161,
COAP_MSG_CODE_RESPONSE_BAD_GATEWAY = 162,
COAP_MSG_CODE_RESPONSE_SERVICE_UNAVAILABLE = 163,
COAP_MSG_CODE_RESPONSE_GATEWAY_TIMEOUT = 164,
COAP_MSG_CODE_RESPONSE_PROXYING_NOT_SUPPORTED = 165
} sn_coap_msg_code_e;
/**
* \brief Enumeration for CoAP Option number, used in CoAP Header
*/
typedef enum sn_coap_option_numbers_ {
COAP_OPTION_IF_MATCH = 1,
COAP_OPTION_URI_HOST = 3,
COAP_OPTION_ETAG = 4,
COAP_OPTION_IF_NONE_MATCH = 5,
COAP_OPTION_OBSERVE = 6,
COAP_OPTION_URI_PORT = 7,
COAP_OPTION_LOCATION_PATH = 8,
COAP_OPTION_URI_PATH = 11,
COAP_OPTION_CONTENT_FORMAT = 12,
COAP_OPTION_MAX_AGE = 14,
COAP_OPTION_URI_QUERY = 15,
COAP_OPTION_ACCEPT = 17,
COAP_OPTION_LOCATION_QUERY = 20,
COAP_OPTION_BLOCK2 = 23,
COAP_OPTION_BLOCK1 = 27,
COAP_OPTION_SIZE2 = 28,
COAP_OPTION_PROXY_URI = 35,
COAP_OPTION_PROXY_SCHEME = 39,
COAP_OPTION_SIZE1 = 60
// 128 = (Reserved)
// 132 = (Reserved)
// 136 = (Reserved)
} sn_coap_option_numbers_e;
/**
* \brief Enumeration for CoAP Content Format codes
*/
typedef enum sn_coap_content_format_ {
COAP_CT_NONE = -1, // internal
COAP_CT_TEXT_PLAIN = 0,
COAP_CT_LINK_FORMAT = 40,
COAP_CT_XML = 41,
COAP_CT_OCTET_STREAM = 42,
COAP_CT_EXI = 47,
COAP_CT_JSON = 50,
COAP_CT__MAX = 0xffff
} sn_coap_content_format_e;
/**
* \brief Enumeration for CoAP Observe option values
*
* draft-ietf-core-observe-16
*/
typedef enum sn_coap_observe_ {
COAP_OBSERVE_NONE = -1, // internal
// Values for GET requests
COAP_OBSERVE_REGISTER = 0,
COAP_OBSERVE_DEREGISTER = 1,
// In responses, value is a 24-bit opaque sequence number
COAP_OBSERVE__MAX = 0xffffff
} sn_coap_observe_e;
/**
* \brief Enumeration for CoAP status, used in CoAP Header
*/
typedef enum sn_coap_status_ {
COAP_STATUS_OK = 0, /**< Default value is OK */
COAP_STATUS_PARSER_ERROR_IN_HEADER = 1, /**< CoAP will send Reset message to invalid message sender */
COAP_STATUS_PARSER_DUPLICATED_MSG = 2, /**< CoAP will send Acknowledgement message to duplicated message sender */
COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVING = 3, /**< User will get whole message after all message blocks received.
User must release messages with this status. */
COAP_STATUS_PARSER_BLOCKWISE_ACK = 4, /**< Acknowledgement for sent Blockwise message received */
COAP_STATUS_PARSER_BLOCKWISE_MSG_REJECTED = 5, /**< Blockwise message received but not supported by compiling switch */
COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED = 6, /**< Blockwise message fully received and returned to app.
User must take care of releasing whole payload of the blockwise messages */
COAP_STATUS_BUILDER_MESSAGE_SENDING_FAILED = 7 /**< When re-transmissions have been done and ACK not received, CoAP library calls
RX callback with this status */
} sn_coap_status_e;
/* * * * * * * * * * * * * */
/* * * * STRUCTURES * * * */
/* * * * * * * * * * * * * */
/**
* \brief Structure for CoAP Options
*/
typedef struct sn_coap_options_list_ {
uint8_t etag_len; /**< 1-8 bytes. Repeatable */
unsigned int use_size1:1;
unsigned int use_size2:1;
uint16_t proxy_uri_len; /**< 1-1034 bytes. */
uint16_t uri_host_len; /**< 1-255 bytes. */
uint16_t location_path_len; /**< 0-255 bytes. Repeatable */
uint16_t location_query_len; /**< 0-255 bytes. Repeatable */
uint16_t uri_query_len; /**< 1-255 bytes. Repeatable */
sn_coap_content_format_e accept; /**< Value 0-65535. COAP_CT_NONE if not used */
uint32_t max_age; /**< Value in seconds (default is 60) */
uint32_t size1; /**< 0-4 bytes. */
uint32_t size2; /**< 0-4 bytes. */
int32_t uri_port; /**< Value 0-65535. -1 if not used */
int32_t observe; /**< Value 0-0xffffff. -1 if not used */
int32_t block1; /**< Value 0-0xffffff. -1 if not used. Not for user */
int32_t block2; /**< Value 0-0xffffff. -1 if not used. Not for user */
uint8_t *proxy_uri_ptr; /**< Must be set to NULL if not used */
uint8_t *etag_ptr; /**< Must be set to NULL if not used */
uint8_t *uri_host_ptr; /**< Must be set to NULL if not used */
uint8_t *location_path_ptr; /**< Must be set to NULL if not used */
uint8_t *location_query_ptr; /**< Must be set to NULL if not used */
uint8_t *uri_query_ptr; /**< Must be set to NULL if not used */
} sn_coap_options_list_s;
/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
/* !!! Main CoAP message struct !!! */
/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
/**
* \brief Main CoAP message struct
*/
typedef struct sn_coap_hdr_ {
uint8_t token_len; /**< 1-8 bytes. */
sn_coap_status_e coap_status; /**< Used for telling to User special cases when parsing message */
sn_coap_msg_code_e msg_code; /**< Empty: 0; Requests: 1-31; Responses: 64-191 */
sn_coap_msg_type_e msg_type; /**< Confirmable, Non-Confirmable, Acknowledgement or Reset */
sn_coap_content_format_e content_format; /**< Set to COAP_CT_NONE if not used */
uint16_t msg_id; /**< Message ID. Parser sets parsed message ID, builder sets message ID of built coap message */
uint16_t uri_path_len; /**< 0-255 bytes. Repeatable. */
uint16_t payload_len; /**< Must be set to zero if not used */
uint8_t *token_ptr; /**< Must be set to NULL if not used */
uint8_t *uri_path_ptr; /**< Must be set to NULL if not used. E.g: temp1/temp2 */
uint8_t *payload_ptr; /**< Must be set to NULL if not used */
/* Here are not so often used Options */
sn_coap_options_list_s *options_list_ptr; /**< Must be set to NULL if not used */
} sn_coap_hdr_s;
/* * * * * * * * * * * * * * */
/* * * * ENUMERATIONS * * * */
/* * * * * * * * * * * * * * */
/**
* \brief Used protocol
*/
typedef enum sn_nsdl_capab_ {
SN_NSDL_PROTOCOL_HTTP = 0x01, /**< Unsupported */
SN_NSDL_PROTOCOL_HTTPS = 0x02, /**< Unsupported */
SN_NSDL_PROTOCOL_COAP = 0x04 /**< Supported */
} sn_nsdl_capab_e;
/* * * * * * * * * * * * * */
/* * * * STRUCTURES * * * */
/* * * * * * * * * * * * * */
/**
* \brief Used for creating manually registration message with sn_coap_register()
*/
typedef struct registration_info_ {
uint8_t endpoint_len;
uint8_t endpoint_type_len;
uint16_t links_len;
uint8_t *endpoint_ptr; /**< Endpoint name */
uint8_t *endpoint_type_ptr; /**< Endpoint type */
uint8_t *links_ptr; /**< Resource registration string */
} registration_info_t;
/**
* \brief Address type of given address
*/
typedef enum sn_nsdl_addr_type_ {
SN_NSDL_ADDRESS_TYPE_IPV6 = 0x01, /**< Supported */
SN_NSDL_ADDRESS_TYPE_IPV4 = 0x02, /**< Supported */
SN_NSDL_ADDRESS_TYPE_HOSTNAME = 0x03, /**< Unsupported */
SN_NSDL_ADDRESS_TYPE_NONE = 0xFF
} sn_nsdl_addr_type_e;
/**
* \brief Address structure of Packet data
*/
typedef struct sn_nsdl_addr_ {
uint8_t addr_len;
sn_nsdl_addr_type_e type;
uint16_t port;
uint8_t *addr_ptr;
} sn_nsdl_addr_s;
/* * * * * * * * * * * * * * * * * * * * * * */
/* * * * EXTERNAL FUNCTION PROTOTYPES * * * */
/* * * * * * * * * * * * * * * * * * * * * * */
/**
* \fn sn_coap_hdr_s *sn_coap_parser(struct coap_s *handle, uint16_t packet_data_len, uint8_t *packet_data_ptr, coap_version_e *coap_version_ptr)
*
* \brief Parses CoAP message from given Packet data
*
* \param *handle Pointer to CoAP library handle
*
* \param packet_data_len is length of given Packet data to be parsed to CoAP message
*
* \param *packet_data_ptr is source for Packet data to be parsed to CoAP message
*
* \param *coap_version_ptr is destination for parsed CoAP specification version
*
* \return Return value is pointer to parsed CoAP message.\n
* In following failure cases NULL is returned:\n
* -Failure in given pointer (= NULL)\n
* -Failure in memory allocation (malloc() returns NULL)
*/
extern sn_coap_hdr_s *sn_coap_parser(struct coap_s *handle, uint16_t packet_data_len, uint8_t *packet_data_ptr, coap_version_e *coap_version_ptr);
/**
* \fn void sn_coap_parser_release_allocated_coap_msg_mem(struct coap_s *handle, sn_coap_hdr_s *freed_coap_msg_ptr)
*
* \brief Releases memory of given CoAP message
*
* \note Does not release Payload part
*
* \param *handle Pointer to CoAP library handle
*
* \param *freed_coap_msg_ptr is pointer to released CoAP message
*/
extern void sn_coap_parser_release_allocated_coap_msg_mem(struct coap_s *handle, sn_coap_hdr_s *freed_coap_msg_ptr);
/**
* \fn int16_t sn_coap_builder(uint8_t *dst_packet_data_ptr, sn_coap_hdr_s *src_coap_msg_ptr)
*
* \brief Builds an outgoing message buffer from a CoAP header structure.
*
* \param *dst_packet_data_ptr is pointer to allocated destination to built CoAP packet
*
* \param *src_coap_msg_ptr is pointer to source structure for building Packet data
*
* \return Return value is byte count of built Packet data. In failure cases:\n
* -1 = Failure in given CoAP header structure\n
* -2 = Failure in given pointer (= NULL)
*/
extern int16_t sn_coap_builder(uint8_t *dst_packet_data_ptr, sn_coap_hdr_s *src_coap_msg_ptr);
/**
* \fn uint16_t sn_coap_builder_calc_needed_packet_data_size(sn_coap_hdr_s *src_coap_msg_ptr)
*
* \brief Calculates needed Packet data memory size for given CoAP message
*
* \param *src_coap_msg_ptr is pointer to data which needed Packet
* data length is calculated
*
* \return Return value is count of needed memory as bytes for build Packet data
* Null if failed
*/
extern uint16_t sn_coap_builder_calc_needed_packet_data_size(sn_coap_hdr_s *src_coap_msg_ptr);
/**
* \fn int16_t sn_coap_builder_2(uint8_t *dst_packet_data_ptr, sn_coap_hdr_s *src_coap_msg_ptr, uint16_t blockwise_size)
*
* \brief Builds an outgoing message buffer from a CoAP header structure.
*
* \param *dst_packet_data_ptr is pointer to allocated destination to built CoAP packet
*
* \param *src_coap_msg_ptr is pointer to source structure for building Packet data
*
* \param blockwise_payload_size Blockwise message maximum payload size
*
* \return Return value is byte count of built Packet data. In failure cases:\n
* -1 = Failure in given CoAP header structure\n
* -2 = Failure in given pointer (= NULL)
*/
extern int16_t sn_coap_builder_2(uint8_t *dst_packet_data_ptr, sn_coap_hdr_s *src_coap_msg_ptr, uint16_t blockwise_payload_size);
/**
* \fn uint16_t sn_coap_builder_calc_needed_packet_data_size_2(sn_coap_hdr_s *src_coap_msg_ptr, uint16_t blockwise_payload_size)
*
* \brief Calculates needed Packet data memory size for given CoAP message
*
* \param *src_coap_msg_ptr is pointer to data which needed Packet
* data length is calculated
* \param blockwise_payload_size Blockwise message maximum payload size
*
* \return Return value is count of needed memory as bytes for build Packet data
* Null if failed
*/
extern uint16_t sn_coap_builder_calc_needed_packet_data_size_2(sn_coap_hdr_s *src_coap_msg_ptr, uint16_t blockwise_payload_size);
/**
* \fn sn_coap_hdr_s *sn_coap_build_response(struct coap_s *handle, sn_coap_hdr_s *coap_packet_ptr, uint8_t msg_code)
*
* \brief Prepares generic response packet from a request packet. This function allocates memory for the resulting sn_coap_hdr_s
*
* \param *handle Pointer to CoAP library handle
* \param *coap_packet_ptr The request packet pointer
* \param msg_code response messages code
*
* \return *coap_packet_ptr The allocated and pre-filled response packet pointer
* NULL Error in parsing the request
*
*/
extern sn_coap_hdr_s *sn_coap_build_response(struct coap_s *handle, sn_coap_hdr_s *coap_packet_ptr, uint8_t msg_code);
/**
* \brief Initialise a message structure to empty
*
* \param *coap_msg_ptr is pointer to CoAP message to initialise
*
* \return Return value is pointer passed in
*/
extern sn_coap_hdr_s *sn_coap_parser_init_message(sn_coap_hdr_s *coap_msg_ptr);
/**
* \brief Allocate an empty message structure
*
* \param *handle Pointer to CoAP library handle
*
* \return Return value is pointer to an empty CoAP message.\n
* In following failure cases NULL is returned:\n
* -Failure in given pointer (= NULL)\n
* -Failure in memory allocation (malloc() returns NULL)
*/
extern sn_coap_hdr_s *sn_coap_parser_alloc_message(struct coap_s *handle);
/**
* \brief Allocates and initializes options list structure
*
* \param *handle Pointer to CoAP library handle
* \param *coap_msg_ptr is pointer to CoAP message that will contain the options
*
* If the message already has a pointer to an option structure, that pointer
* is returned, rather than a new structure being allocated.
*
* \return Return value is pointer to the CoAP options structure.\n
* In following failure cases NULL is returned:\n
* -Failure in given pointer (= NULL)\n
* -Failure in memory allocation (malloc() returns NULL)
*/
extern sn_coap_options_list_s *sn_coap_parser_alloc_options(struct coap_s *handle, sn_coap_hdr_s *coap_msg_ptr);
#ifdef __cplusplus
}
#endif
/*\@}*/
#endif /* SN_COAP_HEADER_H_ */

View file

@ -0,0 +1,78 @@
/*
* Copyright (c) 2011-2015 ARM Limited. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file sn_coap_header_internal.h
*
* \brief Header file for CoAP Header part
*
*/
#ifdef __cplusplus
extern "C" {
#endif
#ifndef SN_COAP_HEADER_INTERNAL_H_
#define SN_COAP_HEADER_INTERNAL_H_
/* * * * * * * * * * * */
/* * * * DEFINES * * * */
/* * * * * * * * * * * */
#define COAP_VERSION COAP_VERSION_1 /* Tells which IETF CoAP specification version the CoAP message supports. */
/* This value is written to CoAP message header part. */
/* CoAP Header defines */
#define COAP_HEADER_LENGTH 4 /* Fixed Header length of CoAP message as bytes */
#define COAP_HEADER_VERSION_MASK 0xC0
#define COAP_HEADER_MSG_TYPE_MASK 0x30
#define COAP_HEADER_TOKEN_LENGTH_MASK 0x0F
#define COAP_HEADER_MSG_ID_MSB_SHIFT 8
/* CoAP Options defines */
#define COAP_OPTIONS_OPTION_NUMBER_SHIFT 4
/* * * * * * * * * * * * * * */
/* * * * ENUMERATIONS * * * */
/* * * * * * * * * * * * * * */
/* * * * * * * * * * * * * */
/* * * * STRUCTURES * * * */
/* * * * * * * * * * * * * */
/**
* \brief This structure is returned by sn_coap_exec() for sending
*/
typedef struct sn_nsdl_transmit_ {
sn_nsdl_addr_s *dst_addr_ptr;
sn_nsdl_capab_e protocol;
uint16_t packet_len;
uint8_t *packet_ptr;
} sn_nsdl_transmit_s;
/* * * * * * * * * * * * * * * * * * * * * * */
/* * * * EXTERNAL FUNCTION PROTOTYPES * * * */
/* * * * * * * * * * * * * * * * * * * * * * */
extern int8_t sn_coap_header_validity_check(sn_coap_hdr_s *src_coap_msg_ptr, coap_version_e coap_version);
#endif /* SN_COAP_HEADER_INTERNAL_H_ */
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,231 @@
/*
* Copyright (c) 2011-2015 ARM Limited. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file sn_coap_protocol.h
*
* \brief CoAP C-library User protocol interface header file
*/
#ifdef __cplusplus
extern "C" {
#endif
#ifndef SN_COAP_PROTOCOL_H_
#define SN_COAP_PROTOCOL_H_
/** @addtogroup coap COAP
* @ingroup network
* @brief mbed CoAP APIs and Ameba wrappers
* @{
*/
#include "sn_coap_header.h"
/**
* \fn struct coap_s *sn_coap_protocol_init(void *(*used_malloc_func_ptr)(uint16_t), void (*used_free_func_ptr)(void *), uint8_t (*used_tx_callback_ptr)(uint8_t *, uint16_t, sn_nsdl_addr_s *, void *), int8_t (*used_rx_callback_ptr)(sn_coap_hdr_s *, sn_nsdl_addr_s *, void *));
*
* \brief Initializes CoAP Protocol part. When using libNsdl, sn_nsdl_init() calls this function.
*
* \param *used_malloc_func_ptr is function pointer for used memory allocation function.
*
* \param *used_free_func_ptr is function pointer for used memory free function.
*
* \param *used_tx_callback_ptr function callback pointer to tx function for sending coap messages
*
* \param *used_rx_callback_ptr used to return CoAP header struct with status COAP_STATUS_BUILDER_MESSAGE_SENDING_FAILED
* when re-sendings exceeded. If set to NULL, no error message is returned.
*
* \return Pointer to handle when success\n
* Null if failed
*/
extern struct coap_s *sn_coap_protocol_init(void *(*used_malloc_func_ptr)(uint16_t), void (*used_free_func_ptr)(void *),
uint8_t (*used_tx_callback_ptr)(uint8_t *, uint16_t, sn_nsdl_addr_s *, void *),
int8_t (*used_rx_callback_ptr)(sn_coap_hdr_s *, sn_nsdl_addr_s *, void *));
/**
* \fn int8_t sn_coap_protocol_destroy(struct coap_s *handle)
*
* \brief Frees all memory from CoAP protocol part
*
* \param *handle Pointer to CoAP library handle
*
* \return Return value is always 0
*/
extern int8_t sn_coap_protocol_destroy(struct coap_s *handle);
/**
* \fn int16_t sn_coap_protocol_build(struct coap_s *handle, sn_nsdl_addr_s *dst_addr_ptr, uint8_t *dst_packet_data_ptr, sn_coap_hdr_s *src_coap_msg_ptr, void *param)
*
* \brief Builds Packet data from given CoAP header structure to be sent
*
* \param *dst_addr_ptr is pointer to destination address where CoAP message
* will be sent (CoAP builder needs that information for message resending purposes)
*
* \param *dst_packet_data_ptr is pointer to destination of built Packet data
*
* \param *src_coap_msg_ptr is pointer to source of built Packet data
*
* \param param void pointer that will be passed to tx/rx function callback when those are called.
*
* \note If message is blockwised, all payload is not sent at the same time
*
* \return Return value is byte count of built Packet data.\n
* In failure cases:\n
* -1 = Failure in CoAP header structure\n
* -2 = Failure in given pointer (= NULL)\n
* -3 = Failure in Reset message\n
* -4 = Failure in Resending message store\n
* If there is not enough memory (or User given limit exceeded) for storing
* resending messages, situation is ignored.
*/
extern int16_t sn_coap_protocol_build(struct coap_s *handle, sn_nsdl_addr_s *dst_addr_ptr, uint8_t *dst_packet_data_ptr, sn_coap_hdr_s *src_coap_msg_ptr, void *param);
/**
* \fn sn_coap_hdr_s *sn_coap_protocol_parse(struct coap_s *handle, sn_nsdl_addr_s *src_addr_ptr, uint16_t packet_data_len, uint8_t *packet_data_ptr, void *param)
*
* \brief Parses received CoAP message from given Packet data
*
* \param *src_addr_ptr is pointer to source address of received CoAP message
* (CoAP parser needs that information for Message acknowledgement)
*
* \param *handle Pointer to CoAP library handle
*
* \param packet_data_len is length of given Packet data to be parsed to CoAP message
*
* \param *packet_data_ptr is pointer to source of Packet data to be parsed to CoAP message
*
* \param *param void pointer that will be passed to tx/rx function callback when those are called.
*
* \return Return value is pointer to parsed CoAP message structure. This structure includes also coap_status field.\n
* In following failure cases NULL is returned:\n
* -Given NULL pointer\n
* -Failure in parsed header of non-confirmable message\n
* -Out of memory (malloc() returns NULL)
*/
extern sn_coap_hdr_s *sn_coap_protocol_parse(struct coap_s *handle, sn_nsdl_addr_s *src_addr_ptr, uint16_t packet_data_len, uint8_t *packet_data_ptr, void *param);
/**
* \fn int8_t sn_coap_protocol_exec(struct coap_s *handle, uint32_t current_time)
*
* \brief Sends CoAP messages from re-sending queue, if there is any.
* Cleans also old messages from the duplication list and from block receiving list
*
* This function can be called e.g. once in a second but also more frequently.
*
* \param *handle Pointer to CoAP library handle
*
* \param current_time is System time in seconds. This time is
* used for message re-sending timing and to identify old saved data.
*
* \return 0 = success\n
* -1 = failed
*/
extern int8_t sn_coap_protocol_exec(struct coap_s *handle, uint32_t current_time);
/**
* \fn int8_t sn_coap_protocol_set_block_size(struct coap_s *handle, uint16_t block_size)
*
* \brief If block transfer is enabled, this function changes the block size.
* \param handle Pointer to CoAP library handle
* \param maximum size of CoAP payload. Valid sizes are 16, 32, 64, 128, 256, 512 and 1024 bytes
* \return 0 = success\n
* -1 = failure
*/
extern int8_t sn_coap_protocol_set_block_size(struct coap_s *handle, uint16_t block_size);
/**
* \fn int8_t sn_coap_protocol_set_duplicate_buffer_size(struct coap_s *handle, uint8_t message_count)
*
* \brief If dublicate message detection is enabled, this function changes buffer size.
* \param handle Pointer to CoAP library handle
* \param message_count max number of messages saved for duplicate control
* \return 0 = success\n
* -1 = failure
*/
extern int8_t sn_coap_protocol_set_duplicate_buffer_size(struct coap_s *handle, uint8_t message_count);
/**
* \fn int8_t sn_coap_protocol_set_retransmission_parameters(struct coap_s *handle, uint8_t resending_count, uint8_t resending_intervall)
*
* \brief If re-transmissions are enabled, this function changes resending count and interval.
* \param *handle Pointer to CoAP library handle
* \param resending_count max number of resendings for message
* \param resending_intervall message resending intervall in seconds
* \return 0 = success\n
* -1 = failure
*/
extern int8_t sn_coap_protocol_set_retransmission_parameters(struct coap_s *handle,
uint8_t resending_count, uint8_t resending_interval);
/**
* \fn int8_t sn_coap_protocol_set_retransmission_buffer(struct coap_s *handle, uint8_t buffer_size_messages, uint16_t buffer_size_bytes)
*
* \brief If re-transmissions are enabled, this function changes message retransmission queue size.
* Set size to '0' to disable feature. If both are set to '0', then re-sendings are disabled.
* \param *handle Pointer to CoAP library handle
* \param buffer_size_messages queue size - maximum number of messages to be saved to queue
* \param buffer_size_bytes queue size - maximum size of messages saved to queue
* \return 0 = success\n
* -1 = failure
*/
extern int8_t sn_coap_protocol_set_retransmission_buffer(struct coap_s *handle,
uint8_t buffer_size_messages, uint16_t buffer_size_bytes);
/**
* \fn void sn_coap_protocol_clear_retransmission_buffer(struct coap_s *handle)
*
* \param *handle Pointer to CoAP library handle
*
* \brief If re-transmissions are enabled, this function removes all messages from the retransmission queue.
*/
extern void sn_coap_protocol_clear_retransmission_buffer(struct coap_s *handle);
/**
* \fn sn_coap_protocol_block_remove(struct coap_s *handle, sn_nsdl_addr_s *source_address, uint16_t payload_length, void *payload)
*
* \brief Remove saved block data. Can be used to remove the data from RAM to enable storing it to other place.
*
* \param handle Pointer to CoAP library handle
* \param source_address Addres from where the block has been received.
* \param payload_length Length of the coap payload of the block.
* \param payload Coap payload of the block.
*
*/
extern void sn_coap_protocol_block_remove(struct coap_s *handle, sn_nsdl_addr_s *source_address, uint16_t payload_length, void *payload);
/**
* \fn void sn_coap_protocol_delete_retransmission(struct coap_s *handle, uint16_t msg_id)
*
* \brief If re-transmissions are enabled, this function removes message from retransmission buffer.
*
* \param *handle Pointer to CoAP library handle
* \param msg_id message ID to be removed
* \return 0 = success\n
* -1 = invalid parameter\n
* -2 = message was not found
*/
extern int8_t sn_coap_protocol_delete_retransmission(struct coap_s *handle, uint16_t msg_id);
/*\@}*/
#endif /* SN_COAP_PROTOCOL_H_ */
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,238 @@
/*
* Copyright (c) 2011-2015 ARM Limited. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file sn_coap_protocol_internal.h
*
* \brief Header file for CoAP Protocol part
*
*/
#ifndef SN_COAP_PROTOCOL_INTERNAL_H_
#define SN_COAP_PROTOCOL_INTERNAL_H_
#include "ns_list.h"
#include "sn_coap_header_internal.h"
#include "sn_config.h"
#ifdef __cplusplus
extern "C" {
#endif
struct sn_coap_hdr_;
/* * * * * * * * * * * */
/* * * * DEFINES * * * */
/* * * * * * * * * * * */
/* * For Message resending * */
#define ENABLE_RESENDINGS 1 /**< Enable / Disable resending from library in building */
#define SN_COAP_RESENDING_MAX_COUNT 3 /**< Default number of re-sendings */
#ifdef YOTTA_CFG_COAP_RESENDING_QUEUE_SIZE_MSGS
#define SN_COAP_RESENDING_QUEUE_SIZE_MSGS YOTTA_CFG_COAP_RESENDING_QUEUE_SIZE_MSGS
#elif defined MBED_CONF_MBED_CLIENT_SN_COAP_RESENDING_QUEUE_SIZE_MSGS
#define SN_COAP_RESENDING_QUEUE_SIZE_MSGS MBED_CONF_MBED_CLIENT_SN_COAP_RESENDING_QUEUE_SIZE_MSGS
#endif
#ifndef SN_COAP_RESENDING_QUEUE_SIZE_MSGS
#define SN_COAP_RESENDING_QUEUE_SIZE_MSGS 2 /**< Default re-sending queue size - defines how many messages can be stored. Setting this to 0 disables feature */
#endif
#ifdef YOTTA_CFG_COAP_RESENDING_QUEUE_SIZE_BYTES
#define SN_COAP_RESENDING_QUEUE_SIZE_BYTES YOTTA_CFG_COAP_RESENDING_QUEUE_SIZE_BYTES
#elif defined MBED_CONF_MBED_CLIENT_SN_COAP_RESENDING_QUEUE_SIZE_BYTES
#define SN_COAP_RESENDING_QUEUE_SIZE_BYTES MBED_CONF_MBED_CLIENT_SN_COAP_RESENDING_QUEUE_SIZE_BYTES
#endif
#ifndef SN_COAP_RESENDING_QUEUE_SIZE_BYTES
#define SN_COAP_RESENDING_QUEUE_SIZE_BYTES 0 /**< Default re-sending queue size - defines size of the re-sending buffer. Setting this to 0 disables feature */
#endif
#define DEFAULT_RESPONSE_TIMEOUT 10 /**< Default re-sending timeout as seconds */
/* These parameters sets maximum values application can set with API */
#define SN_COAP_MAX_ALLOWED_RESENDING_COUNT 6 /**< Maximum allowed count of re-sending */
#define SN_COAP_MAX_ALLOWED_RESENDING_BUFF_SIZE_MSGS 6 /**< Maximum allowed number of saved re-sending messages */
#define SN_COAP_MAX_ALLOWED_RESENDING_BUFF_SIZE_BYTES 512 /**< Maximum allowed size of re-sending buffer */
#define SN_COAP_MAX_ALLOWED_RESPONSE_TIMEOUT 40 /**< Maximum allowed re-sending timeout */
#define RESPONSE_RANDOM_FACTOR 1 /**< Resending random factor, value is specified in IETF CoAP specification */
/* * For Message duplication detecting * */
/* Init value for the maximum count of messages to be stored for duplication detection */
/* Setting of this value to 0 will disable duplication check, also reduce use of ROM memory */
// Keep the old flag to maintain backward compatibility
#ifndef SN_COAP_DUPLICATION_MAX_MSGS_COUNT
#define SN_COAP_DUPLICATION_MAX_MSGS_COUNT 0
#endif
#ifdef YOTTA_CFG_COAP_DUPLICATION_MAX_MSGS_COUNT
#define SN_COAP_DUPLICATION_MAX_MSGS_COUNT YOTTA_CFG_COAP_DUPLICATION_MAX_MSGS_COUNT
#elif defined MBED_CONF_MBED_CLIENT_SN_COAP_DUPLICATION_MAX_MSGS_COUNT
#define SN_COAP_DUPLICATION_MAX_MSGS_COUNT MBED_CONF_MBED_CLIENT_SN_COAP_DUPLICATION_MAX_MSGS_COUNT
#endif
/* Maximum allowed number of saved messages for duplicate searching */
#define SN_COAP_MAX_ALLOWED_DUPLICATION_MESSAGE_COUNT 6
/* Maximum time in seconds of messages to be stored for duplication detection */
#define SN_COAP_DUPLICATION_MAX_TIME_MSGS_STORED 60 /* RESPONSE_TIMEOUT * RESPONSE_RANDOM_FACTOR * (2 ^ MAX_RETRANSMIT - 1) + the expected maximum round trip time */
/* * For Message blockwising * */
/* Init value for the maximum payload size to be sent and received at one blockwise message */
/* Setting of this value to 0 will disable this feature, and also reduce use of ROM memory */
/* Note: This define is common for both received and sent Blockwise messages */
#ifdef YOTTA_CFG_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE
#define SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE YOTTA_CFG_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE
#elif defined MBED_CONF_MBED_CLIENT_SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE
#define SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE MBED_CONF_MBED_CLIENT_SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE
#endif
#ifndef SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE
#define SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE 0 /**< Must be 2^x and x is at least 4. Suitable values: 0, 16, 32, 64, 128, 256, 512 and 1024 */
#endif
#ifndef SN_COAP_BLOCKWISE_MAX_TIME_DATA_STORED
#define SN_COAP_BLOCKWISE_MAX_TIME_DATA_STORED 10 /**< Maximum time in seconds of data (messages and payload) to be stored for blockwising */
#endif
#ifdef YOTTA_CFG_COAP_MAX_INCOMING_BLOCK_MESSAGE_SIZE
#define SN_COAP_MAX_INCOMING_BLOCK_MESSAGE_SIZE YOTTA_CFG_COAP_MAX_INCOMING_BLOCK_MESSAGE_SIZE
#elif defined MBED_CONF_MBED_CLIENT_SN_COAP_MAX_INCOMING_MESSAGE_SIZE
#define SN_COAP_MAX_INCOMING_BLOCK_MESSAGE_SIZE MBED_CONF_MBED_CLIENT_SN_COAP_MAX_INCOMING_MESSAGE_SIZE
#endif
#ifndef SN_COAP_MAX_INCOMING_BLOCK_MESSAGE_SIZE
#define SN_COAP_MAX_INCOMING_BLOCK_MESSAGE_SIZE UINT16_MAX
#endif
/* * For Option handling * */
#define COAP_OPTION_MAX_AGE_DEFAULT 60 /**< Default value of Max-Age if option not present */
#define COAP_OPTION_URI_PORT_NONE (-1) /**< Internal value to represent no Uri-Port option */
#define COAP_OPTION_BLOCK_NONE (-1) /**< Internal value to represent no Block1/2 option */
#if SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE /* If Message blockwising is not used at all, this part of code will not be compiled */
int8_t prepare_blockwise_message(struct coap_s *handle, struct sn_coap_hdr_ *coap_hdr_ptr);
#endif
/* Structure which is stored to Linked list for message sending purposes */
typedef struct coap_send_msg_ {
uint8_t resending_counter; /* Tells how many times message is still tried to resend */
uint32_t resending_time; /* Tells next resending time */
sn_nsdl_transmit_s *send_msg_ptr;
struct coap_s *coap; /* CoAP library handle */
void *param; /* Extra parameter that will be passed to TX/RX callback functions */
ns_list_link_t link;
} coap_send_msg_s;
typedef NS_LIST_HEAD(coap_send_msg_s, link) coap_send_msg_list_t;
/* Structure which is stored to Linked list for message duplication detection purposes */
typedef struct coap_duplication_info_ {
uint32_t timestamp; /* Tells when duplication information is stored to Linked list */
uint8_t addr_len;
uint8_t *addr_ptr;
uint16_t port;
uint16_t msg_id;
struct coap_s *coap; /* CoAP library handle */
ns_list_link_t link;
} coap_duplication_info_s;
typedef NS_LIST_HEAD(coap_duplication_info_s, link) coap_duplication_info_list_t;
/* Structure which is stored to Linked list for blockwise messages sending purposes */
typedef struct coap_blockwise_msg_ {
uint32_t timestamp; /* Tells when Blockwise message is stored to Linked list */
sn_coap_hdr_s *coap_msg_ptr;
struct coap_s *coap; /* CoAP library handle */
ns_list_link_t link;
} coap_blockwise_msg_s;
typedef NS_LIST_HEAD(coap_blockwise_msg_s, link) coap_blockwise_msg_list_t;
/* Structure which is stored to Linked list for blockwise messages receiving purposes */
typedef struct coap_blockwise_payload_ {
uint32_t timestamp; /* Tells when Payload is stored to Linked list */
uint8_t addr_len;
uint8_t *addr_ptr;
uint16_t port;
uint16_t payload_len;
uint8_t *payload_ptr;
struct coap_s *coap; /* CoAP library handle */
ns_list_link_t link;
} coap_blockwise_payload_s;
typedef NS_LIST_HEAD(coap_blockwise_payload_s, link) coap_blockwise_payload_list_t;
struct coap_s {
void *(*sn_coap_protocol_malloc)(uint16_t);
void (*sn_coap_protocol_free)(void *);
uint8_t (*sn_coap_tx_callback)(uint8_t *, uint16_t, sn_nsdl_addr_s *, void *);
int8_t (*sn_coap_rx_callback)(sn_coap_hdr_s *, sn_nsdl_addr_s *, void *);
#if ENABLE_RESENDINGS /* If Message resending is not used at all, this part of code will not be compiled */
coap_send_msg_list_t linked_list_resent_msgs; /* Active resending messages are stored to this Linked list */
uint16_t count_resent_msgs;
#endif
#if SN_COAP_DUPLICATION_MAX_MSGS_COUNT /* If Message duplication detection is not used at all, this part of code will not be compiled */
coap_duplication_info_list_t linked_list_duplication_msgs; /* Messages for duplicated messages detection is stored to this Linked list */
uint16_t count_duplication_msgs;
#endif
#if SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE /* If Message blockwise is not used at all, this part of code will not be compiled */
coap_blockwise_msg_list_t linked_list_blockwise_sent_msgs; /* Blockwise message to to be sent is stored to this Linked list */
coap_blockwise_payload_list_t linked_list_blockwise_received_payloads; /* Blockwise payload to to be received is stored to this Linked list */
#endif
uint32_t system_time; /* System time seconds */
uint16_t sn_coap_block_data_size;
uint8_t sn_coap_resending_queue_msgs;
uint8_t sn_coap_resending_queue_bytes;
uint8_t sn_coap_resending_count;
uint8_t sn_coap_resending_intervall;
uint8_t sn_coap_duplication_buffer_size;
};
#ifdef __cplusplus
}
#endif
#endif /* SN_COAP_PROTOCOL_INTERNAL_H_ */

View file

@ -0,0 +1,92 @@
/*
* Copyright (c) 2016 ARM Limited. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SN_CONFIG_H
#define SN_CONFIG_H
#include "sn_coap_ameba_port.h"
/**
* \brief Configuration options (set of defines and values)
*
* This lists set of compile-time options that needs to be used to enable
* or disable features selectively, and set the values for the mandatory
* parameters.
*/
/**
* \def SN_COAP_DUPLICATION_MAX_MSGS_COUNT
* \brief For Message duplication detection
* Init value for the maximum count of messages to be stored for duplication detection
* Setting of this value to 0 will disable duplication check, also reduce use of ROM memory
* Default is set to 1.
*/
#undef SN_COAP_DUPLICATION_MAX_MSGS_COUNT /* 1 */
/**
* \def SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE
*
* \brief For Message blockwising
* Init value for the maximum payload size to be sent and received at one blockwise message
* Setting of this value to 0 will disable this feature, and also reduce use of ROM memory
* Note: This define is common for both received and sent Blockwise messages
*/
#undef SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE /* 0 */ // < Must be 2^x and x is at least 4. Suitable values: 0, 16, 32, 64, 128, 256, 512 and 1024
/**
* \def COAP_DISABLE_OBS_FEATURE
*
* \brief Disables CoAP 'obs' sending feature
* as part of registration message, this might be
* needed to be enabled for some strict LWM2M server implementation.
* By default, this feature is disabled.
*/
#undef COAP_DISABLE_OBS_FEATURE
/**
* \def SN_COAP_RESENDING_QUEUE_SIZE_MSGS
*
* \brief Sets the number of messages stored
* in the resending queue. Default is 2
*/
#undef SN_COAP_RESENDING_QUEUE_SIZE_MSGS /* 2 */ // < Default re-sending queue size - defines how many messages can be stored. Setting this to 0 disables feature
/**
* \def SN_COAP_RESENDING_QUEUE_SIZE_BYTES
*
* \brief Sets the size of the re-sending buffer.
* Setting this to 0 disables this feature.
* By default, this feature is disabled.
*/
#undef SN_COAP_RESENDING_QUEUE_SIZE_BYTES /* 0 */ // Default re-sending queue size - defines size of the re-sending buffer. Setting this to 0 disables feature
/**
* \def SN_COAP_MAX_INCOMING_MESSAGE_SIZE
*
* \brief Sets the maximum size (in bytes) that
* mbed Client will allow to be handled while
* receiving big payload in blockwise mode.
* Application can set this value based on their
* available storage capability.
* By default, maximum size is UINT16_MAX, 65535 bytes.
*/
#undef SN_COAP_MAX_INCOMING_MESSAGE_SIZE /* UINT16_MAX */
#ifdef MBED_CLIENT_USER_CONFIG_FILE
#include MBED_CLIENT_USER_CONFIG_FILE
#endif
#endif // SN_CONFIG_H

View file

@ -0,0 +1,161 @@
#ifndef __DHCPS_H__
#define __DHCPS_H__
#include "lwip/arch.h"
#include "lwip/netif.h"
#include "lwip/udp.h"
#include "lwip/stats.h"
#include "lwip/sys.h"
#include "netif/etharp.h"
#include <platform/platform_stdlib.h>
#define CONFIG_DHCPS_KEPT_CLIENT_INFO
#define DHCP_POOL_START 100
#define DHCP_POOL_END 200
#define DHCPS_MAX_CLIENT_NUM (DHCP_POOL_END-DHCP_POOL_START+1)
#define IS_USE_FIXED_IP 0
#define debug_dhcps 0
/* dhcp server states */
#define DHCP_SERVER_STATE_OFFER (1)
#define DHCP_SERVER_STATE_DECLINE (2)
#define DHCP_SERVER_STATE_ACK (3)
#define DHCP_SERVER_STATE_NAK (4)
#define DHCP_SERVER_STATE_IDLE (5)
#define BOOTP_BROADCAST (0x8000)
#define DHCP_MESSAGE_OP_REQUEST (1)
#define DHCP_MESSAGE_OP_REPLY (2)
#define DHCP_MESSAGE_HTYPE (1)
#define DHCP_MESSAGE_HLEN (6)
#define DNS_SERVER_PORT (53)
#define DHCP_SERVER_PORT (67)
#define DHCP_CLIENT_PORT (68)
#define DHCP_MESSAGE_TYPE_DISCOVER (1)
#define DHCP_MESSAGE_TYPE_OFFER (2)
#define DHCP_MESSAGE_TYPE_REQUEST (3)
#define DHCP_MESSAGE_TYPE_DECLINE (4)
#define DHCP_MESSAGE_TYPE_ACK (5)
#define DHCP_MESSAGE_TYPE_NAK (6)
#define DHCP_MESSAGE_TYPE_RELEASE (7)
#define DHCP_OPTION_LENGTH_ONE (1)
#define DHCP_OPTION_LENGTH_TWO (2)
#define DHCP_OPTION_LENGTH_THREE (3)
#define DHCP_OPTION_LENGTH_FOUR (4)
#ifndef DHCP_MSG_LEN
#define DHCP_MSG_LEN 236
#endif
#define DHCP_OPTION_TOTAL_LENGTH_MAX 312 //(51)= 4(magic)+3(type)+44(option code: 1,3,6,51,54,28,26,32,end)
#define DHCP_OPTION_CODE_SUBNET_MASK (1)
#define DHCP_OPTION_CODE_ROUTER (3)
#define DHCP_OPTION_CODE_DNS_SERVER (6)
#define DHCP_OPTION_CODE_INTERFACE_MTU (26)
#define DHCP_OPTION_CODE_BROADCAST_ADDRESS (28)
#define DHCP_OPTION_CODE_PERFORM_ROUTER_DISCOVERY (31)
#define DHCP_OPTION_CODE_REQUEST_IP_ADDRESS (50)
#define DHCP_OPTION_CODE_LEASE_TIME (51)
#define DHCP_OPTION_CODE_MSG_TYPE (53)
#define DHCP_OPTION_CODE_SERVER_ID (54)
#define DHCP_OPTION_CODE_REQ_LIST (55)
#define DHCP_OPTION_CODE_END (255)
#define IP_FREE_TO_USE (1)
#define IP_ALREADY_IN_USE (0)
#define HW_ADDRESS_LENGTH (6)
/* Reference by RFC 2131 */
struct dhcp_msg {
uint8_t op; /* Message op code/message type. 1 = BOOTREQUEST, 2 = BOOTREPLY */
uint8_t htype; /* Hardware address type */
uint8_t hlen; /* Hardware address length */
uint8_t hops; /* Client sets to zero, optionally used by relay agents
when booting via a relay agent */
uint8_t xid[4]; /* Transaction ID, a random number chosen by the client,
used by the client and server to associate messages and
responses between a client and a server */
uint16_t secs; /* Filled in by client, seconds elapsed since client began address
acquisition or renewal process.*/
uint16_t flags; /* bit 0: Broadcast flag, bit 1~15:MBZ must 0*/
uint8_t ciaddr[4]; /* Client IP address; only filled in if client is in BOUND,
RENEW or REBINDING state and can respond to ARP requests. */
uint8_t yiaddr[4]; /* 'your' (client) IP address */
uint8_t siaddr[4]; /* IP address of next server to use in bootstrap;
returned in DHCPOFFER, DHCPACK by server. */
uint8_t giaddr[4]; /* Relay agent IP address, used in booting via a relay agent.*/
uint8_t chaddr[16]; /* Client hardware address */
uint8_t sname[64]; /* Optional server host name, null terminated string.*/
uint8_t file[128]; /* Boot file name, null terminated string; "generic" name or
null in DHCPDISCOVER, fully qualified directory-path name in DHCPOFFER.*/
uint8_t options[312]; /* Optional parameters field. reference the RFC 2132 */
};
/* use this to check whether the message is dhcp related or not */
static const uint8_t dhcp_magic_cookie[4] = {99, 130, 83, 99};
static const uint8_t dhcp_option_lease_time[] = {0x00, 0x00, 0x1c, 0x20}; //1 day
//static const uint8_t dhcp_option_lease_time[] = {0x00, 0x00, 0x0e, 0x10}; // one hour
//static const uint8_t dhcp_option_interface_mtu_576[] = {0x02, 0x40};
static const uint8_t dhcp_option_interface_mtu[] = {0x05, 0xDC};
struct table {
uint32_t ip_range[8];
#ifdef CONFIG_DHCPS_KEPT_CLIENT_INFO
uint8_t client_mac[256][6];
#endif
};
struct address_pool{
uint32_t start;
uint32_t end;
};
PACK_STRUCT_BEGIN
/** DNS message header */
struct dns_hdr {
PACK_STRUCT_FIELD(u16_t id);
PACK_STRUCT_FIELD(u8_t flags1);
PACK_STRUCT_FIELD(u8_t flags2);
PACK_STRUCT_FIELD(u16_t numquestions);
PACK_STRUCT_FIELD(u16_t numanswers);
PACK_STRUCT_FIELD(u16_t numauthrr);
PACK_STRUCT_FIELD(u16_t numextrarr);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
/* 01~32 */
#define MARK_RANGE1_IP_BIT(table, ip) ((table.ip_range[0]) | (1 << ((ip) - 1)))
/* 33~64 */
#define MARK_RANGE2_IP_BIT(table, ip) ((table.ip_range[1]) | (1 << ((ip) - 1)))
/* 65~96 */
#define MARK_RANGE3_IP_BIT(table, ip) ((table.ip_range[2]) | (1 << ((ip) - 1)))
/* 97~128 */
#define MARK_RANGE4_IP_BIT(table, ip) ((table.ip_range[3]) | (1 << ((ip) - 1)))
/* 129~160 */
#define MARK_RANGE5_IP_BIT(table, ip) ((table.ip_range[4]) | (1 << ((ip) - 1)))
/* 161~192 */
#define MARK_RANGE6_IP_BIT(table, ip) ((table.ip_range[5]) | (1 << ((ip) - 1)))
/* 193~224 */
#define MARK_RANGE7_IP_BIT(table, ip) ((table.ip_range[6]) | (1 << ((ip) - 1)))
/* 225~255 */
#define MARK_RANGE8_IP_BIT(table, ip) ((table.ip_range[7]) | (1 << ((ip) - 1)))
/* expose API */
void dhcps_set_addr_pool(int addr_pool_set, struct ip_addr * addr_pool_start, struct ip_addr *addr_pool_end);
void dhcps_init(struct netif * pnetif);
void dhcps_deinit(void);
extern struct netif *netif_default;
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,42 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2012, 2013 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGHTTP2VER_H
#define NGHTTP2VER_H
/**
* @macro
* Version number of the nghttp2 library release
*/
#define NGHTTP2_VERSION "1.31.0"
/**
* @macro
* Numerical representation of the version number of the nghttp2 library
* release. This is a 24 bit number with 8 bits for major number, 8 bits
* for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203.
*/
#define NGHTTP2_VERSION_NUM 0x013100
#endif /* NGHTTP2VER_H */

View file

@ -0,0 +1,412 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2014 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGHTTP2_BUF_H
#define NGHTTP2_BUF_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h>
#include "nghttp2_int.h"
#include "nghttp2_mem.h"
typedef struct {
/* This points to the beginning of the buffer. The effective range
of buffer is [begin, end). */
uint8_t *begin;
/* This points to the memory one byte beyond the end of the
buffer. */
uint8_t *end;
/* The position indicator for effective start of the buffer. pos <=
last must be hold. */
uint8_t *pos;
/* The position indicator for effective one beyond of the end of the
buffer. last <= end must be hold. */
uint8_t *last;
/* Mark arbitrary position in buffer [begin, end) */
uint8_t *mark;
} nghttp2_buf;
#define nghttp2_buf_len(BUF) ((size_t)((BUF)->last - (BUF)->pos))
#define nghttp2_buf_avail(BUF) ((size_t)((BUF)->end - (BUF)->last))
#define nghttp2_buf_mark_avail(BUF) ((size_t)((BUF)->mark - (BUF)->last))
#define nghttp2_buf_cap(BUF) ((size_t)((BUF)->end - (BUF)->begin))
#define nghttp2_buf_pos_offset(BUF) ((size_t)((BUF)->pos - (BUF)->begin))
#define nghttp2_buf_last_offset(BUF) ((size_t)((BUF)->last - (BUF)->begin))
#define nghttp2_buf_shift_right(BUF, AMT) \
do { \
(BUF)->pos += AMT; \
(BUF)->last += AMT; \
} while (0)
#define nghttp2_buf_shift_left(BUF, AMT) \
do { \
(BUF)->pos -= AMT; \
(BUF)->last -= AMT; \
} while (0)
/*
* Initializes the |buf|. No memory is allocated in this function. Use
* nghttp2_buf_reserve() to allocate memory.
*/
void nghttp2_buf_init(nghttp2_buf *buf);
/*
* Initializes the |buf| and allocates at least |initial| bytes of
* memory.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
int nghttp2_buf_init2(nghttp2_buf *buf, size_t initial, nghttp2_mem *mem);
/*
* Frees buffer in |buf|.
*/
void nghttp2_buf_free(nghttp2_buf *buf, nghttp2_mem *mem);
/*
* Extends buffer so that nghttp2_buf_cap() returns at least
* |new_cap|. If extensions took place, buffer pointers in |buf| will
* change.
*
* This function returns 0 if it succeeds, or one of the followings
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
int nghttp2_buf_reserve(nghttp2_buf *buf, size_t new_cap, nghttp2_mem *mem);
/*
* Resets pos, last, mark member of |buf| to buf->begin.
*/
void nghttp2_buf_reset(nghttp2_buf *buf);
/*
* Initializes |buf| using supplied buffer |begin| of length
* |len|. Semantically, the application should not call *_reserve() or
* nghttp2_free() functions for |buf|.
*/
void nghttp2_buf_wrap_init(nghttp2_buf *buf, uint8_t *begin, size_t len);
struct nghttp2_buf_chain;
typedef struct nghttp2_buf_chain nghttp2_buf_chain;
/* Chains 2 buffers */
struct nghttp2_buf_chain {
/* Points to the subsequent buffer. NULL if there is no such
buffer. */
nghttp2_buf_chain *next;
nghttp2_buf buf;
};
typedef struct {
/* Points to the first buffer */
nghttp2_buf_chain *head;
/* Buffer pointer where write occurs. */
nghttp2_buf_chain *cur;
/* Memory allocator */
nghttp2_mem *mem;
/* The buffer capacity of each buf. This field may be 0 if
nghttp2_bufs is initialized by nghttp2_bufs_wrap_init* family
functions. */
size_t chunk_length;
/* The maximum number of nghttp2_buf_chain */
size_t max_chunk;
/* The number of nghttp2_buf_chain allocated */
size_t chunk_used;
/* The number of nghttp2_buf_chain to keep on reset */
size_t chunk_keep;
/* pos offset from begin in each buffers. On initialization and
reset, buf->pos and buf->last are positioned at buf->begin +
offset. */
size_t offset;
} nghttp2_bufs;
/*
* This is the same as calling nghttp2_bufs_init2 with the given
* arguments and offset = 0.
*/
int nghttp2_bufs_init(nghttp2_bufs *bufs, size_t chunk_length, size_t max_chunk,
nghttp2_mem *mem);
/*
* This is the same as calling nghttp2_bufs_init3 with the given
* arguments and chunk_keep = max_chunk.
*/
int nghttp2_bufs_init2(nghttp2_bufs *bufs, size_t chunk_length,
size_t max_chunk, size_t offset, nghttp2_mem *mem);
/*
* Initializes |bufs|. Each buffer size is given in the
* |chunk_length|. The maximum number of buffers is given in the
* |max_chunk|. On reset, first |chunk_keep| buffers are kept and
* remaining buffers are deleted. Each buffer will have bufs->pos and
* bufs->last shifted to left by |offset| bytes on creation and reset.
*
* This function allocates first buffer. bufs->head and bufs->cur
* will point to the first buffer after this call.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_INVALID_ARGUMENT
* chunk_keep is 0; or max_chunk < chunk_keep; or offset is too
* long.
*/
int nghttp2_bufs_init3(nghttp2_bufs *bufs, size_t chunk_length,
size_t max_chunk, size_t chunk_keep, size_t offset,
nghttp2_mem *mem);
/*
* Frees any related resources to the |bufs|.
*/
void nghttp2_bufs_free(nghttp2_bufs *bufs);
/*
* Initializes |bufs| using supplied buffer |begin| of length |len|.
* The first buffer bufs->head uses buffer |begin|. The buffer size
* is fixed and no extra chunk buffer is allocated. In other
* words, max_chunk = chunk_keep = 1. To free the resource allocated
* for |bufs|, use nghttp2_bufs_wrap_free().
*
* Don't use the function which performs allocation, such as
* nghttp2_bufs_realloc().
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
int nghttp2_bufs_wrap_init(nghttp2_bufs *bufs, uint8_t *begin, size_t len,
nghttp2_mem *mem);
/*
* Initializes |bufs| using supplied |veclen| size of buf vector
* |vec|. The number of buffers is fixed and no extra chunk buffer is
* allocated. In other words, max_chunk = chunk_keep = |in_len|. To
* free the resource allocated for |bufs|, use
* nghttp2_bufs_wrap_free().
*
* Don't use the function which performs allocation, such as
* nghttp2_bufs_realloc().
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
int nghttp2_bufs_wrap_init2(nghttp2_bufs *bufs, const nghttp2_vec *vec,
size_t veclen, nghttp2_mem *mem);
/*
* Frees any related resource to the |bufs|. This function does not
* free supplied buffer provided in nghttp2_bufs_wrap_init().
*/
void nghttp2_bufs_wrap_free(nghttp2_bufs *bufs);
/*
* Reallocates internal buffer using |chunk_length|. The max_chunk,
* chunk_keep and offset do not change. After successful allocation
* of new buffer, previous buffers are deallocated without copying
* anything into new buffers. chunk_used is reset to 1.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_INVALID_ARGUMENT
* chunk_length < offset
*/
int nghttp2_bufs_realloc(nghttp2_bufs *bufs, size_t chunk_length);
/*
* Appends the |data| of length |len| to the |bufs|. The write starts
* at bufs->cur->buf.last. A new buffers will be allocated to store
* all data.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_BUFFER_ERROR
* Out of buffer space.
*/
int nghttp2_bufs_add(nghttp2_bufs *bufs, const void *data, size_t len);
/*
* Appends a single byte |b| to the |bufs|. The write starts at
* bufs->cur->buf.last. A new buffers will be allocated to store all
* data.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_BUFFER_ERROR
* Out of buffer space.
*/
int nghttp2_bufs_addb(nghttp2_bufs *bufs, uint8_t b);
/*
* Behaves like nghttp2_bufs_addb(), but this does not update
* buf->last pointer.
*/
int nghttp2_bufs_addb_hold(nghttp2_bufs *bufs, uint8_t b);
#define nghttp2_bufs_fast_addb(BUFS, B) \
do { \
*(BUFS)->cur->buf.last++ = B; \
} while (0)
#define nghttp2_bufs_fast_addb_hold(BUFS, B) \
do { \
*(BUFS)->cur->buf.last = B; \
} while (0)
/*
* Performs bitwise-OR of |b| at bufs->cur->buf.last. A new buffers
* will be allocated if necessary.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_BUFFER_ERROR
* Out of buffer space.
*/
int nghttp2_bufs_orb(nghttp2_bufs *bufs, uint8_t b);
/*
* Behaves like nghttp2_bufs_orb(), but does not update buf->last
* pointer.
*/
int nghttp2_bufs_orb_hold(nghttp2_bufs *bufs, uint8_t b);
#define nghttp2_bufs_fast_orb(BUFS, B) \
do { \
uint8_t **p = &(BUFS)->cur->buf.last; \
**p = (uint8_t)(**p | (B)); \
++(*p); \
} while (0)
#define nghttp2_bufs_fast_orb_hold(BUFS, B) \
do { \
uint8_t *p = (BUFS)->cur->buf.last; \
*p = (uint8_t)(*p | (B)); \
} while (0)
/*
* Copies all data stored in |bufs| to the contiguous buffer. This
* function allocates the contiguous memory to store all data in
* |bufs| and assigns it to |*out|.
*
* The contents of |bufs| is left unchanged.
*
* This function returns the length of copied data and assigns the
* pointer to copied data to |*out| if it succeeds, or one of the
* following negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
ssize_t nghttp2_bufs_remove(nghttp2_bufs *bufs, uint8_t **out);
/*
* Copies all data stored in |bufs| to |out|. This function assumes
* that the buffer space pointed by |out| has at least
* nghttp2_bufs(bufs) bytes.
*
* The contents of |bufs| is left unchanged.
*
* This function returns the length of copied data.
*/
size_t nghttp2_bufs_remove_copy(nghttp2_bufs *bufs, uint8_t *out);
/*
* Resets |bufs| and makes the buffers empty.
*/
void nghttp2_bufs_reset(nghttp2_bufs *bufs);
/*
* Moves bufs->cur to bufs->cur->next. If resulting bufs->cur is
* NULL, this function allocates new buffers and bufs->cur points to
* it.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
* NGHTTP2_ERR_BUFFER_ERROR
* Out of buffer space.
*/
int nghttp2_bufs_advance(nghttp2_bufs *bufs);
/* Sets bufs->cur to bufs->head */
#define nghttp2_bufs_rewind(BUFS) \
do { \
(BUFS)->cur = (BUFS)->head; \
} while (0)
/*
* Move bufs->cur, from the current position, using next member, to
* the last buf which has nghttp2_buf_len(buf) > 0 without seeing buf
* which satisfies nghttp2_buf_len(buf) == 0. If
* nghttp2_buf_len(&bufs->cur->buf) == 0 or bufs->cur->next is NULL,
* bufs->cur is unchanged.
*/
void nghttp2_bufs_seek_last_present(nghttp2_bufs *bufs);
/*
* Returns nonzero if bufs->cur->next is not empty.
*/
int nghttp2_bufs_next_present(nghttp2_bufs *bufs);
#define nghttp2_bufs_cur_avail(BUFS) nghttp2_buf_avail(&(BUFS)->cur->buf)
/*
* Returns the total buffer length of |bufs|.
*/
size_t nghttp2_bufs_len(nghttp2_bufs *bufs);
#endif /* NGHTTP2_BUF_H */

View file

@ -0,0 +1,125 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2014 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGHTTP2_CALLBACKS_H
#define NGHTTP2_CALLBACKS_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h>
/*
* Callback functions.
*/
struct nghttp2_session_callbacks {
/**
* Callback function invoked when the session wants to send data to
* the remote peer. This callback is not necessary if the
* application uses solely `nghttp2_session_mem_send()` to serialize
* data to transmit.
*/
nghttp2_send_callback send_callback;
/**
* Callback function invoked when the session wants to receive data
* from the remote peer. This callback is not necessary if the
* application uses solely `nghttp2_session_mem_recv()` to process
* received data.
*/
nghttp2_recv_callback recv_callback;
/**
* Callback function invoked by `nghttp2_session_recv()` when a
* frame is received.
*/
nghttp2_on_frame_recv_callback on_frame_recv_callback;
/**
* Callback function invoked by `nghttp2_session_recv()` when an
* invalid non-DATA frame is received.
*/
nghttp2_on_invalid_frame_recv_callback on_invalid_frame_recv_callback;
/**
* Callback function invoked when a chunk of data in DATA frame is
* received.
*/
nghttp2_on_data_chunk_recv_callback on_data_chunk_recv_callback;
/**
* Callback function invoked before a non-DATA frame is sent.
*/
nghttp2_before_frame_send_callback before_frame_send_callback;
/**
* Callback function invoked after a frame is sent.
*/
nghttp2_on_frame_send_callback on_frame_send_callback;
/**
* The callback function invoked when a non-DATA frame is not sent
* because of an error.
*/
nghttp2_on_frame_not_send_callback on_frame_not_send_callback;
/**
* Callback function invoked when the stream is closed.
*/
nghttp2_on_stream_close_callback on_stream_close_callback;
/**
* Callback function invoked when the reception of header block in
* HEADERS or PUSH_PROMISE is started.
*/
nghttp2_on_begin_headers_callback on_begin_headers_callback;
/**
* Callback function invoked when a header name/value pair is
* received.
*/
nghttp2_on_header_callback on_header_callback;
nghttp2_on_header_callback2 on_header_callback2;
/**
* Callback function invoked when a invalid header name/value pair
* is received which is silently ignored if these callbacks are not
* set.
*/
nghttp2_on_invalid_header_callback on_invalid_header_callback;
nghttp2_on_invalid_header_callback2 on_invalid_header_callback2;
/**
* Callback function invoked when the library asks application how
* many padding bytes are required for the transmission of the given
* frame.
*/
nghttp2_select_padding_callback select_padding_callback;
/**
* The callback function used to determine the length allowed in
* `nghttp2_data_source_read_callback()`
*/
nghttp2_data_source_read_length_callback read_length_callback;
/**
* Sets callback function invoked when a frame header is received.
*/
nghttp2_on_begin_frame_callback on_begin_frame_callback;
nghttp2_send_data_callback send_data_callback;
nghttp2_pack_extension_callback pack_extension_callback;
nghttp2_unpack_extension_callback unpack_extension_callback;
nghttp2_on_extension_chunk_recv_callback on_extension_chunk_recv_callback;
nghttp2_error_callback error_callback;
nghttp2_error_callback2 error_callback2;
};
#endif /* NGHTTP2_CALLBACKS_H */

View file

@ -0,0 +1,43 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2016 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGHTTP2_DEBUG_H
#define NGHTTP2_DEBUG_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h>
#ifdef DEBUGBUILD
#define DEBUGF(...) nghttp2_debug_vprintf(__VA_ARGS__)
void nghttp2_debug_vprintf(const char *format, ...);
#else
#define DEBUGF(...) \
do { \
} while (0)
#endif
#endif /* NGHTTP2_DEBUG_H */

View file

@ -0,0 +1,575 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGHTTP2_FRAME_H
#define NGHTTP2_FRAME_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h>
#include "nghttp2_hd.h"
#include "nghttp2_buf.h"
#define NGHTTP2_STREAM_ID_MASK ((1u << 31) - 1)
#define NGHTTP2_PRI_GROUP_ID_MASK ((1u << 31) - 1)
#define NGHTTP2_PRIORITY_MASK ((1u << 31) - 1)
#define NGHTTP2_WINDOW_SIZE_INCREMENT_MASK ((1u << 31) - 1)
#define NGHTTP2_SETTINGS_ID_MASK ((1 << 24) - 1)
/* The number of bytes of frame header. */
#define NGHTTP2_FRAME_HDLEN 9
#define NGHTTP2_MAX_FRAME_SIZE_MAX ((1 << 24) - 1)
#define NGHTTP2_MAX_FRAME_SIZE_MIN (1 << 14)
#define NGHTTP2_MAX_PAYLOADLEN 16384
/* The one frame buffer length for tranmission. We may use several of
them to support CONTINUATION. To account for Pad Length field, we
allocate extra 1 byte, which saves extra large memcopying. */
#define NGHTTP2_FRAMEBUF_CHUNKLEN \
(NGHTTP2_FRAME_HDLEN + 1 + NGHTTP2_MAX_PAYLOADLEN)
/* The default length of DATA frame payload. */
#define NGHTTP2_DATA_PAYLOADLEN NGHTTP2_MAX_FRAME_SIZE_MIN
/* Maximum headers block size to send, calculated using
nghttp2_hd_deflate_bound(). This is the default value, and can be
overridden by nghttp2_option_set_max_send_header_block_size(). */
#define NGHTTP2_MAX_HEADERSLEN 65536
/* The number of bytes for each SETTINGS entry */
#define NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH 6
/* Length of priority related fields in HEADERS/PRIORITY frames */
#define NGHTTP2_PRIORITY_SPECLEN 5
/* Maximum length of padding in bytes. */
#define NGHTTP2_MAX_PADLEN 256
/* Union of extension frame payload */
typedef union {
nghttp2_ext_altsvc altsvc;
} nghttp2_ext_frame_payload;
void nghttp2_frame_pack_frame_hd(uint8_t *buf, const nghttp2_frame_hd *hd);
void nghttp2_frame_unpack_frame_hd(nghttp2_frame_hd *hd, const uint8_t *buf);
/**
* Initializes frame header |hd| with given parameters. Reserved bit
* is set to 0.
*/
void nghttp2_frame_hd_init(nghttp2_frame_hd *hd, size_t length, uint8_t type,
uint8_t flags, int32_t stream_id);
/**
* Returns the number of priority field depending on the |flags|. If
* |flags| has neither NGHTTP2_FLAG_PRIORITY_GROUP nor
* NGHTTP2_FLAG_PRIORITY_DEPENDENCY set, return 0.
*/
size_t nghttp2_frame_priority_len(uint8_t flags);
/**
* Packs the |pri_spec| in |buf|. This function assumes |buf| has
* enough space for serialization.
*/
void nghttp2_frame_pack_priority_spec(uint8_t *buf,
const nghttp2_priority_spec *pri_spec);
/**
* Unpacks the priority specification from payload |payload| of length
* |payloadlen| to |pri_spec|. The |flags| is used to determine what
* kind of priority specification is in |payload|. This function
* assumes the |payload| contains whole priority specification.
*/
void nghttp2_frame_unpack_priority_spec(nghttp2_priority_spec *pri_spec,
const uint8_t *payload);
/*
* Returns the offset from the HEADERS frame payload where the
* compressed header block starts. The frame payload does not include
* frame header.
*/
size_t nghttp2_frame_headers_payload_nv_offset(nghttp2_headers *frame);
/*
* Packs HEADERS frame |frame| in wire format and store it in |bufs|.
* This function expands |bufs| as necessary to store frame.
*
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
* before calling this function.
*
* frame->hd.length is assigned after length is determined during
* packing process. CONTINUATION frames are also serialized in this
* function. This function does not handle padding.
*
* This function returns 0 if it succeeds, or returns one of the
* following negative error codes:
*
* NGHTTP2_ERR_HEADER_COMP
* The deflate operation failed.
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
int nghttp2_frame_pack_headers(nghttp2_bufs *bufs, nghttp2_headers *frame,
nghttp2_hd_deflater *deflater);
/*
* Unpacks HEADERS frame byte sequence into |frame|. This function
* only unapcks bytes that come before name/value header block and
* after possible Pad Length field.
*
* This function always succeeds and returns 0.
*/
int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
const uint8_t *payload);
/*
* Packs PRIORITY frame |frame| in wire format and store it in
* |bufs|.
*
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
* before calling this function.
*
* This function always succeeds and returns 0.
*/
int nghttp2_frame_pack_priority(nghttp2_bufs *bufs, nghttp2_priority *frame);
/*
* Unpacks PRIORITY wire format into |frame|.
*/
void nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame,
const uint8_t *payload);
/*
* Packs RST_STREAM frame |frame| in wire frame format and store it in
* |bufs|.
*
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
* before calling this function.
*
* This function always succeeds and returns 0.
*/
int nghttp2_frame_pack_rst_stream(nghttp2_bufs *bufs,
nghttp2_rst_stream *frame);
/*
* Unpacks RST_STREAM frame byte sequence into |frame|.
*/
void nghttp2_frame_unpack_rst_stream_payload(nghttp2_rst_stream *frame,
const uint8_t *payload);
/*
* Packs SETTINGS frame |frame| in wire format and store it in
* |bufs|.
*
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
* before calling this function.
*
* This function returns 0 if it succeeds, or returns one of the
* following negative error codes:
*
* NGHTTP2_ERR_FRAME_SIZE_ERROR
* The length of the frame is too large.
*/
int nghttp2_frame_pack_settings(nghttp2_bufs *bufs, nghttp2_settings *frame);
/*
* Packs the |iv|, which includes |niv| entries, in the |buf|,
* assuming the |buf| has at least 8 * |niv| bytes.
*
* Returns the number of bytes written into the |buf|.
*/
size_t nghttp2_frame_pack_settings_payload(uint8_t *buf,
const nghttp2_settings_entry *iv,
size_t niv);
void nghttp2_frame_unpack_settings_entry(nghttp2_settings_entry *iv,
const uint8_t *payload);
/*
* Initializes payload of frame->settings. The |frame| takes
* ownership of |iv|.
*/
void nghttp2_frame_unpack_settings_payload(nghttp2_settings *frame,
nghttp2_settings_entry *iv,
size_t niv);
/*
* Unpacks SETTINGS payload into |*iv_ptr|. The number of entries are
* assigned to the |*niv_ptr|. This function allocates enough memory
* to store the result in |*iv_ptr|. The caller is responsible to free
* |*iv_ptr| after its use.
*
* This function returns 0 if it succeeds or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
int nghttp2_frame_unpack_settings_payload2(nghttp2_settings_entry **iv_ptr,
size_t *niv_ptr,
const uint8_t *payload,
size_t payloadlen, nghttp2_mem *mem);
/*
* Packs PUSH_PROMISE frame |frame| in wire format and store it in
* |bufs|. This function expands |bufs| as necessary to store
* frame.
*
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
* before calling this function.
*
* frame->hd.length is assigned after length is determined during
* packing process. CONTINUATION frames are also serialized in this
* function. This function does not handle padding.
*
* This function returns 0 if it succeeds, or returns one of the
* following negative error codes:
*
* NGHTTP2_ERR_HEADER_COMP
* The deflate operation failed.
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
int nghttp2_frame_pack_push_promise(nghttp2_bufs *bufs,
nghttp2_push_promise *frame,
nghttp2_hd_deflater *deflater);
/*
* Unpacks PUSH_PROMISE frame byte sequence into |frame|. This
* function only unapcks bytes that come before name/value header
* block and after possible Pad Length field.
*
* This function returns 0 if it succeeds or one of the following
* negative error codes:
*
* NGHTTP2_ERR_PROTO
* TODO END_HEADERS flag is not set
*/
int nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame,
const uint8_t *payload);
/*
* Packs PING frame |frame| in wire format and store it in
* |bufs|.
*
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
* before calling this function.
*
* This function always succeeds and returns 0.
*/
int nghttp2_frame_pack_ping(nghttp2_bufs *bufs, nghttp2_ping *frame);
/*
* Unpacks PING wire format into |frame|.
*/
void nghttp2_frame_unpack_ping_payload(nghttp2_ping *frame,
const uint8_t *payload);
/*
* Packs GOAWAY frame |frame| in wire format and store it in |bufs|.
* This function expands |bufs| as necessary to store frame.
*
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
* before calling this function.
*
* This function returns 0 if it succeeds or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_FRAME_SIZE_ERROR
* The length of the frame is too large.
*/
int nghttp2_frame_pack_goaway(nghttp2_bufs *bufs, nghttp2_goaway *frame);
/*
* Unpacks GOAWAY wire format into |frame|. The |payload| of length
* |payloadlen| contains first 8 bytes of payload. The
* |var_gift_payload| of length |var_gift_payloadlen| contains
* remaining payload and its buffer is gifted to the function and then
* |frame|. The |var_gift_payloadlen| must be freed by
* nghttp2_frame_goaway_free().
*/
void nghttp2_frame_unpack_goaway_payload(nghttp2_goaway *frame,
const uint8_t *payload,
uint8_t *var_gift_payload,
size_t var_gift_payloadlen);
/*
* Unpacks GOAWAY wire format into |frame|. This function only exists
* for unit test. After allocating buffer for debug data, this
* function internally calls nghttp2_frame_unpack_goaway_payload().
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
int nghttp2_frame_unpack_goaway_payload2(nghttp2_goaway *frame,
const uint8_t *payload,
size_t payloadlen, nghttp2_mem *mem);
/*
* Packs WINDOW_UPDATE frame |frame| in wire frame format and store it
* in |bufs|.
*
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
* before calling this function.
*
* This function always succeeds and returns 0.
*/
int nghttp2_frame_pack_window_update(nghttp2_bufs *bufs,
nghttp2_window_update *frame);
/*
* Unpacks WINDOW_UPDATE frame byte sequence into |frame|.
*/
void nghttp2_frame_unpack_window_update_payload(nghttp2_window_update *frame,
const uint8_t *payload);
/*
* Packs ALTSVC frame |frame| in wire frame format and store it in
* |bufs|.
*
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
* before calling this function.
*
* This function always succeeds and returns 0.
*/
int nghttp2_frame_pack_altsvc(nghttp2_bufs *bufs, nghttp2_extension *ext);
/*
* Unpacks ALTSVC wire format into |frame|. The |payload| of
* |payloadlen| bytes contains frame payload. This function assumes
* that frame->payload points to the nghttp2_ext_altsvc object.
*
* This function always succeeds and returns 0.
*/
void nghttp2_frame_unpack_altsvc_payload(nghttp2_extension *frame,
size_t origin_len, uint8_t *payload,
size_t payloadlen);
/*
* Unpacks ALTSVC wire format into |frame|. This function only exists
* for unit test. After allocating buffer for fields, this function
* internally calls nghttp2_frame_unpack_altsvc_payload().
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_FRAME_SIZE_ERROR
* The payload is too small.
*/
int nghttp2_frame_unpack_altsvc_payload2(nghttp2_extension *frame,
const uint8_t *payload,
size_t payloadlen, nghttp2_mem *mem);
/*
* Initializes HEADERS frame |frame| with given values. |frame| takes
* ownership of |nva|, so caller must not free it. If |stream_id| is
* not assigned yet, it must be -1.
*/
void nghttp2_frame_headers_init(nghttp2_headers *frame, uint8_t flags,
int32_t stream_id, nghttp2_headers_category cat,
const nghttp2_priority_spec *pri_spec,
nghttp2_nv *nva, size_t nvlen);
void nghttp2_frame_headers_free(nghttp2_headers *frame, nghttp2_mem *mem);
void nghttp2_frame_priority_init(nghttp2_priority *frame, int32_t stream_id,
const nghttp2_priority_spec *pri_spec);
void nghttp2_frame_priority_free(nghttp2_priority *frame);
void nghttp2_frame_rst_stream_init(nghttp2_rst_stream *frame, int32_t stream_id,
uint32_t error_code);
void nghttp2_frame_rst_stream_free(nghttp2_rst_stream *frame);
/*
* Initializes PUSH_PROMISE frame |frame| with given values. |frame|
* takes ownership of |nva|, so caller must not free it.
*/
void nghttp2_frame_push_promise_init(nghttp2_push_promise *frame, uint8_t flags,
int32_t stream_id,
int32_t promised_stream_id,
nghttp2_nv *nva, size_t nvlen);
void nghttp2_frame_push_promise_free(nghttp2_push_promise *frame,
nghttp2_mem *mem);
/*
* Initializes SETTINGS frame |frame| with given values. |frame| takes
* ownership of |iv|, so caller must not free it. The |flags| are
* bitwise-OR of one or more of nghttp2_settings_flag.
*/
void nghttp2_frame_settings_init(nghttp2_settings *frame, uint8_t flags,
nghttp2_settings_entry *iv, size_t niv);
void nghttp2_frame_settings_free(nghttp2_settings *frame, nghttp2_mem *mem);
/*
* Initializes PING frame |frame| with given values. If the
* |opqeue_data| is not NULL, it must point to 8 bytes memory region
* of data. The data pointed by |opaque_data| is copied. It can be
* NULL. In this case, 8 bytes NULL is used.
*/
void nghttp2_frame_ping_init(nghttp2_ping *frame, uint8_t flags,
const uint8_t *opque_data);
void nghttp2_frame_ping_free(nghttp2_ping *frame);
/*
* Initializes GOAWAY frame |frame| with given values. On success,
* this function takes ownership of |opaque_data|, so caller must not
* free it. If the |opaque_data_len| is 0, opaque_data could be NULL.
*/
void nghttp2_frame_goaway_init(nghttp2_goaway *frame, int32_t last_stream_id,
uint32_t error_code, uint8_t *opaque_data,
size_t opaque_data_len);
void nghttp2_frame_goaway_free(nghttp2_goaway *frame, nghttp2_mem *mem);
void nghttp2_frame_window_update_init(nghttp2_window_update *frame,
uint8_t flags, int32_t stream_id,
int32_t window_size_increment);
void nghttp2_frame_window_update_free(nghttp2_window_update *frame);
void nghttp2_frame_extension_init(nghttp2_extension *frame, uint8_t type,
uint8_t flags, int32_t stream_id,
void *payload);
void nghttp2_frame_extension_free(nghttp2_extension *frame);
/*
* Initializes ALTSVC frame |frame| with given values. This function
* assumes that frame->payload points to nghttp2_ext_altsvc object.
* Also |origin| and |field_value| are allocated in single buffer,
* starting |origin|. On success, this function takes ownership of
* |origin|, so caller must not free it.
*/
void nghttp2_frame_altsvc_init(nghttp2_extension *frame, int32_t stream_id,
uint8_t *origin, size_t origin_len,
uint8_t *field_value, size_t field_value_len);
/*
* Frees up resources under |frame|. This function does not free
* nghttp2_ext_altsvc object pointed by frame->payload. This function
* only frees origin pointed by nghttp2_ext_altsvc.origin. Therefore,
* other fields must be allocated in the same buffer with origin.
*/
void nghttp2_frame_altsvc_free(nghttp2_extension *frame, nghttp2_mem *mem);
/*
* Returns the number of padding bytes after payload. The total
* padding length is given in the |padlen|. The returned value does
* not include the Pad Length field. If |padlen| is 0, this function
* returns 0, regardless of frame->hd.flags.
*/
size_t nghttp2_frame_trail_padlen(nghttp2_frame *frame, size_t padlen);
void nghttp2_frame_data_init(nghttp2_data *frame, uint8_t flags,
int32_t stream_id);
void nghttp2_frame_data_free(nghttp2_data *frame);
/*
* Makes copy of |iv| and return the copy. The |niv| is the number of
* entries in |iv|. This function returns the pointer to the copy if
* it succeeds, or NULL.
*/
nghttp2_settings_entry *nghttp2_frame_iv_copy(const nghttp2_settings_entry *iv,
size_t niv, nghttp2_mem *mem);
/*
* Sorts the |nva| in ascending order of name and value. If names are
* equivalent, sort them by value.
*/
void nghttp2_nv_array_sort(nghttp2_nv *nva, size_t nvlen);
/*
* Copies name/value pairs from |nva|, which contains |nvlen| pairs,
* to |*nva_ptr|, which is dynamically allocated so that all items can
* be stored. The resultant name and value in nghttp2_nv are
* guaranteed to be NULL-terminated even if the input is not
* null-terminated.
*
* The |*nva_ptr| must be freed using nghttp2_nv_array_del().
*
* This function returns 0 if it succeeds or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
int nghttp2_nv_array_copy(nghttp2_nv **nva_ptr, const nghttp2_nv *nva,
size_t nvlen, nghttp2_mem *mem);
/*
* Returns nonzero if the name/value pair |a| equals to |b|. The name
* is compared in case-sensitive, because we ensure that this function
* is called after the name is lower-cased.
*/
int nghttp2_nv_equal(const nghttp2_nv *a, const nghttp2_nv *b);
/*
* Frees |nva|.
*/
void nghttp2_nv_array_del(nghttp2_nv *nva, nghttp2_mem *mem);
/*
* Checks that the |iv|, which includes |niv| entries, does not have
* invalid values.
*
* This function returns nonzero if it succeeds, or 0.
*/
int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv);
/*
* Sets Pad Length field and flags and adjusts frame header position
* of each buffers in |bufs|. The number of padding is given in the
* |padlen| including Pad Length field. The |hd| is the frame header
* for the serialized data. This function fills zeros padding region
* unless framehd_only is nonzero.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_FRAME_SIZE_ERROR
* The length of the resulting frame is too large.
*/
int nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd,
size_t padlen, int framehd_only);
#endif /* NGHTTP2_FRAME_H */

View file

@ -0,0 +1,432 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2013 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGHTTP2_HD_H
#define NGHTTP2_HD_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h>
#include "nghttp2_hd_huffman.h"
#include "nghttp2_buf.h"
#include "nghttp2_mem.h"
#include "nghttp2_rcbuf.h"
#define NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE NGHTTP2_DEFAULT_HEADER_TABLE_SIZE
#define NGHTTP2_HD_ENTRY_OVERHEAD 32
/* The maximum length of one name/value pair. This is the sum of the
length of name and value. This is not specified by the spec. We
just chose the arbitrary size */
#define NGHTTP2_HD_MAX_NV 65536
/* Default size of maximum table buffer size for encoder. Even if
remote decoder notifies larger buffer size for its decoding,
encoder only uses the memory up to this value. */
#define NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE (1 << 12)
/* Exported for unit test */
#define NGHTTP2_STATIC_TABLE_LENGTH 61
/* Generated by genlibtokenlookup.py */
typedef enum {
NGHTTP2_TOKEN__AUTHORITY = 0,
NGHTTP2_TOKEN__METHOD = 1,
NGHTTP2_TOKEN__PATH = 3,
NGHTTP2_TOKEN__SCHEME = 5,
NGHTTP2_TOKEN__STATUS = 7,
NGHTTP2_TOKEN_ACCEPT_CHARSET = 14,
NGHTTP2_TOKEN_ACCEPT_ENCODING = 15,
NGHTTP2_TOKEN_ACCEPT_LANGUAGE = 16,
NGHTTP2_TOKEN_ACCEPT_RANGES = 17,
NGHTTP2_TOKEN_ACCEPT = 18,
NGHTTP2_TOKEN_ACCESS_CONTROL_ALLOW_ORIGIN = 19,
NGHTTP2_TOKEN_AGE = 20,
NGHTTP2_TOKEN_ALLOW = 21,
NGHTTP2_TOKEN_AUTHORIZATION = 22,
NGHTTP2_TOKEN_CACHE_CONTROL = 23,
NGHTTP2_TOKEN_CONTENT_DISPOSITION = 24,
NGHTTP2_TOKEN_CONTENT_ENCODING = 25,
NGHTTP2_TOKEN_CONTENT_LANGUAGE = 26,
NGHTTP2_TOKEN_CONTENT_LENGTH = 27,
NGHTTP2_TOKEN_CONTENT_LOCATION = 28,
NGHTTP2_TOKEN_CONTENT_RANGE = 29,
NGHTTP2_TOKEN_CONTENT_TYPE = 30,
NGHTTP2_TOKEN_COOKIE = 31,
NGHTTP2_TOKEN_DATE = 32,
NGHTTP2_TOKEN_ETAG = 33,
NGHTTP2_TOKEN_EXPECT = 34,
NGHTTP2_TOKEN_EXPIRES = 35,
NGHTTP2_TOKEN_FROM = 36,
NGHTTP2_TOKEN_HOST = 37,
NGHTTP2_TOKEN_IF_MATCH = 38,
NGHTTP2_TOKEN_IF_MODIFIED_SINCE = 39,
NGHTTP2_TOKEN_IF_NONE_MATCH = 40,
NGHTTP2_TOKEN_IF_RANGE = 41,
NGHTTP2_TOKEN_IF_UNMODIFIED_SINCE = 42,
NGHTTP2_TOKEN_LAST_MODIFIED = 43,
NGHTTP2_TOKEN_LINK = 44,
NGHTTP2_TOKEN_LOCATION = 45,
NGHTTP2_TOKEN_MAX_FORWARDS = 46,
NGHTTP2_TOKEN_PROXY_AUTHENTICATE = 47,
NGHTTP2_TOKEN_PROXY_AUTHORIZATION = 48,
NGHTTP2_TOKEN_RANGE = 49,
NGHTTP2_TOKEN_REFERER = 50,
NGHTTP2_TOKEN_REFRESH = 51,
NGHTTP2_TOKEN_RETRY_AFTER = 52,
NGHTTP2_TOKEN_SERVER = 53,
NGHTTP2_TOKEN_SET_COOKIE = 54,
NGHTTP2_TOKEN_STRICT_TRANSPORT_SECURITY = 55,
NGHTTP2_TOKEN_TRANSFER_ENCODING = 56,
NGHTTP2_TOKEN_USER_AGENT = 57,
NGHTTP2_TOKEN_VARY = 58,
NGHTTP2_TOKEN_VIA = 59,
NGHTTP2_TOKEN_WWW_AUTHENTICATE = 60,
NGHTTP2_TOKEN_TE,
NGHTTP2_TOKEN_CONNECTION,
NGHTTP2_TOKEN_KEEP_ALIVE,
NGHTTP2_TOKEN_PROXY_CONNECTION,
NGHTTP2_TOKEN_UPGRADE,
} nghttp2_token;
struct nghttp2_hd_entry;
typedef struct nghttp2_hd_entry nghttp2_hd_entry;
typedef struct {
/* The buffer containing header field name. NULL-termination is
guaranteed. */
nghttp2_rcbuf *name;
/* The buffer containing header field value. NULL-termination is
guaranteed. */
nghttp2_rcbuf *value;
/* nghttp2_token value for name. It could be -1 if we have no token
for that header field name. */
int32_t token;
/* Bitwise OR of one or more of nghttp2_nv_flag. */
uint8_t flags;
} nghttp2_hd_nv;
struct nghttp2_hd_entry {
/* The header field name/value pair */
nghttp2_hd_nv nv;
/* This is solely for nghttp2_hd_{deflate,inflate}_get_table_entry
APIs to keep backward compatibility. */
nghttp2_nv cnv;
/* The next entry which shares same bucket in hash table. */
nghttp2_hd_entry *next;
/* The sequence number. We will increment it by one whenever we
store nghttp2_hd_entry to dynamic header table. */
uint32_t seq;
/* The hash value for header name (nv.name). */
uint32_t hash;
};
/* The entry used for static header table. */
typedef struct {
nghttp2_rcbuf name;
nghttp2_rcbuf value;
nghttp2_nv cnv;
int32_t token;
uint32_t hash;
} nghttp2_hd_static_entry;
typedef struct {
nghttp2_hd_entry **buffer;
size_t mask;
size_t first;
size_t len;
} nghttp2_hd_ringbuf;
typedef enum {
NGHTTP2_HD_OPCODE_NONE,
NGHTTP2_HD_OPCODE_INDEXED,
NGHTTP2_HD_OPCODE_NEWNAME,
NGHTTP2_HD_OPCODE_INDNAME
} nghttp2_hd_opcode;
typedef enum {
NGHTTP2_HD_STATE_EXPECT_TABLE_SIZE,
NGHTTP2_HD_STATE_INFLATE_START,
NGHTTP2_HD_STATE_OPCODE,
NGHTTP2_HD_STATE_READ_TABLE_SIZE,
NGHTTP2_HD_STATE_READ_INDEX,
NGHTTP2_HD_STATE_NEWNAME_CHECK_NAMELEN,
NGHTTP2_HD_STATE_NEWNAME_READ_NAMELEN,
NGHTTP2_HD_STATE_NEWNAME_READ_NAMEHUFF,
NGHTTP2_HD_STATE_NEWNAME_READ_NAME,
NGHTTP2_HD_STATE_CHECK_VALUELEN,
NGHTTP2_HD_STATE_READ_VALUELEN,
NGHTTP2_HD_STATE_READ_VALUEHUFF,
NGHTTP2_HD_STATE_READ_VALUE
} nghttp2_hd_inflate_state;
typedef enum {
NGHTTP2_HD_WITH_INDEXING,
NGHTTP2_HD_WITHOUT_INDEXING,
NGHTTP2_HD_NEVER_INDEXING
} nghttp2_hd_indexing_mode;
typedef struct {
/* dynamic header table */
nghttp2_hd_ringbuf hd_table;
/* Memory allocator */
nghttp2_mem *mem;
/* Abstract buffer size of hd_table as described in the spec. This
is the sum of length of name/value in hd_table +
NGHTTP2_HD_ENTRY_OVERHEAD bytes overhead per each entry. */
size_t hd_table_bufsize;
/* The effective header table size. */
size_t hd_table_bufsize_max;
/* Next sequence number for nghttp2_hd_entry */
uint32_t next_seq;
/* If inflate/deflate error occurred, this value is set to 1 and
further invocation of inflate/deflate will fail with
NGHTTP2_ERR_HEADER_COMP. */
uint8_t bad;
} nghttp2_hd_context;
#define HD_MAP_SIZE 128
typedef struct {
nghttp2_hd_entry *table[HD_MAP_SIZE];
} nghttp2_hd_map;
struct nghttp2_hd_deflater {
nghttp2_hd_context ctx;
nghttp2_hd_map map;
/* The upper limit of the header table size the deflater accepts. */
size_t deflate_hd_table_bufsize_max;
/* Minimum header table size notified in the next context update */
size_t min_hd_table_bufsize_max;
/* If nonzero, send header table size using encoding context update
in the next deflate process */
uint8_t notify_table_size_change;
};
struct nghttp2_hd_inflater {
nghttp2_hd_context ctx;
/* Stores current state of huffman decoding */
nghttp2_hd_huff_decode_context huff_decode_ctx;
/* header buffer */
nghttp2_buf namebuf, valuebuf;
nghttp2_rcbuf *namercbuf, *valuercbuf;
/* Pointer to the name/value pair which are used in the current
header emission. */
nghttp2_rcbuf *nv_name_keep, *nv_value_keep;
/* The number of bytes to read */
size_t left;
/* The index in indexed repr or indexed name */
size_t index;
/* The maximum header table size the inflater supports. This is the
same value transmitted in SETTINGS_HEADER_TABLE_SIZE */
size_t settings_hd_table_bufsize_max;
/* Minimum header table size set by nghttp2_hd_inflate_change_table_size */
size_t min_hd_table_bufsize_max;
/* The number of next shift to decode integer */
size_t shift;
nghttp2_hd_opcode opcode;
nghttp2_hd_inflate_state state;
/* nonzero if string is huffman encoded */
uint8_t huffman_encoded;
/* nonzero if deflater requires that current entry is indexed */
uint8_t index_required;
/* nonzero if deflater requires that current entry must not be
indexed */
uint8_t no_index;
};
/*
* Initializes the |ent| members. The reference counts of nv->name
* and nv->value are increased by one for each.
*/
void nghttp2_hd_entry_init(nghttp2_hd_entry *ent, nghttp2_hd_nv *nv);
/*
* This function decreases the reference counts of nv->name and
* nv->value.
*/
void nghttp2_hd_entry_free(nghttp2_hd_entry *ent);
/*
* Initializes |deflater| for deflating name/values pairs.
*
* The encoder only uses up to
* NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE bytes for header table
* even if the larger value is specified later in
* nghttp2_hd_change_table_size().
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
int nghttp2_hd_deflate_init(nghttp2_hd_deflater *deflater, nghttp2_mem *mem);
/*
* Initializes |deflater| for deflating name/values pairs.
*
* The encoder only uses up to |max_deflate_dynamic_table_size| bytes
* for header table even if the larger value is specified later in
* nghttp2_hd_change_table_size().
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
int nghttp2_hd_deflate_init2(nghttp2_hd_deflater *deflater,
size_t max_deflate_dynamic_table_size,
nghttp2_mem *mem);
/*
* Deallocates any resources allocated for |deflater|.
*/
void nghttp2_hd_deflate_free(nghttp2_hd_deflater *deflater);
/*
* Deflates the |nva|, which has the |nvlen| name/value pairs, into
* the |bufs|.
*
* This function expands |bufs| as necessary to store the result. If
* buffers is full and the process still requires more space, this
* function fails and returns NGHTTP2_ERR_HEADER_COMP.
*
* After this function returns, it is safe to delete the |nva|.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_HEADER_COMP
* Deflation process has failed.
* NGHTTP2_ERR_BUFFER_ERROR
* Out of buffer space.
*/
int nghttp2_hd_deflate_hd_bufs(nghttp2_hd_deflater *deflater,
nghttp2_bufs *bufs, const nghttp2_nv *nva,
size_t nvlen);
/*
* Initializes |inflater| for inflating name/values pairs.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* :enum:`NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
int nghttp2_hd_inflate_init(nghttp2_hd_inflater *inflater, nghttp2_mem *mem);
/*
* Deallocates any resources allocated for |inflater|.
*/
void nghttp2_hd_inflate_free(nghttp2_hd_inflater *inflater);
/*
* Similar to nghttp2_hd_inflate_hd(), but this takes nghttp2_hd_nv
* instead of nghttp2_nv as output parameter |nv_out|. Other than
* that return values and semantics are the same as
* nghttp2_hd_inflate_hd().
*/
ssize_t nghttp2_hd_inflate_hd_nv(nghttp2_hd_inflater *inflater,
nghttp2_hd_nv *nv_out, int *inflate_flags,
const uint8_t *in, size_t inlen, int in_final);
/* For unittesting purpose */
int nghttp2_hd_emit_indname_block(nghttp2_bufs *bufs, size_t index,
nghttp2_nv *nv, int indexing_mode);
/* For unittesting purpose */
int nghttp2_hd_emit_newname_block(nghttp2_bufs *bufs, nghttp2_nv *nv,
int indexing_mode);
/* For unittesting purpose */
int nghttp2_hd_emit_table_size(nghttp2_bufs *bufs, size_t table_size);
/* For unittesting purpose */
nghttp2_hd_nv nghttp2_hd_table_get(nghttp2_hd_context *context, size_t index);
/* For unittesting purpose */
ssize_t nghttp2_hd_decode_length(uint32_t *res, size_t *shift_ptr, int *fin,
uint32_t initial, size_t shift, uint8_t *in,
uint8_t *last, size_t prefix);
/* Huffman encoding/decoding functions */
/*
* Counts the required bytes to encode |src| with length |len|.
*
* This function returns the number of required bytes to encode given
* data, including padding of prefix of terminal symbol code. This
* function always succeeds.
*/
size_t nghttp2_hd_huff_encode_count(const uint8_t *src, size_t len);
/*
* Encodes the given data |src| with length |srclen| to the |bufs|.
* This function expands extra buffers in |bufs| if necessary.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_BUFFER_ERROR
* Out of buffer space.
*/
int nghttp2_hd_huff_encode(nghttp2_bufs *bufs, const uint8_t *src,
size_t srclen);
void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx);
/*
* Decodes the given data |src| with length |srclen|. The |ctx| must
* be initialized by nghttp2_hd_huff_decode_context_init(). The result
* will be written to |buf|. This function assumes that |buf| has the
* enough room to store the decoded byte string.
*
* The caller must set the |fin| to nonzero if the given input is the
* final block.
*
* This function returns the number of read bytes from the |in|.
*
* If this function fails, it returns one of the following negative
* return codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_HEADER_COMP
* Decoding process has failed.
*/
ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx,
nghttp2_buf *buf, const uint8_t *src,
size_t srclen, int fin);
#endif /* NGHTTP2_HD_H */

View file

@ -0,0 +1,77 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2013 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGHTTP2_HD_HUFFMAN_H
#define NGHTTP2_HD_HUFFMAN_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h>
typedef enum {
/* FSA accepts this state as the end of huffman encoding
sequence. */
NGHTTP2_HUFF_ACCEPTED = 1,
/* This state emits symbol */
NGHTTP2_HUFF_SYM = (1 << 1),
/* If state machine reaches this state, decoding fails. */
NGHTTP2_HUFF_FAIL = (1 << 2)
} nghttp2_huff_decode_flag;
typedef struct {
/* huffman decoding state, which is actually the node ID of internal
huffman tree. We have 257 leaf nodes, but they are identical to
root node other than emitting a symbol, so we have 256 internal
nodes [1..255], inclusive. */
uint8_t state;
/* bitwise OR of zero or more of the nghttp2_huff_decode_flag */
uint8_t flags;
/* symbol if NGHTTP2_HUFF_SYM flag set */
uint8_t sym;
} nghttp2_huff_decode;
typedef nghttp2_huff_decode huff_decode_table_type[16];
typedef struct {
/* Current huffman decoding state. We stripped leaf nodes, so the
value range is [0..255], inclusive. */
uint8_t state;
/* nonzero if we can say that the decoding process succeeds at this
state */
uint8_t accept;
} nghttp2_hd_huff_decode_context;
typedef struct {
/* The number of bits in this code */
uint32_t nbits;
/* Huffman code aligned to LSB */
uint32_t code;
} nghttp2_huff_sym;
extern const nghttp2_huff_sym huff_sym_table[];
extern const nghttp2_huff_decode huff_decode_table[][16];
#endif /* NGHTTP2_HD_HUFFMAN_H */

View file

@ -0,0 +1,122 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGHTTP2_HELPER_H
#define NGHTTP2_HELPER_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG_H */
#include <string.h>
#include <stddef.h>
#include <nghttp2/nghttp2.h>
#include "nghttp2_mem.h"
#define nghttp2_min(A, B) ((A) < (B) ? (A) : (B))
#define nghttp2_max(A, B) ((A) > (B) ? (A) : (B))
#define lstreq(A, B, N) ((sizeof((A)) - 1) == (N) && memcmp((A), (B), (N)) == 0)
#define nghttp2_struct_of(ptr, type, member) \
((type *)(void *)((char *)(ptr)-offsetof(type, member)))
/*
* Copies 2 byte unsigned integer |n| in host byte order to |buf| in
* network byte order.
*/
void nghttp2_put_uint16be(uint8_t *buf, uint16_t n);
/*
* Copies 4 byte unsigned integer |n| in host byte order to |buf| in
* network byte order.
*/
void nghttp2_put_uint32be(uint8_t *buf, uint32_t n);
/*
* Retrieves 2 byte unsigned integer stored in |data| in network byte
* order and returns it in host byte order.
*/
uint16_t nghttp2_get_uint16(const uint8_t *data);
/*
* Retrieves 4 byte unsigned integer stored in |data| in network byte
* order and returns it in host byte order.
*/
uint32_t nghttp2_get_uint32(const uint8_t *data);
void nghttp2_downcase(uint8_t *s, size_t len);
/*
* Adjusts |*local_window_size_ptr|, |*recv_window_size_ptr|,
* |*recv_reduction_ptr| with |*delta_ptr| which is the
* WINDOW_UPDATE's window_size_increment sent from local side. If
* |delta| is strictly larger than |*recv_window_size_ptr|,
* |*local_window_size_ptr| is increased by delta -
* *recv_window_size_ptr. If |delta| is negative,
* |*local_window_size_ptr| is decreased by delta.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_FLOW_CONTROL
* local_window_size overflow or gets negative.
*/
int nghttp2_adjust_local_window_size(int32_t *local_window_size_ptr,
int32_t *recv_window_size_ptr,
int32_t *recv_reduction_ptr,
int32_t *delta_ptr);
/*
* This function works like nghttp2_adjust_local_window_size(). The
* difference is that this function assumes *delta_ptr >= 0, and
* *recv_window_size_ptr is not decreased by *delta_ptr.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_FLOW_CONTROL
* local_window_size overflow or gets negative.
*/
int nghttp2_increase_local_window_size(int32_t *local_window_size_ptr,
int32_t *recv_window_size_ptr,
int32_t *recv_reduction_ptr,
int32_t *delta_ptr);
/*
* Returns non-zero if the function decided that WINDOW_UPDATE should
* be sent.
*/
int nghttp2_should_send_window_update(int32_t local_window_size,
int32_t recv_window_size);
/*
* Copies the buffer |src| of length |len| to the destination pointed
* by the |dest|, assuming that the |dest| is at lest |len| bytes long
* . Returns dest + len.
*/
uint8_t *nghttp2_cpymem(uint8_t *dest, const void *src, size_t len);
#endif /* NGHTTP2_HELPER_H */

View file

@ -0,0 +1,97 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2015 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGHTTP2_HTTP_H
#define NGHTTP2_HTTP_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h>
#include "nghttp2_session.h"
#include "nghttp2_stream.h"
/*
* This function is called when HTTP header field |nv| in |frame| is
* received for |stream|. This function will validate |nv| against
* the current state of stream.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_HTTP_HEADER
* Invalid HTTP header field was received.
* NGHTTP2_ERR_IGN_HTTP_HEADER
* Invalid HTTP header field was received but it can be treated as
* if it was not received because of compatibility reasons.
*/
int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
nghttp2_frame *frame, nghttp2_hd_nv *nv,
int trailer);
/*
* This function is called when request header is received. This
* function performs validation and returns 0 if it succeeds, or -1.
*/
int nghttp2_http_on_request_headers(nghttp2_stream *stream,
nghttp2_frame *frame);
/*
* This function is called when response header is received. This
* function performs validation and returns 0 if it succeeds, or -1.
*/
int nghttp2_http_on_response_headers(nghttp2_stream *stream);
/*
* This function is called trailer header (for both request and
* response) is received. This function performs validation and
* returns 0 if it succeeds, or -1.
*/
int nghttp2_http_on_trailer_headers(nghttp2_stream *stream,
nghttp2_frame *frame);
/*
* This function is called when END_STREAM flag is seen in incoming
* frame. This function performs validation and returns 0 if it
* succeeds, or -1.
*/
int nghttp2_http_on_remote_end_stream(nghttp2_stream *stream);
/*
* This function is called when chunk of data is received. This
* function performs validation and returns 0 if it succeeds, or -1.
*/
int nghttp2_http_on_data_chunk(nghttp2_stream *stream, size_t n);
/*
* This function inspects header field in |frame| and records its
* method in stream->http_flags. If frame->hd.type is neither
* NGHTTP2_HEADERS nor NGHTTP2_PUSH_PROMISE, this function does
* nothing.
*/
void nghttp2_http_record_request_method(nghttp2_stream *stream,
nghttp2_frame *frame);
#endif /* NGHTTP2_HTTP_H */

View file

@ -0,0 +1,58 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGHTTP2_INT_H
#define NGHTTP2_INT_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h>
/* Macros, types and constants for internal use */
/* "less" function, return nonzero if |lhs| is less than |rhs|. */
typedef int (*nghttp2_less)(const void *lhs, const void *rhs);
/* Internal error code. They must be in the range [-499, -100],
inclusive. */
typedef enum {
NGHTTP2_ERR_CREDENTIAL_PENDING = -101,
NGHTTP2_ERR_IGN_HEADER_BLOCK = -103,
NGHTTP2_ERR_IGN_PAYLOAD = -104,
/*
* Invalid HTTP header field was received but it can be treated as
* if it was not received because of compatibility reasons.
*/
NGHTTP2_ERR_IGN_HTTP_HEADER = -105,
/*
* Invalid HTTP header field was received, and it is ignored.
* Unlike NGHTTP2_ERR_IGN_HTTP_HEADER, this does not invoke
* nghttp2_on_invalid_header_callback.
*/
NGHTTP2_ERR_REMOVE_HTTP_HEADER = -106
} nghttp2_internal_error;
#endif /* NGHTTP2_INT_H */

View file

@ -0,0 +1,144 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGHTTP2_MAP_H
#define NGHTTP2_MAP_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h>
#include "nghttp2_int.h"
#include "nghttp2_mem.h"
/* Implementation of unordered map */
typedef int32_t key_type;
typedef struct nghttp2_map_entry {
struct nghttp2_map_entry *next;
key_type key;
#if SIZEOF_INT_P == 4
/* we requires 8 bytes aligment */
int64_t pad;
#endif
} nghttp2_map_entry;
typedef struct {
nghttp2_map_entry **table;
nghttp2_mem *mem;
size_t size;
uint32_t tablelen;
} nghttp2_map;
/*
* Initializes the map |map|.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
int nghttp2_map_init(nghttp2_map *map, nghttp2_mem *mem);
/*
* Deallocates any resources allocated for |map|. The stored entries
* are not freed by this function. Use nghttp2_map_each_free() to free
* each entries.
*/
void nghttp2_map_free(nghttp2_map *map);
/*
* Deallocates each entries using |func| function and any resources
* allocated for |map|. The |func| function is responsible for freeing
* given the |entry| object. The |ptr| will be passed to the |func| as
* send argument. The return value of the |func| will be ignored.
*/
void nghttp2_map_each_free(nghttp2_map *map,
int (*func)(nghttp2_map_entry *entry, void *ptr),
void *ptr);
/*
* Initializes the |entry| with the |key|. All entries to be inserted
* to the map must be initialized with this function.
*/
void nghttp2_map_entry_init(nghttp2_map_entry *entry, key_type key);
/*
* Inserts the new |entry| with the key |entry->key| to the map |map|.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_INVALID_ARGUMENT
* The item associated by |key| already exists.
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_entry *entry);
/*
* Returns the entry associated by the key |key|. If there is no such
* entry, this function returns NULL.
*/
nghttp2_map_entry *nghttp2_map_find(nghttp2_map *map, key_type key);
/*
* Removes the entry associated by the key |key| from the |map|. The
* removed entry is not freed by this function.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_INVALID_ARGUMENT
* The entry associated by |key| does not exist.
*/
int nghttp2_map_remove(nghttp2_map *map, key_type key);
/*
* Returns the number of items stored in the map |map|.
*/
size_t nghttp2_map_size(nghttp2_map *map);
/*
* Applies the function |func| to each entry in the |map| with the
* optional user supplied pointer |ptr|.
*
* If the |func| returns 0, this function calls the |func| with the
* next entry. If the |func| returns nonzero, it will not call the
* |func| for further entries and return the return value of the
* |func| immediately. Thus, this function returns 0 if all the
* invocations of the |func| return 0, or nonzero value which the last
* invocation of |func| returns.
*
* Don't use this function to free each entry. Use
* nghttp2_map_each_free() instead.
*/
int nghttp2_map_each(nghttp2_map *map,
int (*func)(nghttp2_map_entry *entry, void *ptr),
void *ptr);
#endif /* NGHTTP2_MAP_H */

View file

@ -0,0 +1,45 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2014 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGHTTP2_MEM_H
#define NGHTTP2_MEM_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h>
/* The default, system standard memory allocator */
nghttp2_mem *nghttp2_mem_default(void);
/* Convenient wrapper functions to call allocator function in
|mem|. */
void *nghttp2_mem_malloc(nghttp2_mem *mem, size_t size);
void nghttp2_mem_free(nghttp2_mem *mem, void *ptr);
void nghttp2_mem_free2(nghttp2_free free_func, void *ptr, void *mem_user_data);
void *nghttp2_mem_calloc(nghttp2_mem *mem, size_t nmemb, size_t size);
void *nghttp2_mem_realloc(nghttp2_mem *mem, void *ptr, size_t size);
#endif /* NGHTTP2_MEM_H */

View file

@ -0,0 +1,91 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGHTTP2_NET_H
#define NGHTTP2_NET_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG_H */
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif /* HAVE_ARPA_INET_H */
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif /* HAVE_NETINET_IN_H */
#include <nghttp2/nghttp2.h>
#if defined(WIN32)
/* Windows requires ws2_32 library for ntonl family functions. We
define inline functions for those function so that we don't have
dependeny on that lib. */
#ifdef _MSC_VER
#define STIN static __inline
#else
#define STIN static inline
#endif
STIN uint32_t htonl(uint32_t hostlong) {
uint32_t res;
unsigned char *p = (unsigned char *)&res;
*p++ = hostlong >> 24;
*p++ = (hostlong >> 16) & 0xffu;
*p++ = (hostlong >> 8) & 0xffu;
*p = hostlong & 0xffu;
return res;
}
STIN uint16_t htons(uint16_t hostshort) {
uint16_t res;
unsigned char *p = (unsigned char *)&res;
*p++ = hostshort >> 8;
*p = hostshort & 0xffu;
return res;
}
STIN uint32_t ntohl(uint32_t netlong) {
uint32_t res;
unsigned char *p = (unsigned char *)&netlong;
res = *p++ << 24;
res += *p++ << 16;
res += *p++ << 8;
res += *p;
return res;
}
STIN uint16_t ntohs(uint16_t netshort) {
uint16_t res;
unsigned char *p = (unsigned char *)&netshort;
res = *p++ << 8;
res += *p;
return res;
}
#endif /* WIN32 */
#endif /* NGHTTP2_NET_H */

View file

@ -0,0 +1,34 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGHTTP2_NPN_H
#define NGHTTP2_NPN_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h>
#endif /* NGHTTP2_NPN_H */

View file

@ -0,0 +1,126 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2014 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGHTTP2_OPTION_H
#define NGHTTP2_OPTION_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h>
/**
* Configuration options
*/
typedef enum {
/**
* This option prevents the library from sending WINDOW_UPDATE for a
* connection automatically. If this option is set to nonzero, the
* library won't send WINDOW_UPDATE for DATA until application calls
* nghttp2_session_consume() to indicate the amount of consumed
* DATA. By default, this option is set to zero.
*/
NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE = 1,
/**
* This option sets the SETTINGS_MAX_CONCURRENT_STREAMS value of
* remote endpoint as if it is received in SETTINGS frame. Without
* specifying this option, before the local endpoint receives
* SETTINGS_MAX_CONCURRENT_STREAMS in SETTINGS frame from remote
* endpoint, SETTINGS_MAX_CONCURRENT_STREAMS is unlimited. This may
* cause problem if local endpoint submits lots of requests
* initially and sending them at once to the remote peer may lead to
* the rejection of some requests. Specifying this option to the
* sensible value, say 100, may avoid this kind of issue. This value
* will be overwritten if the local endpoint receives
* SETTINGS_MAX_CONCURRENT_STREAMS from the remote endpoint.
*/
NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS = 1 << 1,
NGHTTP2_OPT_NO_RECV_CLIENT_MAGIC = 1 << 2,
NGHTTP2_OPT_NO_HTTP_MESSAGING = 1 << 3,
NGHTTP2_OPT_MAX_RESERVED_REMOTE_STREAMS = 1 << 4,
NGHTTP2_OPT_USER_RECV_EXT_TYPES = 1 << 5,
NGHTTP2_OPT_NO_AUTO_PING_ACK = 1 << 6,
NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES = 1 << 7,
NGHTTP2_OPT_MAX_SEND_HEADER_BLOCK_LENGTH = 1 << 8,
NGHTTP2_OPT_MAX_DEFLATE_DYNAMIC_TABLE_SIZE = 1 << 9,
NGHTTP2_OPT_NO_CLOSED_STREAMS = 1 << 10,
} nghttp2_option_flag;
/**
* Struct to store option values for nghttp2_session.
*/
struct nghttp2_option {
/**
* NGHTTP2_OPT_MAX_SEND_HEADER_BLOCK_LENGTH
*/
size_t max_send_header_block_length;
/**
* NGHTTP2_OPT_MAX_DEFLATE_DYNAMIC_TABLE_SIZE
*/
size_t max_deflate_dynamic_table_size;
/**
* Bitwise OR of nghttp2_option_flag to determine that which fields
* are specified.
*/
uint32_t opt_set_mask;
/**
* NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS
*/
uint32_t peer_max_concurrent_streams;
/**
* NGHTTP2_OPT_MAX_RESERVED_REMOTE_STREAMS
*/
uint32_t max_reserved_remote_streams;
/**
* NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES
*/
uint32_t builtin_recv_ext_types;
/**
* NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE
*/
int no_auto_window_update;
/**
* NGHTTP2_OPT_NO_RECV_CLIENT_MAGIC
*/
int no_recv_client_magic;
/**
* NGHTTP2_OPT_NO_HTTP_MESSAGING
*/
int no_http_messaging;
/**
* NGHTTP2_OPT_NO_AUTO_PING_ACK
*/
int no_auto_ping_ack;
/**
* NGHTTP2_OPT_NO_CLOSED_STREAMS
*/
int no_closed_streams;
/**
* NGHTTP2_OPT_USER_RECV_EXT_TYPES
*/
uint8_t user_recv_ext_types[32];
};
#endif /* NGHTTP2_OPTION_H */

View file

@ -0,0 +1,166 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGHTTP2_OUTBOUND_ITEM_H
#define NGHTTP2_OUTBOUND_ITEM_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h>
#include "nghttp2_frame.h"
#include "nghttp2_mem.h"
/* struct used for HEADERS and PUSH_PROMISE frame */
typedef struct {
nghttp2_data_provider data_prd;
void *stream_user_data;
/* error code when request HEADERS is canceled by RST_STREAM while
it is in queue. */
uint32_t error_code;
/* nonzero if request HEADERS is canceled. The error code is stored
in |error_code|. */
uint8_t canceled;
} nghttp2_headers_aux_data;
/* struct used for DATA frame */
typedef struct {
/**
* The data to be sent for this DATA frame.
*/
nghttp2_data_provider data_prd;
/**
* The flags of DATA frame. We use separate flags here and
* nghttp2_data frame. The latter contains flags actually sent to
* peer. This |flags| may contain NGHTTP2_FLAG_END_STREAM and only
* when |eof| becomes nonzero, flags in nghttp2_data has
* NGHTTP2_FLAG_END_STREAM set.
*/
uint8_t flags;
/**
* The flag to indicate whether EOF was reached or not. Initially
* |eof| is 0. It becomes 1 after all data were read.
*/
uint8_t eof;
/**
* The flag to indicate that NGHTTP2_DATA_FLAG_NO_COPY is used.
*/
uint8_t no_copy;
} nghttp2_data_aux_data;
typedef enum {
NGHTTP2_GOAWAY_AUX_NONE = 0x0,
/* indicates that session should be terminated after the
transmission of this frame. */
NGHTTP2_GOAWAY_AUX_TERM_ON_SEND = 0x1,
/* indicates that this GOAWAY is just a notification for graceful
shutdown. No nghttp2_session.goaway_flags should be updated on
the reaction to this frame. */
NGHTTP2_GOAWAY_AUX_SHUTDOWN_NOTICE = 0x2
} nghttp2_goaway_aux_flag;
/* struct used for GOAWAY frame */
typedef struct {
/* bitwise-OR of one or more of nghttp2_goaway_aux_flag. */
uint8_t flags;
} nghttp2_goaway_aux_data;
/* struct used for extension frame */
typedef struct {
/* nonzero if this extension frame is serialized by library
function, instead of user-defined callbacks. */
uint8_t builtin;
} nghttp2_ext_aux_data;
/* Additional data which cannot be stored in nghttp2_frame struct */
typedef union {
nghttp2_data_aux_data data;
nghttp2_headers_aux_data headers;
nghttp2_goaway_aux_data goaway;
nghttp2_ext_aux_data ext;
} nghttp2_aux_data;
struct nghttp2_outbound_item;
typedef struct nghttp2_outbound_item nghttp2_outbound_item;
struct nghttp2_outbound_item {
nghttp2_frame frame;
/* Storage for extension frame payload. frame->ext.payload points
to this structure to avoid frequent memory allocation. */
nghttp2_ext_frame_payload ext_frame_payload;
nghttp2_aux_data aux_data;
/* The priority used in priority comparion. Smaller is served
earlier. For PING, SETTINGS and non-DATA frames (excluding
response HEADERS frame) have dedicated cycle value defined above.
For DATA frame, cycle is computed by taking into account of
effective weight and frame payload length previously sent, so
that the amount of transmission is distributed across streams
proportional to effective weight (inside a tree). */
uint64_t cycle;
nghttp2_outbound_item *qnext;
/* nonzero if this object is queued, except for DATA or HEADERS
which are attached to stream as item. */
uint8_t queued;
};
/*
* Initializes |item|. No memory allocation is done in this function.
* Don't call nghttp2_outbound_item_free() until frame member is
* initialized.
*/
void nghttp2_outbound_item_init(nghttp2_outbound_item *item);
/*
* Deallocates resource for |item|. If |item| is NULL, this function
* does nothing.
*/
void nghttp2_outbound_item_free(nghttp2_outbound_item *item, nghttp2_mem *mem);
/*
* queue for nghttp2_outbound_item.
*/
typedef struct {
nghttp2_outbound_item *head, *tail;
/* number of items in this queue. */
size_t n;
} nghttp2_outbound_queue;
void nghttp2_outbound_queue_init(nghttp2_outbound_queue *q);
/* Pushes |item| into |q| */
void nghttp2_outbound_queue_push(nghttp2_outbound_queue *q,
nghttp2_outbound_item *item);
/* Pops |item| at the top from |q|. If |q| is empty, nothing
happens. */
void nghttp2_outbound_queue_pop(nghttp2_outbound_queue *q);
/* Returns the top item. */
#define nghttp2_outbound_queue_top(Q) ((Q)->head)
/* Returns the size of the queue */
#define nghttp2_outbound_queue_size(Q) ((Q)->n)
#endif /* NGHTTP2_OUTBOUND_ITEM_H */

View file

@ -0,0 +1,130 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGHTTP2_PQ_H
#define NGHTTP2_PQ_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h>
#include "nghttp2_int.h"
#include "nghttp2_mem.h"
/* Implementation of priority queue */
typedef struct {
size_t index;
} nghttp2_pq_entry;
typedef struct {
/* The pointer to the pointer to the item stored */
nghttp2_pq_entry **q;
/* Memory allocator */
nghttp2_mem *mem;
/* The number of items stored */
size_t length;
/* The maximum number of items this pq can store. This is
automatically extended when length is reached to this value. */
size_t capacity;
/* The less function between items */
nghttp2_less less;
} nghttp2_pq;
/*
* Initializes priority queue |pq| with compare function |cmp|.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
int nghttp2_pq_init(nghttp2_pq *pq, nghttp2_less less, nghttp2_mem *mem);
/*
* Deallocates any resources allocated for |pq|. The stored items are
* not freed by this function.
*/
void nghttp2_pq_free(nghttp2_pq *pq);
/*
* Adds |item| to the priority queue |pq|.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
int nghttp2_pq_push(nghttp2_pq *pq, nghttp2_pq_entry *item);
/*
* Returns item at the top of the queue |pq|. If the queue is empty,
* this function returns NULL.
*/
nghttp2_pq_entry *nghttp2_pq_top(nghttp2_pq *pq);
/*
* Pops item at the top of the queue |pq|. The popped item is not
* freed by this function.
*/
void nghttp2_pq_pop(nghttp2_pq *pq);
/*
* Returns nonzero if the queue |pq| is empty.
*/
int nghttp2_pq_empty(nghttp2_pq *pq);
/*
* Returns the number of items in the queue |pq|.
*/
size_t nghttp2_pq_size(nghttp2_pq *pq);
typedef int (*nghttp2_pq_item_cb)(nghttp2_pq_entry *item, void *arg);
/*
* Updates each item in |pq| using function |fun| and re-construct
* priority queue. The |fun| must return non-zero if it modifies the
* item in a way that it affects ordering in the priority queue. The
* |arg| is passed to the 2nd parameter of |fun|.
*/
void nghttp2_pq_update(nghttp2_pq *pq, nghttp2_pq_item_cb fun, void *arg);
/*
* Applys |fun| to each item in |pq|. The |arg| is passed as arg
* parameter to callback function. This function must not change the
* ordering key. If the return value from callback is nonzero, this
* function returns 1 immediately without iterating remaining items.
* Otherwise this function returns 0.
*/
int nghttp2_pq_each(nghttp2_pq *pq, nghttp2_pq_item_cb fun, void *arg);
/*
* Removes |item| from priority queue.
*/
void nghttp2_pq_remove(nghttp2_pq *pq, nghttp2_pq_entry *item);
#endif /* NGHTTP2_PQ_H */

View file

@ -0,0 +1,42 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2014 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGHTTP2_PRIORITY_SPEC_H
#define NGHTTP2_PRIORITY_SPEC_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h>
/*
* This function normalizes pri_spec->weight if it is out of range.
* If pri_spec->weight is less than NGHTTP2_MIN_WEIGHT, it is set to
* NGHTTP2_MIN_WEIGHT. If pri_spec->weight is larger than
* NGHTTP2_MAX_WEIGHT, it is set to NGHTTP2_MAX_WEIGHT.
*/
void nghttp2_priority_spec_normalize_weight(nghttp2_priority_spec *pri_spec);
#endif /* NGHTTP2_PRIORITY_SPEC_H */

View file

@ -0,0 +1,51 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGHTTP2_QUEUE_H
#define NGHTTP2_QUEUE_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h>
typedef struct nghttp2_queue_cell {
void *data;
struct nghttp2_queue_cell *next;
} nghttp2_queue_cell;
typedef struct {
nghttp2_queue_cell *front, *back;
} nghttp2_queue;
void nghttp2_queue_init(nghttp2_queue *queue);
void nghttp2_queue_free(nghttp2_queue *queue);
int nghttp2_queue_push(nghttp2_queue *queue, void *data);
void nghttp2_queue_pop(nghttp2_queue *queue);
void *nghttp2_queue_front(nghttp2_queue *queue);
void *nghttp2_queue_back(nghttp2_queue *queue);
int nghttp2_queue_empty(nghttp2_queue *queue);
#endif /* NGHTTP2_QUEUE_H */

View file

@ -0,0 +1,80 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2016 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGHTTP2_RCBUF_H
#define NGHTTP2_RCBUF_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h>
struct nghttp2_rcbuf {
/* custom memory allocator belongs to the mem parameter when
creating this object. */
void *mem_user_data;
nghttp2_free free;
/* The pointer to the underlying buffer */
uint8_t *base;
/* Size of buffer pointed by |base|. */
size_t len;
/* Reference count */
int32_t ref;
};
/*
* Allocates nghttp2_rcbuf object with |size| as initial buffer size.
* When the function succeeds, the reference count becomes 1.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM:
* Out of memory.
*/
int nghttp2_rcbuf_new(nghttp2_rcbuf **rcbuf_ptr, size_t size, nghttp2_mem *mem);
/*
* Like nghttp2_rcbuf_new(), but initializes the buffer with |src| of
* length |srclen|. This function allocates additional byte at the
* end and puts '\0' into it, so that the resulting buffer could be
* used as NULL-terminated string. Still (*rcbuf_ptr)->len equals to
* |srclen|.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM:
* Out of memory.
*/
int nghttp2_rcbuf_new2(nghttp2_rcbuf **rcbuf_ptr, const uint8_t *src,
size_t srclen, nghttp2_mem *mem);
/*
* Frees |rcbuf| itself, regardless of its reference cout.
*/
void nghttp2_rcbuf_del(nghttp2_rcbuf *rcbuf);
#endif /* NGHTTP2_RCBUF_H */

View file

@ -0,0 +1,879 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGHTTP2_SESSION_H
#define NGHTTP2_SESSION_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h>
#include "nghttp2_map.h"
#include "nghttp2_frame.h"
#include "nghttp2_hd.h"
#include "nghttp2_stream.h"
#include "nghttp2_outbound_item.h"
#include "nghttp2_int.h"
#include "nghttp2_buf.h"
#include "nghttp2_callbacks.h"
#include "nghttp2_mem.h"
/* The global variable for tests where we want to disable strict
preface handling. */
extern int nghttp2_enable_strict_preface;
/*
* Option flags.
*/
typedef enum {
NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE = 1 << 0,
NGHTTP2_OPTMASK_NO_RECV_CLIENT_MAGIC = 1 << 1,
NGHTTP2_OPTMASK_NO_HTTP_MESSAGING = 1 << 2,
NGHTTP2_OPTMASK_NO_AUTO_PING_ACK = 1 << 3,
NGHTTP2_OPTMASK_NO_CLOSED_STREAMS = 1 << 4
} nghttp2_optmask;
/*
* bitmask for built-in type to enable the default handling for that
* type of the frame.
*/
typedef enum {
NGHTTP2_TYPEMASK_NONE = 0,
NGHTTP2_TYPEMASK_ALTSVC = 1 << 0
} nghttp2_typemask;
typedef enum {
NGHTTP2_OB_POP_ITEM,
NGHTTP2_OB_SEND_DATA,
NGHTTP2_OB_SEND_NO_COPY,
NGHTTP2_OB_SEND_CLIENT_MAGIC
} nghttp2_outbound_state;
typedef struct {
nghttp2_outbound_item *item;
nghttp2_bufs framebufs;
nghttp2_outbound_state state;
} nghttp2_active_outbound_item;
/* Buffer length for inbound raw byte stream used in
nghttp2_session_recv(). */
#define NGHTTP2_INBOUND_BUFFER_LENGTH 16384
/* The default maximum number of incoming reserved streams */
#define NGHTTP2_MAX_INCOMING_RESERVED_STREAMS 200
/* Even if we have less SETTINGS_MAX_CONCURRENT_STREAMS than this
number, we keep NGHTTP2_MIN_IDLE_STREAMS streams in idle state */
#define NGHTTP2_MIN_IDLE_STREAMS 16
/* The maximum number of items in outbound queue, which is considered
as flooding caused by peer. All frames are not considered here.
We only consider PING + ACK and SETTINGS + ACK. This is because
they both are response to the frame initiated by peer and peer can
send as many of them as they want. If peer does not read network,
response frames are stacked up, which leads to memory exhaustion.
The value selected here is arbitrary, but safe value and if we have
these frames in this number, it is considered suspicious. */
#define NGHTTP2_MAX_OBQ_FLOOD_ITEM 10000
/* The default value of maximum number of concurrent streams. */
#define NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS 0xffffffffu
/* Internal state when receiving incoming frame */
typedef enum {
/* Receiving frame header */
NGHTTP2_IB_READ_CLIENT_MAGIC,
NGHTTP2_IB_READ_FIRST_SETTINGS,
NGHTTP2_IB_READ_HEAD,
NGHTTP2_IB_READ_NBYTE,
NGHTTP2_IB_READ_HEADER_BLOCK,
NGHTTP2_IB_IGN_HEADER_BLOCK,
NGHTTP2_IB_IGN_PAYLOAD,
NGHTTP2_IB_FRAME_SIZE_ERROR,
NGHTTP2_IB_READ_SETTINGS,
NGHTTP2_IB_READ_GOAWAY_DEBUG,
NGHTTP2_IB_EXPECT_CONTINUATION,
NGHTTP2_IB_IGN_CONTINUATION,
NGHTTP2_IB_READ_PAD_DATA,
NGHTTP2_IB_READ_DATA,
NGHTTP2_IB_IGN_DATA,
NGHTTP2_IB_IGN_ALL,
NGHTTP2_IB_READ_ALTSVC_PAYLOAD,
NGHTTP2_IB_READ_EXTENSION_PAYLOAD
} nghttp2_inbound_state;
typedef struct {
nghttp2_frame frame;
/* Storage for extension frame payload. frame->ext.payload points
to this structure to avoid frequent memory allocation. */
nghttp2_ext_frame_payload ext_frame_payload;
/* The received SETTINGS entry. For the standard settings entries,
we only keep the last seen value. For
SETTINGS_HEADER_TABLE_SIZE, we also keep minimum value in the
last index. */
nghttp2_settings_entry *iv;
/* buffer pointers to small buffer, raw_sbuf */
nghttp2_buf sbuf;
/* buffer pointers to large buffer, raw_lbuf */
nghttp2_buf lbuf;
/* Large buffer, malloced on demand */
uint8_t *raw_lbuf;
/* The number of entry filled in |iv| */
size_t niv;
/* The number of entries |iv| can store. */
size_t max_niv;
/* How many bytes we still need to receive for current frame */
size_t payloadleft;
/* padding length for the current frame */
size_t padlen;
nghttp2_inbound_state state;
/* Small buffer. Currently the largest contiguous chunk to buffer
is frame header. We buffer part of payload, but they are smaller
than frame header. */
uint8_t raw_sbuf[NGHTTP2_FRAME_HDLEN];
} nghttp2_inbound_frame;
typedef struct {
uint32_t header_table_size;
uint32_t enable_push;
uint32_t max_concurrent_streams;
uint32_t initial_window_size;
uint32_t max_frame_size;
uint32_t max_header_list_size;
} nghttp2_settings_storage;
typedef enum {
NGHTTP2_GOAWAY_NONE = 0,
/* Flag means that connection should be terminated after sending GOAWAY. */
NGHTTP2_GOAWAY_TERM_ON_SEND = 0x1,
/* Flag means GOAWAY to terminate session has been sent */
NGHTTP2_GOAWAY_TERM_SENT = 0x2,
/* Flag means GOAWAY was sent */
NGHTTP2_GOAWAY_SENT = 0x4,
/* Flag means GOAWAY was received */
NGHTTP2_GOAWAY_RECV = 0x8
} nghttp2_goaway_flag;
/* nghttp2_inflight_settings stores the SETTINGS entries which local
endpoint has sent to the remote endpoint, and has not received ACK
yet. */
struct nghttp2_inflight_settings {
struct nghttp2_inflight_settings *next;
nghttp2_settings_entry *iv;
size_t niv;
};
typedef struct nghttp2_inflight_settings nghttp2_inflight_settings;
struct nghttp2_session {
nghttp2_map /* <nghttp2_stream*> */ streams;
/* root of dependency tree*/
nghttp2_stream root;
/* Queue for outbound urgent frames (PING and SETTINGS) */
nghttp2_outbound_queue ob_urgent;
/* Queue for non-DATA frames */
nghttp2_outbound_queue ob_reg;
/* Queue for outbound stream-creating HEADERS (request or push
response) frame, which are subject to
SETTINGS_MAX_CONCURRENT_STREAMS limit. */
nghttp2_outbound_queue ob_syn;
nghttp2_active_outbound_item aob;
nghttp2_inbound_frame iframe;
nghttp2_hd_deflater hd_deflater;
nghttp2_hd_inflater hd_inflater;
nghttp2_session_callbacks callbacks;
/* Memory allocator */
nghttp2_mem mem;
/* Base value when we schedule next DATA frame write. This is
updated when one frame was written. */
uint64_t last_cycle;
void *user_data;
/* Points to the latest incoming closed stream. NULL if there is no
closed stream. Only used when session is initialized as
server. */
nghttp2_stream *closed_stream_head;
/* Points to the oldest incoming closed stream. NULL if there is no
closed stream. Only used when session is initialized as
server. */
nghttp2_stream *closed_stream_tail;
/* Points to the latest idle stream. NULL if there is no idle
stream. Only used when session is initialized as server .*/
nghttp2_stream *idle_stream_head;
/* Points to the oldest idle stream. NULL if there is no idle
stream. Only used when session is initialized as erver. */
nghttp2_stream *idle_stream_tail;
/* Queue of In-flight SETTINGS values. SETTINGS bearing ACK is not
considered as in-flight. */
nghttp2_inflight_settings *inflight_settings_head;
/* The number of outgoing streams. This will be capped by
remote_settings.max_concurrent_streams. */
size_t num_outgoing_streams;
/* The number of incoming streams. This will be capped by
local_settings.max_concurrent_streams. */
size_t num_incoming_streams;
/* The number of incoming reserved streams. This is the number of
streams in reserved (remote) state. RFC 7540 does not limit this
number. nghttp2 offers
nghttp2_option_set_max_reserved_remote_streams() to achieve this.
If it is used, num_incoming_streams is capped by
max_incoming_reserved_streams. Client application should
consider to set this because without that server can send
arbitrary number of PUSH_PROMISE, and exhaust client's memory. */
size_t num_incoming_reserved_streams;
/* The maximum number of incoming reserved streams (reserved
(remote) state). RST_STREAM will be sent for the pushed stream
which exceeds this limit. */
size_t max_incoming_reserved_streams;
/* The number of closed streams still kept in |streams| hash. The
closed streams can be accessed through single linked list
|closed_stream_head|. The current implementation only keeps
incoming streams and session is initialized as server. */
size_t num_closed_streams;
/* The number of idle streams kept in |streams| hash. The idle
streams can be accessed through doubly linked list
|idle_stream_head|. The current implementation only keeps idle
streams if session is initialized as server. */
size_t num_idle_streams;
/* The number of bytes allocated for nvbuf */
size_t nvbuflen;
/* Counter for detecting flooding in outbound queue */
size_t obq_flood_counter_;
/* The maximum length of header block to send. Calculated by the
same way as nghttp2_hd_deflate_bound() does. */
size_t max_send_header_block_length;
/* Next Stream ID. Made unsigned int to detect >= (1 << 31). */
uint32_t next_stream_id;
/* The last stream ID this session initiated. For client session,
this is the last stream ID it has sent. For server session, it
is the last promised stream ID sent in PUSH_PROMISE. */
int32_t last_sent_stream_id;
/* The largest stream ID received so far */
int32_t last_recv_stream_id;
/* The largest stream ID which has been processed in some way. This
value will be used as last-stream-id when sending GOAWAY
frame. */
int32_t last_proc_stream_id;
/* Counter of unique ID of PING. Wraps when it exceeds
NGHTTP2_MAX_UNIQUE_ID */
uint32_t next_unique_id;
/* This is the last-stream-ID we have sent in GOAWAY */
int32_t local_last_stream_id;
/* This is the value in GOAWAY frame received from remote endpoint. */
int32_t remote_last_stream_id;
/* Current sender window size. This value is computed against the
current initial window size of remote endpoint. */
int32_t remote_window_size;
/* Keep track of the number of bytes received without
WINDOW_UPDATE. This could be negative after submitting negative
value to WINDOW_UPDATE. */
int32_t recv_window_size;
/* The number of bytes consumed by the application and now is
subject to WINDOW_UPDATE. This is only used when auto
WINDOW_UPDATE is turned off. */
int32_t consumed_size;
/* The amount of recv_window_size cut using submitting negative
value to WINDOW_UPDATE */
int32_t recv_reduction;
/* window size for local flow control. It is initially set to
NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE and could be
increased/decreased by submitting WINDOW_UPDATE. See
nghttp2_submit_window_update(). */
int32_t local_window_size;
/* Settings value received from the remote endpoint. We just use ID
as index. The index = 0 is unused. */
nghttp2_settings_storage remote_settings;
/* Settings value of the local endpoint. */
nghttp2_settings_storage local_settings;
/* Option flags. This is bitwise-OR of 0 or more of nghttp2_optmask. */
uint32_t opt_flags;
/* Unacked local SETTINGS_MAX_CONCURRENT_STREAMS value. We use this
to refuse the incoming stream if it exceeds this value. */
uint32_t pending_local_max_concurrent_stream;
/* The bitwise OR of zero or more of nghttp2_typemask to indicate
that the default handling of extension frame is enabled. */
uint32_t builtin_recv_ext_types;
/* Unacked local ENABLE_PUSH value. We use this to refuse
PUSH_PROMISE before SETTINGS ACK is received. */
uint8_t pending_enable_push;
/* Nonzero if the session is server side. */
uint8_t server;
/* Flags indicating GOAWAY is sent and/or received. The flags are
composed by bitwise OR-ing nghttp2_goaway_flag. */
uint8_t goaway_flags;
/* This flag is used to reduce excessive queuing of WINDOW_UPDATE to
this session. The nonzero does not necessarily mean
WINDOW_UPDATE is not queued. */
uint8_t window_update_queued;
/* Bitfield of extension frame types that application is willing to
receive. To designate the bit of given frame type i, use
user_recv_ext_types[i / 8] & (1 << (i & 0x7)). First 10 frame
types are standard frame types and not used in this bitfield. If
bit is set, it indicates that incoming frame with that type is
passed to user defined callbacks, otherwise they are ignored. */
uint8_t user_recv_ext_types[32];
};
/* Struct used when updating initial window size of each active
stream. */
typedef struct {
nghttp2_session *session;
int32_t new_window_size, old_window_size;
} nghttp2_update_window_size_arg;
typedef struct {
nghttp2_session *session;
/* linked list of streams to close */
nghttp2_stream *head;
int32_t last_stream_id;
/* nonzero if GOAWAY is sent to peer, which means we are going to
close incoming streams. zero if GOAWAY is received from peer and
we are going to close outgoing streams. */
int incoming;
} nghttp2_close_stream_on_goaway_arg;
/* TODO stream timeout etc */
/*
* Returns nonzero value if |stream_id| is initiated by local
* endpoint.
*/
int nghttp2_session_is_my_stream_id(nghttp2_session *session,
int32_t stream_id);
/*
* Adds |item| to the outbound queue in |session|. When this function
* succeeds, it takes ownership of |item|. So caller must not free it
* on success.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_STREAM_CLOSED
* Stream already closed (DATA and PUSH_PROMISE frame only)
*/
int nghttp2_session_add_item(nghttp2_session *session,
nghttp2_outbound_item *item);
/*
* Adds RST_STREAM frame for the stream |stream_id| with the error
* code |error_code|. This is a convenient function built on top of
* nghttp2_session_add_frame() to add RST_STREAM easily.
*
* This function simply returns 0 without adding RST_STREAM frame if
* given stream is in NGHTTP2_STREAM_CLOSING state, because multiple
* RST_STREAM for a stream is redundant.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
int nghttp2_session_add_rst_stream(nghttp2_session *session, int32_t stream_id,
uint32_t error_code);
/*
* Adds PING frame. This is a convenient functin built on top of
* nghttp2_session_add_frame() to add PING easily.
*
* If the |opaque_data| is not NULL, it must point to 8 bytes memory
* region of data. The data pointed by |opaque_data| is copied. It can
* be NULL. In this case, 8 bytes NULL is used.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_FLOODED
* There are too many items in outbound queue; this only happens
* if NGHTTP2_FLAG_ACK is set in |flags|
*/
int nghttp2_session_add_ping(nghttp2_session *session, uint8_t flags,
const uint8_t *opaque_data);
/*
* Adds GOAWAY frame with the last-stream-ID |last_stream_id| and the
* error code |error_code|. This is a convenient function built on top
* of nghttp2_session_add_frame() to add GOAWAY easily. The
* |aux_flags| are bitwise-OR of one or more of
* nghttp2_goaway_aux_flag.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_INVALID_ARGUMENT
* The |opaque_data_len| is too large.
*/
int nghttp2_session_add_goaway(nghttp2_session *session, int32_t last_stream_id,
uint32_t error_code, const uint8_t *opaque_data,
size_t opaque_data_len, uint8_t aux_flags);
/*
* Adds WINDOW_UPDATE frame with stream ID |stream_id| and
* window-size-increment |window_size_increment|. This is a convenient
* function built on top of nghttp2_session_add_frame() to add
* WINDOW_UPDATE easily.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
*/
int nghttp2_session_add_window_update(nghttp2_session *session, uint8_t flags,
int32_t stream_id,
int32_t window_size_increment);
/*
* Adds SETTINGS frame.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_FLOODED
* There are too many items in outbound queue; this only happens
* if NGHTTP2_FLAG_ACK is set in |flags|
*/
int nghttp2_session_add_settings(nghttp2_session *session, uint8_t flags,
const nghttp2_settings_entry *iv, size_t niv);
/*
* Creates new stream in |session| with stream ID |stream_id|,
* priority |pri_spec| and flags |flags|. The |flags| is bitwise OR
* of nghttp2_stream_flag. Since this function is called when initial
* HEADERS is sent or received, these flags are taken from it. The
* state of stream is set to |initial_state|. The |stream_user_data|
* is a pointer to the arbitrary user supplied data to be associated
* to this stream.
*
* If |initial_state| is NGHTTP2_STREAM_RESERVED, this function sets
* NGHTTP2_STREAM_FLAG_PUSH flag set.
*
* This function returns a pointer to created new stream object, or
* NULL.
*
* This function adjusts neither the number of closed streams or idle
* streams. The caller should manually call
* nghttp2_session_adjust_closed_stream() or
* nghttp2_session_adjust_idle_stream() respectively.
*/
nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session,
int32_t stream_id, uint8_t flags,
nghttp2_priority_spec *pri_spec,
nghttp2_stream_state initial_state,
void *stream_user_data);
/*
* Closes stream whose stream ID is |stream_id|. The reason of closure
* is indicated by the |error_code|. When closing the stream,
* on_stream_close_callback will be called.
*
* If the session is initialized as server and |stream| is incoming
* stream, stream is just marked closed and this function calls
* nghttp2_session_keep_closed_stream() with |stream|. Otherwise,
* |stream| will be deleted from memory.
*
* This function returns 0 if it succeeds, or one the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
* NGHTTP2_ERR_INVALID_ARGUMENT
* The specified stream does not exist.
* NGHTTP2_ERR_CALLBACK_FAILURE
* The callback function failed.
*/
int nghttp2_session_close_stream(nghttp2_session *session, int32_t stream_id,
uint32_t error_code);
/*
* Deletes |stream| from memory. After this function returns, stream
* cannot be accessed.
*
* This function returns 0 if it succeeds, or one the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
int nghttp2_session_destroy_stream(nghttp2_session *session,
nghttp2_stream *stream);
/*
* Tries to keep incoming closed stream |stream|. Due to the
* limitation of maximum number of streams in memory, |stream| is not
* closed and just deleted from memory (see
* nghttp2_session_destroy_stream).
*/
void nghttp2_session_keep_closed_stream(nghttp2_session *session,
nghttp2_stream *stream);
/*
* Appends |stream| to linked list |session->idle_stream_head|. We
* apply fixed limit for list size. To fit into that limit, one or
* more oldest streams are removed from list as necessary.
*/
void nghttp2_session_keep_idle_stream(nghttp2_session *session,
nghttp2_stream *stream);
/*
* Detaches |stream| from idle streams linked list.
*/
void nghttp2_session_detach_idle_stream(nghttp2_session *session,
nghttp2_stream *stream);
/*
* Deletes closed stream to ensure that number of incoming streams
* including active and closed is in the maximum number of allowed
* stream.
*
* This function returns 0 if it succeeds, or one the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
int nghttp2_session_adjust_closed_stream(nghttp2_session *session);
/*
* Deletes idle stream to ensure that number of idle streams is in
* certain limit.
*
* This function returns 0 if it succeeds, or one the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
int nghttp2_session_adjust_idle_stream(nghttp2_session *session);
/*
* If further receptions and transmissions over the stream |stream_id|
* are disallowed, close the stream with error code NGHTTP2_NO_ERROR.
*
* This function returns 0 if it
* succeeds, or one of the following negative error codes:
*
* NGHTTP2_ERR_INVALID_ARGUMENT
* The specified stream does not exist.
*/
int nghttp2_session_close_stream_if_shut_rdwr(nghttp2_session *session,
nghttp2_stream *stream);
int nghttp2_session_on_request_headers_received(nghttp2_session *session,
nghttp2_frame *frame);
int nghttp2_session_on_response_headers_received(nghttp2_session *session,
nghttp2_frame *frame,
nghttp2_stream *stream);
int nghttp2_session_on_push_response_headers_received(nghttp2_session *session,
nghttp2_frame *frame,
nghttp2_stream *stream);
/*
* Called when HEADERS is received, assuming |frame| is properly
* initialized. This function does first validate received frame and
* then open stream and call callback functions.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_IGN_HEADER_BLOCK
* Frame was rejected and header block must be decoded but
* result must be ignored.
* NGHTTP2_ERR_CALLBACK_FAILURE
* The read_callback failed
*/
int nghttp2_session_on_headers_received(nghttp2_session *session,
nghttp2_frame *frame,
nghttp2_stream *stream);
/*
* Called when PRIORITY is received, assuming |frame| is properly
* initialized.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_CALLBACK_FAILURE
* The read_callback failed
*/
int nghttp2_session_on_priority_received(nghttp2_session *session,
nghttp2_frame *frame);
/*
* Called when RST_STREAM is received, assuming |frame| is properly
* initialized.
*
* This function returns 0 if it succeeds, or one the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
* NGHTTP2_ERR_CALLBACK_FAILURE
* The read_callback failed
*/
int nghttp2_session_on_rst_stream_received(nghttp2_session *session,
nghttp2_frame *frame);
/*
* Called when SETTINGS is received, assuming |frame| is properly
* initialized. If |noack| is non-zero, SETTINGS with ACK will not be
* submitted. If |frame| has NGHTTP2_FLAG_ACK flag set, no SETTINGS
* with ACK will not be submitted regardless of |noack|.
*
* This function returns 0 if it succeeds, or one the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
* NGHTTP2_ERR_CALLBACK_FAILURE
* The read_callback failed
* NGHTTP2_ERR_FLOODED
* There are too many items in outbound queue, and this is most
* likely caused by misbehaviour of peer.
*/
int nghttp2_session_on_settings_received(nghttp2_session *session,
nghttp2_frame *frame, int noack);
/*
* Called when PUSH_PROMISE is received, assuming |frame| is properly
* initialized.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_IGN_HEADER_BLOCK
* Frame was rejected and header block must be decoded but
* result must be ignored.
* NGHTTP2_ERR_CALLBACK_FAILURE
* The read_callback failed
*/
int nghttp2_session_on_push_promise_received(nghttp2_session *session,
nghttp2_frame *frame);
/*
* Called when PING is received, assuming |frame| is properly
* initialized.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_CALLBACK_FAILURE
* The callback function failed.
* NGHTTP2_ERR_FLOODED
* There are too many items in outbound queue, and this is most
* likely caused by misbehaviour of peer.
*/
int nghttp2_session_on_ping_received(nghttp2_session *session,
nghttp2_frame *frame);
/*
* Called when GOAWAY is received, assuming |frame| is properly
* initialized.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_CALLBACK_FAILURE
* The callback function failed.
*/
int nghttp2_session_on_goaway_received(nghttp2_session *session,
nghttp2_frame *frame);
/*
* Called when WINDOW_UPDATE is received, assuming |frame| is properly
* initialized.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_CALLBACK_FAILURE
* The callback function failed.
*/
int nghttp2_session_on_window_update_received(nghttp2_session *session,
nghttp2_frame *frame);
/*
* Called when ALTSVC is received, assuming |frame| is properly
* initialized.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_CALLBACK_FAILURE
* The callback function failed.
*/
int nghttp2_session_on_altsvc_received(nghttp2_session *session,
nghttp2_frame *frame);
/*
* Called when DATA is received, assuming |frame| is properly
* initialized.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_CALLBACK_FAILURE
* The callback function failed.
*/
int nghttp2_session_on_data_received(nghttp2_session *session,
nghttp2_frame *frame);
/*
* Returns nghttp2_stream* object whose stream ID is |stream_id|. It
* could be NULL if such stream does not exist. This function returns
* NULL if stream is marked as closed.
*/
nghttp2_stream *nghttp2_session_get_stream(nghttp2_session *session,
int32_t stream_id);
/*
* This function behaves like nghttp2_session_get_stream(), but it
* returns stream object even if it is marked as closed or in
* NGHTTP2_STREAM_IDLE state.
*/
nghttp2_stream *nghttp2_session_get_stream_raw(nghttp2_session *session,
int32_t stream_id);
/*
* Packs DATA frame |frame| in wire frame format and stores it in
* |bufs|. Payload will be read using |aux_data->data_prd|. The
* length of payload is at most |datamax| bytes.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_DEFERRED
* The DATA frame is postponed.
* NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE
* The read_callback failed (stream error).
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_CALLBACK_FAILURE
* The read_callback failed (session error).
*/
int nghttp2_session_pack_data(nghttp2_session *session, nghttp2_bufs *bufs,
size_t datamax, nghttp2_frame *frame,
nghttp2_data_aux_data *aux_data,
nghttp2_stream *stream);
/*
* Pops and returns next item to send. If there is no such item,
* returns NULL. This function takes into account max concurrent
* streams. That means if session->ob_syn has item and max concurrent
* streams is reached, the even if other queues contain items, then
* this function returns NULL.
*/
nghttp2_outbound_item *
nghttp2_session_pop_next_ob_item(nghttp2_session *session);
/*
* Returns next item to send. If there is no such item, this function
* returns NULL. This function takes into account max concurrent
* streams. That means if session->ob_syn has item and max concurrent
* streams is reached, the even if other queues contain items, then
* this function returns NULL.
*/
nghttp2_outbound_item *
nghttp2_session_get_next_ob_item(nghttp2_session *session);
/*
* Updates local settings with the |iv|. The number of elements in the
* array pointed by the |iv| is given by the |niv|. This function
* assumes that the all settings_id member in |iv| are in range 1 to
* NGHTTP2_SETTINGS_MAX, inclusive.
*
* While updating individual stream's local window size, if the window
* size becomes strictly larger than NGHTTP2_MAX_WINDOW_SIZE,
* RST_STREAM is issued against such a stream.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
int nghttp2_session_update_local_settings(nghttp2_session *session,
nghttp2_settings_entry *iv,
size_t niv);
/*
* Re-prioritize |stream|. The new priority specification is
* |pri_spec|. Caller must ensure that stream->hd.stream_id !=
* pri_spec->stream_id.
*
* This function does not adjust the number of idle streams. The
* caller should call nghttp2_session_adjust_idle_stream() later.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
int nghttp2_session_reprioritize_stream(nghttp2_session *session,
nghttp2_stream *stream,
const nghttp2_priority_spec *pri_spec);
/*
* Terminates current |session| with the |error_code|. The |reason|
* is NULL-terminated debug string.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_INVALID_ARGUMENT
* The |reason| is too long.
*/
int nghttp2_session_terminate_session_with_reason(nghttp2_session *session,
uint32_t error_code,
const char *reason);
#endif /* NGHTTP2_SESSION_H */

View file

@ -0,0 +1,436 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGHTTP2_STREAM_H
#define NGHTTP2_STREAM_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h>
#include "nghttp2_outbound_item.h"
#include "nghttp2_map.h"
#include "nghttp2_pq.h"
#include "nghttp2_int.h"
/*
* If local peer is stream initiator:
* NGHTTP2_STREAM_OPENING : upon sending request HEADERS
* NGHTTP2_STREAM_OPENED : upon receiving response HEADERS
* NGHTTP2_STREAM_CLOSING : upon queuing RST_STREAM
*
* If remote peer is stream initiator:
* NGHTTP2_STREAM_OPENING : upon receiving request HEADERS
* NGHTTP2_STREAM_OPENED : upon sending response HEADERS
* NGHTTP2_STREAM_CLOSING : upon queuing RST_STREAM
*/
typedef enum {
/* Initial state */
NGHTTP2_STREAM_INITIAL,
/* For stream initiator: request HEADERS has been sent, but response
HEADERS has not been received yet. For receiver: request HEADERS
has been received, but it does not send response HEADERS yet. */
NGHTTP2_STREAM_OPENING,
/* For stream initiator: response HEADERS is received. For receiver:
response HEADERS is sent. */
NGHTTP2_STREAM_OPENED,
/* RST_STREAM is received, but somehow we need to keep stream in
memory. */
NGHTTP2_STREAM_CLOSING,
/* PUSH_PROMISE is received or sent */
NGHTTP2_STREAM_RESERVED,
/* Stream is created in this state if it is used as anchor in
dependency tree. */
NGHTTP2_STREAM_IDLE
} nghttp2_stream_state;
typedef enum {
NGHTTP2_SHUT_NONE = 0,
/* Indicates further receptions will be disallowed. */
NGHTTP2_SHUT_RD = 0x01,
/* Indicates further transmissions will be disallowed. */
NGHTTP2_SHUT_WR = 0x02,
/* Indicates both further receptions and transmissions will be
disallowed. */
NGHTTP2_SHUT_RDWR = NGHTTP2_SHUT_RD | NGHTTP2_SHUT_WR
} nghttp2_shut_flag;
typedef enum {
NGHTTP2_STREAM_FLAG_NONE = 0,
/* Indicates that this stream is pushed stream and not opened
yet. */
NGHTTP2_STREAM_FLAG_PUSH = 0x01,
/* Indicates that this stream was closed */
NGHTTP2_STREAM_FLAG_CLOSED = 0x02,
/* Indicates the item is deferred due to flow control. */
NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL = 0x04,
/* Indicates the item is deferred by user callback */
NGHTTP2_STREAM_FLAG_DEFERRED_USER = 0x08,
/* bitwise OR of NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL and
NGHTTP2_STREAM_FLAG_DEFERRED_USER. */
NGHTTP2_STREAM_FLAG_DEFERRED_ALL = 0x0c
} nghttp2_stream_flag;
/* HTTP related flags to enforce HTTP semantics */
typedef enum {
NGHTTP2_HTTP_FLAG_NONE = 0,
/* header field seen so far */
NGHTTP2_HTTP_FLAG__AUTHORITY = 1,
NGHTTP2_HTTP_FLAG__PATH = 1 << 1,
NGHTTP2_HTTP_FLAG__METHOD = 1 << 2,
NGHTTP2_HTTP_FLAG__SCHEME = 1 << 3,
/* host is not pseudo header, but we require either host or
:authority */
NGHTTP2_HTTP_FLAG_HOST = 1 << 4,
NGHTTP2_HTTP_FLAG__STATUS = 1 << 5,
/* required header fields for HTTP request except for CONNECT
method. */
NGHTTP2_HTTP_FLAG_REQ_HEADERS = NGHTTP2_HTTP_FLAG__METHOD |
NGHTTP2_HTTP_FLAG__PATH |
NGHTTP2_HTTP_FLAG__SCHEME,
NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED = 1 << 6,
/* HTTP method flags */
NGHTTP2_HTTP_FLAG_METH_CONNECT = 1 << 7,
NGHTTP2_HTTP_FLAG_METH_HEAD = 1 << 8,
NGHTTP2_HTTP_FLAG_METH_OPTIONS = 1 << 9,
NGHTTP2_HTTP_FLAG_METH_UPGRADE_WORKAROUND = 1 << 10,
NGHTTP2_HTTP_FLAG_METH_ALL = NGHTTP2_HTTP_FLAG_METH_CONNECT |
NGHTTP2_HTTP_FLAG_METH_HEAD |
NGHTTP2_HTTP_FLAG_METH_OPTIONS |
NGHTTP2_HTTP_FLAG_METH_UPGRADE_WORKAROUND,
/* :path category */
/* path starts with "/" */
NGHTTP2_HTTP_FLAG_PATH_REGULAR = 1 << 11,
/* path "*" */
NGHTTP2_HTTP_FLAG_PATH_ASTERISK = 1 << 12,
/* scheme */
/* "http" or "https" scheme */
NGHTTP2_HTTP_FLAG_SCHEME_HTTP = 1 << 13,
/* set if final response is expected */
NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE = 1 << 14
} nghttp2_http_flag;
struct nghttp2_stream {
/* Intrusive Map */
nghttp2_map_entry map_entry;
/* Entry for dep_prev->obq */
nghttp2_pq_entry pq_entry;
/* Priority Queue storing direct descendant (nghttp2_stream). Only
streams which itself has some data to send, or has a descendant
which has some data to sent. */
nghttp2_pq obq;
/* Content-Length of request/response body. -1 if unknown. */
int64_t content_length;
/* Received body so far */
int64_t recv_content_length;
/* Base last_cycle for direct descendent streams. */
uint32_t descendant_last_cycle;
/* Next scheduled time to sent item */
uint32_t cycle;
/* Next seq used for direct descendant streams */
uint64_t descendant_next_seq;
/* Secondary key for prioritization to break a tie for cycle. This
value is monotonically increased for single parent stream. */
uint64_t seq;
/* pointers to form dependency tree. If multiple streams depend on
a stream, only one stream (left most) has non-NULL dep_prev which
points to the stream it depends on. The remaining streams are
linked using sib_prev and sib_next. The stream which has
non-NULL dep_prev always NULL sib_prev. The right most stream
has NULL sib_next. If this stream is a root of dependency tree,
dep_prev and sib_prev are NULL. */
nghttp2_stream *dep_prev, *dep_next;
nghttp2_stream *sib_prev, *sib_next;
/* When stream is kept after closure, it may be kept in doubly
linked list pointed by nghttp2_session closed_stream_head.
closed_next points to the next stream object if it is the element
of the list. */
nghttp2_stream *closed_prev, *closed_next;
/* The arbitrary data provided by user for this stream. */
void *stream_user_data;
/* Item to send */
nghttp2_outbound_item *item;
/* Last written length of frame payload */
size_t last_writelen;
/* stream ID */
int32_t stream_id;
/* Current remote window size. This value is computed against the
current initial window size of remote endpoint. */
int32_t remote_window_size;
/* Keep track of the number of bytes received without
WINDOW_UPDATE. This could be negative after submitting negative
value to WINDOW_UPDATE */
int32_t recv_window_size;
/* The number of bytes consumed by the application and now is
subject to WINDOW_UPDATE. This is only used when auto
WINDOW_UPDATE is turned off. */
int32_t consumed_size;
/* The amount of recv_window_size cut using submitting negative
value to WINDOW_UPDATE */
int32_t recv_reduction;
/* window size for local flow control. It is initially set to
NGHTTP2_INITIAL_WINDOW_SIZE and could be increased/decreased by
submitting WINDOW_UPDATE. See nghttp2_submit_window_update(). */
int32_t local_window_size;
/* weight of this stream */
int32_t weight;
/* This is unpaid penalty (offset) when calculating cycle. */
uint32_t pending_penalty;
/* sum of weight of direct descendants */
int32_t sum_dep_weight;
nghttp2_stream_state state;
/* status code from remote server */
int16_t status_code;
/* Bitwise OR of zero or more nghttp2_http_flag values */
uint16_t http_flags;
/* This is bitwise-OR of 0 or more of nghttp2_stream_flag. */
uint8_t flags;
/* Bitwise OR of zero or more nghttp2_shut_flag values */
uint8_t shut_flags;
/* Nonzero if this stream has been queued to stream pointed by
dep_prev. We maintain the invariant that if a stream is queued,
then its ancestors, except for root, are also queued. This
invariant may break in fatal error condition. */
uint8_t queued;
/* This flag is used to reduce excessive queuing of WINDOW_UPDATE to
this stream. The nonzero does not necessarily mean WINDOW_UPDATE
is not queued. */
uint8_t window_update_queued;
};
void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
uint8_t flags, nghttp2_stream_state initial_state,
int32_t weight, int32_t remote_initial_window_size,
int32_t local_initial_window_size,
void *stream_user_data, nghttp2_mem *mem);
void nghttp2_stream_free(nghttp2_stream *stream);
/*
* Disallow either further receptions or transmissions, or both.
* |flag| is bitwise OR of one or more of nghttp2_shut_flag.
*/
void nghttp2_stream_shutdown(nghttp2_stream *stream, nghttp2_shut_flag flag);
/*
* Defer |stream->item|. We won't call this function in the situation
* where |stream->item| == NULL. The |flags| is bitwise OR of zero or
* more of NGHTTP2_STREAM_FLAG_DEFERRED_USER and
* NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL. The |flags| indicates
* the reason of this action.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
int nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags);
/*
* Put back deferred data in this stream to active state. The |flags|
* are one or more of bitwise OR of the following values:
* NGHTTP2_STREAM_FLAG_DEFERRED_USER and
* NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL and given masks are
* cleared if they are set. So even if this function is called, if
* one of flag is still set, data does not become active.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
int nghttp2_stream_resume_deferred_item(nghttp2_stream *stream, uint8_t flags);
/*
* Returns nonzero if item is deferred by whatever reason.
*/
int nghttp2_stream_check_deferred_item(nghttp2_stream *stream);
/*
* Returns nonzero if item is deferred by flow control.
*/
int nghttp2_stream_check_deferred_by_flow_control(nghttp2_stream *stream);
/*
* Updates the remote window size with the new value
* |new_initial_window_size|. The |old_initial_window_size| is used to
* calculate the current window size.
*
* This function returns 0 if it succeeds or -1. The failure is due to
* overflow.
*/
int nghttp2_stream_update_remote_initial_window_size(
nghttp2_stream *stream, int32_t new_initial_window_size,
int32_t old_initial_window_size);
/*
* Updates the local window size with the new value
* |new_initial_window_size|. The |old_initial_window_size| is used to
* calculate the current window size.
*
* This function returns 0 if it succeeds or -1. The failure is due to
* overflow.
*/
int nghttp2_stream_update_local_initial_window_size(
nghttp2_stream *stream, int32_t new_initial_window_size,
int32_t old_initial_window_size);
/*
* Call this function if promised stream |stream| is replied with
* HEADERS. This function makes the state of the |stream| to
* NGHTTP2_STREAM_OPENED.
*/
void nghttp2_stream_promise_fulfilled(nghttp2_stream *stream);
/*
* Returns nonzero if |target| is an ancestor of |stream|.
*/
int nghttp2_stream_dep_find_ancestor(nghttp2_stream *stream,
nghttp2_stream *target);
/*
* Computes distributed weight of a stream of the |weight| under the
* |stream| if |stream| is removed from a dependency tree.
*/
int32_t nghttp2_stream_dep_distributed_weight(nghttp2_stream *stream,
int32_t weight);
/*
* Makes the |stream| depend on the |dep_stream|. This dependency is
* exclusive. All existing direct descendants of |dep_stream| become
* the descendants of the |stream|. This function assumes
* |stream->item| is NULL.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
int nghttp2_stream_dep_insert(nghttp2_stream *dep_stream,
nghttp2_stream *stream);
/*
* Makes the |stream| depend on the |dep_stream|. This dependency is
* not exclusive. This function assumes |stream->item| is NULL.
*/
void nghttp2_stream_dep_add(nghttp2_stream *dep_stream, nghttp2_stream *stream);
/*
* Removes the |stream| from the current dependency tree. This
* function assumes |stream->item| is NULL.
*/
int nghttp2_stream_dep_remove(nghttp2_stream *stream);
/*
* Attaches |item| to |stream|.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
int nghttp2_stream_attach_item(nghttp2_stream *stream,
nghttp2_outbound_item *item);
/*
* Detaches |stream->item|. This function does not free
* |stream->item|. The caller must free it.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
int nghttp2_stream_detach_item(nghttp2_stream *stream);
/*
* Makes the |stream| depend on the |dep_stream|. This dependency is
* exclusive.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
nghttp2_stream *stream);
/*
* Makes the |stream| depend on the |dep_stream|. This dependency is
* not exclusive.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream,
nghttp2_stream *stream);
/*
* Removes subtree whose root stream is |stream|. The
* effective_weight of streams in removed subtree is not updated.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream);
/*
* Returns nonzero if |stream| is in any dependency tree.
*/
int nghttp2_stream_in_dep_tree(nghttp2_stream *stream);
/*
* Schedules transmission of |stream|'s item, assuming stream->item is
* attached, and stream->last_writelen was updated.
*/
void nghttp2_stream_reschedule(nghttp2_stream *stream);
/*
* Changes |stream|'s weight to |weight|. If |stream| is queued, it
* will be rescheduled based on new weight.
*/
void nghttp2_stream_change_weight(nghttp2_stream *stream, int32_t weight);
/*
* Returns a stream which has highest priority, updating
* descendant_last_cycle of selected stream's ancestors.
*/
nghttp2_outbound_item *
nghttp2_stream_next_outbound_item(nghttp2_stream *stream);
#endif /* NGHTTP2_STREAM */

View file

@ -0,0 +1,34 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGHTTP2_SUBMIT_H
#define NGHTTP2_SUBMIT_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h>
#endif /* NGHTTP2_SUBMIT_H */

View file

@ -0,0 +1,224 @@
/**
******************************************************************************
* @file httpc.h
* @author
* @version
* @brief This file provides user interface for HTTP/HTTPS client.
******************************************************************************
* @attention
*
* This module is a confidential and proprietary property of RealTek and possession or use of this module requires written permission of RealTek.
*
* Copyright(c) 2016, Realtek Semiconductor Corporation. All rights reserved.
******************************************************************************
*/
#ifndef _HTTPC_H_
#define _HTTPC_H_
/** @addtogroup httpc HTTPC
* @ingroup network
* @brief HTTP/HTTPS client functions
* @{
*/
#include "platform_stdlib.h"
#include "platform_opts.h"
#define HTTPC_SECURE_NONE 0 /*!< Running with HTTP client */
#define HTTPC_SECURE_TLS 1 /*!< Running with HTTPS client */
#define HTTPC_DEBUG_OFF 0 /*!< Disable httpc debug log */
#define HTTPC_DEBUG_ON 1 /*!< Enable httpc debug log */
#define HTTPC_DEBUG_VERBOSE 2 /*!< Enable httpc verbose debug log */
#define HTTPC_TLS_POLARSSL 0 /*!< Use PolarSSL for TLS when HTTPS */
#define HTTPC_TLS_MBEDTLS 1 /*!< Use mbedTLS for TLS when HTTPS */
#if CONFIG_USE_POLARSSL
#define HTTPC_USE_TLS HTTPC_TLS_POLARSSL
#elif CONFIG_USE_MBEDTLS
#define HTTPC_USE_TLS HTTPC_TLS_MBEDTLS
#endif
/**
* @brief The structure is the context used for HTTP response header parsing.
* @note Only header string includes string terminator.
*/
struct http_response {
uint8_t *header; /*!< HTTP header string parsed in HTTP response */
size_t header_len; /*!< HTTP header string length */
uint8_t *version; /*!< Pointer to HTTP version in the parsed HTTP header string */
size_t version_len; /*!< HTTP version data length */
uint8_t *status; /*!< Pointer to HTTP status code in the parsed HTTP header string */
size_t status_len; /*!< HTTP status code data length */
uint8_t *content_type; /*!< Pointer to Content-Type header field in the parsed HTTP header string */
size_t content_type_len; /*!< Content-Type header field data length */
size_t content_len; /*!< Value of Content-Length header field parsed in HTTP header string */
};
/**
* @brief The structure is the context used for connection.
*/
struct httpc_conn {
int ignore_content_len;
int sock; /*!< Client socket descriptor for connection */
struct http_response response; /*!< Context for HTTP response */
void *tls; /*!< Context for TLS connection */
uint8_t *request_header; /*!< Pointer to transmission buffer of HTTP request header */
char *host; /*!< String of server host name or IP */
uint16_t port; /*!< Service port */
char *user_password; /*!< Base64 string for HTTP basic authorization */
};
/**
* @brief This function is used to generate connection context for an HTTP/HTTPS client.
* @param[in] secure: security mode for HTTP or HTTPS. Must be HTTPC_SECURE_NONE, HTTPC_SECURE_TLS.
* @param[in] client_cert: string of client certificate if required to be verified by server.
* @param[in] client_key: string of client private key if required to be verified by server.
* @param[in] ca_certs: string including certificates in CA trusted chain if want to verify server certificate.
* @return pointer to the generated connection context
*/
struct httpc_conn *httpc_conn_new(uint8_t secure, char *client_cert, char *client_key, char *ca_certs);
/**
* @brief This function is used to deallocate a connection context.
* @param[in] conn: pointer to connection context
* @return None
*/
void httpc_conn_free(struct httpc_conn *conn);
/**
* @brief This function is used to connect to a server.
* @param[in] conn: pointer to connection context
* @param[in] host: string of server host name or IP
* @param[in] port: service port
* @param[in] timeout: connection timeout in seconds
* @return 0 : if successful
* @return -1 : if error occurred
*/
int httpc_conn_connect(struct httpc_conn *conn, char *host, uint16_t port, uint32_t timeout);
/**
* @brief This function is used to close connection from a server.
* @param[in] conn: pointer to connection context
* @return None
*/
void httpc_conn_close(struct httpc_conn *conn);
/**
* @brief This function is used to setup authorization for connection.
* @param[in] conn: pointer to connection context
* @param[in] user: string of user name for authorization
* @param[in] password: string of password for authorization
* @return 0 : if successful
* @return -1 : if error occurred
* @note Must be used before httpc_conn_connect() if basic authorization is used
*/
int httpc_conn_setup_user_password(struct httpc_conn *conn, char *user, char *password);
/**
* @brief This function is used to setup httpc debug.
* @param[in] debug: flag to enable/disable httpc debug. Must be HTTPC_DEBUG_OFF, HTTPC_DEBUG_ON, HTTPC_DEBUG_VERBOSE.
* @return None
*/
void httpc_setup_debug(uint8_t debug);
/**
* @brief This function is used to enable ignoring content_len eqauls 0.
* @param[in] conn: pointer to connection context.
* @return None
*/
void httpc_enable_ignore_content_len(struct httpc_conn *conn);
/**
* @brief This function is used to free memory allocated by httpc API, such as httpc_response_get_header_field().
* @param[in] ptr: pointer to memory to be deallocated
* @return None
*/
void httpc_free(void *ptr);
/**
* @brief This function is used to dump the parsed HTTP header of response in connection context.
* @param[in] conn: pointer to connection context
* @return None
*/
void httpc_conn_dump_header(struct httpc_conn *conn);
/**
* @brief This function is used to start a HTTP request in connection.
* @param[in] conn: pointer to connection context
* @param[in] method: string of HTTP method in HTTP request
* @param[in] resource: string including path and query string to identify a resource
* @param[in] content_type: string of Content-Type header field written to HTTP request. No Content-Type in HTTP request if NULL.
* @param[in] content_len: value of Content-Length header field written to HTTP request. No Content-Length in HTTP request if NULL.
* @return 0 : if successful
* @return -1 : if error occurred
*/
int httpc_request_write_header_start(struct httpc_conn *conn, char *method, char *resource, char *content_type, size_t content_len);
/**
* @brief This function is used to add an HTTP header field to HTTP request.
* @param[in] conn: pointer to connection context
* @param[in] name: HTTP header field name string
* @param[in] value: HTTP header field value
* @return 0 : if successful
* @return -1 : if error occurred
*/
int httpc_request_write_header(struct httpc_conn *conn, char *name, char *value);
/**
* @brief This function is used to write HTTP request header data to connection.
* @param[in] conn: pointer to connection context
* @return return value of lwip socket write() for HTTP and PolarSSL ssl_write() for HTTPS
*/
int httpc_request_write_header_finish(struct httpc_conn *conn);
/**
* @brief This function is used to write HTTP request body data to connection.
* @param[in] conn: pointer to connection context
* @param[in] data: data to be written
* @param[in] data_len: data length
* @return return value of lwip socket write() for HTTP and PolarSSL ssl_write() for HTTPS
*/
int httpc_request_write_data(struct httpc_conn *conn, uint8_t *data, size_t data_len);
/**
* @brief This function is used to check HTTP status of response in connection context.
* @param[in] conn: pointer to connection context
* @param[in] status: HTTP status string to compare with
* @return 0 : if different
* @return 1 : if matched
*/
int httpc_response_is_status(struct httpc_conn *conn, char *status);
/**
* @brief This function is used to read HTTP header from client socket descriptor and parse content to connection context.
* @param[in] conn: pointer to connection context
* @return 0 : if successful
* @return -1 : if error occurred
*/
int httpc_response_read_header(struct httpc_conn *conn);
/**
* @brief This function is used to read data from HTTP/HTTPS connection.
* @param[in] conn: pointer to connection context
* @param[out] data: buffer for data read
* @param[in] data_len: buffer length
* @return return value of lwip socket read() for HTTP and PolarSSL ssl_read() for HTTPS
*/
int httpc_response_read_data(struct httpc_conn *conn, uint8_t *data, size_t data_len);
/**
* @brief This function is used to get a header field from HTTP header of connection context.
* @param[in] conn: pointer to connection context
* @param[in] field: header field string to search
* @param[out] value: search result stored in memory allocated
* @return 0 : if found
* @return -1 : if not found
* @note The search result memory should be free by httpc_free().
*/
int httpc_response_get_header_field(struct httpc_conn *conn, char *field, char **value);
/*\@}*/
#endif /* _HTTPC_H_ */

View file

@ -0,0 +1,42 @@
#ifndef _HTTPC_UTIL_H_
#define _HTTPC_UTIL_H_
#include "httpc.h"
extern uint8_t httpc_debug;
#define httpc_log(...) \
do { \
if(httpc_debug) { \
rtw_enter_critical(NULL, NULL); \
printf("\n\r[HTTPC] "); \
printf(__VA_ARGS__); \
printf("\n\r"); \
rtw_exit_critical(NULL, NULL); \
} \
} while(0)
#define httpc_log_verbose(...) \
do { \
if(httpc_debug == HTTPC_DEBUG_VERBOSE) { \
rtw_enter_critical(NULL, NULL); \
printf("\n\r[HTTPC] "); \
printf(__VA_ARGS__); \
printf("\n\r"); \
rtw_exit_critical(NULL, NULL); \
} \
} while(0)
void *httpc_malloc(size_t size);
int httpc_write(struct httpc_conn *conn, uint8_t *buf, size_t buf_len);
int httpc_read(struct httpc_conn *conn, uint8_t *buf, size_t buf_len);
void *httpc_tls_new(int *sock, char *client_cert, char *client_key, char *ca_certs);
void httpc_tls_free(void *tls_in);
int httpc_tls_handshake(void *tls_in, char *host);
void httpc_tls_close(void *tls_in);
int httpc_tls_read(void *tls_in, uint8_t *buf, size_t buf_len);
int httpc_tls_write(void *tls_in, uint8_t *buf, size_t buf_len);
int httpc_base64_encode(uint8_t *data, size_t data_len, char *base64_buf, size_t buf_len);
#endif /* _HTTPD_UTIL_H_ */

View file

@ -0,0 +1,314 @@
/**
******************************************************************************
* @file httpd.h
* @author
* @version
* @brief This file provides user interface for HTTP/HTTPS server.
******************************************************************************
* @attention
*
* This module is a confidential and proprietary property of RealTek and possession or use of this module requires written permission of RealTek.
*
* Copyright(c) 2016, Realtek Semiconductor Corporation. All rights reserved.
******************************************************************************
*/
#ifndef _HTTPD_H_
#define _HTTPD_H_
/** @addtogroup httpd HTTPD
* @ingroup network
* @brief HTTP/HTTPS server functions
* @{
*/
#include "platform_stdlib.h"
#include "platform_opts.h"
#define HTTPD_SECURE_NONE 0 /*!< Running with HTTP server */
#define HTTPD_SECURE_TLS 1 /*!< Running with HTTPS server */
#define HTTPD_SECURE_TLS_VERIFY 2 /*!< Running with HTTPS server and verify client */
#define HTTPD_THREAD_SINGLE 0 /*!< Single-thread mode for request handling */
#define HTTPD_THREAD_MULTIPLE 1 /*!< Multi-thread mode for request handling */
#define HTTPD_DEBUG_OFF 0 /*!< Disable httpd debug log */
#define HTTPD_DEBUG_ON 1 /*!< Enable httpd debug log */
#define HTTPD_DEBUG_VERBOSE 2 /*!< Enable httpd verbose debug log */
#define HTTPD_TLS_POLARSSL 0 /*!< Use PolarSSL for TLS when HTTPS */
#define HTTPD_TLS_MBEDTLS 1 /*!< Use mbedTLS for TLS when HTTPS */
#if CONFIG_USE_POLARSSL
#define HTTPD_USE_TLS HTTPD_TLS_POLARSSL
#elif CONFIG_USE_MBEDTLS
#define HTTPD_USE_TLS HTTPD_TLS_MBEDTLS
#endif
/**
* @brief The structure is the context used for HTTP request header parsing.
* @note Only header string includes string terminator.
*/
struct http_request {
uint8_t *header; /*!< HTTP header string parsed in HTTP request */
size_t header_len; /*!< HTTP header string length */
uint8_t *method; /*!< Pointer to HTTP method in the parsed HTTP header string */
size_t method_len; /*!< HTTP method data length */
uint8_t *path; /*!< Pointer to resource path in the parsed HTTP header string */
size_t path_len; /*!< Resource path data length */
uint8_t *query; /*!< Pointer to query string in the parsed HTTP header string */
size_t query_len; /*!< Query string data length */
uint8_t *version; /*!< Pointer to HTTP version in the parsed HTTP header string */
size_t version_len; /*!< HTTP version data length */
uint8_t *host; /*!< Pointer to Host header field in the parsed HTTP header string */
size_t host_len; /*!< Host header field data length */
uint8_t *content_type; /*!< Pointer to Content-Type header field in the parsed HTTP header string */
size_t content_type_len; /*!< Content-Type header field data length */
size_t content_len; /*!< Value of Content-Length header field parsed in HTTP header string */
};
/**
* @brief The structure is the context used for client connection.
*/
struct httpd_conn {
int sock; /*!< Client socket descriptor for connection */
struct http_request request; /*!< Context for HTTP request */
void *tls; /*!< Context for TLS connection */
uint8_t *response_header; /*!< Pointer to transmission buffer of HTTP response header */
uint32_t last_req_time; /*!< Last request time in system ticks */
};
/**
* @brief This function is used to start an HTTP or HTTPS server.
* @param[in] port: service port
* @param[in] max_conn: max client connections allowed
* @param[in] stack_bytes: thread stack size in bytes
* @param[in] thread_mode: server running thread mode. Must be HTTPD_THREAD_SINGLE, HTTPD_THREAD_MULTIPLE.
* @param[in] secure: security mode for HTTP or HTTPS. Must be HTTPD_SECURE_NONE, HTTPD_SECURE_TLS, HTTPD_SECURE_TLS_VERIFY.
* @return 0 : if successful
* @return -1 : if error occurred
*/
int httpd_start(uint16_t port, uint8_t max_conn, uint32_t stack_bytes, uint8_t thread_mode, uint8_t secure);
/**
* @brief This function is used to stop a running server
* @return None
*/
void httpd_stop(void);
/**
* @brief This function is used to check whether httpd server is running
* @return 1 : if is running
* @return 0 : if is not running
*/
int httpd_is_running(void);
/**
* @brief This function is used to register a callback function for a Web page request handling.
* @param[in] path: resource path for a page
* @param[in] callback: callback function to handle the request to page
* @return 0 : if successful
* @return -1 : if error occurred
*/
int httpd_reg_page_callback(char *path, void (*callback)(struct httpd_conn *conn));
/**
* @brief This function is used to clear all registered page callback functions.
* @return None
* @note All page callback will be cleared automatically if httpd_stop().
*/
void httpd_clear_page_callbacks(void);
/**
* @brief This function is used to setup httpd debug.
* @param[in] debug: flag to enable/disable httpd debug. Must be HTTPD_DEBUG_OFF, HTTPD_DEBUG_ON, HTTPD_DEBUG_VERBOSE.
* @return None
*/
void httpd_setup_debug(uint8_t debug);
/**
* @brief This function is used to setup connection idle timeout for server.
* @param[in] idle_timeout: timeout in seconds
* @return None
*/
void httpd_setup_idle_timeout(int idle_timeout);
/**
* @brief This function is used to setup certificate and key for server before starting with HTTPS.
* @param[in] server_cert: string of server certificate
* @param[in] server_key: string of server private key
* @param[in] ca_certs: string including certificates in CA trusted chain
* @return 0 : if successful
* @return -1 : if error occurred
* @note Must be used before httpd_start() if staring HTTPS server
*/
int httpd_setup_cert(const char *server_cert, const char *server_key, const char *ca_certs);
/**
* @brief This function is used to setup authorization for server.
* @param[in] user: string of user name for authorization
* @param[in] password: string of password for authorization
* @return 0 : if successful
* @return -1 : if error occurred
* @note Must be used before httpd_start() if basic authorization is used
*/
int httpd_setup_user_password(char *user, char *password);
/**
* @brief This function is used to free memory allocated by httpd API, such as httpd_request_get_header_field() and httpd_request_get_query_key().
* @param[in] ptr: pointer to memory to be deallocated
* @return None
*/
void httpd_free(void *ptr);
/**
* @brief This function is used to close a client connection and release context resource.
* @param[in] conn: pointer to connection context
* @return None
* @note Multiple requests/response can be handled in a connection before connection closed. All connections will be closed automatically if httpd_stop().
*/
void httpd_conn_close(struct httpd_conn *conn);
/**
* @brief This function is used to dump the parsed HTTP header of request in connection context.
* @param[in] conn: pointer to connection context
* @return None
*/
void httpd_conn_dump_header(struct httpd_conn *conn);
/**
* @brief This function is used to check HTTP method of request in connection context.
* @param[in] conn: pointer to connection context
* @param[in] method: HTTP method string to compare with
* @return 0 : if different
* @return 1 : if matched
*/
int httpd_request_is_method(struct httpd_conn *conn, char *method);
/**
* @brief This function is used to read HTTP header from client socket descriptor and parse content to connection context.
* @param[in] conn: pointer to connection context
* @return 0 : if successful
* @return -1 : if error occurred
* @note httpd_request_read_header() is automatically invoked by httpd server to parse request before executing page callback
*/
int httpd_request_read_header(struct httpd_conn *conn);
/**
* @brief This function is used to read data from HTTP/HTTPS connection.
* @param[in] conn: pointer to connection context
* @param[out] data: buffer for data read
* @param[in] data_len: buffer length
* @return return value of lwip socket read() for HTTP and PolarSSL ssl_read() for HTTPS
*/
int httpd_request_read_data(struct httpd_conn *conn, uint8_t *data, size_t data_len);
/**
* @brief This function is used to get a header field from HTTP header of connection context.
* @param[in] conn: pointer to connection context
* @param[in] field: header field string to search
* @param[out] value: search result stored in memory allocated
* @return 0 : if found
* @return -1 : if not found
* @note The search result memory should be free by httpd_free().
*/
int httpd_request_get_header_field(struct httpd_conn *conn, char *field, char **value);
/**
* @brief This function is used to get a key value from query string in HTTP header of connection context.
* @param[in] conn: pointer to connection context
* @param[in] key: key name string to search
* @param[out] value: search result stored in memory allocated
* @return 0 : if found
* @return -1 : if not found
* @note The search result memory should be free by httpd_free().
*/
int httpd_request_get_query_key(struct httpd_conn *conn, char *key, char **value);
/**
* @brief This function is used to start a HTTP response in connection.
* @param[in] conn: pointer to connection context
* @param[in] status: string of status code in HTTP response
* @param[in] content_type: string of Content-Type header field written to HTTP response. No Content-Type in HTTP response if NULL.
* @param[in] content_len: value of Content-Length header field written to HTTP response. No Content-Length in HTTP response if NULL.
* @return 0 : if successful
* @return -1 : if error occurred
*/
int httpd_response_write_header_start(struct httpd_conn *conn, char *status, char *content_type, size_t content_len);
/**
* @brief This function is used to add an HTTP header field to HTTP response.
* @param[in] conn: pointer to connection context
* @param[in] name: HTTP header field name string
* @param[in] value: HTTP header field value
* @return 0 : if successful
* @return -1 : if error occurred
*/
int httpd_response_write_header(struct httpd_conn *conn, char *name, char *value);
/**
* @brief This function is used to write HTTP response header data to connection.
* @param[in] conn: pointer to connection context
* @return return value of lwip socket write() for HTTP and PolarSSL ssl_write() for HTTPS
*/
int httpd_response_write_header_finish(struct httpd_conn *conn);
/**
* @brief This function is used to write HTTP response body data to connection.
* @param[in] conn: pointer to connection context
* @param[in] data: data to be written
* @param[in] data_len: data length
* @return return value of lwip socket write() for HTTP and PolarSSL ssl_write() for HTTPS
*/
int httpd_response_write_data(struct httpd_conn *conn, uint8_t *data, size_t data_len);
/**
* @brief This function is used to write a default HTTP response for error of 400 Bad Request.
* @param[in] conn: pointer to connection context
* @param[in] msg: message write to HTTP response body. A default message will be used if NULL.
* @return None
*/
void httpd_response_bad_request(struct httpd_conn *conn, char *msg);
/**
* @brief This function is used to write a default HTTP response for error of 401 Unauthorized.
* @param[in] conn: pointer to connection context
* @param[in] msg: message write to HTTP response body. A default message will be used if NULL.
* @return None
*/
void httpd_response_unauthorized(struct httpd_conn *conn, char *msg);
/**
* @brief This function is used to write a default HTTP response for error of 404 Not Found.
* @param[in] conn: pointer to connection context
* @param[in] msg: message write to HTTP response body. A default message will be used if NULL.
* @return None
*/
void httpd_response_not_found(struct httpd_conn *conn, char *msg);
/**
* @brief This function is used to write a default HTTP response for error of 405 Method Not Allowed.
* @param[in] conn: pointer to connection context
* @param[in] msg: message write to HTTP response body. A default message will be used if NULL.
* @return None
*/
void httpd_response_method_not_allowed(struct httpd_conn *conn, char *msg);
/**
* @brief This function is used to write a default HTTP response for error of 429 Too Many Requests.
* @param[in] conn: pointer to connection context
* @param[in] msg: message write to HTTP response body. A default message will be used if NULL.
* @return None
*/
void httpd_response_too_many_requests(struct httpd_conn *conn, char *msg);
/**
* @brief This function is used to write a default HTTP response for error of 500 Internal Server Error.
* @param[in] conn: pointer to connection context
* @param[in] msg: message write to HTTP response body. A default message will be used if NULL.
* @return None
*/
void httpd_response_internal_server_error(struct httpd_conn *conn, char *msg);
/*\@}*/
#endif /* _HTTPD_H_ */

View file

@ -0,0 +1,16 @@
#ifndef _HTTPD_INT_H_
#define _HTTPD_INT_H_
#include "httpd.h"
int httpd_init(void);
void httpd_deinit(void);
void httpd_setup(uint16_t port, uint8_t max_conn, uint8_t secure);
int httpd_return_server_sock(void);
int httpd_accept(int server_sock, struct httpd_conn **client_conn, int accept_timeout);
int httpd_write(struct httpd_conn *conn, uint8_t *buf, size_t buf_len);
int httpd_read(struct httpd_conn *conn, uint8_t *buf, size_t buf_len);
int httpd_read_with_timeout(struct httpd_conn *conn, uint8_t *buf, uint16_t buf_len, int recv_timeout);
#endif /* _HTTPD_INT_H_ */

View file

@ -0,0 +1,57 @@
#ifndef _HTTPD_UTIL_H_
#define _HTTPD_UTIL_H_
#include "httpd.h"
extern uint8_t httpd_debug;
#define httpd_log(...) \
do { \
if(httpd_debug) { \
taskENTER_CRITICAL(); \
printf("\n\r[HTTPD] "); \
printf(__VA_ARGS__); \
printf("\n\r"); \
taskEXIT_CRITICAL(); \
} \
} while(0)
#define httpd_log_verbose(...) \
do { \
if(httpd_debug == HTTPD_DEBUG_VERBOSE) { \
taskENTER_CRITICAL(); \
printf("\n\r[HTTPD] "); \
printf(__VA_ARGS__); \
printf("\n\r"); \
taskEXIT_CRITICAL(); \
} \
} while(0)
struct httpd_page {
struct httpd_page *next;
char *path;
void (*callback)(struct httpd_conn *conn);
};
void *httpd_malloc(size_t size);
int httpd_page_add(char *path, void (*callback)(struct httpd_conn *conn));
void httpd_page_remove(struct httpd_page *page);
void httpd_page_clear(void);
struct httpd_conn *httpd_conn_add(int sock);
void httpd_conn_remove(struct httpd_conn *conn);
void httpd_conn_clear(void);
void httpd_query_remove_special(uint8_t *input, size_t input_len, uint8_t *output, size_t output_len);
int httpd_write(struct httpd_conn *conn, uint8_t *buf, size_t buf_len);
int httpd_read(struct httpd_conn *conn, uint8_t *buf, size_t buf_len);
int httpd_read_with_timeout(struct httpd_conn *conn, uint8_t *buf, uint16_t buf_len, int recv_timeout);
int httpd_tls_setup_init(const char *server_cert,const char *server_key, const char *ca_certs);
void httpd_tls_setup_free(void);
void *httpd_tls_new_handshake(int *sock, uint8_t secure);
void httpd_tls_free(void *tls_in);
void httpd_tls_close(void *tls_in);
int httpd_tls_read(void *tls_in, uint8_t *buf, size_t buf_len);
int httpd_tls_write(void *tls_in, uint8_t *buf, size_t buf_len);
int httpd_base64_encode(uint8_t *data, size_t data_len, char *base64_buf, size_t buf_len);
#endif /* _HTTPD_UTIL_H_ */

View file

@ -0,0 +1,228 @@
/* address.h -- representation of network addresses
*
* Copyright (C) 2010,2011 Olaf Bergmann <bergmann@tzi.org>
*
* This file is part of the CoAP library libcoap. Please see
* README for terms of use.
*/
/**
* @file address.h
* @brief representation of network addresses
*/
#ifndef _COAP_ADDRESS_H_
#define _COAP_ADDRESS_H_
#include "config.h"
#ifdef HAVE_ASSERT_H
#include <assert.h>
#else
#ifndef assert
#warning "assertions are disabled"
# define assert(x)
#endif
#endif
#include <string.h>
#include <stdint.h>
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef HAVE_WINSOCK2_H
#include <winsock2.h>
#endif
#ifdef HAVE_WS2TCPIP_H
#include <ws2tcpip.h>
#endif
#ifdef WITH_ARDUINO
#define DEV_ADDR_SIZE_MAX (16)
#endif
#ifdef WITH_LWIP
#include <lwip/ip_addr.h>
typedef struct coap_address_t
{
uint16_t port;
ip_addr_t addr;
}coap_address_t;
#if defined(AMEBA)
#define _coap_address_equals_impl(A, B) ((ip_addr_cmp(&(A)->addr, &(B)->addr)) && (A->port == B->port))
#define _coap_is_mcast_impl(Address) ip_addr_ismulticast(&(Address)->addr)
#else
/* FIXME oversimplification: just assuming it's an ipv4 address instead of
* looking up the appropraite lwip function */
#define _coap_address_equals_impl(A, B) ((A)->addr.addr == (B)->addr.addr && A->port == B->port)
/* FIXME sure there is something in lwip */
#define _coap_is_mcast_impl(Address) 0
#endif
#endif /* WITH_LWIP */
#ifdef WITH_CONTIKI
#include "uip.h"
typedef struct coap_address_t
{
unsigned char size;
uip_ipaddr_t addr;
unsigned short port;
}coap_address_t;
#define _coap_address_equals_impl(A,B) \
((A)->size == (B)->size \
&& (A)->port == (B)->port \
&& uip_ipaddr_cmp(&((A)->addr),&((B)->addr)))
#define _coap_is_mcast_impl(Address) uip_is_addr_mcast(&((Address)->addr))
#endif /* WITH_CONTIKI */
#if defined(WITH_POSIX) || defined(_WIN32)
/** multi-purpose address abstraction */
typedef struct coap_address_t
{
socklen_t size; /**< size of addr */
union
{
struct sockaddr sa;
struct sockaddr_storage st;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
}addr;
}coap_address_t;
INLINE_API int
_coap_address_equals_impl(const coap_address_t *a,
const coap_address_t *b)
{
if (a->size != b->size || a->addr.sa.sa_family != b->addr.sa.sa_family)
return 0;
/* need to compare only relevant parts of sockaddr_in6 */
switch (a->addr.sa.sa_family)
{
case AF_INET:
return
a->addr.sin.sin_port == b->addr.sin.sin_port &&
memcmp(&a->addr.sin.sin_addr, &b->addr.sin.sin_addr,
sizeof(struct in_addr)) == 0;
case AF_INET6:
return a->addr.sin6.sin6_port == b->addr.sin6.sin6_port &&
memcmp(&a->addr.sin6.sin6_addr, &b->addr.sin6.sin6_addr,
sizeof(struct in6_addr)) == 0;
default: /* fall through and signal error */
;
}
return 0;
}
INLINE_API int
_coap_is_mcast_impl(const coap_address_t *a)
{
if (!a)
{
return 0;
}
switch (a->addr.sa.sa_family)
{
case AF_INET:
return IN_MULTICAST(a->addr.sin.sin_addr.s_addr);
case AF_INET6:
return IN6_IS_ADDR_MULTICAST(&a->addr.sin6.sin6_addr);
default: /* fall through and signal error */
;
}
return 0;
}
#endif /* WITH_POSIX */
#ifdef WITH_ARDUINO
typedef struct coap_address_t
{
uint32_t size; /**< length of the address stored in addr field. */
uint8_t addr[DEV_ADDR_SIZE_MAX]; /**< device address. */
} coap_address_t;
INLINE_API int
_coap_address_equals_impl(const coap_address_t *a,
const coap_address_t *b)
{
uint32_t i;
if ((a == NULL) || (b == NULL))
return 0;
if (a->size != b->size)
return 0;
for (i = 0; i < a->size; i++)
{
if (a->addr[i] != b->addr[i])
return 0;
}
return 1;
}
INLINE_API int
_coap_is_mcast_impl(const coap_address_t *a)
{
if (!a)
return 0;
/* TODO */
return 0;
}
#endif /* WITH_ARDUINO */
/**
* Resets the given coap_address_t object @p addr to its default
* values. In particular, the member size must be initialized to the
* available size for storing addresses.
*
* @param addr The coap_address_t object to initialize.
*/
INLINE_API void coap_address_init(coap_address_t *addr)
{
assert(addr);
memset(addr, 0, sizeof(coap_address_t));
#ifndef WITH_LWIP
/* lwip has constandt address sizes and doesn't need the .size part */
addr->size = sizeof(addr->addr);
#endif
}
/**
* Compares given address objects @p a and @p b. This function returns
* @c 1 if addresses are equal, @c 0 otherwise. The parameters @p a
* and @p b must not be @c NULL;
*/
INLINE_API int coap_address_equals(const coap_address_t *a, const coap_address_t *b)
{
assert(a);
assert(b);
return _coap_address_equals_impl(a, b);
}
/**
* Checks if given address @p a denotes a multicast address. This
* function returns @c 1 if @p a is multicast, @c 0 otherwise.
*/
INLINE_API int coap_is_mcast(const coap_address_t *a)
{
return a && _coap_is_mcast_impl(a);
}
#endif /* _COAP_ADDRESS_H_ */

View file

@ -0,0 +1,148 @@
/* async.h -- state management for asynchronous messages
*
* Copyright (C) 2010,2011 Olaf Bergmann <bergmann@tzi.org>
*
* This file is part of the CoAP library libcoap. Please see
* README for terms of use.
*/
/**
* @file async.h
* @brief state management for asynchronous messages
*/
#ifndef _COAP_ASYNC_H_
#define _COAP_ASYNC_H_
#include "config.h"
#include "net.h"
#ifndef WITHOUT_ASYNC
/**
* @defgroup coap_async Asynchronous Messaging
* @{
* Structure for managing asynchronous state of CoAP resources. A
* coap_resource_t object holds a list of coap_async_state_t objects
* that can be used to generate a separate response in case a result
* of an operation cannot be delivered in time, or the resource has
* been explicitly subscribed to with the option @c observe.
*/
typedef struct coap_async_state_t
{
unsigned char flags; /**< holds the flags to control behaviour */
/**
* Holds the internal time when the object was registered with a
* resource. This field will be updated whenever
* coap_register_async() is called for a specific resource.
*/
coap_tick_t created;
/**
* This field can be used to register opaque application data with
* the asynchronous state object. */
void *appdata;
unsigned short message_id; /**< id of last message seen */
coap_tid_t id; /**< transaction id */
struct coap_async_state_t *next; /**< internally used for linking */
coap_address_t peer; /**< the peer to notify */
size_t tokenlen; /**< length of the token */
unsigned char token[]; /**< the token to use in a response */
} coap_async_state_t;
/* Definitions for Async Status Flags These flags can be used to
* control the behaviour of asynchronous response generation. */
#define COAP_ASYNC_CONFIRM 0x01 /**< send confirmable response */
#define COAP_ASYNC_SEPARATE 0x02 /**< send separate response */
#define COAP_ASYNC_OBSERVED 0x04 /**< the resource is being observed */
/** release application data on destruction */
#define COAP_ASYNC_RELEASE_DATA 0x08
/**
* Allocates a new coap_async_state_t object and fills its fields
* according to the given @p request. The @p flags are used to control
* generation of empty ACK responses to stop retransmissions and to
* release registered @p data when the resource is deleted by
* coap_free_async(). This function returns a pointer to the registered
* coap_async_t object or @c NULL on error. Note that this function will
* return @c NULL in case that an object with the same identifier is
* already registered.
*
* @param context The context to use.
* @param peer The remote peer that is to be asynchronously notified.
* @param request The request that is handled asynchronously.
* @param flags Flags to control state management.
* @param data Opaque application data to register. Note that the
* storage occupied by @p data is released on destruction
* only if flag COAP_ASYNC_RELEASE_DATA is set.
*
* @return A pointer to the registered coap_async_state_t object or
* @c NULL in case of an error.
*/
coap_async_state_t *
coap_register_async(coap_context_t *context, coap_address_t *peer, coap_pdu_t *request,
unsigned char flags, void *data);
/**
* Removes the state object identified by @p id from @p context. The
* removed object is returned in @p s, if found. Otherwise, @p s is
* undefined. This function returns @c 1 if the object was removed, @c
* 0 otherwise. Note that the storage allocated for the stored object
* is not released by this functions. You will have to call
* coap_free_async() to do so.
*
* @param context The context where the async object is registered.
* @param id The identifier of the asynchronous transaction.
* @param s Will be set to the object identified by @p id
* after removal.
*
* @return @c 1 if object was removed and @p s updated, or @c 0 if no
* object was found with the given id. @p s is valid only if the
* return value is @c 1.
*/
int coap_remove_async(coap_context_t *context, coap_tid_t id, coap_async_state_t **s);
/**
* Releases the memory that was allocated by coap_async_state_init()
* for the object @p s. The registered application data will be
* released automatically if COAP_ASYNC_RELEASE_DATA is set.
*
* @param s The object to delete.
*/
void
coap_free_async(coap_async_state_t *state);
/**
* Retrieves the object identified by @p id from the list of asynchronous
* transactions that are registered with @p context. This function returns
* a pointer to that object or @c NULL if not found.
*
* @param context The context where the asynchronous objects are
* registered with.
* @param id The id of the object to retrieve.
*
* @return A pointer to the object identified by @p id or @c NULL if
* not found.
*/
coap_async_state_t *coap_find_async(coap_context_t *context, coap_tid_t id);
/**
* Updates the time stamp of @p s.
*
* @param s The state object to update.
*/
INLINE_API void coap_touch_async(coap_async_state_t *s)
{
coap_ticks(&s->created);
}
/** @} */
#endif /* WITHOUT_ASYNC */
#endif /* _COAP_ASYNC_H_ */

View file

@ -0,0 +1,83 @@
/*
* bits.h -- bit vector manipulation
*
* Copyright (C) 2010,2011 Olaf Bergmann <bergmann@tzi.org>
*
* This file is part of the CoAP library libcoap. Please see
* README for terms of use.
*/
/**
* @file bits.h
* @brief bit vector manipulation
*/
#ifndef _BITS_H_
#define _BITS_H_
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include <stdint.h>
#if AMEBA
#include <stdio.h>
#endif
/**
* Sets the bit @p bit in bit-vector @p vec. This function returns @c
* 1 if bit was set or @c -1 on error (i.e. when the given bit does
* not fit in the vector).
*
* @param vec The bit-vector to change.
* @param size The size of @p vec in bytes.
* @param bit The bit to set in @p vec.
*
* @return @c -1 if @p bit does not fit into @p vec, @c 1 otherwise.
*/
INLINE_API int bits_setb(uint8_t *vec, size_t size, uint8_t bit)
{
if (size <= (size_t)(bit >> 3))
return -1;
*(vec + (bit >> 3)) |= (uint8_t)(1 << (bit & 0x07));
return 1;
}
/**
* Clears the bit @p bit from bit-vector @p vec. This function returns
* @c 1 if bit was cleared or @c -1 on error (i.e. when the given bit
* does not fit in the vector).
*
* @param vec The bit-vector to change.
* @param size The size of @p vec in bytes.
* @param bit The bit to clear from @p vec.
*
* @return @c -1 if @p bit does not fit into @p vec, @c 1 otherwise.
*/
INLINE_API int bits_clrb(uint8_t *vec, size_t size, uint8_t bit)
{
if (size <= (size_t)(bit >> 3))
return -1;
*(vec + (bit >> 3)) &= (uint8_t)(~(1 << (bit & 0x07)));
return 1;
}
/**
* Gets the status of bit @p bit from bit-vector @p vec. This function returns
* @c 1 if the bit is set, @c 0 otherwise (even in case of an error)..
*
* @param vec The bit-vector to read from..
* @param size The size of @p vec in bytes.
* @param bit The bit to get from @p vec.
*
* @return @c 1 if the bit is set, @c 0 otherwise.
*/
INLINE_API int bits_getb(const uint8_t *vec, size_t size, uint8_t bit)
{
if (size <= (size_t)(bit >> 3))
return -1;
return (*(vec + (bit >> 3)) & (1 << (bit & 0x07))) != 0;
}
#endif /* _BITS_H_ */

View file

@ -0,0 +1,142 @@
/* block.h -- block transfer
*
* Copyright (C) 2010--2012,2014 Olaf Bergmann <bergmann@tzi.org>
*
* This file is part of the CoAP library libcoap. Please see
* README for terms of use.
*/
#ifndef _COAP_BLOCK_H_
#define _COAP_BLOCK_H_
#include "option.h"
#include "encode.h"
#include "pdu.h"
/**
* @defgroup block Block Transfer
* @{
*/
#ifndef COAP_MAX_BLOCK_SZX
/**
* The largest value for the SZX component in a Block option. Note
* that 1 << (COAP_MAX_BLOCK_SZX + 4) should not exceed
* COAP_MAX_PDU_SIZE.
*/
#define COAP_MAX_BLOCK_SZX 4
#endif /* COAP_MAX_BLOCK_SZX */
#if (COAP_MAX_PDU_SIZE - 6) < (1 << (COAP_MAX_BLOCK_SZX + 4))
#error "COAP_MAX_BLOCK_SZX too large"
#endif
/**
* Structure of Block options.
*/
typedef struct
{
#ifdef WITH_ARDUINO
unsigned long int num : 20;
#else
unsigned int num : 20;
#endif
unsigned int m : 1; /**< 1 if more blocks follow, 0 otherwise */
unsigned int szx : 3; /**< block size */
} coap_block_t;
/**
* Returns the value of the least significant byte of a Block option @p opt.
* For zero-length options (i.e. num == m == szx == 0), COAP_OPT_BLOCK_LAST
* returns @c NULL.
*/
#define COAP_OPT_BLOCK_LAST(opt) \
(COAP_OPT_LENGTH(opt) ? (COAP_OPT_VALUE(opt) + (COAP_OPT_LENGTH(opt)-1)) : 0)
/** Returns the value of the More-bit of a Block option @p opt. */
#define COAP_OPT_BLOCK_MORE(opt) \
(COAP_OPT_LENGTH(opt) ? (*COAP_OPT_BLOCK_LAST(opt) & 0x08) : 0)
/** Returns the value of the SZX-field of a Block option @p opt. */
#define COAP_OPT_BLOCK_SZX(opt) \
(COAP_OPT_LENGTH(opt) ? (*COAP_OPT_BLOCK_LAST(opt) & 0x07) : 0)
/**
* Returns the value of field @c num in the given block option @p
* block_opt.
*/
unsigned int coap_opt_block_num(const coap_opt_t *block_opt);
/**
* Checks if more than @p num blocks are required to deliver @p data_len
* bytes of data for a block size of 1 << (@p szx + 4).
*/
INLINE_API int coap_more_blocks(size_t data_len, unsigned int num, unsigned short szx)
{
return ((num + 1) << (szx + 4)) < data_len;
}
/** Sets the More-bit in @p block_opt */
INLINE_API void coap_opt_block_set_m(coap_opt_t *block_opt, int m)
{
if (m)
*(COAP_OPT_VALUE(block_opt) + (COAP_OPT_LENGTH(block_opt) - 1)) |= 0x08;
else
*(COAP_OPT_VALUE(block_opt) + (COAP_OPT_LENGTH(block_opt) - 1)) &= ~0x08;
}
/**
* Initializes @p block from @p pdu. @p type must be either COAP_OPTION_BLOCK1
* or COAP_OPTION_BLOCK2. When option @p type was found in @p pdu, @p block
* is initialized with values from this option and the function returns the
* value @c 1. Otherwise, @c 0 is returned.
*
* @param pdu The pdu to search for option @p type.
* @param type The option to search for (must be COAP_OPTION_BLOCK1 or
* COAP_OPTION_BLOCK2)
* @param block The block structure to initilize.
* @return @c 1 on success, @c 0 otherwise.
*/
int coap_get_block(coap_pdu_t *pdu, unsigned short type, coap_block_t *block);
/**
* Writes a block option of type @p type to message @p pdu. If the
* requested block size is too large to fit in @p pdu, it is reduced
* accordingly. An exception is made for the final block when less
* space is required. The actual length of the resource is specified
* in @p data_length.
*
* This function may change *block to reflect the values written to
* @p pdu. As the function takes into consideration the remaining space
* @p pdu, no more options should be added after coap_write_block_opt()
* has returned.
*
* @param block The block structure to use. On return, this object
* is updated according to the values that have been
* written to @p pdu.
* @param type COAP_OPTION_BLOCK1 or COAP_OPTION_BLOCK2
* @param pdu The message where the block option should be
* written.
* @param data_length The length of the actual data that will be added
* the @p pdu by calling coap_add_block().
* @return @c 1 on success, or a negative value on error.
*/
int coap_write_block_opt(coap_block_t *block, unsigned short type, coap_pdu_t *pdu,
size_t data_length);
/**
* Adds the @p block_num block of size 1 << (@p block_szx + 4) from
* source @p data to @p pdu.
*
* @param pdu The message to add the block
* @param len The length of @p data.
* @param data The source data to fill the block with
* @param block_num The actual block number
* @param block_szx Encoded size of block @p block_number
* @return @c 1 on success, @c 0 otherwise.
*/
int coap_add_block(coap_pdu_t *pdu, unsigned int len, const unsigned char *data,
unsigned int block_num, unsigned char block_szx);
/**@}*/
#endif /* _COAP_BLOCK_H_ */

View file

@ -0,0 +1,37 @@
/* coap.h -- main header file for CoAP stack
*
* Copyright (C) 2010--2012 Olaf Bergmann <bergmann@tzi.org>
*
* This file is part of the CoAP library libcoap. Please see
* README for terms of use.
*/
#ifndef _COAP_H_
#define _COAP_H_
#ifdef __cplusplus
extern "C"
{
#endif
#include "config.h"
#include "debug.h"
#include "mem.h"
#include "coap_list.h"
#include "pdu.h"
#include "option.h"
#include "net.h"
#include "encode.h"
#include "str.h"
#include "uri.h"
#include "async.h"
#include "resource.h"
#include "subscribe.h"
#include "block.h"
#ifdef __cplusplus
}
#endif
#endif /* _COAP_H_ */

View file

@ -0,0 +1,45 @@
/* coap_list.h -- CoAP list structures
*
* Copyright (C) 2010,2011 Olaf Bergmann <bergmann@tzi.org>
*
* This file is part of the CoAP library libcoap. Please see
* README for terms of use.
*/
#ifndef _COAP_LIST_H_
#define _COAP_LIST_H_
struct coap_linkedlistnode
{
struct coap_linkedlistnode *next;
void *data;
/**
* Callback function that is called from coap_delete to release
* additional memory allocated by data Set to NULL if you do not
* need this. Note that data is free'd automatically. */
void (*delete_func)(void *);
};
typedef struct coap_linkedlistnode coap_list_t;
/**
* Adds node to given queue, ordered by specified order function. Returns 1
* when insert was successful, 0 otherwise.
*/
int coap_insert(coap_list_t **queue, coap_list_t *node, int (*order)(void *, void *));
/* destroys specified node */
int coap_delete(coap_list_t *node);
/* removes all items from given queue and frees the allocated storage */
void coap_delete_list(coap_list_t *queue);
/**
* Creates a new list node and adds the given data object. The memory allocated
* by data will be released by coap_delete() with the new node. Returns the
* new list node.
*/
coap_list_t *coap_new_listnode(void *data, void (*delete_func)(void *));
#endif /* _COAP_LIST_H_ */

View file

@ -0,0 +1,241 @@
/* coap_time.h -- Clock Handling
*
* Copyright (C) 2010--2013 Olaf Bergmann <bergmann@tzi.org>
*
* This file is part of the CoAP library libcoap. Please see
* README for terms of use.
*/
/**
* @file coap_time.h
* @brief Clock Handling
*/
#ifndef _COAP_TIME_H_
#define _COAP_TIME_H_
/*
** Make sure we can call this stuff from C++.
*/
#ifdef __cplusplus
extern "C"
{
#endif
#include "config.h"
/**
* @defgroup clock Clock Handling
* Default implementation of internal clock. You should redefine this if
* you do not have time() and gettimeofday().
* @{
*/
#ifdef HAVE_TIME_H
#include <time.h>
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef WITH_LWIP
#include <stdint.h>
#include <lwip/sys.h>
/* lwIP provides ms in sys_now */
#define COAP_TICKS_PER_SECOND 1000
typedef uint32_t coap_tick_t;
INLINE_API void coap_ticks_impl(coap_tick_t *t)
{
*t = sys_now();
}
INLINE_API void coap_clock_init_impl(void)
{
}
#define coap_clock_init coap_clock_init_impl
#define coap_ticks coap_ticks_impl
#endif
#ifdef WITH_CONTIKI
#include "clock.h"
typedef clock_time_t coap_tick_t;
/**
* This data type is used to represent the difference between two
* clock_tick_t values. This data type must have the same size in
* memory as coap_tick_t to allow wrapping.
*/
typedef int coap_tick_diff_t;
#define COAP_TICKS_PER_SECOND CLOCK_SECOND
/** Set at startup to initialize the internal clock (time in seconds). */
extern clock_time_t clock_offset;
INLINE_API void
contiki_clock_init_impl(void)
{
clock_init();
clock_offset = clock_time();
}
#define coap_clock_init contiki_clock_init_impl
INLINE_API void
contiki_ticks_impl(coap_tick_t *t)
{
*t = clock_time();
}
#define coap_ticks contiki_ticks_impl
#endif /* WITH_CONTIKI */
#if defined(WITH_POSIX) || defined(_WIN32)
typedef unsigned int coap_tick_t;
/**
* This data type is used to represent the difference between two
* clock_tick_t values. This data type must have the same size in
* memory as coap_tick_t to allow wrapping.
*/
typedef int coap_tick_diff_t;
#define COAP_TICKS_PER_SECOND 1024
/** Set at startup to initialize the internal clock (time in seconds). */
extern time_t clock_offset;
#endif /* WITH_POSIX || _WIN32 */
#ifdef WITH_ARDUINO
#include "Time.h"
#ifdef ARDUINO_ARCH_SAM
#include <sys/types.h> // time_t is defined in sys/types.h for ARM compiler
#else
typedef unsigned long time_t; //AVR compiler doesnt define time_t
#endif
typedef time_t coap_tick_t;
/**
* This data type is used to represent the difference between two
* clock_tick_t values. This data type must have the same size in
* memory as coap_tick_t to allow wrapping.
*/
typedef int coap_tick_diff_t;
/* TODO: Ticks per second value for Arduino needs verification from
* documentation */
#define COAP_TICKS_PER_SECOND 1000
extern time_t clock_offset;
#endif /* WITH_ARDUINO */
#ifdef AMEBA
//typedef unsigned long time_t; //AVR compiler doesnt define time_t
//typedef time_t coap_tick_t;
/**
* This data type is used to represent the difference between two
* clock_tick_t values. This data type must have the same size in
* memory as coap_tick_t to allow wrapping.
*/
typedef int coap_tick_diff_t;
/* TODO: Ticks per second value for Arduino needs verification from
* documentation */
#define COAP_TICKS_PER_SECOND 1000
extern time_t clock_offset;
#endif /* AMEBA */
#ifndef coap_clock_init
INLINE_API void coap_clock_init_impl(void)
{
#ifdef HAVE_TIME_H
clock_offset = time(NULL);
#else
# ifdef WITH_ARDUINO
#ifdef __AVR__
clock_offset = 1; //now();
#else
clock_offset = now();
#endif
# else
# ifdef __GNUC__
/* Issue a warning when using gcc. Other prepropressors do
* not seem to have a similar feature. */
# warning "cannot initialize clock"
# endif
clock_offset = 0;
# endif /* WITH_ARDUINO */
#endif /* HAVE_TIME */
}
#define coap_clock_init coap_clock_init_impl
#endif /* coap_clock_init */
#ifndef coap_ticks
INLINE_API void coap_ticks_impl(coap_tick_t *t)
{
#ifdef HAVE_SYS_TIME_H
struct timeval tv;
gettimeofday(&tv, NULL);
*t = (tv.tv_sec - clock_offset) * COAP_TICKS_PER_SECOND
+ (tv.tv_usec * COAP_TICKS_PER_SECOND / 1000000);
#else
# ifdef WITH_ARDUINO
coap_tick_t tv;
#ifdef __AVR__
tv = 1; //now();
#else
tv = now();
#endif
*t = (tv - clock_offset) * COAP_TICKS_PER_SECOND;
# else
#ifdef HAVE_TIME_H
time_t tv = time(NULL);
*t = difftime(tv, clock_offset) * COAP_TICKS_PER_SECOND;
#else
# error "clock not implemented"
#endif /* HAVE_TIME_H */
# endif /* WITH_ARDUINO */
#endif /* HAVE_SYS_TIME_H */
}
#define coap_ticks coap_ticks_impl
#endif /* coap_ticks */
/**
* Returns @c 1 if and only if @p a is less than @p b where less is
* defined on a signed data type.
*/
INLINE_API
int coap_time_lt(coap_tick_t a, coap_tick_t b)
{
return ((coap_tick_diff_t)(a - b)) < 0;
}
/**
* Returns @c 1 if and only if @p a is less than or equal @p b where
* less is defined on a signed data type.
*/
INLINE_API
int coap_time_le(coap_tick_t a, coap_tick_t b)
{
return a == b || coap_time_lt(a, b);
}
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* _COAP_TIME_H_ */

View file

@ -0,0 +1,172 @@
/* config.h. Generated from config.h.in by configure. */
/* config.h.in. Generated from configure.in by autoheader. */
//Realtek add
#define AMEBA 1
#define WITH_LWIP 1
#define LWIP_NOASSERT 1
#define NO_DECLTYPE 1
#define NDEBUG 1
#ifdef __ICCARM__ //add for GCC compile error
#define ssize_t int
#define FILE void
#endif
//Realtek add end
/* Define if building universal (internal helper macro) */
/* #undef AC_APPLE_UNIVERSAL_BUILD */
/* Define to 1 if you have the <assert.h> header file. */
#define HAVE_ASSERT_H 1
/* Define to 1 if you have the `getaddrinfo' function. */
#define HAVE_GETADDRINFO 1
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define to 1 if you have the `coap' library (-lcoap). */
/* #undef HAVE_LIBCOAP */
/* Define to 1 if you have the <limits.h> header file. */
#define HAVE_LIMITS_H 1
/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
to 0 otherwise. */
#define HAVE_MALLOC 1
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* Define to 1 if you have the `memset' function. */
#define HAVE_MEMSET 1
/* Define to 1 if you have the <netinet/in.h> header file. */
#if !defined(WITH_ARDUINO) && !defined(_WIN32) && !defined(AMEBA)
#define HAVE_NETINET_IN_H 1
#endif
/* Define to 1 if you have the `select' function. */
#define HAVE_SELECT 1
/* Define to 1 if you have the `socket' function. */
#define HAVE_SOCKET 1
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the `strcasecmp' function. */
#define HAVE_STRCASECMP 1
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the `strnlen' function. */
#define HAVE_STRNLEN 1
/* Define to 1 if you have the `strrchr' function. */
#define HAVE_STRRCHR 1
/* Define to 1 if you have the <syslog.h> header file. */
#if !defined(WITH_ARDUINO) && !defined(_WIN32) && !defined(AMEBA)
#define HAVE_SYSLOG_H 1
#endif
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#if !defined(WITH_ARDUINO) && !defined(_WIN32) && !defined(AMEBA)
#define HAVE_SYS_TYPES_H 1
#endif
/* Define to 1 if you have the <sys/unistd.h> header file. */
#if !defined(WITH_ARDUINO) && !defined(_WIN32) && !defined(AMEBA)
#define HAVE_SYS_UNISTD_H 1
#endif
/* Define to 1 if you have <Ws2tcpip.h> header file. */
#if defined(_WIN32)
#define HAVE_WS2TCPIP_H 1
#endif
/* Define to 1 if you have <Winsock2.h> header file. */
#if defined(_WIN32)
#define HAVE_WINSOCK2_H 1
#endif
/* Define to 1 if you have <Windows.h> header file. */
#if defined(_WIN32)
#define HAVE_WINDOWS_H 1
#endif
/* Define to 1 if you have the <time.h> header file. */
#if (!defined(WITH_ARDUINO) && !defined(AMEBA)) || (defined(WITH_LWIP) && defined(AMEBA))
#define HAVE_TIME_H 1
#endif
/* Define to 1 if you have the <unistd.h> header file. */
#if !defined(WITH_ARDUINO) && !defined(_WIN32) && !defined(AMEBA)
#define HAVE_UNISTD_H 1
#endif
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT ""
/* Define to the full name of this package. */
#define PACKAGE_NAME "libcoap"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "libcoap 4.1.1"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "libcoap"
/* Define to the home page for this package. */
#define PACKAGE_URL ""
/* Define to the version of this package. */
#define PACKAGE_VERSION "4.1.1"
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
significant byte first (like Motorola and SPARC, unlike Intel). */
#if defined AC_APPLE_UNIVERSAL_BUILD
# if defined __BIG_ENDIAN__
# define WORDS_BIGENDIAN 1
# endif
#else
# if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
# define WORDS_BIGENDIAN 1
# endif
#endif
#ifndef INLINE_API
# if defined(__cplusplus)
# define INLINE_API inline
# else
# ifdef _MSC_VER
# define INLINE_API static __inline
# else
# define INLINE_API static inline
# endif
# endif
#endif
/* Define to rpl_malloc if the replacement function should be used. */
/* #undef malloc */
/* Define to `unsigned int' if <sys/types.h> does not define. */
/* #undef size_t */
/* Define to `int' if <sys/types.h> does not define. */
/* #undef ssize_t */

View file

@ -0,0 +1,77 @@
/* debug.h -- debug utilities
*
* Copyright (C) 2010,2011 Olaf Bergmann <bergmann@tzi.org>
*
* This file is part of the CoAP library libcoap. Please see
* README for terms of use.
*/
#ifndef _COAP_DEBUG_H_
#define _COAP_DEBUG_H_
#include "config.h"
#ifndef COAP_DEBUG_FD
#define COAP_DEBUG_FD stdout
#endif
#ifndef COAP_ERR_FD
#define COAP_ERR_FD stderr
#endif
#ifdef HAVE_SYSLOG_H
#include <syslog.h>
typedef short coap_log_t;
#else
/** Pre-defined log levels akin to what is used in \b syslog. */
typedef enum
{ LOG_EMERG=0, LOG_ALERT, LOG_CRIT, LOG_WARNING,
LOG_NOTICE, LOG_INFO, LOG_DEBUG
}coap_log_t;
#endif
/** Returns the current log level. */
coap_log_t coap_get_log_level(void);
/** Sets the log level to the specified value. */
void coap_set_log_level(coap_log_t level);
/**
* Writes the given text to @c COAP_ERR_FD (for @p level <= @c
* LOG_CRIT) or @c COAP_DEBUG_FD (for @p level >= @c LOG_WARNING). The
* text is output only when @p level is below or equal to the log
* level that set by coap_set_log_level().
*/
void coap_log_impl(coap_log_t level, const char *format, ...);
#ifndef coap_log
#define coap_log(...) coap_log_impl(__VA_ARGS__)
#endif
#ifndef NDEBUG
/* A set of convenience macros for common log levels. */
#define info(...) coap_log(LOG_INFO, __VA_ARGS__)
#define warn(...) coap_log(LOG_WARNING, __VA_ARGS__)
#define debug(...) coap_log(LOG_DEBUG, __VA_ARGS__)
#include "pdu.h"
void coap_show_pdu(const coap_pdu_t *);
struct coap_address_t;
unsigned int print_readable(const unsigned char *data, unsigned int len, unsigned char *result,
unsigned int buflen, int encode_always);
size_t coap_print_addr(const struct coap_address_t *, unsigned char *, size_t);
#else
#define debug(...)
#define info(...)
#define warn(...)
#define coap_show_pdu(x)
#define coap_print_addr(...)
#endif
#endif /* _COAP_DEBUG_H_ */

View file

@ -0,0 +1,62 @@
/* encode.h -- encoding and decoding of CoAP data types
*
* Copyright (C) 2010--2012 Olaf Bergmann <bergmann@tzi.org>
*
* This file is part of the CoAP library libcoap. Please see
* README for terms of use.
*/
#ifndef _COAP_ENCODE_H_
#define _COAP_ENCODE_H_
#if ((defined BSD)&&(BSD >= 199103)) || defined(WITH_CONTIKI)
# include <string.h>
#else
#if !defined(WITH_ARDUINO) && !defined(_MSC_VER)&& !defined(AMEBA)
# include <strings.h>
#endif
#endif
#include "option.h"
#define Nn 8 /* duplicate definition of N if built on sky motes */
#define E 4
#define HIBIT (1 << (Nn - 1))
#define EMASK ((1 << E) - 1)
#define MMASK ((1 << Nn) - 1 - EMASK)
#define MAX_VALUE ( (1 << Nn) - (1 << E) ) * (1 << ((1 << E) - 1))
#define COAP_PSEUDOFP_DECODE_8_4(r) (r < HIBIT ? r : (r & MMASK) << (r & EMASK))
#ifndef HAVE_FLS
/* include this only if fls() is not available */
extern int coap_fls(unsigned int i);
#else
#define coap_fls(i) fls(i)
#endif
/* ls and s must be integer variables */
#define COAP_PSEUDOFP_ENCODE_8_4_DOWN(v,ls) (v < HIBIT ? v : (ls = coap_fls(v) - Nn, (v >> ls) & MMASK) + ls)
#define COAP_PSEUDOFP_ENCODE_8_4_UP(v,ls,s) (v < HIBIT ? v : (ls = coap_fls(v) - Nn, (s = (((v + ((1<<E<<ls)-1)) >> ls) & MMASK)), s == 0 ? HIBIT + ls + 1 : s + ls))
/**
* Decodes multiple-length byte sequences. buf points to an input byte
* sequence of length len. Returns the decoded value.
*/
unsigned int coap_decode_var_bytes(unsigned char *buf, unsigned int len);
/**
* Encodes multiple-length byte sequences. buf points to an output
* buffer of sufficient length to store the encoded bytes. val is
* the value to encode. Returns the number of bytes used to encode
* val or 0 on error.
*/
unsigned int coap_encode_var_bytes(unsigned char *buf, unsigned int val);
/**
* Tests whether the option definition has a type that allows variable byte encoding.
* Returns true when supported, false when not supported.
*/
bool coap_is_var_bytes(coap_option_def_t* def);
#endif /* _COAP_ENCODE_H_ */

View file

@ -0,0 +1,57 @@
/* hashkey.h -- definition of hash key type and helper functions
*
* Copyright (C) 2010,2011 Olaf Bergmann <bergmann@tzi.org>
*
* This file is part of the CoAP library libcoap. Please see
* README for terms of use.
*/
/**
* @file hashkey.h
* @brief definition of hash key type and helper functions
*/
#ifndef _COAP_HASHKEY_H_
#define _COAP_HASHKEY_H_
#include "str.h"
typedef unsigned char coap_key_t[4];
#ifndef coap_hash
/**
* Calculates a fast hash over the given string @p s of length @p len
* and stores the result into @p h. Depending on the exact
* implementation, this function cannot be used as one-way function to
* check message integrity or simlar.
*
* @param s The string used for hash calculation.
* @param len The length of @p s.
* @param h The result buffer to store the calculated hash key.
*/
void coap_hash_impl(const unsigned char *s, unsigned int len, coap_key_t h);
#define coap_hash(String,Length,Result) \
coap_hash_impl((String),(Length),(Result))
/* This is used to control the pre-set hash-keys for resources. */
#define __COAP_DEFAULT_HASH
#else
#undef __COAP_DEFAULT_HASH
#endif /* coap_hash */
/**
* Calls coap_hash() with given @c str object as parameter.
*
* @param Str Must contain a pointer to a coap string object.
* @param H A coap_key_t object to store the result.
*
* @hideinitializer
*/
#define coap_str_hash(Str,H) { \
assert(Str); \
memset((H), 0, sizeof(coap_key_t)); \
coap_hash((H), (Str)->s, (Str)->length); \
}
#endif /* _COAP_HASHKEY_H_ */

View file

@ -0,0 +1,18 @@
/* mem.h -- CoAP memory handling
* Currently, this is just a dummy for malloc/free
*
* Copyright (C) 2010,2011 Olaf Bergmann <bergmann@tzi.org>
*
* This file is part of the CoAP library libcoap. Please see
* README for terms of use.
*/
#ifndef _COAP_MEM_H_
#define _COAP_MEM_H_
#include <stdlib.h>
#define coap_malloc(size) malloc(size)
#define coap_free(size) free(size)
#endif /* _COAP_MEM_H_ */

View file

@ -0,0 +1,455 @@
/* net.h -- CoAP network interface
*
* Copyright (C) 2010--2013 Olaf Bergmann <bergmann@tzi.org>
*
* This file is part of the CoAP library libcoap. Please see
* README for terms of use.
*/
#ifndef _COAP_NET_H_
#define _COAP_NET_H_
#ifdef WITH_ARDUINO
#include "Time.h"
#endif /* WITH_ARDUINO */
#ifdef __cplusplus
extern "C"
{
#endif
#include "config.h"
#ifdef HAVE_ASSERT_H
#include <assert.h>
#else
#ifndef assert
#warning "assertions are disabled"
# define assert(x)
#endif
#endif
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifdef HAVE_TIME_H
#include <time.h>
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef WITH_LWIP
#include <lwip/ip_addr.h>
#endif
#include "option.h"
#include "address.h"
#include "prng.h"
#include "pdu.h"
#include "coap_time.h"
struct coap_queue_t;
typedef struct coap_queue_t
{
struct coap_queue_t *next;
coap_tick_t t; /**< when to send PDU for the next time */
unsigned char retransmit_cnt; /**< retransmission counter, will be removed when zero */
unsigned int timeout; /**< the randomized timeout value */
coap_address_t local; /**< local address */
coap_address_t remote; /**< remote address */
coap_tid_t id; /**< unique transaction id */
coap_pdu_t *pdu; /**< the CoAP PDU to send */
} coap_queue_t;
/** Adds node to given queue, ordered by node->t. */
int coap_insert_node(coap_queue_t **queue, coap_queue_t *node);
/** Destroys specified node. */
int coap_delete_node(coap_queue_t *node);
/** Removes all items from given queue and frees the allocated storage. */
void coap_delete_all(coap_queue_t *queue);
/** Creates a new node suitable for adding to the CoAP sendqueue. */
coap_queue_t *coap_new_node(void);
struct coap_resource_t;
struct coap_context_t;
#ifndef WITHOUT_ASYNC
struct coap_async_state_t;
#endif
/** Message handler that is used as call-back in coap_context_t */
typedef void (*coap_response_handler_t)(struct coap_context_t *, const coap_address_t *remote,
coap_pdu_t *sent, coap_pdu_t *received, const coap_tid_t id);
#define COAP_MID_CACHE_SIZE 3
typedef struct
{
unsigned char flags[COAP_MID_CACHE_SIZE];
coap_key_t item[COAP_MID_CACHE_SIZE];
} coap_mid_cache_t;
/** The CoAP stack's global state is stored in a coap_context_t object */
typedef struct coap_context_t
{
coap_opt_filter_t known_options;
#ifndef WITH_CONTIKI
struct coap_resource_t *resources; /**< hash table or list of known resources */
#endif /* WITH_CONTIKI */
#ifndef WITHOUT_ASYNC
/** list of asynchronous transactions */
struct coap_async_state_t *async_state;
#endif /* WITHOUT_ASYNC */
/**
* The time stamp in the first element of the sendqeue is relative
* to sendqueue_basetime. */
coap_tick_t sendqueue_basetime;
coap_queue_t *sendqueue, *recvqueue;
#if defined(WITH_POSIX) || defined(WITH_ARDUINO) || defined(_WIN32) || defined(AMEBA)
int sockfd; /**< send/receive socket */
#endif /* WITH_POSIX || WITH_ARDUINO */
#ifdef WITH_CONTIKI
struct uip_udp_conn *conn; /**< uIP connection object */
struct etimer retransmit_timer; /**< fires when the next packet must be sent */
struct etimer notify_timer; /**< used to check resources periodically */
#endif /* WITH_CONTIKI */
#ifdef WITH_LWIP
struct udp_pcb *pcb; /**< the underlying lwIP UDP PCB */
struct pbuf *pending_package; /**< pbuf containing the last received package if not handled yet. This is only used to pass the package from the udp_recv callback into the coap_read function, which frees the pbuf and clears this field. */
ip_addr_t pending_address; /**< the address associated with pending_package */
u16_t pending_port; /**< the port associated with pending_package */
uint8_t timer_configured; /**< Set to 1 when a retransmission is scheduled using lwIP timers for this context, otherwise 0. */
#endif /* WITH_LWIP */
/**
* The last message id that was used is stored in this field. The
* initial value is set by coap_new_context() and is usually a
* random value. A new message id can be created with
* coap_new_message_id().
*/
unsigned short message_id;
/**
* The next value to be used for Observe. This field is global for
* all resources and will be updated when notifications are created.
*/
unsigned int observe;
coap_response_handler_t response_handler;
} coap_context_t;
/**
* Registers a new message handler that is called whenever a response
* was received that matches an ongoing transaction.
*
* @param context The context to register the handler for.
* @param handler The response handler to register.
*/
INLINE_API void coap_register_response_handler(coap_context_t *context,
coap_response_handler_t handler)
{
context->response_handler = handler;
}
/**
* Registers the option type @p type with the given context object @p
* ctx.
*
* @param ctx The context to use.
* @param type The option type to register.
*/
INLINE_API void coap_register_option(coap_context_t *ctx, unsigned char type)
{
coap_option_setb(ctx->known_options, type);
}
/**
* Set sendqueue_basetime in the given context object @p ctx to @p
* now. This function returns the number of elements in the queue
* head that have timed out.
*/
unsigned int coap_adjust_basetime(coap_context_t *ctx, coap_tick_t now);
/** Returns the next pdu to send without removing from sendqeue. */
coap_queue_t *coap_peek_next(coap_context_t *context);
/** Returns the next pdu to send and removes it from the sendqeue. */
coap_queue_t *coap_pop_next(coap_context_t *context);
/** Creates a new coap_context_t object that will hold the CoAP stack status. */
coap_context_t *coap_new_context(const coap_address_t *listen_addr);
/**
* Returns a new message id and updates @p context->message_id
* accordingly. The message id is returned in network byte order
* to make it easier to read in tracing tools.
*
* @param context the current coap_context_t object
* @return incremented message id in network byte order
*/
INLINE_API unsigned short coap_new_message_id(coap_context_t *context)
{
++(context->message_id);
#if defined(WITH_ARDUINO)
return ((context->message_id << 8) | ((context->message_id >> 8) & (0xFF)));
#elif defined(WITH_CONTIKI)
return uip_htons(context->message_id);
#else /* WITH_CONTIKI */
return htons(context->message_id);
#endif
}
/* CoAP stack context must be released with coap_free_context() */
void coap_free_context(coap_context_t *context);
/**
* Sends a confirmed CoAP message to given destination. The memory
* that is allocated by pdu will not be released by
* coap_send_confirmed(). The caller must release the memory.
*
* @param context The CoAP context to use.
* @param dst The address to send to.
* @param pdu The CoAP PDU to send.
* @return The message id of the sent message or @c COAP_INVALID_TID on error.
*/
coap_tid_t coap_send_confirmed(coap_context_t *context, const coap_address_t *dst,
coap_pdu_t *pdu);
/**
* Creates a new ACK PDU with specified error @p code. The options
* specified by the filter expression @p opts will be copied from the
* original request contained in @p request. Unless @c
* SHORT_ERROR_RESPONSE was defined at build time, the textual reason
* phrase for @p code will be added as payload, with Content-Type @c
* 0. This function returns a pointer to the new response message, or
* @c NULL on error. The storage allocated for the new message must be
* relased with coap_free().
*
* @param request Specification of the received (confirmable) request.
* @param code The error code to set.
* @param opts An option filter that specifies which options to copy
* from the original request in @p node.
*
* @return A pointer to the new message or @c NULL on error.
*/
coap_pdu_t *coap_new_error_response(coap_pdu_t *request, unsigned char code,
coap_opt_filter_t opts);
/**
* Sends a non-confirmed CoAP message to given destination. The memory
* that is allocated by pdu will not be released by coap_send().
* The caller must release the memory.
*
* @param context The CoAP context to use.
* @param dst The address to send to.
* @param pdu The CoAP PDU to send.
* @return The message id of the sent message or @c COAP_INVALID_TID on error.
*/
coap_tid_t coap_send(coap_context_t *context, const coap_address_t *dst, coap_pdu_t *pdu);
/**
* Sends an error response with code @p code for request @p request to
* @p dst. @p opts will be passed to coap_new_error_response() to
* copy marked options from the request. This function returns the
* transaction id if the message was sent, or @c COAP_INVALID_TID
* otherwise.
*
* @param context The context to use.
* @param request The original request to respond to.
* @param dst The remote peer that sent the request.
* @param code The reponse code.
* @param opts A filter that specifies the options to copy from the
* @p request.
*
* @return The transaction id if the message was sent, or @c
* COAP_INVALID_TID otherwise.
*/
coap_tid_t coap_send_error(coap_context_t *context, coap_pdu_t *request,
const coap_address_t *dst, unsigned char code, coap_opt_filter_t opts);
/**
* Helper funktion to create and send a message with @p type (usually
* ACK or RST). This function returns @c COAP_INVALID_TID when the
* message was not sent, a valid transaction id otherwise.
*
* @param context The CoAP context.
* @param dst Where to send the context.
* @param request The request that should be responded to.
* @param type Which type to set
* @return transaction id on success or @c COAP_INVALID_TID otherwise.
*/
coap_tid_t
coap_send_message_type(coap_context_t *context, const coap_address_t *dst, coap_pdu_t *request,
unsigned char type);
/**
* Sends an ACK message with code @c 0 for the specified @p request to
* @p dst. This function returns the corresponding transaction id if
* the message was sent or @c COAP_INVALID_TID on error.
*
* @param context The context to use.
* @param dst The destination address.
* @param request The request to be acknowledged.
*
* @return The transaction id if ACK was sent or @c COAP_INVALID_TID
* on error.
*/
coap_tid_t coap_send_ack(coap_context_t *context, const coap_address_t *dst,
coap_pdu_t *request);
/**
* Sends an RST message with code @c 0 for the specified @p request to
* @p dst. This function returns the corresponding transaction id if
* the message was sent or @c COAP_INVALID_TID on error.
*
* @param context The context to use.
* @param dst The destination address.
* @param request The request to be reset.
*
* @return The transaction id if RST was sent or @c COAP_INVALID_TID
* on error.
*/
INLINE_API coap_tid_t coap_send_rst(coap_context_t *context, const coap_address_t *dst,
coap_pdu_t *request)
{
return coap_send_message_type(context, dst, request, COAP_MESSAGE_RST);
}
/** Handles retransmissions of confirmable messages */
coap_tid_t coap_retransmit(coap_context_t *context, coap_queue_t *node);
/**
* Reads data from the network and tries to parse as CoAP PDU. On success, 0 is returned
* and a new node with the parsed PDU is added to the receive queue in the specified context
* object.
*/
int coap_read(coap_context_t *context);
/**
* Calculates a unique transaction id from given arguments @p peer and
* @p pdu. The id is returned in @p id.
*
* @param peer The remote party who sent @p pdu.
* @param pdu The message that initiated the transaction.
* @param id Set to the new id.
*/
void coap_transaction_id(const coap_address_t *peer, const coap_pdu_t *pdu, coap_tid_t *id);
/**
* This function removes the element with given @p id from the list
* given list. If @p id was found, @p node is updated to point to the
* removed element. Note that the storage allocated by @p node is
* @b not released. The caller must do this manually using
* coap_delete_node(). This function returns @c 1 if the element with
* id @p id was found, @c 0 otherwise. For a return value of @c 0,
* the contents of @p node is undefined.
*
* @param queue The queue to search for @p id.
* @param id The node id to look for.
* @param node If found, @p node is updated to point to the
* removed node. You must release the storage pointed to by
* @p node manually.
*
* @return @c 1 if @p id was found, @c 0 otherwise.
*/
int coap_remove_from_queue(coap_queue_t **queue, coap_tid_t id, coap_queue_t **node);
/**
* Removes the transaction identified by @p id from given @p queue.
* This is a convenience function for coap_remove_from_queue() with
* automatic deletion of the removed node.
*
* @param queue The queue to search for @p id.
* @param id The transaction id.
*
* @return @c 1 if node was found, removed and destroyed, @c 0 otherwise.
*/
INLINE_API int coap_remove_transaction(coap_queue_t **queue, coap_tid_t id)
{
coap_queue_t *node;
if (!coap_remove_from_queue(queue, id, &node))
return 0;
coap_delete_node(node);
return 1;
}
/**
* Retrieves transaction from queue.
* @queue The transaction queue to be searched
* @id Unique key of the transaction to find.
* @return A pointer to the transaction object or NULL if not found
*/
coap_queue_t *coap_find_transaction(coap_queue_t *queue, coap_tid_t id);
/**
* Cancels all outstanding messages for peer @p dst that have the
* specified token.
*
* @param context The context in use
* @param dst Destination address of the messages to remove.
* @param token Message token
* @param token_length Actual length of @p token
*/
void coap_cancel_all_messages(coap_context_t *context, const coap_address_t *dst,
const unsigned char *token, size_t token_length);
/** Dispatches the PDUs from the receive queue in given context. */
void coap_dispatch(coap_context_t *context, const char* responseData);
/** Returns 1 if there are no messages to send or to dispatch in the context's queues. */
int coap_can_exit(coap_context_t *context);
/**
* Returns the current value of an internal tick counter. The counter
* counts \c COAP_TICKS_PER_SECOND ticks every second.
*/
void coap_ticks(coap_tick_t *);
/**
* Verifies that @p pdu contains no unknown critical options. Options
* must be registered at @p ctx, using the function
* coap_register_option(). A basic set of options is registered
* automatically by coap_new_context(). This function returns @c 1 if
* @p pdu is ok, @c 0 otherwise. The given filter object @p unknown
* will be updated with the unknown options. As only @c COAP_MAX_OPT
* options can be signalled this way, remaining options must be
* examined manually.
*
* @code
coap_opt_filter_t f = COAP_OPT_NONE;
coap_opt_iterator_t opt_iter;
if (coap_option_check_critical(ctx, pdu, f) == 0) {
coap_option_iterator_init(pdu, &opt_iter, f);
while (coap_option_next(&opt_iter)) {
if (opt_iter.type & 0x01) {
... handle unknown critical option in opt_iter ...
}
}
}
* @endcode
*
* @param ctx The context where all known options are registered.
* @param pdu The PDU to check.
* @param unknown The output filter that will be updated to indicate the
* unknown critical options found in @p pdu.
*
* @return @c 1 if everything was ok, @c 0 otherwise.
*/
int coap_option_check_critical(coap_context_t *ctx, coap_pdu_t *pdu, coap_opt_filter_t unknown);
#ifdef __cplusplus
}
#endif
#endif /* _COAP_NET_H_ */

View file

@ -0,0 +1,363 @@
/*
* option.h -- helpers for handling options in CoAP PDUs
*
* Copyright (C) 2010-2013 Olaf Bergmann <bergmann@tzi.org>
*
* This file is part of the CoAP library libcoap. Please see
* README for terms of use.
*/
/**
* @file option.h
* @brief helpers for handling options in CoAP PDUs
*/
#ifndef _OPTION_H_
#define _OPTION_H_
#include "bits.h"
#include "pdu.h"
/**
* Use byte-oriented access methods here because sliding a complex
* struct coap_opt_t over the data buffer may cause bus error on
* certain platforms.
*/
typedef unsigned char coap_opt_t;
#define PCHAR(p) ((coap_opt_t *)(p))
/** Representation of CoAP options. */
typedef struct
{
unsigned short delta;
size_t length;
unsigned char *value;
} coap_option_t;
/** Representation of the association between a CoAP option key and its
* data type and valid data length ranges.
*/
typedef struct
{
unsigned short key; /**< The ID of the option the following values apply to. */
unsigned char type; /**< The type of the option: u=uint, s=string, o=opaque. */
unsigned int min; /**< The minimum number of bytes allowed for the option data */
unsigned int max; /**< The maximum number of bytes allowed for the option data */
} coap_option_def_t;
/**
* Parses the option pointed to by @p opt into @p result. This
* function returns the number of bytes that have been parsed, or @c 0
* on error. An error is signaled when illegal delta or length values
* are encountered or when option parsing would result in reading past
* the option (i.e. beyond opt + length).
*
* @param opt The beginning of the option to parse.
* @param length The maximum length of @p opt.
* @param result A pointer to the coap_option_t structure that is
* filled with actual values iff coap_opt_parse() > 0.
* @return The number of bytes parsed or @c 0 on error.
*/
size_t coap_opt_parse(const coap_opt_t *opt, size_t length, coap_option_t *result);
/**
* Returns the size of the given option, taking into account a
* possible option jump.
*
* @param opt An option jump or the beginning of the option.
* @return The number of bytes between @p opt and the end of
* the option starting at @p opt. In case of an error,
* this function returns @c 0 as options need at least
* one byte storage space.
*/
size_t coap_opt_size(const coap_opt_t *opt);
/** @deprecated { Use coap_opt_size() instead. } */
#define COAP_OPT_SIZE(opt) coap_opt_size(opt)
/**
* Calculates the beginning of the PDU's option section.
*
* @param pdu The PDU containing the options.
* @return A pointer to the first option if available, or @c NULL otherwise.
*/
coap_opt_t *options_start(coap_pdu_t *pdu, coap_transport_t transport);
/**
* Interprets @p opt as pointer to a CoAP option and advances to
* the next byte past this option.
* @hideinitializer
*/
#define options_next(opt) \
((coap_opt_t *)((unsigned char *)(opt) + COAP_OPT_SIZE(opt)))
/**
* @defgroup opt_filter Option Filters
* @{
*/
/**
* Fixed-size bit-vector we use for option filtering. It is large
* enough to hold the highest option number known at build time (20 in
* the core spec).
*/
typedef unsigned char coap_opt_filter_t[(COAP_MAX_OPT >> 3) + 1];
/** Pre-defined filter that includes all options. */
#define COAP_OPT_ALL NULL
/**
* Clears filter @p f.
*
* @param f The filter to clear.
*/
INLINE_API void coap_option_filter_clear(coap_opt_filter_t f)
{
memset(f, 0, sizeof(coap_opt_filter_t));
}
/**
* Sets the corresponding bit for @p type in @p filter. This function
* returns @c 1 if bit was set or @c -1 on error (i.e. when the given
* type does not fit in the filter).
*
* @param filter The filter object to change.
* @param type The type for which the bit should be set.
*
* @return @c 1 if bit was set, @c -1 otherwise.
*/
INLINE_API int coap_option_setb(coap_opt_filter_t filter, unsigned short type)
{
return bits_setb((uint8_t *) filter, sizeof(coap_opt_filter_t), type);
}
/**
* Clears the corresponding bit for @p type in @p filter. This function
* returns @c 1 if bit was cleared or @c -1 on error (i.e. when the given
* type does not fit in the filter).
*
* @param filter The filter object to change.
* @param type The type for which the bit should be cleared.
*
* @return @c 1 if bit was set, @c -1 otherwise.
*/
INLINE_API int coap_option_clrb(coap_opt_filter_t filter, unsigned short type)
{
return bits_clrb((uint8_t *) filter, sizeof(coap_opt_filter_t), type);
}
/**
* Gets the corresponding bit for @p type in @p filter. This function
* returns @c 1 if the bit is set @c 0 if not, or @c -1 on error (i.e.
* when the given type does not fit in the filter).
*
* @param filter The filter object to read bit from..
* @param type The type for which the bit should be read.
*
* @return @c 1 if bit was set, @c 0 if not, @c -1 on error.
*/
INLINE_API int coap_option_getb(const coap_opt_filter_t filter, unsigned short type)
{
return bits_getb((uint8_t *) filter, sizeof(coap_opt_filter_t), type);
}
/**
* Iterator to run through PDU options. This object must be
* initialized with coap_option_iterator_init(). Call
* coap_option_next() to walk through the list of options until
* coap_option_next() returns @c NULL.
*
* @code
* coap_opt_t *option;
* coap_opt_iterator_t opt_iter;
* coap_option_iterator_init(pdu, &opt_iter, COAP_OPT_ALL);
*
* while ((option = coap_option_next(&opt_iter))) {
* ... do something with option ...
* }
* @endcode
*/
typedef struct
{
size_t length; /**< remaining length of PDU */
unsigned short type; /**< decoded option type */
unsigned int bad :1; /**< iterator object is ok if not set */
unsigned int filtered :1; /**< denotes whether or not filter is used */
coap_opt_t *next_option; /**< pointer to the unparsed next option */
coap_opt_filter_t filter; /**< option filter */
} coap_opt_iterator_t;
/**
* Initializes the given option iterator @p oi to point to the beginning of the
* @p pdu's option list. This function returns @p oi on success, @c NULL
* otherwise (i.e. when no options exist). Note that a length check on the
* option list must be performed before coap_option_iterator_init() is called.
*
* @param pdu The PDU the options of which should be walked through.
* @param oi An iterator object that will be initilized.
* @param filter An optional option type filter.
* With @p type != @c COAP_OPT_ALL, coap_option_next()
* will return only options matching this bitmask.
* Fence-post options @c 14, @c 28, @c 42, ... are always
* skipped.
*
* @return The iterator object @p oi on success, @c NULL otherwise.
*/
coap_opt_iterator_t *coap_option_iterator_init(coap_pdu_t *pdu,
coap_opt_iterator_t *oi,
const coap_opt_filter_t filter);
/**
* Initializes the given option iterator @p oi to point to the
* beginning of the @p pdu's option list. This function returns @p oi
* on success, @c NULL otherwise (i.e. when no options exist).
* Note that a length check on the option list must be performed before
* coap_option_iterator_init() is called.
*
* @param pdu The PDU the options of which should be walked through.
* @param oi An iterator object that will be initilized.
* @param filter An optional option type filter.
* With @p type != @c COAP_OPT_ALL, coap_option_next()
* will return only options matching this bitmask.
* Fence-post options @c 14, @c 28, @c 42, ... are always
* skipped.
*
* @return The iterator object @p oi on success, @c NULL otherwise.
*/
coap_opt_iterator_t *coap_option_iterator_init2(coap_pdu_t *pdu, coap_opt_iterator_t *oi,
const coap_opt_filter_t filter, coap_transport_t transport);
/**
* Updates the iterator @p oi to point to the next option. This
* function returns a pointer to that option or @c NULL if no more
* options exist. The contents of @p oi will be updated. In
* particular, @c oi->n specifies the current option's ordinal number
* (counted from @c 1), @c oi->type is the option's type code, and @c
* oi->option points to the beginning of the current option
* itself. When advanced past the last option, @c oi->option will be
* @c NULL.
*
* Note that options are skipped whose corresponding bits in the
* filter specified with coap_option_iterator_init() are @c 0. Options
* with type codes that do not fit in this filter hence will always be
* returned.
*
* @param oi The option iterator to update.
*
* @return The next option or @c NULL if no more options exist.
*/
coap_opt_t *coap_option_next(coap_opt_iterator_t *oi);
/**
* Retrieves the first option of type @p type from @p pdu. @p oi must
* point to a coap_opt_iterator_t object that will be initialized by
* this function to filter only options with code @p type. This
* function returns the first option with this type, or @c NULL if not
* found.
*
* @param pdu The PDU to parse for options.
* @param type The option type code to search for.
* @param oi An iterator object to use.
*
* @return A pointer to the first option of type @p type, or @c NULL
* if not found.
*/
coap_opt_t *coap_check_option(coap_pdu_t *pdu, unsigned char type, coap_opt_iterator_t *oi);
/**
* Encodes the given delta and length values into @p opt. This
* function returns the number of bytes that were required to encode
* @p delta and @p length or @c 0 on error. Note that the result
* indicates by how many bytes @p opt must be advanced to encode the
* option value.
*
* @param opt The option buffer space where @p delta and @p length are
* written
* @param maxlen The maximum length of @p opt
* @param delta The actual delta value to encode.
* @param length The actual length value to encode.
* @return The number of bytes used or @c 0 on error.
*/
size_t coap_opt_setheader(coap_opt_t *opt, size_t maxlen, unsigned short delta, size_t length);
/**
* Encodes option with given @p delta into @p opt. This function returns
* the number of bytes written to @p opt or @c 0 on error. This happens
* especially when @p opt does not provide sufficient space to store
* the option value, delta, and option jumps when required.
*
* @param opt The option buffer space where @p val is written
* @param n Maximum length of @p opt.
* @param delta The option delta.
* @param val The option value to copy into @p opt.
* @param len The actual length of @p val.
* @return The number of bytes that have been written to @p opt or
* @c 0 on error. The return value will always be less than @p n.
*/
size_t coap_opt_encode(coap_opt_t *opt, size_t n, unsigned short delta, const unsigned char *val,
size_t length);
/**
* Decodes the delta value of the next option. This function returns
* the number of bytes read or @c 0 on error. The caller of this
* function must ensure that it does not read over the boundaries
* of @p opt (e.g. by calling coap_opt_check_delta().
*
* @param opt The option to examine
* @return The number of bytes read or @c 0 on error.
*/
unsigned short coap_opt_delta(const coap_opt_t *opt);
/** @deprecated { Use coap_opt_delta() instead. } */
#define COAP_OPT_DELTA(opt) coap_opt_delta(opt)
/** @deprecated { Use coap_opt_encode() instead. } */
#ifndef WITH_TCP
#define COAP_OPT_SETDELTA(opt,val) \
coap_opt_encode((opt), COAP_MAX_PDU_SIZE, (val), NULL, 0)
#endif
/**
* Returns the length of the given option. @p opt must point to an
* option jump or the beginning of the option. This function returns
* @c 0 when @p opt is not an option or the actual length of @p opt
* (which can be @c 0 as well).
*
* @note {The rationale for using @c 0 in case of an error is that in
* most contexts, the result of this function is used to skip the next
* coap_opt_length() bytes. }
*
* @param opt The option whose length should be returned.
* @return The option's length or @c 0 when undefined.
*/
unsigned short coap_opt_length(const coap_opt_t *opt);
/** @deprecated { Use coap_opt_length() instead. } */
#define COAP_OPT_LENGTH(opt) coap_opt_length(opt)
/**
* Returns a pointer to the value of the given option. @p opt must
* point to an option jump or the beginning of the option. This
* function returns @c NULL if @p opt is not a valid option.
*
* @param opt The option whose value should be returned.
* @return A pointer to the option value or @c NULL on error.
*/
unsigned char *coap_opt_value(coap_opt_t *opt);
/**
* Returns a pointer to the coap option range definitions. @key
* must be a valid option ID. This function returns @c NULL if
* @p key is not a valid option ID.
*
* @param key The option ID whose definition should be returned.
* @return A pointer to the option definition.
*/
coap_option_def_t* coap_opt_def(unsigned short key);
/** @deprecated { Use coap_opt_value() instead. } */
#define COAP_OPT_VALUE(opt) coap_opt_value((coap_opt_t *)opt)
/** @} */
#endif /* _OPTION_H_ */

View file

@ -0,0 +1,660 @@
/* pdu.h -- CoAP message structure
*
* Copyright (C) 2010--2012 Olaf Bergmann <bergmann@tzi.org>
*
* This file is part of the CoAP library libcoap. Please see
* README for terms of use.
*/
#ifndef _COAP_PDU_H_
#define _COAP_PDU_H_
#include "config.h"
#include "coap_list.h"
#include "uri.h"
#ifdef WITH_LWIP
#include <lwip/pbuf.h>
#endif
/* pre-defined constants that reflect defaults for CoAP */
#define COAP_DEFAULT_RESPONSE_TIMEOUT 2 /* response timeout in seconds */
#define COAP_DEFAULT_MAX_RETRANSMIT 4 /* max number of retransmissions */
#define COAP_DEFAULT_PORT 5683 /* CoAP default UDP port */
#define COAP_DEFAULT_MAX_AGE 60 /* default maximum object lifetime in seconds */
#ifndef COAP_MAX_PDU_SIZE
#ifdef WITH_ARDUINO
#define COAP_MAX_PDU_SIZE 320 /* maximum size of a CoAP PDU for embedded platforms*/
#else
#define COAP_MAX_PDU_SIZE 1400 /* maximum size of a CoAP PDU for big platforms*/
#endif
#endif /* COAP_MAX_PDU_SIZE */
#define COAP_DEFAULT_VERSION 1 /* version of CoAP supported */
#define COAP_DEFAULT_SCHEME "coap" /* the default scheme for CoAP URIs */
/** well-known resources URI */
#define COAP_DEFAULT_URI_WELLKNOWN ".well-known/core"
#ifdef __COAP_DEFAULT_HASH
/* pre-calculated hash key for the default well-known URI */
#define COAP_DEFAULT_WKC_HASHKEY "\345\130\144\245"
#endif
/* CoAP message types */
#define COAP_MESSAGE_CON 0 /* confirmable message (requires ACK/RST) */
#define COAP_MESSAGE_NON 1 /* non-confirmable message (one-shot message) */
#define COAP_MESSAGE_ACK 2 /* used to acknowledge confirmable messages */
#define COAP_MESSAGE_RST 3 /* indicates error in received messages */
/* CoAP request methods */
#define COAP_REQUEST_GET 1
#define COAP_REQUEST_POST 2
#define COAP_REQUEST_PUT 3
#define COAP_REQUEST_DELETE 4
/* CoAP option types (be sure to update check_critical when adding options */
#define COAP_OPTION_IF_MATCH 1 /* C, opaque, 0-8 B, (none) */
#define COAP_OPTION_URI_HOST 3 /* C, String, 1-255 B, destination address */
#define COAP_OPTION_ETAG 4 /* E, opaque, 1-8 B, (none) */
#define COAP_OPTION_IF_NONE_MATCH 5 /* empty, 0 B, (none) */
#define COAP_OPTION_URI_PORT 7 /* C, uint, 0-2 B, destination port */
#define COAP_OPTION_LOCATION_PATH 8 /* E, String, 0-255 B, - */
#define COAP_OPTION_URI_PATH 11 /* C, String, 0-255 B, (none) */
#define COAP_OPTION_CONTENT_FORMAT 12 /* E, uint, 0-2 B, (none) */
#define COAP_OPTION_CONTENT_TYPE COAP_OPTION_CONTENT_FORMAT
#define COAP_OPTION_MAXAGE 14 /* E, uint, 0--4 B, 60 Seconds */
#define COAP_OPTION_URI_QUERY 15 /* C, String, 1-255 B, (none) */
#define COAP_OPTION_ACCEPT 17 /* C, uint, 0-2 B, (none) */
#define COAP_OPTION_LOCATION_QUERY 20 /* E, String, 0-255 B, (none) */
#define COAP_OPTION_PROXY_URI 35 /* C, String, 1-1034 B, (none) */
#define COAP_OPTION_PROXY_SCHEME 39 /* C, String, 1-255 B, (none) */
#define COAP_OPTION_SIZE1 60 /* E, uint, 0-4 B, (none) */
#define COAP_OPTION_SIZE2 28 /* E, uint, 0-4 B, (none) */
/* option types from draft-ietf-coap-observe-09 */
#define COAP_OPTION_OBSERVE 6 /* E, empty/uint, 0 B/0-3 B, (none) */
#define COAP_OPTION_SUBSCRIPTION COAP_OPTION_OBSERVE
/* selected option types from draft-core-block-04 */
#define COAP_OPTION_BLOCK2 23 /* C, uint, 0--3 B, (none) */
#define COAP_OPTION_BLOCK1 27 /* C, uint, 0--3 B, (none) */
#define COAP_MAX_OPT 63 /**< the highest option number we know */
/* CoAP result codes (HTTP-Code / 100 * 40 + HTTP-Code % 100) */
/* As of draft-ietf-core-coap-04, response codes are encoded to base
* 32, i.e. the three upper bits determine the response class while
* the remaining five fine-grained information specific to that class.
*/
#define COAP_RESPONSE_CODE(N) (((N)/100 << 5) | (N)%100)
/* Determines the class of response code C */
#define COAP_RESPONSE_CLASS(C) (((C) >> 5) & 0xFF)
#ifndef SHORT_ERROR_RESPONSE
/**
* Returns a human-readable response phrase for the specified CoAP response @p
* code. This function returns @c NULL if not found.
*
* @param code The response code for which the literal phrase should be
* retrieved.
*
* @return A zero-terminated string describing the error, or @c NULL if not
* found.
*/
char *coap_response_phrase(unsigned char code);
#define COAP_ERROR_PHRASE_LENGTH 32 /**< maximum length of error phrase */
#else
#define coap_response_phrase(x) ((char *)NULL)
#define COAP_ERROR_PHRASE_LENGTH 0 /**< maximum length of error phrase */
#endif /* SHORT_ERROR_RESPONSE */
/* The following definitions exist for backwards compatibility */
#if 0 /* this does not exist any more */
#define COAP_RESPONSE_100 40 /* 100 Continue */
#endif
#define COAP_RESPONSE_200 COAP_RESPONSE_CODE(200) /* 2.00 OK */
#define COAP_RESPONSE_201 COAP_RESPONSE_CODE(201) /* 2.01 Created */
#define COAP_RESPONSE_304 COAP_RESPONSE_CODE(203) /* 2.03 Valid */
#define COAP_RESPONSE_400 COAP_RESPONSE_CODE(400) /* 4.00 Bad Request */
#define COAP_RESPONSE_404 COAP_RESPONSE_CODE(404) /* 4.04 Not Found */
#define COAP_RESPONSE_405 COAP_RESPONSE_CODE(405) /* 4.05 Method Not Allowed */
#define COAP_RESPONSE_415 COAP_RESPONSE_CODE(415) /* 4.15 Unsupported Media Type */
#define COAP_RESPONSE_500 COAP_RESPONSE_CODE(500) /* 5.00 Internal Server Error */
#define COAP_RESPONSE_501 COAP_RESPONSE_CODE(501) /* 5.01 Not Implemented */
#define COAP_RESPONSE_503 COAP_RESPONSE_CODE(503) /* 5.03 Service Unavailable */
#define COAP_RESPONSE_504 COAP_RESPONSE_CODE(504) /* 5.04 Gateway Timeout */
#if 0 /* these response codes do not have a valid code any more */
# define COAP_RESPONSE_X_240 240 /* Token Option required by server */
# define COAP_RESPONSE_X_241 241 /* Uri-Authority Option required by server */
#endif
#define COAP_RESPONSE_X_242 COAP_RESPONSE_CODE(402) /* Critical Option not supported */
/* CoAP media type encoding */
#define COAP_MEDIATYPE_TEXT_PLAIN 0 /* text/plain (UTF-8) */
#define COAP_MEDIATYPE_APPLICATION_LINK_FORMAT 40 /* application/link-format */
#define COAP_MEDIATYPE_APPLICATION_XML 41 /* application/xml */
#define COAP_MEDIATYPE_APPLICATION_OCTET_STREAM 42 /* application/octet-stream */
#define COAP_MEDIATYPE_APPLICATION_RDF_XML 43 /* application/rdf+xml */
#define COAP_MEDIATYPE_APPLICATION_EXI 47 /* application/exi */
#define COAP_MEDIATYPE_APPLICATION_JSON 50 /* application/json */
#define COAP_MEDIATYPE_APPLICATION_CBOR 60 /* application/cbor */
/* Note that identifiers for registered media types are in the range 0-65535. We
* use an unallocated type here and hope for the best. */
#define COAP_MEDIATYPE_ANY 0xff /* any media type */
/**
* coap_tid_t is used to store CoAP transaction id, i.e. a hash value
* built from the remote transport address and the message id of a
* CoAP PDU. Valid transaction ids are greater or equal zero.
*/
typedef int coap_tid_t;
/** Indicates an invalid transaction id. */
#define COAP_INVALID_TID -1
#define COAP_TCP_HEADER_NO_FIELD 2
#define COAP_TCP_HEADER_8_BIT 3
#define COAP_TCP_HEADER_16_BIT 4
#define COAP_TCP_HEADER_32_BIT 6
#define COAP_TCP_LENGTH_FIELD_8_BIT 13
#define COAP_TCP_LENGTH_FIELD_16_BIT 269
#define COAP_TCP_LENGTH_FIELD_32_BIT 65805
#define COAP_TCP_LENGTH_LIMIT_8_BIT 13
#define COAP_TCP_LENGTH_LIMIT_16_BIT 256
#define COAP_TCP_LENGTH_LIMIT_32_BIT 65536
#define COAP_TCP_LENGTH_FIELD_NUM_8_BIT 13
#define COAP_TCP_LENGTH_FIELD_NUM_16_BIT 14
#define COAP_TCP_LENGTH_FIELD_NUM_32_BIT 15
#define COAP_OPTION_FIELD_8_BIT 12
#define COAP_OPTION_FIELD_16_BIT 256
#define COAP_OPTION_FIELD_32_BIT 65536
typedef enum {
COAP_UDP = 0,
COAP_TCP,
COAP_TCP_8BIT,
COAP_TCP_16BIT,
COAP_TCP_32BIT
} coap_transport_t;
#ifdef WORDS_BIGENDIAN
typedef struct {
unsigned short version:2; /* protocol version */
unsigned short type:2; /* type flag */
unsigned short token_length:4; /* length of Token */
unsigned short code:8; /* request method (value 1--10) or response
code (value 40-255) */
unsigned short id; /* message id */
unsigned char token[]; /* the actual token, if any */
} coap_hdr_udp_t;
#else
typedef struct {
unsigned short token_length:4; /* length of Token */
unsigned short type:2; /* type flag */
unsigned short version:2; /* protocol version */
unsigned short code:8; /* request method (value 1--10) or response
code (value 40-255) */
unsigned short id; /* transaction id (network byte order!) */
unsigned char token[]; /* the actual token, if any */
} coap_hdr_udp_t;
#endif
typedef struct {
unsigned char header_data[COAP_TCP_HEADER_NO_FIELD];
unsigned char token[]; /* the actual token, if any */
} coap_hdr_tcp_t;
typedef struct {
unsigned char header_data[COAP_TCP_HEADER_8_BIT];
unsigned char token[]; /* the actual token, if any */
} coap_hdr_tcp_8bit_t;
typedef struct {
unsigned char header_data[COAP_TCP_HEADER_16_BIT];
unsigned char token[]; /* the actual token, if any */
} coap_hdr_tcp_16bit_t;
typedef struct {
unsigned char header_data[6];
unsigned char token[]; /* the actual token, if any */
} coap_hdr_tcp_32bit_t;
typedef union {
coap_hdr_udp_t udp;
coap_hdr_tcp_t tcp;
coap_hdr_tcp_8bit_t tcp_8bit;
coap_hdr_tcp_16bit_t tcp_16bit;
coap_hdr_tcp_32bit_t tcp_32bit;
} coap_hdr_transport_t;
// Typedef for backwards compatibility.
typedef coap_hdr_udp_t coap_hdr_t;
#define COAP_MESSAGE_IS_EMPTY(MSG) ((MSG).code == 0)
#define COAP_MESSAGE_IS_REQUEST(MSG) (!COAP_MESSAGE_IS_EMPTY(MSG) \
&& ((MSG).code < 32))
#define COAP_MESSAGE_IS_RESPONSE(MSG) ((MSG).code >= 64 && (MSG).code <= 191)
#define COAP_OPT_LONG 0x0F /* OC == 0b1111 indicates that the option list
* in a CoAP message is limited by 0b11110000
* marker */
#define COAP_OPT_END 0xF0 /* end marker */
#define COAP_PAYLOAD_START 0xFF /* payload marker */
/**
* Structures for more convenient handling of options. (To be used with ordered
* coap_list_t.) The option's data will be added to the end of the coap_option
* structure (see macro COAP_OPTION_DATA).
*/
typedef struct {
unsigned short key; /* the option key (no delta coding) */
unsigned int length;
} coap_option;
#define COAP_OPTION_KEY(option) (option).key
#define COAP_OPTION_LENGTH(option) (option).length
#define COAP_OPTION_DATA(option) ((unsigned char *)&(option) + sizeof(coap_option))
/**
* Header structure for CoAP PDUs
*/
typedef struct {
size_t max_size; /**< allocated storage for options and data */
union {
coap_hdr_t *hdr; /**< Address of the first byte of the CoAP message.
* This may or may not equal (coap_hdr_t*)(pdu+1)
* depending on the memory management
* implementation. */
coap_hdr_transport_t *transport_hdr; /**< Address of the first byte of the CoAP message.
* This may or may not equal (coap_hdr_t*)(pdu+1)
* depending on the memory management
* implementation. */
};
unsigned short max_delta; /**< highest option number */
unsigned int length; /**< PDU length (including header, options, data) */
unsigned char *data; /**< payload */
#ifdef WITH_LWIP
struct pbuf *pbuf; /**< lwIP PBUF. The package data will always reside
* inside the pbuf's payload, but this pointer
* has to be kept because no exact offset can be
* given. This field must not be accessed from
* outside, because the pbuf's reference count
* is checked to be 1 when the pbuf is assigned
* to the pdu, and the pbuf stays exclusive to
* this pdu. */
#endif
} coap_pdu_t;
/**
* Options in coap_pdu_t are accessed with the macro COAP_OPTION.
*/
#define COAP_OPTION(node) ((coap_option *)(node)->options)
#ifdef __cplusplus
extern "C"
{
#endif
#ifdef WITH_LWIP
/**
* Creates a CoAP PDU from an lwIP @p pbuf, whose reference is passed on to this
* function.
*
* The pbuf is checked for being contiguous, for having enough head space for
* the PDU struct (which is located directly in front of the data, overwriting
* the old other headers), and for having only one reference. The reference is
* stored in the PDU and will be freed when the PDU is freed.
*
* (For now, these are fatal errors; in future, a new pbuf might be allocated,
* the data copied and the passed pbuf freed).
*
* This behaves like coap_pdu_init(0, 0, 0, pbuf->tot_len), and afterwards
* copying the contents of the pbuf to the pdu.
*
* @return A pointer to the new PDU object or @c NULL on error.
*/
coap_pdu_t * coap_pdu_from_pbuf(struct pbuf *pbuf);
#endif
/**
* Creates a new CoAP PDU of given @p size (must be large enough to hold the
* basic CoAP message header (coap_hdr_t). The function returns a pointer to the
* node coap_pdu_t object on success, or @c NULL on error. The storage allocated
* for the result must be released with coap_delete_pdu().
*
* @param type The type of the PDU (one of COAP_MESSAGE_CON, COAP_MESSAGE_NON,
* COAP_MESSAGE_ACK, COAP_MESSAGE_RST).
* @param code The message code.
* @param id The message id to set or COAP_INVALID_TID if unknown.
* @param size The number of bytes to allocate for the actual message.
*
* @return A pointer to the new PDU object or @c NULL on error.
*/
coap_pdu_t *
coap_pdu_init(unsigned char type,
unsigned char code,
unsigned short id,
size_t size);
/**
* Creates a new CoAP PDU of given @p size (must be large enough to hold the
* basic CoAP message header (coap_hdr_t). The function returns a pointer to
* the node coap_pdu_t object on success, or @c NULL on error. The storage
* allocated for the result must be released with coap_delete_pdu().
*
* @param type The type of the PDU (one of COAP_MESSAGE_CON,
* COAP_MESSAGE_NON, COAP_MESSAGE_ACK, COAP_MESSAGE_RST).
* @param code The message code.
* @param id The message id to set or COAP_INVALID_TID if unknown.
* @param size The number of bytes to allocate for the actual message.
* @param transport The transport type.
*
* @return A pointer to the new PDU object or @c NULL on error.
*/
coap_pdu_t *
coap_pdu_init2(unsigned char type, unsigned char code, unsigned short id,
size_t size, coap_transport_t transport);
/**
* Clears any contents from @p pdu and resets @c version field, @c
* length and @c data pointers. @c max_size is set to @p size, any
* other field is set to @c 0. Note that @p pdu must be a valid
* pointer to a coap_pdu_t object created e.g. by coap_pdu_init().
*/
void coap_pdu_clear(coap_pdu_t *pdu, size_t size);
/**
* Clears any contents from @p pdu and resets @c version field, @c
* length and @c data pointers. @c max_size is set to @p size, any
* other field is set to @c 0. Note that @p pdu must be a valid
* pointer to a coap_pdu_t object created e.g. by coap_pdu_init().
*/
void coap_pdu_clear2(coap_pdu_t *pdu, size_t size, coap_transport_t transport,
unsigned int length);
/**
* Creates a new CoAP PDU.
* The object is created on the heap and must be released using
* coap_delete_pdu();
*
* @deprecated This function allocates the maximum storage for each
* PDU. Use coap_pdu_init() instead.
*/
coap_pdu_t *coap_new_pdu(void);
/**
* Creates a new CoAP PDU. The object is created on the heap and must be released
* using coap_delete_pdu();
*
* @deprecated This function allocates the maximum storage for each
* PDU. Use coap_pdu_init2() instead.
*/
coap_pdu_t *coap_new_pdu2(coap_transport_t transport, unsigned int size);
void coap_delete_pdu(coap_pdu_t *);
/**
* Parses @p data into the CoAP PDU structure given in @p result.
* This function returns @c 0 on error or a number greater than zero on success.
*
* @param data The raw data to parse as CoAP PDU
* @param length The actual size of @p data
* @param result The PDU structure to fill. Note that the structure must
* provide space for at least @p length bytes to hold the
* entire CoAP PDU.
*
* @return A value greater than zero on success or @c 0 on error.
*/
int coap_pdu_parse(unsigned char *data,
size_t length,
coap_pdu_t *result);
/**
* Parses @p data into the CoAP PDU structure given in @p result.
* This function returns @c 0 on error or a number greater than zero on success.
*
* @param data The raw data to parse as CoAP PDU
* @param length The actual size of @p data
* @param result The PDU structure to fill. Note that the structure must
* provide space for at least @p length bytes to hold the
* entire CoAP PDU.
* @param transport The transport type.
* @return A value greater than zero on success or @c 0 on error.
*/
int coap_pdu_parse2(unsigned char *data, size_t length, coap_pdu_t *pdu,
coap_transport_t transport);
#ifdef WITH_TCP
/**
* Get total pdu size including header + option + payload (with marker) from pdu data.
*
* @param data The raw data to parse as CoAP PDU.
* @param size payload size of pdu.
* @return Total message length.
*/
size_t coap_get_total_message_length(const unsigned char *data, size_t size);
/**
* Get transport type of coap header for coap over tcp
* through payload size(including payload marker) + option size.
*
* @param size payload size of pdu.
* @return The transport type.
*/
coap_transport_t coap_get_tcp_header_type_from_size(unsigned int size);
/**
* Get transport type of coap header for coap over tcp
* through first nibble(0~E) of init-byte .
*
* @param legnth length value of init byte.
* @return The transport type.
*/
coap_transport_t coap_get_tcp_header_type_from_initbyte(unsigned int length);
/**
* Add length of option/payload into 'Len+ byte...' field of coap header
* for coap over tcp.
*
* @param pdu The pdu pointer.
* @param transport The transport type.
* @param length length value of init byte.
*/
void coap_add_length(const coap_pdu_t *pdu, coap_transport_t transport,
unsigned int length);
/**
* Get the length of option/payload field of coap header for coap over tcp.
*
* @param pdu The pdu pointer.
* @param transport The transport type.
* @return length value of init byte.
*/
unsigned int coap_get_length(const coap_pdu_t *pdu, coap_transport_t transport);
/**
* Get the length of option/payload field of coap header for coap over tcp.
*
* @param header The header to parse.
* @return transport The transport type.
*/
unsigned int coap_get_length_from_header(const unsigned char *header,
coap_transport_t transport);
/**
* Get length of header including len, TKL, Len+bytes, Code, token bytes for coap over tcp.
*
* @param data The raw data to parse as CoAP PDU
* @return header length + token length
*/
unsigned int coap_get_tcp_header_length(unsigned char *data);
/**
* Get length of header including len, TKL, Len+bytes, Code
* without token bytes for coap over tcp.
*
* @param transport The transport type.
* @return header length.
*/
unsigned int coap_get_tcp_header_length_for_transport(coap_transport_t transport);
/**
* Get option length.
*
* @param key delta of option
* @param length length of option
* @return total option length
*/
size_t coap_get_opt_header_length(unsigned short key, size_t length);
#endif /* WITH_TCP */
/**
* Add code in coap header.
*
* @param pdu The pdu pointer.
* @param transport The transport type.
* @param code The message code.
*/
void coap_add_code(const coap_pdu_t *pdu, coap_transport_t transport,
unsigned int code);
/**
* Get message code from coap header
*
* @param pdu The pdu pointer.
* @param transport The transport type.
* @return The message code.
*/
unsigned int coap_get_code(const coap_pdu_t *pdu, coap_transport_t transport);
/**
* Adds token of length @p len to @p pdu.
* Adding the token destroys any following contents of the pdu. Hence options
* and data must be added after coap_add_token() has been called. In @p pdu,
* length is set to @p len + @c 4, and max_delta is set to @c 0. This funtion
* returns @c 0 on error or a value greater than zero on success.
*
* @param pdu The PDU where the token is to be added.
* @param len The length of the new token.
* @param data The token to add.
*
* @return A value greater than zero on success, or @c 0 on error.
*/
int coap_add_token(coap_pdu_t *pdu,
size_t len,
const unsigned char *data);
/**
* Adds token of length @p len to @p pdu. Adding the token destroys
* any following contents of the pdu. Hence options and data must be
* added after coap_add_token2() has been called. In @p pdu, length is
* set to @p len + @c 4, and max_delta is set to @c 0. This funtion
* returns @c 0 on error or a value greater than zero on success.
*
* @param pdu The pdu pointer.
* @param len The length of the new token.
* @param data The token to add.
* @param transport The transport type.
* @return A value greater than zero on success, or @c 0 on error.
*/
int coap_add_token2(coap_pdu_t *pdu, size_t len, const unsigned char *data,
coap_transport_t transport);
/**
* Get token from coap header
*
* @param pdu_hdr The header pointer of PDU.
* @param token out parameter to get token.
* @param token_length out parameter to get token length.
*/
void coap_get_token(const coap_hdr_t *pdu_hdr,
unsigned char **token, unsigned int *token_length);
/**
* Get token from coap header based on transport type
*
* @param pdu_hdr The header pointer of PDU.
* @param transport The transport type.
* @param token out parameter to get token.
* @param token_length out parameter to get token length.
*/
void coap_get_token2(const coap_hdr_transport_t *pdu_hdr, coap_transport_t transport,
unsigned char **token, unsigned int *token_length);
/**
* Adds option of given type to pdu that is passed as first parameter.
* coap_add_option() destroys the PDU's data, so coap_add_data() must be called
* after all options have been added. As coap_add_token() destroys the options
* following the token, the token must be added before coap_add_option() is
* called. This function returns the number of bytes written or @c 0 on error.
*/
size_t coap_add_option(coap_pdu_t *pdu,
unsigned short type,
unsigned int len,
const unsigned char *data);
/**
* Adds option of given type to pdu that is passed as first
* parameter. coap_add_option2() destroys the PDU's data, so
* coap_add_data() must be called after all options have been added.
* As coap_add_token2() destroys the options following the token,
* the token must be added before coap_add_option2() is called.
* This function returns the number of bytes written or @c 0 on error.
*/
size_t coap_add_option2(coap_pdu_t *pdu, unsigned short type, unsigned int len,
const unsigned char *data, coap_transport_t transport);
/**
* Adds option of given type to pdu that is passed as first parameter, but does
* not write a value. It works like coap_add_option with respect to calling
* sequence (i.e. after token and before data). This function returns a memory
* address to which the option data has to be written before the PDU can be
* sent, or @c NULL on error.
*/
unsigned char *coap_add_option_later(coap_pdu_t *pdu,
unsigned short type,
unsigned int len);
/**
* Adds given data to the pdu that is passed as first parameter. Note that the
* PDU's data is destroyed by coap_add_option(). coap_add_data() must be called
* only once per PDU, otherwise the result is undefined.
*/
int coap_add_data(coap_pdu_t *pdu,
unsigned int len,
const unsigned char *data);
/**
* Retrieves the length and data pointer of specified PDU. Returns 0 on error or
* 1 if *len and *data have correct values. Note that these values are destroyed
* with the pdu.
*/
int coap_get_data(const coap_pdu_t *pdu,
size_t *len,
unsigned char **data);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* _COAP_PDU_H_ */

View file

@ -0,0 +1,87 @@
/* prng.h -- Pseudo Random Numbers
*
* Copyright (C) 2010,2011 Olaf Bergmann <bergmann@tzi.org>
*
* This file is part of the CoAP library libcoap. Please see
* README for terms of use.
*/
/**
* @file prng.h
* @brief Pseudo Random Numbers
*/
#ifndef _COAP_PRNG_H_
#define _COAP_PRNG_H_
#include "config.h"
/**
* @defgroup prng Pseudo Random Numbers
* @{
*/
#ifndef WITH_CONTIKI
#include <stdlib.h>
/**
* Fills \p buf with \p len random bytes. This is the default
* implementation for prng(). You might want to change prng() to use
* a better PRNG on your specific platform.
*/
INLINE_API int coap_prng_impl(unsigned char *buf, size_t len)
{
while (len--)
*buf++ = rand() & 0xFF;
return 1;
}
#else /* WITH_CONTIKI */
#include <string.h>
/**
* Fills \p buf with \p len random bytes. This is the default
* implementation for prng(). You might want to change prng() to use
* a better PRNG on your specific platform.
*/
INLINE_API int
contiki_prng_impl(unsigned char *buf, size_t len)
{
unsigned short v = random_rand();
while (len > sizeof(v))
{
memcpy(buf, &v, sizeof(v));
len -= sizeof(v);
buf += sizeof(v);
v = random_rand();
}
memcpy(buf, &v, len);
return 1;
}
#define prng(Buf,Length) contiki_prng_impl((Buf), (Length))
#define prng_init(Value) random_init((unsigned short)(Value))
#endif /* WITH_CONTIKI */
#ifndef prng
/**
* Fills \p Buf with \p Length bytes of random data.
*
* @hideinitializer
*/
#define prng(Buf,Length) coap_prng_impl((Buf), (Length))
#endif
#ifndef prng_init
/**
* Called to set the PRNG seed. You may want to re-define this to
* allow for a better PRNG.
*
* @hideinitializer
*/
#define prng_init(Value) srand((unsigned long)(Value))
#endif
/** @} */
#endif /* _COAP_PRNG_H_ */

View file

@ -0,0 +1,318 @@
/* resource.h -- generic resource handling
*
* Copyright (C) 2010,2011,2014 Olaf Bergmann <bergmann@tzi.org>
*
* This file is part of the CoAP library libcoap. Please see
* README for terms of use.
*/
/**
* @file resource.h
* @brief generic resource handling
*/
#ifndef _COAP_RESOURCE_H_
#define _COAP_RESOURCE_H_
#include "config.h"
#include "t_list.h"
#if defined(HAVE_ASSERT_H) && !defined(assert)
# include <assert.h>
#endif
#ifndef COAP_RESOURCE_CHECK_TIME
/** The interval in seconds to check if resources have changed. */
#define COAP_RESOURCE_CHECK_TIME 2
#endif /* COAP_RESOURCE_CHECK_TIME */
#ifndef WITH_CONTIKI
# ifdef COAP_RESOURCES_NOHASH
# include "utlist.h"
# else
# include "uthash.h"
# endif
#else /* WITH_CONTIKI */
#endif /* WITH_CONTIKI */
#include "hashkey.h"
#include "async.h"
#include "str.h"
#include "pdu.h"
#include "net.h"
#include "subscribe.h"
/** Definition of message handler function (@sa coap_resource_t). */
typedef void (*coap_method_handler_t)(coap_context_t *, struct coap_resource_t *, coap_address_t *,
coap_pdu_t *, str * /* token */, coap_pdu_t * /* response */);
#define COAP_ATTR_FLAGS_RELEASE_NAME 0x1
#define COAP_ATTR_FLAGS_RELEASE_VALUE 0x2
typedef struct coap_attr_t
{
struct coap_attr_t *next;
str name;
str value;
int flags;
} coap_attr_t;
#define COAP_RESOURCE_FLAGS_RELEASE_URI 0x1
typedef struct coap_resource_t
{
unsigned int dirty :1; /**< set to 1 if resource has changed */
unsigned int partiallydirty :1; /**< set to 1 if some subscribers have not yet been notified of the last change */
unsigned int observable :1; /**< can be observed */
unsigned int cacheable :1; /**< can be cached */
/**
* Used to store handlers for the four coap methods @c GET, @c POST,
* @c PUT, and @c DELETE. coap_dispatch() will pass incoming
* requests to the handler that corresponds to its request method or
* generate a 4.05 response if no handler is available.
*/
coap_method_handler_t handler[4];
coap_key_t key; /**< the actual key bytes for this resource */
#ifndef WITH_CONTIKI
#ifdef COAP_RESOURCES_NOHASH
struct coap_resource_t *next;
#else
UT_hash_handle hh;
#endif
#endif /* WITH_CONTIKI */
#ifndef WITH_CONTIKI
coap_attr_t *link_attr; /**< attributes to be included with the link format */
#else /* WITH_CONTIKI */
LIST_STRUCT(link_attr); /**< attributes to be included with the link format */
#endif /* WITH_CONTIKI */
LIST_STRUCT(subscribers); /**< list of observers for this resource */
/**
* Request URI for this resource. This field will point into the
* static memory. */
str uri;
int flags;
} coap_resource_t;
/**
* Creates a new resource object and initializes the link field to the
* string of length @p len. This function returns the
* new coap_resource_t object.
*
* @param uri The URI path of the new resource.
* @param len The length of @p uri.
* @param flags Flags for memory management (in particular release of memory)
*
* @return A pointer to the new object or @c NULL on error.
*/
coap_resource_t *coap_resource_init(const unsigned char *uri, size_t len, int flags);
/**
* Registers the given @p resource for @p context. The resource must
* have been created by coap_resource_init(), the storage allocated
* for the resource will be released by coap_delete_resource().
*
* @param context The context to use.
* @param resource The resource to store.
*/
void coap_add_resource(coap_context_t *context, coap_resource_t *resource);
/**
* Deletes a resource identified by @p key. The storage allocated for
* that resource is freed.
*
* @param context The context where the resources are stored.
* @param key The unique key for the resource to delete.
*
* @return @c 1 if the resource was found (and destroyed), @c 0 otherwise.
*/
int coap_delete_resource(coap_context_t *context, coap_key_t key);
/**
* Registers a new attribute with the given @p resource. As the
* attributes str fields will point to @p name and @p val the
* caller must ensure that these pointers are valid during the
* attribute's lifetime.
*
* @param resource The resource to register the attribute with.
* @param name The attribute's name.
* @param nlen Length of @p name.
* @param val The attribute's value or @c NULL if none.
* @param vlen Length of @p val if specified.
* @param flags Flags for memory management (in particular release of memory)
*
* @return A pointer to the new attribute or @c NULL on error.
*/
coap_attr_t *coap_add_attr(coap_resource_t *resource, const unsigned char *name, size_t nlen,
const unsigned char *val, size_t vlen, int flags);
/**
* Returns @p resource's coap_attr_t object with given @p name if
* found, @c NULL otherwise.
*
* @param resource The resource to search for attribute @p name.
* @param name Name of the requested attribute.
* @param nlen Actual length of @p name.
* @return The first attribute with specified @p name or @c NULL if
* none was found.
*/
coap_attr_t *coap_find_attr(coap_resource_t *resource, const unsigned char *name, size_t nlen);
/**
* Deletes an attribute
*
* @param attr Pointer to a previously created attribute
*
*/
void coap_delete_attr(coap_attr_t *attr);
/**
* Status word to encode the result of conditional print or copy
* operations such as coap_print_link(). The lower 28 bits of
* coap_print_status_t are used to encode the number of characters
* that has actually been printed, bits 28 to 31 encode the status.
* When COAP_PRINT_STATUS_ERROR is set, an error occurred during
* output. In this case, the other bits are undefined.
* COAP_PRINT_STATUS_TRUNC indicates that the output is truncated,
* i.e. the printing would have exceeded the current buffer.
*/
typedef unsigned int coap_print_status_t;
#define COAP_PRINT_STATUS_MASK 0xF0000000u
#define COAP_PRINT_OUTPUT_LENGTH(v) ((v) & ~COAP_PRINT_STATUS_MASK)
#define COAP_PRINT_STATUS_ERROR 0x80000000u
#define COAP_PRINT_STATUS_TRUNC 0x40000000u
/**
* Writes a description of this resource in link-format to given text
* buffer. @p len must be initialized to the maximum length of @p buf
* and will be set to the number of characters actually written if
* successful. This function returns @c 1 on success or @c 0 on
* error.
*
* @param resource The resource to describe.
* @param buf The output buffer to write the description to.
* @param len Must be initialized to the length of @p buf and
* will be set to the length of the printed link description.
* @param offset The offset within the resource description where to
* start writing into @p buf. This is useful for dealing
* with the Block2 option. @p offset is updated during
* output as it is consumed.
*
* @return If COAP_PRINT_STATUS_ERROR is set, an error occured. Otherwise,
* the lower 28 bits will indicate the number of characters that
* have actually been output into @p buffer. The flag
* COAP_PRINT_STATUS_TRUNC indicates that the output has been
* truncated.
*/
coap_print_status_t coap_print_link(const coap_resource_t *resource, unsigned char *buf,
size_t *len, size_t *offset);
/**
* Registers the specified @p handler as message handler for the request type
* @p method
*
* @param resource The resource for which the handler shall be registered.
* @param method The CoAP request method to handle.
* @param handler The handler to register with @p resource.
*/
INLINE_API void coap_register_handler(coap_resource_t *resource, unsigned char method,
coap_method_handler_t handler)
{
assert(resource);
assert(
method > 0
&& (size_t)(method - 1)
< sizeof(resource->handler) / sizeof(coap_method_handler_t));
resource->handler[method - 1] = handler;
}
/**
* Returns the resource identified by the unique string @p key. If no
* resource was found, this function returns @c NULL.
*
* @param context The context to look for this resource.
* @param key The unique key of the resource.
*
* @return A pointer to the resource or @c NULL if not found.
*/
coap_resource_t *coap_get_resource_from_key(coap_context_t *context, coap_key_t key);
/**
* Calculates the hash key for the resource requested by the
* Uri-Options of @p request. This function calls coap_hash() for
* every path segment.
*
* @param request The requesting pdu.
* @param key The resulting hash is stored in @p key
*/
void coap_hash_request_uri(const coap_pdu_t *request, coap_key_t key);
/**
* @addtogroup observe
*/
/**
* Adds the specified peer as observer for @p resource. The
* subscription is identified by the given @p token. This function
* returns the registered subscription information if the @p observer
* has been added, or @c NULL on error.
*
* @param resource The observed resource.
* @param observer The remote peer that wants to received status updates.
* @param token The token that identifies this subscription.
* @param token_length The actual length of @p token. Must be @c 0 when
* @p token is @c NULL.
* @return A pointer to the added/updated subscription information or
* @c NULL on error.
*/
coap_subscription_t *coap_add_observer(coap_resource_t *resource, const coap_address_t *observer,
const str *token);
/**
* Returns a subscription object for given @p peer.
*
* @param resource The observed resource.
* @param peer The address to search for.
* @param token The token that identifies this subscription or @c NULL for any
* token.
* @return A valid subscription if exists or @c NULL otherwise.
*/
coap_subscription_t *coap_find_observer(coap_resource_t *resource, const coap_address_t *peer,
const str *token);
/**
* Marks an observer as alive.
*
* @param context The CoAP context to use
* @param observer The transport address of the observer
* @param token The corresponding token that has been used for
* the subscription
*/
void coap_touch_observer(coap_context_t *context, const coap_address_t *observer, const str *token);
/**
* Removes any subscription for @p observer from @p resource and releases
* the allocated storage.
*
* @param resource The observed resource.
* @param observer The observer's address.
* @param token The token that identifies this subscription or @c NULL for any
* token.
*/
void coap_delete_observer(coap_resource_t *resource, const coap_address_t *observer,
const str *token);
/**
* Checks for all known resources, if they are dirty and notifies
* subscribed observers.
*/
void coap_check_notify(coap_context_t *context);
/** @} */
#endif /* _COAP_RESOURCE_H_ */

View file

@ -0,0 +1,31 @@
/* str.h -- strings to be used in the CoAP library
*
* Copyright (C) 2010,2011 Olaf Bergmann <bergmann@tzi.org>
*
* This file is part of the CoAP library libcoap. Please see
* README for terms of use.
*/
#ifndef _COAP_STR_H_
#define _COAP_STR_H_
#include <string.h>
typedef struct
{
size_t length; /* length of string */
unsigned char *s; /* string data */
} str;
#define COAP_SET_STR(st,l,v) { (st)->length = (l), (st)->s = (v); }
/**
* Returns a new string object with at least size bytes storage
* allocated. The string must be released using coap_delete_string();
*/
str *coap_new_string(size_t size);
/** Deletes the given string and releases any memory allocated. */
void coap_delete_string(str *);
#endif /* _COAP_STR_H_ */

View file

@ -0,0 +1,201 @@
/* subscribe.h -- subscription handling for CoAP
* see draft-hartke-coap-observe-03
*
* Copyright (C) 2010--2012 Olaf Bergmann <bergmann@tzi.org>
*
* This file is part of the CoAP library libcoap. Please see
* README for terms of use.
*/
#ifndef _COAP_SUBSCRIBE_H_
#define _COAP_SUBSCRIBE_H_
#include "config.h"
#include "address.h"
/**
* @defgroup observe Resource observation
* @{
*/
#ifndef COAP_OBS_MAX_NON
/**
* Number of notifications that may be sent non-confirmable before a
* confirmable message is sent to detect if observers are alive. The
* maximum allowed value here is @c 15.
*/
#define COAP_OBS_MAX_NON 5
#endif /* COAP_OBS_MAX_NON */
#ifndef COAP_OBS_MAX_FAIL
/**
* Number of confirmable notifications that may fail (i.e. time out
* without being ACKed) before an observer is removed. The maximum
* value for COAP_OBS_MAX_FAIL is @c 3.
*/
#define COAP_OBS_MAX_FAIL 3
#endif /* COAP_OBS_MAX_FAIL */
/** Subscriber information */
typedef struct coap_subscription_t
{
struct coap_subscription_t *next; /**< next element in linked list */
coap_address_t subscriber; /**< address and port of subscriber */
unsigned int non :1; /**< send non-confirmable notifies if @c 1 */
unsigned int non_cnt :4; /**< up to 15 non-confirmable notifies allowed */
unsigned int fail_cnt :2; /**< up to 3 confirmable notifies can fail */
unsigned int dirty :1; /**< set if the notification temporarily could not be sent (in that case, the resource's partiallydirty flag is set too) */
size_t token_length; /**< actual length of token */
unsigned char token[8]; /**< token used for subscription */
/* @todo CON/NON flag, block size */
} coap_subscription_t;
void coap_subscription_init(coap_subscription_t *);
#if 0
#include "uthash.h"
#include "uri.h"
#include "list.h"
#include "pdu.h"
#include "net.h"
#if 0
typedef unsigned long coap_key_t;
/** Used to indicate that a hashkey is invalid. */
#define COAP_INVALID_HASHKEY ((coap_key_t)-1)
typedef struct
{
coap_uri_t *uri; /* unique identifier; memory is released by coap_delete_resource() */
UT_hash_handle hh; /**< hash handle (for internal use only) */
str *name; /* display name of the resource */
unsigned char mediatype; /* media type for resource representation */
unsigned int dirty:1; /* set to 1 if resource has changed */
unsigned int writable:1; /* set to 1 if resource can be changed using PUT */
/* cache-control */
unsigned char etag[4]; /* version identifier for this resource
* (zero terminated, first byte is zero if not set). */
unsigned int maxage; /* maximum cache time (zero means no Max-age option) */
/**
* Callback function that copies the resource representation into the provided data
* buffer (PDU payload). finished is set to 1 to indicate that this was the last block
* of buflen data for this resource representation, 0 means that data is not finished
* and a subsequent call with offset updated by buflen would yield more data (i.e.
* the M-bit of CoAP's block option must be set if offset and buflen are selected
* accordingly.
* When called, buflen must be set to the maximum length of buf that is to be filled
* with the mediatype representation of the resource identified by uri.
* The mediatype must be set to the requested mediatype of COAP_MEDIATYPE_ANY if
* none was given. On return, the mediatype will be set to the type that is
* actually used.
* The return value indicates the result code that should be used in a response to
* this function.
*/
int (*data)(coap_uri_t *uri, unsigned char *mediatype, unsigned int offset, unsigned char *buf, unsigned int *buflen, int *finished);
}coap_resource_t;
#endif
typedef struct
{
coap_key_t resource; /* hash key for subscribed resource */
time_t expires; /* expiry time of subscription */
coap_address_t subscriber; /**< subscriber's address */
str token; /**< subscription token */
}coap_subscription_t;
#define COAP_RESOURCE(node) ((coap_resource_t *)(node)->data)
#define COAP_SUBSCRIPTION(node) ((coap_subscription_t *)(node)->data)
/** Checks subscribed resources for updates and notifies subscribers of changes. */
void coap_check_resource_list(coap_context_t *context);
/** Removes expired subscriptions. */
void coap_check_subscriptions(coap_context_t *context);
#if 0
/**
* Adds specified resource to the resource observation list. Returns a
* unique key for the resource. The alloceted memory is released when
* the resource is destroyed with coap_delete_resource().
*/
coap_key_t coap_add_resource(coap_context_t *context, coap_resource_t *);
/**
* Deletes the resource that is identified by key. Returns 1 if the resource was
* removed, 0 on error (e.g. if no such resource exists).
*/
int coap_delete_resource(coap_context_t *context, coap_key_t key);
#endif
/**
* Creates a new subscription object filled with the given data. The storage
* allocated for this object must be released using coap_free(). */
coap_subscription_t *coap_new_subscription(coap_context_t *context,
const coap_uri_t *resource,
const struct sockaddr *subscriber,
socklen_t addrlen,
time_t expiry);
/**
* Adds the given subsription object to the observer list.
* @param context The CoAP context
* @param subscription A new subscription oobject created with coap_new_subscription()
* @return A unique hash key for this resource or COAP_INVALID_HASHKEY on error.
* The storage allocated for the subscription object is released when it is
* removed from the subscription list, unless the function has returned
* COAP_INVALID_HASHKEY. In this case, the storage must be released by the
* caller of this function.
*/
coap_key_t coap_add_subscription(coap_context_t *context,
coap_subscription_t *subscription);
/**
* Returns the subscription from subscriber for the resource identified
* by hashkey. When token is not NULL the subscription must have the
* same token.
* @param context The CoAP context
* @param hashkey The unique key that identifies the subscription
* @param subscriber The subscriber's transport address
* @param token If not NULL, this specifies a token given by the
* subscriber to identify its subscription.
* @return The requested subscription object or NULL when not found.
*/
coap_subscription_t * coap_find_subscription(coap_context_t *context,
coap_key_t hashkey,
struct sockaddr *subscriber,
str *token);
/**
* Removes a subscription from the subscription list stored in context and
* releases the storage that was allocated for this subscription.
* @param context The CoAP context.
* @param haskey The unique key that identifies the subscription to remove.
* @return 1 if a subscription was removed, 0 otherwise.
*/
int coap_delete_subscription(coap_context_t *context,
coap_key_t hashkey,
struct sockaddr *subscriber);
/** Returns a unique hash for the specified URI or COAP_INVALID_HASHKEY on error. */
coap_key_t coap_uri_hash(const coap_uri_t *uri);
/** Returns a unique hash for the specified subscription or COAP_INVALID_HASHKEY on error. */
coap_key_t coap_subscription_hash(coap_subscription_t *subscription);
#if 0
/** Returns the resource identified by key or NULL if not found. */
coap_resource_t *coap_get_resource_from_key(coap_context_t *ctx, coap_key_t key);
/** Returns the resource identified by uri or NULL if not found. */
coap_resource_t *coap_get_resource(coap_context_t *ctx, coap_uri_t *uri);
#endif
#endif
/** @} */
#endif /* _COAP_SUBSCRIBE_H_ */

View file

@ -0,0 +1,156 @@
/* t_list -- tinydtls lists
*
* Copyright (C) 2012 Olaf Bergmann <bergmann@tzi.org>
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* @file t_list.h
* @brief Wrappers for list structures and functions
*/
#ifndef _DTLS_LIST_H_
#define _DTLS_LIST_H_
#ifndef WITH_CONTIKI
#include "uthash.h"
#include "utlist.h"
/* We define list structures and utility functions to be compatible
* with Contiki list structures. The Contiki list API is part of the
* Contiki operating system, and therefore the following licensing
* terms apply (taken from contiki/core/lib/list.h):
*
* Copyright (c) 2004, Swedish Institute of Computer Science.
* 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.
*
* Author: Adam Dunkels <adam@sics.se>
*
* $ Id: list.h,v 1.5 2010/09/13 13:31:00 adamdunkels Exp $
*/
typedef void **list_t;
struct list
{
struct list *next;
};
#define LIST_CONCAT(s1, s2) s1##s2
#define LIST_STRUCT(name) \
void *LIST_CONCAT(name, _list); \
list_t name
#define LIST_STRUCT_INIT(struct_ptr, name) { \
(struct_ptr)->name = &((struct_ptr)->LIST_CONCAT(name,_list)); \
(struct_ptr)->LIST_CONCAT(name,_list) = NULL; \
}
INLINE_API void *
list_head(list_t the_list)
{
return *the_list;
}
INLINE_API void list_remove(list_t the_list, void *item)
{
if (list_head(the_list))
LL_DELETE(*(struct list **)the_list, (struct list *)item);
}
#if !AMEBA
INLINE_API void list_add(list_t the_list, void *item)
#else
INLINE_API void coap_list_add(list_t the_list, void *item)
#endif
{
list_remove(the_list, item);
LL_APPEND(*(struct list **)the_list, (struct list *)item);
}
INLINE_API void list_push(list_t the_list, void *item)
{
LL_PREPEND(*(struct list **)the_list, (struct list *)item);
}
INLINE_API void *
list_pop(list_t the_list)
{
struct list *l;
l = (struct list*) *the_list;
if (l)
list_remove(the_list, l);
return l;
}
INLINE_API void list_insert(list_t the_list, void *previtem, void *newitem)
{
if (previtem == NULL)
{
list_push(the_list, newitem);
}
else
{
((struct list *) newitem)->next = ((struct list *) previtem)->next;
((struct list *) previtem)->next = (struct list*) newitem;
}
}
INLINE_API void *
list_item_next(void *item)
{
return item == NULL ? NULL : ((struct list *) item)->next;
}
#else /* WITH_CONTIKI */
#include "list.h"
#endif /* WITH_CONTIKI */
#endif /* _DTLS_LIST_H_ */

View file

@ -0,0 +1,174 @@
/* uri.h -- helper functions for URI treatment
*
* Copyright (C) 2010,2011 Olaf Bergmann <bergmann@tzi.org>
*
* This file is part of the CoAP library libcoap. Please see
* README for terms of use.
*/
#ifndef _COAP_URI_H_
#define _COAP_URI_H_
#include "hashkey.h"
#include "str.h"
#include <stdbool.h>
///Separtor for multiple query string
#define OC_QUERY_SEPARATOR "&;"
/** Representation of parsed URI. Components may be filled from a
* string with coap_split_uri() and can be used as input for
* option-creation functions. */
typedef struct
{
str host; /**< host part of the URI */
unsigned short port; /**< The port in host byte order */
str path; /**< Beginning of the first path segment.
Use coap_split_path() to create Uri-Path options */
str query; /**< The query part if present */
} coap_uri_t;
/**
* Creates a new coap_uri_t object from the specified URI. Returns the new
* object or NULL on error. The memory allocated by the new coap_uri_t
* must be released using coap_free().
* @param uri The URI path to copy.
* @para length The length of uri.
*
* @return New URI object or NULL on error.
*/
coap_uri_t *coap_new_uri(const unsigned char *uri, unsigned int length);
/**
* Clones the specified coap_uri_t object. Thie function allocates sufficient
* memory to hold the coap_uri_t structure and its contents. The object must
* be released with coap_free(). */
coap_uri_t *coap_clone_uri(const coap_uri_t *uri);
/**
* Calculates a hash over the given path and stores the result in
* @p key. This function returns @c 0 on error or @c 1 on success.
*
* @param path The URI path to generate hash for.
* @param len The length of @p path.
* @param key The output buffer.
*
* @return @c 1 if @p key was set, @c 0 otherwise.
*/
int coap_hash_path(const unsigned char *path, size_t len, coap_key_t key);
/**
* @defgroup uri_parse URI Parsing Functions
*
* CoAP PDUs contain normalized URIs with their path and query split into
* multiple segments. The functions in this module help splitting strings.
* @{
*/
/**
* Iterator to for tokenizing a URI path or query. This structure must
* be initialized with coap_parse_iterator_init(). Call
* coap_parse_next() to walk through the tokens.
*
* @code
* unsigned char *token;
* coap_parse_iterator_t pi;
* coap_parse_iterator_init(uri.path.s, uri.path.length, "/", "?#", 2, &pi);
*
* while ((token = coap_parse_next(&pi))) {
* ... do something with token ...
* }
* @endcode
*/
typedef struct
{
size_t n; /**< number of remaining characters in buffer */
unsigned char *separator; /**< segment separators */
unsigned char *delim; /**< delimiters where to split the string */
size_t dlen; /**< length of separator */
unsigned char *pos; /**< current position in buffer */
size_t segment_length; /**< length of current segment */
} coap_parse_iterator_t;
/**
* Initializes the given iterator @p pi.
*
* @param s The string to tokenize.
* @param n The length of @p s.
* @param separator The separator character that delimits tokens.
* @param delim A set of characters that delimit @s.
* @param dlen The length of @p delim.
* @param pi The iterator object to initialize.
*
* @return The initialized iterator object @p pi.
*/
coap_parse_iterator_t *
coap_parse_iterator_init(unsigned char *s, size_t n, unsigned char *separator, unsigned char *delim,
size_t dlen, coap_parse_iterator_t *pi);
/**
* Updates the iterator @p pi to point to the next token. This
* function returns a pointer to that token or @c NULL if no more
* tokens exist. The contents of @p pi will be updated. In particular,
* @c pi->segment_length specifies the length of the current token, @c
* pi->pos points to its beginning.
*
* @param pi The iterator to update.
*
* @return The next token or @c NULL if no more tokens exist.
*/
unsigned char *coap_parse_next(coap_parse_iterator_t *pi);
/**
* Parses a given string into URI components. The identified syntactic
* components are stored in the result parameter @p uri. Optional URI
* components that are not specified will be set to { 0, 0 }, except
* for the port which is set to @c COAP_DEFAULT_PORT. This function
* returns @p 0 if parsing succeeded, a value less than zero
* otherwise.
*
* @param str_var The string to split up.
* @param len The actual length of @p str_var
* @param uri The coap_uri_t object to store the result.
* @return @c 0 on success, or < 0 on error.
*
* @note The host name part will be converted to lower case by this
* function.
*/
int
coap_split_uri(unsigned char *str_var, size_t len, coap_uri_t *uri);
/**
* Splits the given URI path into segments. Each segment is preceded
* by an option pseudo-header with delta-value 0 and the actual length
* of the respective segment after percent-decoding.
*
* @param s The path string to split.
* @param length The actual length of @p s.
* @param buf Result buffer for parsed segments.
* @param buflen Maximum length of @p buf. Will be set to the actual number
* of bytes written into buf on success.
*
* @return The number of segments created or @c -1 on error.
*/
int coap_split_path(const unsigned char *s, size_t length, unsigned char *buf, size_t *buflen);
/**
* Splits the given URI query into segments. Each segment is preceded
* by an option pseudo-header with delta-value 0 and the actual length
* of the respective query term.
*
* @param s The query string to split.
* @param length The actual length of @p s.
* @param buf Result buffer for parsed segments.
* @param buflen Maximum length of @p buf. Will be set to the actual number
* of bytes written into buf on success.
*
* @return The number of segments created or @c -1 on error.
*
* @bug This function does not reserve additional space for delta > 12.
*/
int coap_split_query(const unsigned char *s, size_t length, unsigned char *buf, size_t *buflen);
/** @} */
#endif /* _COAP_URI_H_ */

View file

@ -0,0 +1,974 @@
/*
Copyright (c) 2003-2010, Troy D. Hanson http://uthash.sourceforge.net
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.
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.
*/
#ifndef UTHASH_H
#define UTHASH_H
#include <string.h> /* memcmp,strlen */
#include <stddef.h> /* ptrdiff_t */
/* These macros use decltype or the earlier __typeof GNU extension.
As decltype is only available in newer compilers (VS2010 or gcc 4.3+
when compiling c++ source) this code uses whatever method is needed
or, for VS2008 where neither is available, uses casting workarounds. */
#ifdef _MSC_VER /* MS compiler */
#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */
#define DECLTYPE(x) (decltype(x))
#else /* VS2008 or older (or VS2010 in C mode) */
#define NO_DECLTYPE
#define DECLTYPE(x)
#endif
#else /* GNU, Sun and other compilers */
#define DECLTYPE(x) (__typeof(x))
#endif
#ifdef NO_DECLTYPE
#define DECLTYPE_ASSIGN(dst,src) \
do { \
char **_da_dst = (char**)(&(dst)); \
*_da_dst = (char*)(src); \
} while(0)
#else
#define DECLTYPE_ASSIGN(dst,src) \
do { \
(dst) = DECLTYPE(dst)(src); \
} while(0)
#endif
/* a number of the hash function use uint32_t which isn't defined on win32 */
#ifdef _MSC_VER
typedef unsigned int uint32_t;
#else
#include <inttypes.h> /* uint32_t */
#endif
#define UTHASH_VERSION 1.9.3
#ifndef uthash_fatal
#define uthash_fatal(msg) exit(-1) /* fatal error (out of memory,etc) */
#endif
#define uthash_malloc(sz) malloc(sz) /* malloc fcn */
#define uthash_free(ptr,sz) free(ptr) /* free fcn */
#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */
#define uthash_expand_fyi(tbl) /* can be defined to log expands */
/* initial number of buckets */
#define HASH_INITIAL_NUM_BUCKETS 32 /* initial number of buckets */
#define HASH_INITIAL_NUM_BUCKETS_LOG2 5 /* lg2 of initial number of buckets */
#define HASH_BKT_CAPACITY_THRESH 10 /* expand when bucket count reaches */
/* calculate the element whose hash handle address is hhe */
#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho)))
#define HASH_FIND(hh,head,keyptr,keylen,out) \
do { \
unsigned _hf_bkt,_hf_hashv; \
out=NULL; \
if (head) { \
HASH_FCN(keyptr,keylen, (head)->hh.tbl->num_buckets, _hf_hashv, _hf_bkt); \
if (HASH_BLOOM_TEST((head)->hh.tbl, _hf_hashv)) { \
HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], \
keyptr,keylen,out); \
} \
} \
} while (0)
#ifdef HASH_BLOOM
#define HASH_BLOOM_BITLEN (1ULL << HASH_BLOOM)
#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8) + ((HASH_BLOOM_BITLEN%8) ? 1:0)
#define HASH_BLOOM_MAKE(tbl) \
do { \
(tbl)->bloom_nbits = HASH_BLOOM; \
(tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \
if (!((tbl)->bloom_bv)) { uthash_fatal( "out of memory"); } \
memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN); \
(tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \
} while (0);
#define HASH_BLOOM_FREE(tbl) \
do { \
uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \
} while (0);
#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8] |= (1U << ((idx)%8)))
#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8] & (1U << ((idx)%8)))
#define HASH_BLOOM_ADD(tbl,hashv) \
HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1)))
#define HASH_BLOOM_TEST(tbl,hashv) \
HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1)))
#else
#define HASH_BLOOM_MAKE(tbl)
#define HASH_BLOOM_FREE(tbl)
#define HASH_BLOOM_ADD(tbl,hashv)
#define HASH_BLOOM_TEST(tbl,hashv) (1)
#endif
#define HASH_MAKE_TABLE(hh,head) \
do { \
(head)->hh.tbl = (UT_hash_table*)uthash_malloc( \
sizeof(UT_hash_table)); \
if (!((head)->hh.tbl)) { uthash_fatal( "out of memory"); } \
memset((head)->hh.tbl, 0, sizeof(UT_hash_table)); \
(head)->hh.tbl->tail = &((head)->hh); \
(head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \
(head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \
(head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \
(head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \
HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \
if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); } \
memset((head)->hh.tbl->buckets, 0, \
HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \
HASH_BLOOM_MAKE((head)->hh.tbl); \
(head)->hh.tbl->signature = HASH_SIGNATURE; \
} while(0)
#define HASH_ADD(hh,head,fieldname,keylen_in,add) \
HASH_ADD_KEYPTR(hh,head,&add->fieldname,keylen_in,add)
#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \
do { \
unsigned _ha_bkt; \
(add)->hh.next = NULL; \
(add)->hh.key = (char*)keyptr; \
(add)->hh.keylen = keylen_in; \
if (!(head)) { \
head = (add); \
(head)->hh.prev = NULL; \
HASH_MAKE_TABLE(hh,head); \
} else { \
(head)->hh.tbl->tail->next = (add); \
(add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \
(head)->hh.tbl->tail = &((add)->hh); \
} \
(head)->hh.tbl->num_items++; \
(add)->hh.tbl = (head)->hh.tbl; \
HASH_FCN(keyptr,keylen_in, (head)->hh.tbl->num_buckets, \
(add)->hh.hashv, _ha_bkt); \
HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt],&(add)->hh); \
HASH_BLOOM_ADD((head)->hh.tbl,(add)->hh.hashv); \
HASH_EMIT_KEY(hh,head,keyptr,keylen_in); \
HASH_FSCK(hh,head); \
} while(0)
#define HASH_TO_BKT( hashv, num_bkts, bkt ) \
do { \
bkt = ((hashv) & ((num_bkts) - 1)); \
} while(0)
/* delete "delptr" from the hash table.
* "the usual" patch-up process for the app-order doubly-linked-list.
* The use of _hd_hh_del below deserves special explanation.
* These used to be expressed using (delptr) but that led to a bug
* if someone used the same symbol for the head and deletee, like
* HASH_DELETE(hh,users,users);
* We want that to work, but by changing the head (users) below
* we were forfeiting our ability to further refer to the deletee (users)
* in the patch-up process. Solution: use scratch space to
* copy the deletee pointer, then the latter references are via that
* scratch pointer rather than through the repointed (users) symbol.
*/
#define HASH_DELETE(hh,head,delptr) \
do { \
unsigned _hd_bkt; \
struct UT_hash_handle *_hd_hh_del; \
if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) ) { \
uthash_free((head)->hh.tbl->buckets, \
(head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \
HASH_BLOOM_FREE((head)->hh.tbl); \
uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \
head = NULL; \
} else { \
_hd_hh_del = &((delptr)->hh); \
if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) { \
(head)->hh.tbl->tail = \
(UT_hash_handle*)((char*)((delptr)->hh.prev) + \
(head)->hh.tbl->hho); \
} \
if ((delptr)->hh.prev) { \
((UT_hash_handle*)((char*)((delptr)->hh.prev) + \
(head)->hh.tbl->hho))->next = (delptr)->hh.next; \
} else { \
DECLTYPE_ASSIGN(head,(delptr)->hh.next); \
} \
if (_hd_hh_del->next) { \
((UT_hash_handle*)((char*)_hd_hh_del->next + \
(head)->hh.tbl->hho))->prev = \
_hd_hh_del->prev; \
} \
HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \
HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \
(head)->hh.tbl->num_items--; \
} \
HASH_FSCK(hh,head); \
} while (0)
/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */
#define HASH_FIND_STR(head,findstr,out) \
HASH_FIND(hh,head,findstr,strlen(findstr),out)
#define HASH_ADD_STR(head,strfield,add) \
HASH_ADD(hh,head,strfield,strlen(add->strfield),add)
#define HASH_FIND_INT(head,findint,out) \
HASH_FIND(hh,head,findint,sizeof(int),out)
#define HASH_ADD_INT(head,intfield,add) \
HASH_ADD(hh,head,intfield,sizeof(int),add)
#define HASH_FIND_PTR(head,findptr,out) \
HASH_FIND(hh,head,findptr,sizeof(void *),out)
#define HASH_ADD_PTR(head,ptrfield,add) \
HASH_ADD(hh,head,ptrfield,sizeof(void *),add)
#define HASH_DEL(head,delptr) \
HASH_DELETE(hh,head,delptr)
/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined.
* This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined.
*/
#ifdef HASH_DEBUG
#define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0)
#define HASH_FSCK(hh,head) \
do { \
unsigned _bkt_i; \
unsigned _count, _bkt_count; \
char *_prev; \
struct UT_hash_handle *_thh; \
if (head) { \
_count = 0; \
for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) { \
_bkt_count = 0; \
_thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \
_prev = NULL; \
while (_thh) { \
if (_prev != (char*)(_thh->hh_prev)) { \
HASH_OOPS("invalid hh_prev %p, actual %p\n", \
_thh->hh_prev, _prev ); \
} \
_bkt_count++; \
_prev = (char*)(_thh); \
_thh = _thh->hh_next; \
} \
_count += _bkt_count; \
if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \
HASH_OOPS("invalid bucket count %d, actual %d\n", \
(head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \
} \
} \
if (_count != (head)->hh.tbl->num_items) { \
HASH_OOPS("invalid hh item count %d, actual %d\n", \
(head)->hh.tbl->num_items, _count ); \
} \
/* traverse hh in app order; check next/prev integrity, count */ \
_count = 0; \
_prev = NULL; \
_thh = &(head)->hh; \
while (_thh) { \
_count++; \
if (_prev !=(char*)(_thh->prev)) { \
HASH_OOPS("invalid prev %p, actual %p\n", \
_thh->prev, _prev ); \
} \
_prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \
_thh = ( _thh->next ? (UT_hash_handle*)((char*)(_thh->next) + \
(head)->hh.tbl->hho) : NULL ); \
} \
if (_count != (head)->hh.tbl->num_items) { \
HASH_OOPS("invalid app item count %d, actual %d\n", \
(head)->hh.tbl->num_items, _count ); \
} \
} \
} while (0)
#else
#define HASH_FSCK(hh,head)
#endif
/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to
* the descriptor to which this macro is defined for tuning the hash function.
* The app can #include <unistd.h> to get the prototype for write(2). */
#ifdef HASH_EMIT_KEYS
#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \
do { \
unsigned _klen = fieldlen; \
write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \
write(HASH_EMIT_KEYS, keyptr, fieldlen); \
} while (0)
#else
#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen)
#endif
/* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */
#ifdef HASH_FUNCTION
#define HASH_FCN HASH_FUNCTION
#else
#define HASH_FCN HASH_JEN
#endif
/* The Bernstein hash function, used in Perl prior to v5.6 */
#define HASH_BER(key,keylen,num_bkts,hashv,bkt) \
do { \
unsigned _hb_keylen=keylen; \
char *_hb_key=(char*)(key); \
(hashv) = 0; \
while (_hb_keylen--) { (hashv) = ((hashv) * 33) + *_hb_key++; } \
bkt = (hashv) & (num_bkts-1); \
} while (0)
/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at
* http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */
#define HASH_SAX(key,keylen,num_bkts,hashv,bkt) \
do { \
unsigned _sx_i; \
char *_hs_key=(char*)(key); \
hashv = 0; \
for(_sx_i=0; _sx_i < keylen; _sx_i++) \
hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \
bkt = hashv & (num_bkts-1); \
} while (0)
#define HASH_FNV(key,keylen,num_bkts,hashv,bkt) \
do { \
unsigned _fn_i; \
char *_hf_key=(char*)(key); \
hashv = 2166136261UL; \
for(_fn_i=0; _fn_i < keylen; _fn_i++) \
hashv = (hashv * 16777619) ^ _hf_key[_fn_i]; \
bkt = hashv & (num_bkts-1); \
} while(0);
#define HASH_OAT(key,keylen,num_bkts,hashv,bkt) \
do { \
unsigned _ho_i; \
char *_ho_key=(char*)(key); \
hashv = 0; \
for(_ho_i=0; _ho_i < keylen; _ho_i++) { \
hashv += _ho_key[_ho_i]; \
hashv += (hashv << 10); \
hashv ^= (hashv >> 6); \
} \
hashv += (hashv << 3); \
hashv ^= (hashv >> 11); \
hashv += (hashv << 15); \
bkt = hashv & (num_bkts-1); \
} while(0)
#define HASH_JEN_MIX(a,b,c) \
do { \
a -= b; a -= c; a ^= ( c >> 13 ); \
b -= c; b -= a; b ^= ( a << 8 ); \
c -= a; c -= b; c ^= ( b >> 13 ); \
a -= b; a -= c; a ^= ( c >> 12 ); \
b -= c; b -= a; b ^= ( a << 16 ); \
c -= a; c -= b; c ^= ( b >> 5 ); \
a -= b; a -= c; a ^= ( c >> 3 ); \
b -= c; b -= a; b ^= ( a << 10 ); \
c -= a; c -= b; c ^= ( b >> 15 ); \
} while (0)
#define HASH_JEN(key,keylen,num_bkts,hashv,bkt) \
do { \
unsigned _hj_i,_hj_j,_hj_k; \
char *_hj_key=(char*)(key); \
hashv = 0xfeedbeef; \
_hj_i = _hj_j = 0x9e3779b9; \
_hj_k = keylen; \
while (_hj_k >= 12) { \
_hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \
+ ( (unsigned)_hj_key[2] << 16 ) \
+ ( (unsigned)_hj_key[3] << 24 ) ); \
_hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \
+ ( (unsigned)_hj_key[6] << 16 ) \
+ ( (unsigned)_hj_key[7] << 24 ) ); \
hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \
+ ( (unsigned)_hj_key[10] << 16 ) \
+ ( (unsigned)_hj_key[11] << 24 ) ); \
\
HASH_JEN_MIX(_hj_i, _hj_j, hashv); \
\
_hj_key += 12; \
_hj_k -= 12; \
} \
hashv += keylen; \
switch ( _hj_k ) { \
case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); \
case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); \
case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); \
case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); \
case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); \
case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); \
case 5: _hj_j += _hj_key[4]; \
case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); \
case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); \
case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); \
case 1: _hj_i += _hj_key[0]; \
} \
HASH_JEN_MIX(_hj_i, _hj_j, hashv); \
bkt = hashv & (num_bkts-1); \
} while(0)
/* The Paul Hsieh hash function */
#undef get16bits
#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
|| defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
#define get16bits(d) (*((const uint16_t *) (d)))
#endif
#if !defined (get16bits)
#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \
+(uint32_t)(((const uint8_t *)(d))[0]) )
#endif
#define HASH_SFH(key,keylen,num_bkts,hashv,bkt) \
do { \
char *_sfh_key=(char*)(key); \
uint32_t _sfh_tmp, _sfh_len = keylen; \
\
int _sfh_rem = _sfh_len & 3; \
_sfh_len >>= 2; \
hashv = 0xcafebabe; \
\
/* Main loop */ \
for (;_sfh_len > 0; _sfh_len--) { \
hashv += get16bits (_sfh_key); \
_sfh_tmp = (get16bits (_sfh_key+2) << 11) ^ hashv; \
hashv = (hashv << 16) ^ _sfh_tmp; \
_sfh_key += 2*sizeof (uint16_t); \
hashv += hashv >> 11; \
} \
\
/* Handle end cases */ \
switch (_sfh_rem) { \
case 3: hashv += get16bits (_sfh_key); \
hashv ^= hashv << 16; \
hashv ^= _sfh_key[sizeof (uint16_t)] << 18; \
hashv += hashv >> 11; \
break; \
case 2: hashv += get16bits (_sfh_key); \
hashv ^= hashv << 11; \
hashv += hashv >> 17; \
break; \
case 1: hashv += *_sfh_key; \
hashv ^= hashv << 10; \
hashv += hashv >> 1; \
} \
\
/* Force "avalanching" of final 127 bits */ \
hashv ^= hashv << 3; \
hashv += hashv >> 5; \
hashv ^= hashv << 4; \
hashv += hashv >> 17; \
hashv ^= hashv << 25; \
hashv += hashv >> 6; \
bkt = hashv & (num_bkts-1); \
} while(0);
#ifdef HASH_USING_NO_STRICT_ALIASING
/* The MurmurHash exploits some CPU's (e.g. x86) tolerance for unaligned reads.
* For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error.
* So MurmurHash comes in two versions, the faster unaligned one and the slower
* aligned one. We only use the faster one on CPU's where we know it's safe.
*
* Note the preprocessor built-in defines can be emitted using:
*
* gcc -m64 -dM -E - < /dev/null (on gcc)
* cc -## a.c (where a.c is a simple test file) (Sun Studio)
*/
#if (defined(__i386__) || defined(__x86_64__))
#define HASH_MUR HASH_MUR_UNALIGNED
#else
#define HASH_MUR HASH_MUR_ALIGNED
#endif
/* Appleby's MurmurHash fast version for unaligned-tolerant archs like i386 */
#define HASH_MUR_UNALIGNED(key,keylen,num_bkts,hashv,bkt) \
do { \
const unsigned int _mur_m = 0x5bd1e995; \
const int _mur_r = 24; \
hashv = 0xcafebabe ^ keylen; \
char *_mur_key = (char *)(key); \
uint32_t _mur_tmp, _mur_len = keylen; \
\
for (;_mur_len >= 4; _mur_len-=4) { \
_mur_tmp = *(uint32_t *)_mur_key; \
_mur_tmp *= _mur_m; \
_mur_tmp ^= _mur_tmp >> _mur_r; \
_mur_tmp *= _mur_m; \
hashv *= _mur_m; \
hashv ^= _mur_tmp; \
_mur_key += 4; \
} \
\
switch(_mur_len) \
{ \
case 3: hashv ^= _mur_key[2] << 16; \
case 2: hashv ^= _mur_key[1] << 8; \
case 1: hashv ^= _mur_key[0]; \
hashv *= _mur_m; \
}; \
\
hashv ^= hashv >> 13; \
hashv *= _mur_m; \
hashv ^= hashv >> 15; \
\
bkt = hashv & (num_bkts-1); \
} while(0)
/* Appleby's MurmurHash version for alignment-sensitive archs like Sparc */
#define HASH_MUR_ALIGNED(key,keylen,num_bkts,hashv,bkt) \
do { \
const unsigned int _mur_m = 0x5bd1e995; \
const int _mur_r = 24; \
hashv = 0xcafebabe ^ (keylen); \
char *_mur_key = (char *)(key); \
uint32_t _mur_len = keylen; \
int _mur_align = (int)_mur_key & 3; \
\
if (_mur_align && (_mur_len >= 4)) { \
unsigned _mur_t = 0, _mur_d = 0; \
switch(_mur_align) { \
case 1: _mur_t |= _mur_key[2] << 16; \
case 2: _mur_t |= _mur_key[1] << 8; \
case 3: _mur_t |= _mur_key[0]; \
} \
_mur_t <<= (8 * _mur_align); \
_mur_key += 4-_mur_align; \
_mur_len -= 4-_mur_align; \
int _mur_sl = 8 * (4-_mur_align); \
int _mur_sr = 8 * _mur_align; \
\
for (;_mur_len >= 4; _mur_len-=4) { \
_mur_d = *(unsigned *)_mur_key; \
_mur_t = (_mur_t >> _mur_sr) | (_mur_d << _mur_sl); \
unsigned _mur_k = _mur_t; \
_mur_k *= _mur_m; \
_mur_k ^= _mur_k >> _mur_r; \
_mur_k *= _mur_m; \
hashv *= _mur_m; \
hashv ^= _mur_k; \
_mur_t = _mur_d; \
_mur_key += 4; \
} \
_mur_d = 0; \
if(_mur_len >= _mur_align) { \
switch(_mur_align) { \
case 3: _mur_d |= _mur_key[2] << 16; \
case 2: _mur_d |= _mur_key[1] << 8; \
case 1: _mur_d |= _mur_key[0]; \
} \
unsigned _mur_k = (_mur_t >> _mur_sr) | (_mur_d << _mur_sl); \
_mur_k *= _mur_m; \
_mur_k ^= _mur_k >> _mur_r; \
_mur_k *= _mur_m; \
hashv *= _mur_m; \
hashv ^= _mur_k; \
_mur_k += _mur_align; \
_mur_len -= _mur_align; \
\
switch(_mur_len) \
{ \
case 3: hashv ^= _mur_key[2] << 16; \
case 2: hashv ^= _mur_key[1] << 8; \
case 1: hashv ^= _mur_key[0]; \
hashv *= _mur_m; \
} \
} else { \
switch(_mur_len) \
{ \
case 3: _mur_d ^= _mur_key[2] << 16; \
case 2: _mur_d ^= _mur_key[1] << 8; \
case 1: _mur_d ^= _mur_key[0]; \
case 0: hashv ^= (_mur_t >> _mur_sr) | (_mur_d << _mur_sl); \
hashv *= _mur_m; \
} \
} \
\
hashv ^= hashv >> 13; \
hashv *= _mur_m; \
hashv ^= hashv >> 15; \
} else { \
for (;_mur_len >= 4; _mur_len-=4) { \
unsigned _mur_k = *(unsigned*)_mur_key; \
_mur_k *= _mur_m; \
_mur_k ^= _mur_k >> _mur_r; \
_mur_k *= _mur_m; \
hashv *= _mur_m; \
hashv ^= _mur_k; \
_mur_key += 4; \
} \
switch(_mur_len) \
{ \
case 3: hashv ^= _mur_key[2] << 16; \
case 2: hashv ^= _mur_key[1] << 8; \
case 1: hashv ^= _mur_key[0]; \
hashv *= _mur_m; \
} \
\
hashv ^= hashv >> 13; \
hashv *= _mur_m; \
hashv ^= hashv >> 15; \
} \
bkt = hashv & (num_bkts-1); \
} while(0)
#endif /* HASH_USING_NO_STRICT_ALIASING */
/* key comparison function; return 0 if keys equal */
#define HASH_KEYCMP(a,b,len) memcmp(a,b,len)
/* iterate over items in a known bucket to find desired item */
#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,out) \
do { \
if (head.hh_head) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,head.hh_head)); \
else out=NULL; \
while (out) { \
if (out->hh.keylen == keylen_in) { \
if ((HASH_KEYCMP(out->hh.key,keyptr,keylen_in)) == 0) break; \
} \
if (out->hh.hh_next) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,out->hh.hh_next)); \
else out = NULL; \
} \
} while(0)
/* add an item to a bucket */
#define HASH_ADD_TO_BKT(head,addhh) \
do { \
head.count++; \
(addhh)->hh_next = head.hh_head; \
(addhh)->hh_prev = NULL; \
if (head.hh_head) { (head).hh_head->hh_prev = (addhh); } \
(head).hh_head=addhh; \
if (head.count >= ((head.expand_mult+1) * HASH_BKT_CAPACITY_THRESH) \
&& (addhh)->tbl->noexpand != 1) { \
HASH_EXPAND_BUCKETS((addhh)->tbl); \
} \
} while(0)
/* remove an item from a given bucket */
#define HASH_DEL_IN_BKT(hh,head,hh_del) \
(head).count--; \
if ((head).hh_head == hh_del) { \
(head).hh_head = hh_del->hh_next; \
} \
if (hh_del->hh_prev) { \
hh_del->hh_prev->hh_next = hh_del->hh_next; \
} \
if (hh_del->hh_next) { \
hh_del->hh_next->hh_prev = hh_del->hh_prev; \
}
/* Bucket expansion has the effect of doubling the number of buckets
* and redistributing the items into the new buckets. Ideally the
* items will distribute more or less evenly into the new buckets
* (the extent to which this is true is a measure of the quality of
* the hash function as it applies to the key domain).
*
* With the items distributed into more buckets, the chain length
* (item count) in each bucket is reduced. Thus by expanding buckets
* the hash keeps a bound on the chain length. This bounded chain
* length is the essence of how a hash provides constant time lookup.
*
* The calculation of tbl->ideal_chain_maxlen below deserves some
* explanation. First, keep in mind that we're calculating the ideal
* maximum chain length based on the *new* (doubled) bucket count.
* In fractions this is just n/b (n=number of items,b=new num buckets).
* Since the ideal chain length is an integer, we want to calculate
* ceil(n/b). We don't depend on floating point arithmetic in this
* hash, so to calculate ceil(n/b) with integers we could write
*
* ceil(n/b) = (n/b) + ((n%b)?1:0)
*
* and in fact a previous version of this hash did just that.
* But now we have improved things a bit by recognizing that b is
* always a power of two. We keep its base 2 log handy (call it lb),
* so now we can write this with a bit shift and logical AND:
*
* ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0)
*
*/
#define HASH_EXPAND_BUCKETS(tbl) \
do { \
unsigned _he_bkt; \
unsigned _he_bkt_i; \
struct UT_hash_handle *_he_thh, *_he_hh_nxt; \
UT_hash_bucket *_he_new_buckets, *_he_newbkt; \
_he_new_buckets = (UT_hash_bucket*)uthash_malloc( \
2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \
if (!_he_new_buckets) { uthash_fatal( "out of memory"); } \
memset(_he_new_buckets, 0, \
2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \
tbl->ideal_chain_maxlen = \
(tbl->num_items >> (tbl->log2_num_buckets+1)) + \
((tbl->num_items & ((tbl->num_buckets*2)-1)) ? 1 : 0); \
tbl->nonideal_items = 0; \
for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++) \
{ \
_he_thh = tbl->buckets[ _he_bkt_i ].hh_head; \
while (_he_thh) { \
_he_hh_nxt = _he_thh->hh_next; \
HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2, _he_bkt); \
_he_newbkt = &(_he_new_buckets[ _he_bkt ]); \
if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) { \
tbl->nonideal_items++; \
_he_newbkt->expand_mult = _he_newbkt->count / \
tbl->ideal_chain_maxlen; \
} \
_he_thh->hh_prev = NULL; \
_he_thh->hh_next = _he_newbkt->hh_head; \
if (_he_newbkt->hh_head) _he_newbkt->hh_head->hh_prev = \
_he_thh; \
_he_newbkt->hh_head = _he_thh; \
_he_thh = _he_hh_nxt; \
} \
} \
uthash_free( tbl->buckets, tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \
tbl->num_buckets *= 2; \
tbl->log2_num_buckets++; \
tbl->buckets = _he_new_buckets; \
tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ? \
(tbl->ineff_expands+1) : 0; \
if (tbl->ineff_expands > 1) { \
tbl->noexpand=1; \
uthash_noexpand_fyi(tbl); \
} \
uthash_expand_fyi(tbl); \
} while(0)
/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */
/* Note that HASH_SORT assumes the hash handle name to be hh.
* HASH_SRT was added to allow the hash handle name to be passed in. */
#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn)
#define HASH_SRT(hh,head,cmpfcn) \
do { \
unsigned _hs_i; \
unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \
struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \
if (head) { \
_hs_insize = 1; \
_hs_looping = 1; \
_hs_list = &((head)->hh); \
while (_hs_looping) { \
_hs_p = _hs_list; \
_hs_list = NULL; \
_hs_tail = NULL; \
_hs_nmerges = 0; \
while (_hs_p) { \
_hs_nmerges++; \
_hs_q = _hs_p; \
_hs_psize = 0; \
for ( _hs_i = 0; _hs_i < _hs_insize; _hs_i++ ) { \
_hs_psize++; \
_hs_q = (UT_hash_handle*)((_hs_q->next) ? \
((void*)((char*)(_hs_q->next) + \
(head)->hh.tbl->hho)) : NULL); \
if (! (_hs_q) ) break; \
} \
_hs_qsize = _hs_insize; \
while ((_hs_psize > 0) || ((_hs_qsize > 0) && _hs_q )) { \
if (_hs_psize == 0) { \
_hs_e = _hs_q; \
_hs_q = (UT_hash_handle*)((_hs_q->next) ? \
((void*)((char*)(_hs_q->next) + \
(head)->hh.tbl->hho)) : NULL); \
_hs_qsize--; \
} else if ( (_hs_qsize == 0) || !(_hs_q) ) { \
_hs_e = _hs_p; \
_hs_p = (UT_hash_handle*)((_hs_p->next) ? \
((void*)((char*)(_hs_p->next) + \
(head)->hh.tbl->hho)) : NULL); \
_hs_psize--; \
} else if (( \
cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \
DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \
) <= 0) { \
_hs_e = _hs_p; \
_hs_p = (UT_hash_handle*)((_hs_p->next) ? \
((void*)((char*)(_hs_p->next) + \
(head)->hh.tbl->hho)) : NULL); \
_hs_psize--; \
} else { \
_hs_e = _hs_q; \
_hs_q = (UT_hash_handle*)((_hs_q->next) ? \
((void*)((char*)(_hs_q->next) + \
(head)->hh.tbl->hho)) : NULL); \
_hs_qsize--; \
} \
if ( _hs_tail ) { \
_hs_tail->next = ((_hs_e) ? \
ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL); \
} else { \
_hs_list = _hs_e; \
} \
_hs_e->prev = ((_hs_tail) ? \
ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL); \
_hs_tail = _hs_e; \
} \
_hs_p = _hs_q; \
} \
_hs_tail->next = NULL; \
if ( _hs_nmerges <= 1 ) { \
_hs_looping=0; \
(head)->hh.tbl->tail = _hs_tail; \
DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \
} \
_hs_insize *= 2; \
} \
HASH_FSCK(hh,head); \
} \
} while (0)
/* This function selects items from one hash into another hash.
* The end result is that the selected items have dual presence
* in both hashes. There is no copy of the items made; rather
* they are added into the new hash through a secondary hash
* hash handle that must be present in the structure. */
#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \
do { \
unsigned _src_bkt, _dst_bkt; \
void *_last_elt=NULL, *_elt; \
UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \
ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \
if (src) { \
for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \
for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \
_src_hh; \
_src_hh = _src_hh->hh_next) { \
_elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \
if (cond(_elt)) { \
_dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \
_dst_hh->key = _src_hh->key; \
_dst_hh->keylen = _src_hh->keylen; \
_dst_hh->hashv = _src_hh->hashv; \
_dst_hh->prev = _last_elt; \
_dst_hh->next = NULL; \
if (_last_elt_hh) { _last_elt_hh->next = _elt; } \
if (!dst) { \
DECLTYPE_ASSIGN(dst,_elt); \
HASH_MAKE_TABLE(hh_dst,dst); \
} else { \
_dst_hh->tbl = (dst)->hh_dst.tbl; \
} \
HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \
HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh); \
(dst)->hh_dst.tbl->num_items++; \
_last_elt = _elt; \
_last_elt_hh = _dst_hh; \
} \
} \
} \
} \
HASH_FSCK(hh_dst,dst); \
} while (0)
#define HASH_CLEAR(hh,head) \
do { \
if (head) { \
uthash_free((head)->hh.tbl->buckets, \
(head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \
uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \
(head)=NULL; \
} \
} while(0)
#ifdef NO_DECLTYPE
#define HASH_ITER(hh,head,el,tmp) \
for((el)=(head), (*(char**)(&(tmp)))=(char*)((head)?(head)->hh.next:NULL); \
el; (el)=(tmp),(*(char**)(&(tmp)))=(char*)((tmp)?(tmp)->hh.next:NULL))
#else
#define HASH_ITER(hh,head,el,tmp) \
for((el)=(head),(tmp)=DECLTYPE(el)((head)?(head)->hh.next:NULL); \
el; (el)=(tmp),(tmp)=DECLTYPE(el)((tmp)?(tmp)->hh.next:NULL))
#endif
/* obtain a count of items in the hash */
#define HASH_COUNT(head) HASH_CNT(hh,head)
#define HASH_CNT(hh,head) ((head)?((head)->hh.tbl->num_items):0)
typedef struct UT_hash_bucket
{
struct UT_hash_handle *hh_head;
unsigned count;
/* expand_mult is normally set to 0. In this situation, the max chain length
* threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If
* the bucket's chain exceeds this length, bucket expansion is triggered).
* However, setting expand_mult to a non-zero value delays bucket expansion
* (that would be triggered by additions to this particular bucket)
* until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH.
* (The multiplier is simply expand_mult+1). The whole idea of this
* multiplier is to reduce bucket expansions, since they are expensive, in
* situations where we know that a particular bucket tends to be overused.
* It is better to let its chain length grow to a longer yet-still-bounded
* value, than to do an O(n) bucket expansion too often.
*/
unsigned expand_mult;
} UT_hash_bucket;
/* random signature used only to find hash tables in external analysis */
#define HASH_SIGNATURE 0xa0111fe1
#define HASH_BLOOM_SIGNATURE 0xb12220f2
typedef struct UT_hash_table
{
UT_hash_bucket *buckets;
unsigned num_buckets, log2_num_buckets;
unsigned num_items;
struct UT_hash_handle *tail; /* tail hh in app order, for fast append */
ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */
/* in an ideal situation (all buckets used equally), no bucket would have
* more than ceil(#items/#buckets) items. that's the ideal chain length. */
unsigned ideal_chain_maxlen;
/* nonideal_items is the number of items in the hash whose chain position
* exceeds the ideal chain maxlen. these items pay the penalty for an uneven
* hash distribution; reaching them in a chain traversal takes >ideal steps */
unsigned nonideal_items;
/* ineffective expands occur when a bucket doubling was performed, but
* afterward, more than half the items in the hash had nonideal chain
* positions. If this happens on two consecutive expansions we inhibit any
* further expansion, as it's not helping; this happens when the hash
* function isn't a good fit for the key domain. When expansion is inhibited
* the hash will still work, albeit no longer in constant time. */
unsigned ineff_expands, noexpand;
uint32_t signature; /* used only to find hash tables in external analysis */
#ifdef HASH_BLOOM
uint32_t bloom_sig; /* used only to test bloom exists in external analysis */
uint8_t *bloom_bv;
char bloom_nbits;
#endif
} UT_hash_table;
typedef struct UT_hash_handle
{
struct UT_hash_table *tbl;
void *prev; /* prev element in app order */
void *next; /* next element in app order */
struct UT_hash_handle *hh_prev; /* previous hh in bucket order */
struct UT_hash_handle *hh_next; /* next hh in bucket order */
void *key; /* ptr to enclosing struct's key */
unsigned keylen; /* enclosing struct's key len */
unsigned hashv; /* result of hash-fcn(key) */
} UT_hash_handle;
#endif /* UTHASH_H */

View file

@ -0,0 +1,489 @@
/*
Copyright (c) 2007-2010, Troy D. Hanson http://uthash.sourceforge.net
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.
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.
*/
#ifndef UTLIST_H
#define UTLIST_H
#define UTLIST_VERSION 1.9.1
/*
* This file contains macros to manipulate singly and doubly-linked lists.
*
* 1. LL_ macros: singly-linked lists.
* 2. DL_ macros: doubly-linked lists.
* 3. CDL_ macros: circular doubly-linked lists.
*
* To use singly-linked lists, your structure must have a "next" pointer.
* To use doubly-linked lists, your structure must "prev" and "next" pointers.
* Either way, the pointer to the head of the list must be initialized to NULL.
*
* ----------------.EXAMPLE -------------------------
* struct item {
* int id;
* struct item *prev, *next;
* }
*
* struct item *list = NULL:
*
* int main() {
* struct item *item;
* ... allocate and populate item ...
* DL_APPEND(list, item);
* }
* --------------------------------------------------
*
* For doubly-linked lists, the append and delete macros are O(1)
* For singly-linked lists, append and delete are O(n) but prepend is O(1)
* The sort macro is O(n log(n)) for all types of single/double/circular lists.
*/
/* These macros use decltype or the earlier __typeof GNU extension.
As decltype is only available in newer compilers (VS2010 or gcc 4.3+
when compiling c++ code), this code uses whatever method is needed
or, for VS2008 where neither is available, uses casting workarounds. */
#ifdef _MSC_VER /* MS compiler */
#if (_MSC_VER >= 1600) && (defined(__cplusplus) && (__cplusplus >= 201103L)) /* VS2010 and newer in C++ mode */
#define LDECLTYPE(x) decltype(x)
#else /* VS2008 or older (or VS2010 in C mode) */
#define NO_DECLTYPE
#define LDECLTYPE(x) char*
#endif
#else /* GNU, Sun and other compilers */
#define LDECLTYPE(x) __typeof(x)
#endif
/* for VS2008 we use some workarounds to get around the lack of decltype,
* namely, we always reassign our tmp variable to the list head if we need
* to dereference its prev/next pointers, and save/restore the real head.*/
#ifdef NO_DECLTYPE
#define _SV(elt,list) _tmp = (char*)(list); {char **_alias = (char**)&(list); *_alias = (elt); }
#define _NEXT(elt,list) ((char*)((list)->next))
#define _NEXTASGN(elt,list,to) { char **_alias = (char**)&((list)->next); *_alias=(char*)(to); }
#define _PREV(elt,list) ((char*)((list)->prev))
#define _PREVASGN(elt,list,to) { char **_alias = (char**)&((list)->prev); *_alias=(char*)(to); }
#define _RS(list) { char **_alias = (char**)&(list); *_alias=_tmp; }
#define _CASTASGN(a,b) { char **_alias = (char**)&(a); *_alias=(char*)(b); }
#else
#define _SV(elt,list)
#define _NEXT(elt,list) ((elt)->next)
#define _NEXTASGN(elt,list,to) ((elt)->next)=(to)
#define _PREV(elt,list) ((elt)->prev)
#define _PREVASGN(elt,list,to) ((elt)->prev)=(to)
#define _RS(list)
#define _CASTASGN(a,b) (a)=(b)
#endif
/******************************************************************************
* The sort macro is an adaptation of Simon Tatham's O(n log(n)) mergesort *
* Unwieldy variable names used here to avoid shadowing passed-in variables. *
*****************************************************************************/
#define LL_SORT(list, cmp) \
do { \
LDECLTYPE(list) _ls_p; \
LDECLTYPE(list) _ls_q; \
LDECLTYPE(list) _ls_e; \
LDECLTYPE(list) _ls_tail; \
LDECLTYPE(list) _ls_oldhead; \
LDECLTYPE(list) _tmp; \
int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \
if (list) { \
_ls_insize = 1; \
_ls_looping = 1; \
while (_ls_looping) { \
_CASTASGN(_ls_p,list); \
_CASTASGN(_ls_oldhead,list); \
list = NULL; \
_ls_tail = NULL; \
_ls_nmerges = 0; \
while (_ls_p) { \
_ls_nmerges++; \
_ls_q = _ls_p; \
_ls_psize = 0; \
for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \
_ls_psize++; \
_SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); \
if (!_ls_q) break; \
} \
_ls_qsize = _ls_insize; \
while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \
if (_ls_psize == 0) { \
_ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \
} else if (_ls_qsize == 0 || !_ls_q) { \
_ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \
} else if (cmp(_ls_p,_ls_q) <= 0) { \
_ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \
} else { \
_ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \
} \
if (_ls_tail) { \
_SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e); _RS(list); \
} else { \
_CASTASGN(list,_ls_e); \
} \
_ls_tail = _ls_e; \
} \
_ls_p = _ls_q; \
} \
_SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL); _RS(list); \
if (_ls_nmerges <= 1) { \
_ls_looping=0; \
} \
_ls_insize *= 2; \
} \
} else _tmp=NULL; /* quiet gcc unused variable warning */ \
} while (0)
#define DL_SORT(list, cmp) \
do { \
LDECLTYPE(list) _ls_p; \
LDECLTYPE(list) _ls_q; \
LDECLTYPE(list) _ls_e; \
LDECLTYPE(list) _ls_tail; \
LDECLTYPE(list) _ls_oldhead; \
LDECLTYPE(list) _tmp; \
int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \
if (list) { \
_ls_insize = 1; \
_ls_looping = 1; \
while (_ls_looping) { \
_CASTASGN(_ls_p,list); \
_CASTASGN(_ls_oldhead,list); \
list = NULL; \
_ls_tail = NULL; \
_ls_nmerges = 0; \
while (_ls_p) { \
_ls_nmerges++; \
_ls_q = _ls_p; \
_ls_psize = 0; \
for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \
_ls_psize++; \
_SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); \
if (!_ls_q) break; \
} \
_ls_qsize = _ls_insize; \
while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \
if (_ls_psize == 0) { \
_ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \
} else if (_ls_qsize == 0 || !_ls_q) { \
_ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \
} else if (cmp(_ls_p,_ls_q) <= 0) { \
_ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \
} else { \
_ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \
} \
if (_ls_tail) { \
_SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e); _RS(list); \
} else { \
_CASTASGN(list,_ls_e); \
} \
_SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail); _RS(list); \
_ls_tail = _ls_e; \
} \
_ls_p = _ls_q; \
} \
_CASTASGN(list->prev, _ls_tail); \
_SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL); _RS(list); \
if (_ls_nmerges <= 1) { \
_ls_looping=0; \
} \
_ls_insize *= 2; \
} \
} else _tmp=NULL; /* quiet gcc unused variable warning */ \
} while (0)
#define CDL_SORT(list, cmp) \
do { \
LDECLTYPE(list) _ls_p; \
LDECLTYPE(list) _ls_q; \
LDECLTYPE(list) _ls_e; \
LDECLTYPE(list) _ls_tail; \
LDECLTYPE(list) _ls_oldhead; \
LDECLTYPE(list) _tmp; \
LDECLTYPE(list) _tmp2; \
int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \
if (list) { \
_ls_insize = 1; \
_ls_looping = 1; \
while (_ls_looping) { \
_CASTASGN(_ls_p,list); \
_CASTASGN(_ls_oldhead,list); \
list = NULL; \
_ls_tail = NULL; \
_ls_nmerges = 0; \
while (_ls_p) { \
_ls_nmerges++; \
_ls_q = _ls_p; \
_ls_psize = 0; \
for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \
_ls_psize++; \
_SV(_ls_q,list); \
if (_NEXT(_ls_q,list) == _ls_oldhead) { \
_ls_q = NULL; \
} else { \
_ls_q = _NEXT(_ls_q,list); \
} \
_RS(list); \
if (!_ls_q) break; \
} \
_ls_qsize = _ls_insize; \
while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \
if (_ls_psize == 0) { \
_ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \
if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \
} else if (_ls_qsize == 0 || !_ls_q) { \
_ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \
if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \
} else if (cmp(_ls_p,_ls_q) <= 0) { \
_ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \
if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \
} else { \
_ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \
if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \
} \
if (_ls_tail) { \
_SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e); _RS(list); \
} else { \
_CASTASGN(list,_ls_e); \
} \
_SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail); _RS(list); \
_ls_tail = _ls_e; \
} \
_ls_p = _ls_q; \
} \
_CASTASGN(list->prev,_ls_tail); \
_CASTASGN(_tmp2,list); \
_SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_tmp2); _RS(list); \
if (_ls_nmerges <= 1) { \
_ls_looping=0; \
} \
_ls_insize *= 2; \
} \
} else _tmp=NULL; /* quiet gcc unused variable warning */ \
} while (0)
/******************************************************************************
* singly linked list macros (non-circular) *
*****************************************************************************/
#define LL_PREPEND(head,add) \
do { \
(add)->next = head; \
head = add; \
} while (0)
#define LL_APPEND(head,add) \
do { \
LDECLTYPE(head) _tmp; \
(add)->next=NULL; \
if (head) { \
_tmp = head; \
while (_tmp->next) { _tmp = _tmp->next; } \
_tmp->next=(add); \
} else { \
(head)=(add); \
} \
} while (0)
#define LL_DELETE(head,del) \
do { \
LDECLTYPE(head) _tmp; \
if ((head) == (del)) { \
(head)=(head)->next; \
} else { \
_tmp = head; \
while (_tmp->next && (_tmp->next != (del))) { \
_tmp = _tmp->next; \
} \
if (_tmp->next) { \
_tmp->next = ((del)->next); \
} \
} \
} while (0)
/* Here are VS2008 replacements for LL_APPEND and LL_DELETE */
#define LL_APPEND_VS2008(head,add) \
do { \
if (head) { \
(add)->next = head; /* use add->next as a temp variable */ \
while ((add)->next->next) { (add)->next = (add)->next->next; } \
(add)->next->next=(add); \
} else { \
(head)=(add); \
} \
(add)->next=NULL; \
} while (0)
#define LL_DELETE_VS2008(head,del) \
do { \
if ((head) == (del)) { \
(head)=(head)->next; \
} else { \
char *_tmp = (char*)(head); \
while ((head)->next && ((head)->next != (del))) { \
(head) = (head)->next; \
} \
if ((head)->next) { \
(head)->next = ((del)->next); \
} \
{ \
char **_head_alias = (char**)&(head); \
*_head_alias = _tmp; \
} \
} \
} while (0)
#ifdef NO_DECLTYPE
#undef LL_APPEND
#define LL_APPEND LL_APPEND_VS2008
#undef LL_DELETE
#define LL_DELETE LL_DELETE_VS2008
#endif
/* end VS2008 replacements */
#define LL_FOREACH(head,el) \
for(el=head;el;el=el->next)
#define LL_FOREACH_SAFE(head,el,tmp) \
for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp)
#define LL_SEARCH_SCALAR(head,out,field,val) \
do { \
LL_FOREACH(head,out) { \
if ((out)->field == (val)) break; \
} \
} while(0)
#define LL_SEARCH(head,out,elt,cmp) \
do { \
LL_FOREACH(head,out) { \
if ((cmp(out,elt))==0) break; \
} \
} while(0)
/******************************************************************************
* doubly linked list macros (non-circular) *
*****************************************************************************/
#define DL_PREPEND(head,add) \
do { \
(add)->next = head; \
if (head) { \
(add)->prev = (head)->prev; \
(head)->prev = (add); \
} else { \
(add)->prev = (add); \
} \
(head) = (add); \
} while (0)
#define DL_APPEND(head,add) \
do { \
if (head) { \
(add)->prev = (head)->prev; \
(head)->prev->next = (add); \
(head)->prev = (add); \
(add)->next = NULL; \
} else { \
(head)=(add); \
(head)->prev = (head); \
(head)->next = NULL; \
} \
} while (0);
#define DL_DELETE(head,del) \
do { \
if ((del)->prev == (del)) { \
(head)=NULL; \
} else if ((del)==(head)) { \
(del)->next->prev = (del)->prev; \
(head) = (del)->next; \
} else { \
(del)->prev->next = (del)->next; \
if ((del)->next) { \
(del)->next->prev = (del)->prev; \
} else { \
(head)->prev = (del)->prev; \
} \
} \
} while (0);
#define DL_FOREACH(head,el) \
for(el=head;el;el=el->next)
/* this version is safe for deleting the elements during iteration */
#define DL_FOREACH_SAFE(head,el,tmp) \
for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp)
/* these are identical to their singly-linked list counterparts */
#define DL_SEARCH_SCALAR LL_SEARCH_SCALAR
#define DL_SEARCH LL_SEARCH
/******************************************************************************
* circular doubly linked list macros *
*****************************************************************************/
#define CDL_PREPEND(head,add) \
do { \
if (head) { \
(add)->prev = (head)->prev; \
(add)->next = (head); \
(head)->prev = (add); \
(add)->prev->next = (add); \
} else { \
(add)->prev = (add); \
(add)->next = (add); \
} \
(head)=(add); \
} while (0)
#define CDL_DELETE(head,del) \
do { \
if ( ((head)==(del)) && ((head)->next == (head))) { \
(head) = 0L; \
} else { \
(del)->next->prev = (del)->prev; \
(del)->prev->next = (del)->next; \
if ((del) == (head)) (head)=(del)->next; \
} \
} while (0);
#define CDL_FOREACH(head,el) \
for(el=head;el;el=(el->next==head ? 0L : el->next))
#define CDL_FOREACH_SAFE(head,el,tmp1,tmp2) \
for((el)=(head), ((tmp1)=(head)?((head)->prev):NULL); \
(el) && ((tmp2)=(el)->next, 1); \
((el) = (((el)==(tmp1)) ? 0L : (tmp2))))
#define CDL_SEARCH_SCALAR(head,out,field,val) \
do { \
CDL_FOREACH(head,out) { \
if ((out)->field == (val)) break; \
} \
} while(0)
#define CDL_SEARCH(head,out,elt,cmp) \
do { \
CDL_FOREACH(head,out) { \
if ((cmp(out,elt))==0) break; \
} \
} while(0)
#endif /* UTLIST_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,5 @@
Modifications made by Realtek to patch lwip_v2.0.0 on Ameba's SDK which is originally based on lwip_v1.4.1
2017-01-10: Chris (chrisyang@realtek.com)
* Add empty loopif.h into src/include/netif to avoid compile error

View file

@ -0,0 +1,33 @@
/*
* Copyright (c) 2001, 2002 Swedish Institute of Computer Science.
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/

View file

@ -0,0 +1,5 @@
src/ - The source code for the lwIP TCP/IP stack.
doc/ - The documentation for lwIP.
test/ - Some code to test whether the sources do what they should.
See also the FILES file in each subdirectory.

View file

@ -0,0 +1,100 @@
INTRODUCTION
lwIP is a small independent implementation of the TCP/IP protocol
suite that has been developed by Adam Dunkels at the Computer and
Networks Architectures (CNA) lab at the Swedish Institute of Computer
Science (SICS).
The focus of the lwIP TCP/IP implementation is to reduce the RAM usage
while still having a full scale TCP. This making lwIP suitable for use
in embedded systems with tens of kilobytes of free RAM and room for
around 40 kilobytes of code ROM.
FEATURES
* IP (Internet Protocol, IPv4 and IPv6) including packet forwarding over
multiple network interfaces
* ICMP (Internet Control Message Protocol) for network maintenance and debugging
* IGMP (Internet Group Management Protocol) for multicast traffic management
* MLD (Multicast listener discovery for IPv6). Aims to be compliant with
RFC 2710. No support for MLDv2
* ND (Neighbor discovery and stateless address autoconfiguration for IPv6).
Aims to be compliant with RFC 4861 (Neighbor discovery) and RFC 4862
(Address autoconfiguration)
* UDP (User Datagram Protocol) including experimental UDP-lite extensions
* TCP (Transmission Control Protocol) with congestion control, RTT estimation
and fast recovery/fast retransmit
* raw/native API for enhanced performance
* Optional Berkeley-like socket API
* DNS (Domain names resolver)
APPLICATIONS
* HTTP server with SSI and CGI
* SNMPv2c agent with MIB compiler (Simple Network Management Protocol)
* SNTP (Simple network time protocol)
* NetBIOS name service responder
* MDNS (Multicast DNS) responder
* iPerf server implementation
LICENSE
lwIP is freely available under a BSD license.
DEVELOPMENT
lwIP has grown into an excellent TCP/IP stack for embedded devices,
and developers using the stack often submit bug fixes, improvements,
and additions to the stack to further increase its usefulness.
Development of lwIP is hosted on Savannah, a central point for
software development, maintenance and distribution. Everyone can
help improve lwIP by use of Savannah's interface, Git and the
mailing list. A core team of developers will commit changes to the
Git source tree.
The lwIP TCP/IP stack is maintained in the 'lwip' Git module and
contributions (such as platform ports) are in the 'contrib' Git module.
See doc/savannah.txt for details on Git server access for users and
developers.
The current Git trees are web-browsable:
http://git.savannah.gnu.org/cgit/lwip.git
http://git.savannah.gnu.org/cgit/lwip/lwip-contrib.git
Submit patches and bugs via the lwIP project page:
http://savannah.nongnu.org/projects/lwip/
Continuous integration builds (GCC, clang):
https://travis-ci.org/yarrick/lwip-merged
DOCUMENTATION
Self documentation of the source code is regularly extracted from the current
Git sources and is available from this web page:
http://www.nongnu.org/lwip/
There is now a constantly growing wiki about lwIP at
http://lwip.wikia.com/wiki/LwIP_Wiki
Also, there are mailing lists you can subscribe at
http://savannah.nongnu.org/mail/?group=lwip
plus searchable archives:
http://lists.nongnu.org/archive/html/lwip-users/
http://lists.nongnu.org/archive/html/lwip-devel/
lwIP was originally written by Adam Dunkels:
http://dunkels.com/adam/
Reading Adam's papers, the files in docs/, browsing the source code
documentation and browsing the mailing list archives is a good way to
become familiar with the design of lwIP.
Adam Dunkels <adam@sics.se>
Leon Woestenberg <leon.woestenberg@gmx.net>

View file

@ -0,0 +1,243 @@
This file lists major changes between release versions that require
ports or applications to be changed. Use it to update a port or an
application written for an older version of lwIP to correctly work
with newer versions.
(git master)
* [Enter new changes just after this line - do not remove this line]
(2.0.2)
++ Application changes:
* slipif: The way to pass serial port number has changed. netif->num is not
supported any more, netif->state is interpreted as an u8_t port number now
(it's not a POINTER to an u8_t any more!)
(2.0.1)
++ Application changes:
* UDP does NOT receive multicast traffic from ALL netifs on an UDP PCB bound to a specific
netif any more. Users need to bind to IP_ADDR_ANY to receive multicast traffic and compare
ip_current_netif() to the desired netif for every packet.
See bug #49662 for an explanation.
(2.0.0)
++ Application changes:
* Changed netif "up" flag handling to be an administrative flag (as opposed to the previous meaning of
"ip4-address-valid", a netif will now not be used for transmission if not up) -> even a DHCP netif
has to be set "up" before starting the DHCP client
* Added IPv6 support (dual-stack or IPv4/IPv6 only)
* Changed ip_addr_t to be a union in dual-stack mode (use ip4_addr_t where referring to IPv4 only).
* Major rewrite of SNMP (added MIB parser that creates code stubs for custom MIBs);
supports SNMPv2c (experimental v3 support)
* Moved some core applications from contrib repository to src/apps (and include/lwip/apps)
+++ Raw API:
* Changed TCP listen backlog: removed tcp_accepted(), added the function pair tcp_backlog_delayed()/
tcp_backlog_accepted() to explicitly delay backlog handling on a connection pcb
+++ Socket API:
* Added an implementation for posix sendmsg()
* Added LWIP_FIONREAD_LINUXMODE that makes ioctl/FIONREAD return the size of the next pending datagram
++ Port changes
+++ new files:
* MANY new and moved files!
* Added src/Filelists.mk for use in Makefile projects
* Continued moving stack-internal parts from abc.h to abc_priv.h in sub-folder "priv"
to let abc.h only contain the actual application programmer's API
+++ sys layer:
* Made LWIP_TCPIP_CORE_LOCKING==1 the default as it usually performs better than
the traditional message passing (although with LWIP_COMPAT_MUTEX you are still
open to priority inversion, so this is not recommended any more)
* Added LWIP_NETCONN_SEM_PER_THREAD to use one "op_completed" semaphore per thread
instead of using one per netconn (these semaphores are used even with core locking
enabled as some longer lasting functions like big writes still need to delay)
* Added generalized abstraction for itoa(), strnicmp(), stricmp() and strnstr()
in def.h (to be overridden in cc.h) instead of config
options for netbiosns, httpd, dns, etc. ...
* New abstraction for hton* and ntoh* functions in def.h.
To override them, use the following in cc.h:
#define lwip_htons(x) <your_htons>
#define lwip_htonl(x) <your_htonl>
+++ new options:
* TODO
+++ new pools:
* Added LWIP_MEMPOOL_* (declare/init/alloc/free) to declare private memp pools
that share memp.c code but do not have to be made global via lwippools.h
* Added pools for IPv6, MPU_COMPATIBLE, dns-api, netif-api, etc.
* added hook LWIP_HOOK_MEMP_AVAILABLE() to get informed when a memp pool was empty and an item
is now available
* Signature of LWIP_HOOK_VLAN_SET macro was changed
* LWIP_DECLARE_MEMORY_ALIGNED() may be used to declare aligned memory buffers (mem/memp)
or to move buffers to dedicated memory using compiler attributes
* Standard C headers are used to define sized types and printf formatters
(disable by setting LWIP_NO_STDINT_H=1 or LWIP_NO_INTTYPES_H=1 if your compiler
does not support these)
++ Major bugfixes/improvements
* Added IPv6 support (dual-stack or IPv4/IPv6 only)
* Major rewrite of PPP (incl. keep-up with apache pppd)
see doc/ppp.txt for an upgrading how-to
* Major rewrite of SNMP (incl. MIB parser)
* Fixed timing issues that might have lead to losing a DHCP lease
* Made rx processing path more robust against crafted errors
* TCP window scaling support
* modification of api modules to support FreeRTOS-MPU (don't pass stack-pointers to other threads)
* made DNS client more robust
* support PBUF_REF for RX packets
* LWIP_NETCONN_FULLDUPLEX allows netconn/sockets to be used for reading/writing from separate
threads each (needs LWIP_NETCONN_SEM_PER_THREAD)
* Moved and reordered stats (mainly memp/mib2)
(1.4.0)
++ Application changes:
* Replaced struct ip_addr by typedef ip_addr_t (struct ip_addr is kept for
compatibility to old applications, but will be removed in the future).
* Renamed mem_realloc() to mem_trim() to prevent confusion with realloc()
+++ Raw API:
* Changed the semantics of tcp_close() (since it was rather a
shutdown before): Now the application does *NOT* get any calls to the recv
callback (aside from NULL/closed) after calling tcp_close()
* When calling tcp_abort() from a raw API TCP callback function,
make sure you return ERR_ABRT to prevent accessing unallocated memory.
(ERR_ABRT now means the applicaiton has called tcp_abort!)
+++ Netconn API:
* Changed netconn_receive() and netconn_accept() to return
err_t, not a pointer to new data/netconn.
+++ Socket API:
* LWIP_SO_RCVTIMEO: when accept() or recv() time out, they
now set errno to EWOULDBLOCK/EAGAIN, not ETIMEDOUT.
* Added a minimal version of posix fctl() to have a
standardised way to set O_NONBLOCK for nonblocking sockets.
+++ all APIs:
* correctly implemented SO(F)_REUSEADDR
++ Port changes
+++ new files:
* Added 4 new files: def.c, timers.c, timers.h, tcp_impl.h:
* Moved stack-internal parts of tcp.h to tcp_impl.h, tcp.h now only contains
the actual application programmer's API
* Separated timer implementation from sys.h/.c, moved to timers.h/.c;
Added timer implementation for NO_SYS==1, set NO_SYS_NO_TIMERS==1 if you
still want to use your own timer implementation for NO_SYS==0 (as before).
+++ sys layer:
* Converted mbox- and semaphore-functions to take pointers to sys_mbox_t/
sys_sem_t;
* Converted sys_mbox_new/sys_sem_new to take pointers and return err_t;
* Added Mutex concept in sys_arch (define LWIP_COMPAT_MUTEX to let sys.h use
binary semaphores instead of mutexes - as before)
+++ new options:
* Don't waste memory when chaining segments, added option TCP_OVERSIZE to
prevent creating many small pbufs when calling tcp_write with many small
blocks of data. Instead, pbufs are allocated larger than needed and the
space is used for later calls to tcp_write.
* Added LWIP_NETIF_TX_SINGLE_PBUF to always copy to try to create single pbufs
in tcp_write/udp_send.
* Added an additional option LWIP_ETHERNET to support ethernet without ARP
(necessary for pure PPPoE)
* Add MEMP_SEPARATE_POOLS to place memory pools in separate arrays. This may
be used to place these pools into user-defined memory by using external
declaration.
* Added TCP_SNDQUEUELOWAT corresponding to TCP_SNDLOWAT
+++ new pools:
* Netdb uses a memp pool for allocating memory when getaddrinfo() is called,
so MEMP_NUM_NETDB has to be set accordingly.
* DNS_LOCAL_HOSTLIST_IS_DYNAMIC uses a memp pool instead of the heap, so
MEMP_NUM_LOCALHOSTLIST has to be set accordingly.
* Snmp-agent uses a memp pools instead of the heap, so MEMP_NUM_SNMP_* have
to be set accordingly.
* PPPoE uses a MEMP pool instead of the heap, so MEMP_NUM_PPPOE_INTERFACES
has to be set accordingly
* Integrated loopif into netif.c - loopif does not have to be created by the
port any more, just define LWIP_HAVE_LOOPIF to 1.
* Added define LWIP_RAND() for lwip-wide randomization (needs to be defined
in cc.h, e.g. used by igmp)
* Added printf-formatter X8_F to printf u8_t as hex
* The heap now may be moved to user-defined memory by defining
LWIP_RAM_HEAP_POINTER as a void pointer to that memory's address
* added autoip_set_struct() and dhcp_set_struct() to let autoip and dhcp work
with user-allocated structs instead of calling mem_malloc
* Added const char* name to mem- and memp-stats for easier debugging.
* Calculate the TCP/UDP checksum while copying to only fetch data once:
Define LWIP_CHKSUM_COPY to a memcpy-like function that returns the checksum
* Added SO_REUSE_RXTOALL to pass received UDP broadcast/multicast packets to
more than one pcb.
* Changed the semantics of ARP_QUEUEING==0: ARP_QUEUEING now cannot be turned
off any more, if this is set to 0, only one packet (the most recent one) is
queued (like demanded by RFC 1122).
++ Major bugfixes/improvements
* Implemented tcp_shutdown() to only shut down one end of a connection
* Implemented shutdown() at socket- and netconn-level
* Added errorset support to select() + improved select speed overhead
* Merged pppd to v2.3.11 (including some backported bugfixes from 2.4.x)
* Added timer implementation for NO_SYS==1 (may be disabled with NO_SYS_NO_TIMERS==1
* Use macros defined in ip_addr.h to work with IP addresses
* Implemented many nonblocking socket/netconn functions
* Fixed ARP input processing: only add a new entry if a request was directed as us
* mem_realloc() to mem_trim() to prevent confusion with realloc()
* Some improvements for AutoIP (don't route/forward link-local addresses, don't break
existing connections when assigning a routable address)
* Correctly handle remote side overrunning our rcv_wnd in ooseq case
* Removed packing from ip_addr_t, the packed version is now only used in protocol headers
* Corrected PBUF_POOL_BUFSIZE for ports where ETH_PAD_SIZE > 0
* Added support for static ARP table entries
(STABLE-1.3.2)
* initial version of this file

View file

@ -0,0 +1,9 @@
doxygen/ - Configuration files and scripts to create the lwIP doxygen source
documentation (found at http://www.nongnu.org/lwip/)
savannah.txt - How to obtain the current development source code.
contrib.txt - How to contribute to lwIP as a developer.
rawapi.txt - The documentation for the core API of lwIP.
Also provides an overview about the other APIs and multithreading.
sys_arch.txt - The documentation for a system abstraction layer of lwIP.
ppp.txt - Documentation of the PPP interface for lwIP.

View file

@ -0,0 +1,58 @@
1 Introduction
This document describes some guidelines for people participating
in lwIP development.
2 How to contribute to lwIP
Here is a short list of suggestions to anybody working with lwIP and
trying to contribute bug reports, fixes, enhancements, platform ports etc.
First of all as you may already know lwIP is a volunteer project so feedback
to fixes or questions might often come late. Hopefully the bug and patch tracking
features of Savannah help us not lose users' input.
2.1 Source code style:
1. do not use tabs.
2. indentation is two spaces per level (i.e. per tab).
3. end debug messages with a trailing newline (\n).
4. one space between keyword and opening bracket.
5. no space between function and opening bracket.
6. one space and no newline before opening curly braces of a block.
7. closing curly brace on a single line.
8. spaces surrounding assignment and comparisons.
9. don't initialize static and/or global variables to zero, the compiler takes care of that.
10. use current source code style as further reference.
2.2 Source code documentation style:
1. JavaDoc compliant and Doxygen compatible.
2. Function documentation above functions in .c files, not .h files.
(This forces you to synchronize documentation and implementation.)
3. Use current documentation style as further reference.
2.3 Bug reports and patches:
1. Make sure you are reporting bugs or send patches against the latest
sources. (From the latest release and/or the current Git sources.)
2. If you think you found a bug make sure it's not already filed in the
bugtracker at Savannah.
3. If you have a fix put the patch on Savannah. If it is a patch that affects
both core and arch specific stuff please separate them so that the core can
be applied separately while leaving the other patch 'open'. The preferred way
is to NOT touch archs you can't test and let maintainers take care of them.
This is a good way to see if they are used at all - the same goes for unix
netifs except tapif.
4. Do not file a bug and post a fix to it to the patch area. Either a bug report
or a patch will be enough.
If you correct an existing bug then attach the patch to the bug rather than creating a new entry in the patch area.
5. Patches should be specific to a single change or to related changes. Do not mix bugfixes with spelling and other
trivial fixes unless the bugfix is trivial too. Do not reorganize code and rename identifiers in the same patch you
change behaviour if not necessary. A patch is easier to read and understand if it's to the point and short than
if it's not to the point and long :) so the chances for it to be applied are greater.
2.4 Platform porters:
1. If you have ported lwIP to a platform (an OS, a uC/processor or a combination of these) and
you think it could benefit others[1] you might want discuss this on the mailing list. You
can also ask for Git access to submit and maintain your port in the contrib Git module.

View file

@ -0,0 +1 @@
doxygen lwip.Doxyfile

View file

@ -0,0 +1,3 @@
#!/bin/sh
doxygen lwip.Doxyfile

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,132 @@
/**
* @defgroup lwip lwIP
*
* @defgroup infrastructure Infrastructure
*
* @defgroup callbackstyle_api Callback-style APIs
* Non thread-safe APIs, callback style for maximum performance and minimum
* memory footprint.
*
* @defgroup sequential_api Sequential-style APIs
* Sequential-style APIs, blocking functions. More overhead, but can be called
* from any thread except TCPIP thread.
*
* @defgroup addons Addons
*
* @defgroup apps Applications
*/
/**
* @mainpage Overview
* @verbinclude "README"
*/
/**
* @page upgrading Upgrading
* @verbinclude "UPGRADING"
*/
/**
* @page changelog Changelog
* @verbinclude "CHANGELOG"
*/
/**
* @page contrib How to contribute to lwIP
* @verbinclude "contrib.txt"
*/
/**
* @page pitfalls Common pitfalls
*
* Multiple Execution Contexts in lwIP code
* ========================================
*
* The most common source of lwIP problems is to have multiple execution contexts
* inside the lwIP code.
*
* lwIP can be used in two basic modes: @ref lwip_nosys (no OS/RTOS
* running on target system) or @ref lwip_os (there is an OS running
* on the target system).
*
* Mainloop Mode
* -------------
* In mainloop mode, only @ref callbackstyle_api can be used.
* The user has two possibilities to ensure there is only one
* exection context at a time in lwIP:
*
* 1) Deliver RX ethernet packets directly in interrupt context to lwIP
* by calling netif->input directly in interrupt. This implies all lwIP
* callback functions are called in IRQ context, which may cause further
* problems in application code: IRQ is blocked for a long time, multiple
* execution contexts in application code etc. When the application wants
* to call lwIP, it only needs to disable interrupts during the call.
* If timers are involved, even more locking code is needed to lock out
* timer IRQ and ethernet IRQ from each other, assuming these may be nested.
*
* 2) Run lwIP in a mainloop. There is example code here: @ref lwip_nosys.
* lwIP is _ONLY_ called from mainloop callstacks here. The ethernet IRQ
* has to put received telegrams into a queue which is polled in the
* mainloop. Ensure lwIP is _NEVER_ called from an interrupt, e.g.
* some SPI IRQ wants to forward data to udp_send() or tcp_write()!
*
* OS Mode
* -------
* In OS mode, @ref callbackstyle_api AND @ref sequential_api can be used.
* @ref sequential_api are designed to be called from threads other than
* the TCPIP thread, so there is nothing to consider here.
* But @ref callbackstyle_api functions must _ONLY_ be called from
* TCPIP thread. It is a common error to call these from other threads
* or from IRQ contexts. Ethernet RX needs to deliver incoming packets
* in the correct way by sending a message to TCPIP thread, this is
* implemented in tcpip_input().
* Again, ensure lwIP is _NEVER_ called from an interrupt, e.g.
* some SPI IRQ wants to forward data to udp_send() or tcp_write()!
*
* 1) tcpip_callback() can be used get called back from TCPIP thread,
* it is safe to call any @ref callbackstyle_api from there.
*
* 2) Use @ref LWIP_TCPIP_CORE_LOCKING. All @ref callbackstyle_api
* functions can be called when lwIP core lock is aquired, see
* @ref LOCK_TCPIP_CORE() and @ref UNLOCK_TCPIP_CORE().
* These macros cannot be used in an interrupt context!
* Note the OS must correctly handle priority inversion for this.
*/
/**
* @page bugs Reporting bugs
* Please report bugs in the lwIP bug tracker at savannah.\n
* BEFORE submitting, please check if the bug has already been reported!\n
* https://savannah.nongnu.org/bugs/?group=lwip
*/
/**
* @defgroup lwip_nosys Mainloop mode ("NO_SYS")
* @ingroup lwip
* Use this mode if you do not run an OS on your system. \#define NO_SYS to 1.
* Feed incoming packets to netif->input(pbuf, netif) function from mainloop,
* *not* *from* *interrupt* *context*. You can allocate a @ref pbuf in interrupt
* context and put them into a queue which is processed from mainloop.\n
* Call sys_check_timeouts() periodically in the mainloop.\n
* Porting: implement all functions in @ref sys_time, @ref sys_prot and
* @ref compiler_abstraction.\n
* You can only use @ref callbackstyle_api in this mode.\n
* Sample code:\n
* @include NO_SYS_SampleCode.c
*/
/**
* @defgroup lwip_os OS mode (TCPIP thread)
* @ingroup lwip
* Use this mode if you run an OS on your system. It is recommended to
* use an RTOS that correctly handles priority inversion and
* to use @ref LWIP_TCPIP_CORE_LOCKING.\n
* Porting: implement all functions in @ref sys_layer.\n
* You can use @ref callbackstyle_api together with @ref tcpip_callback,
* and all @ref sequential_api.
*/
/**
* @page raw_api lwIP API
* @verbinclude "rawapi.txt"
*/

View file

@ -0,0 +1,10 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Redirection</title>
<meta http-equiv="refresh" content="0; url=html/index.html" />
</head>
<body>
<a href="html/index.html">index.html</a>
</body>
</html>

View file

@ -0,0 +1,113 @@
Multicast DNS for lwIP
Author: Erik Ekman
Note! The MDNS responder does not have all features required by the standards.
See notes in src/apps/mdns/mdns.c for what is left. It is however usable in normal
cases - but watch out if many devices on the same network try to use the same
host/service instance names.
How to enable:
==============
MDNS support does not depend on DNS.
MDNS supports using IPv4 only, v6 only, or v4+v6.
To enable MDNS responder, set
LWIP_MDNS_RESPONDER = 1
in lwipopts.h and add src/apps/mdns/mdns.c to your list of files to build.
The max number of services supported per netif is defined by MDNS_MAX_SERVICES,
default is 1.
Increase MEMP_NUM_UDP_PCB by 1. MDNS needs one PCB.
Increase LWIP_NUM_NETIF_CLIENT_DATA by 1 (MDNS needs one entry on netif).
MDNS with IPv4 requires LWIP_IGMP = 1, and preferably LWIP_AUTOIP = 1.
MDNS with IPv6 requires LWIP_IPV6_MLD = 1, and that a link-local address is
generated.
The MDNS code puts its structs on the stack where suitable to reduce dynamic
memory allocation. It may use up to 1kB of stack.
MDNS needs a strncasecmp() implementation. If you have one, define
LWIP_MDNS_STRNCASECMP to it. Otherwise the code will provide an implementation
for you.
How to use:
===========
Call mdns_resp_init() during system initialization.
This opens UDP sockets on port 5353 for IPv4 and IPv6.
To start responding on a netif, run
mdns_resp_add_netif(struct netif *netif, char *hostname, u32_t dns_ttl)
The hostname will be copied. If this returns successfully, the netif will join
the multicast groups and any MDNS/legacy DNS requests sent unicast or multicast
to port 5353 will be handled:
- <hostname>.local type A, AAAA or ANY returns relevant IP addresses
- Reverse lookups (PTR in-addr.arpa, ip6.arpa) of netif addresses
returns <hostname>.local
Answers will use the supplied TTL (in seconds)
MDNS allows UTF-8 names, but it is recommended to stay within ASCII,
since the default case-insensitive comparison assumes this.
It is recommended to call this function after an IPv4 address has been set,
since there is currently no check if the v4 address is valid.
Call mdns_resp_netif_settings_changed() every time the IP address
on the netif has changed.
To stop responding on a netif, run
mdns_resp_remove_netif(struct netif *netif)
Adding services:
================
The netif first needs to be registered. Then run
mdns_resp_add_service(struct netif *netif, char *name, char *service,
u16_t proto, u16_t port, u32_t dns_ttl,
service_get_txt_fn_t txt_fn, void *txt_userdata);
The name and service pointers will be copied. Name refers to the name of the
service instance, and service is the type of service, like _http
proto can be DNSSD_PROTO_UDP or DNSSD_PROTO_TCP which represent _udp and _tcp.
If this call returns successfully, the following queries will be answered:
- _services._dns-sd._udp.local type PTR returns <service>.<proto>.local
- <service>.<proto>.local type PTR returns <name>.<service>.<proto>.local
- <name>.<service>.<proto>.local type SRV returns hostname and port of service
- <name>.<service>.<proto>.local type TXT builds text strings by calling txt_fn
with the supplied userdata. The callback adds strings to the reply by calling
mdns_resp_add_service_txtitem(struct mdns_service *service, char *txt,
int txt_len). Example callback method:
static void srv_txt(struct mdns_service *service, void *txt_userdata)
{
res = mdns_resp_add_service_txtitem(service, "path=/", 6);
LWIP_ERROR("mdns add service txt failed\n", (res == ERR_OK), return);
}
Since a hostname struct is used for TXT storage each single item can be max
63 bytes long, and the total max length (including length bytes for each
item) is 255 bytes.
If your device runs a webserver on port 80, an example call might be:
mdns_resp_add_service(netif, "myweb", "_http"
DNSSD_PROTO_TCP, 80, 3600, srv_txt, NULL);
which will publish myweb._http._tcp.local for any hosts looking for web servers,
and point them to <hostname>.local:80
Relevant information will be sent as additional records to reduce number of
requests required from a client.
Removing services is currently not supported. Services are removed when the
netif is removed.

View file

@ -0,0 +1,162 @@
MQTT client for lwIP
Author: Erik Andersson
Details of the MQTT protocol can be found at:
http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html
-----------------------------------------------------------------
1. Initial steps, reserve memory and make connection to server:
1.1: Provide storage
Static allocation:
mqtt_client_t static_client;
example_do_connect(&static_client);
Dynamic allocation:
mqtt_client_t *client = mqtt_client_new();
if(client != NULL) {
example_do_connect(&client);
}
1.2: Establish Connection with server
void example_do_connect(mqtt_client_t *client)
{
struct mqtt_connect_client_info_t ci;
err_t err;
/* Setup an empty client info structure */
memset(&ci, 0, sizeof(ci));
/* Minimal amount of information required is client identifier, so set it here */
ci.client_id = "lwip_test";
/* Initiate client and connect to server, if this fails immediately an error code is returned
otherwise mqtt_connection_cb will be called with connection result after attempting
to establish a connection with the server.
For now MQTT version 3.1.1 is always used */
err = mqtt_client_connect(client, ip_addr, MQTT_PORT, mqtt_connection_cb, 0, &ci);
/* For now just print the result code if something goes wrong
if(err != ERR_OK) {
printf("mqtt_connect return %d\n", err);
}
}
Connection to server can also be probed by calling mqtt_client_is_connected(client)
-----------------------------------------------------------------
2. Implementing the connection status callback
static void mqtt_connection_cb(mqtt_client_t *client, void *arg, mqtt_connection_status_t status)
{
err_t err;
if(status == MQTT_CONNECT_ACCEPTED) {
printf("mqtt_connection_cb: Successfully connected\n");
/* Setup callback for incoming publish requests */
mqtt_set_inpub_callback(client, mqtt_incoming_publish_cb, mqtt_incoming_data_cb, arg);
/* Subscribe to a topic named "subtopic" with QoS level 1, call mqtt_sub_request_cb with result */
err = mqtt_subscribe(client, "subtopic", 1, mqtt_sub_request_cb, arg);
if(err != ERR_OK) {
printf("mqtt_subscribe return: %d\n", err);
}
} else {
printf("mqtt_connection_cb: Disconnected, reason: %d\n", status);
/* Its more nice to be connected, so try to reconnect */
example_do_connect(client);
}
}
static void mqtt_sub_request_cb(void *arg, err_t result)
{
/* Just print the result code here for simplicity,
normal behaviour would be to take some action if subscribe fails like
notifying user, retry subscribe or disconnect from server */
printf("Subscribe result: %d\n", result);
}
-----------------------------------------------------------------
3. Implementing callbacks for incoming publish and data
/* The idea is to demultiplex topic and create some reference to be used in data callbacks
Example here uses a global variable, better would be to use a member in arg
If RAM and CPU budget allows it, the easiest implementation might be to just take a copy of
the topic string and use it in mqtt_incoming_data_cb
*/
static int inpub_id;
static void mqtt_incoming_publish_cb(void *arg, const char *topic, u32_t tot_len)
{
printf("Incoming publish at topic %s with total length %u\n", topic, (unsigned int)tot_len);
/* Decode topic string into a user defined reference */
if(strcmp(topic, "print_payload") == 0) {
inpub_id = 0;
} else if(topic[0] == 'A') {
/* All topics starting with 'A' might be handled at the same way */
inpub_id = 1;
} else {
/* For all other topics */
inpub_id = 2;
}
}
static void mqtt_incoming_data_cb(void *arg, const u8_t *data, u16_t len, u8_t flags)
{
printf("Incoming publish payload with length %d, flags %u\n", len, (unsigned int)flags);
if(flags & MQTT_DATA_FLAG_LAST) {
/* Last fragment of payload received (or whole part if payload fits receive buffer
See MQTT_VAR_HEADER_BUFFER_LEN) */
/* Call function or do action depending on reference, in this case inpub_id */
if(inpub_id == 0) {
/* Don't trust the publisher, check zero termination */
if(data[len-1] == 0) {
printf("mqtt_incoming_data_cb: %s\n", (const char *)data);
}
} else if(inpub_id == 1) {
/* Call an 'A' function... */
} else {
printf("mqtt_incoming_data_cb: Ignoring payload...\n");
}
} else {
/* Handle fragmented payload, store in buffer, write to file or whatever */
}
}
-----------------------------------------------------------------
4. Using outgoing publish
void example_publish(mqtt_client_t *client, void *arg)
{
const char *pub_payload= "PubSubHubLubJub";
err_t err;
u8_t qos = 2; /* 0 1 or 2, see MQTT specification */
u8_t retain = 0; /* No don't retain such crappy payload... */
err = mqtt_publish(client, "pub_topic", pub_payload, strlen(pub_payload), qos, retain, mqtt_pub_request_cb, arg);
if(err != ERR_OK) {
printf("Publish err: %d\n", err);
}
}
/* Called when publish is complete either with sucess or failure */
static void mqtt_pub_request_cb(void *arg, err_t result)
{
if(result != ERR_OK) {
printf("Publish result: %d\n", result);
}
}
-----------------------------------------------------------------
5. Disconnecting
Simply call mqtt_disconnect(client)

View file

@ -0,0 +1,529 @@
PPP interface for lwIP
Author: Sylvain Rochet
Table of Contents:
1 - Supported PPP protocols and features
2 - Raw API PPP example for all protocols
3 - PPPoS input path (raw API, IRQ safe API, TCPIP API)
4 - Thread safe PPP API (PPPAPI)
5 - Notify phase callback (PPP_NOTIFY_PHASE)
6 - Upgrading from lwIP <= 1.4.x to lwIP >= 2.0.x
1 Supported PPP protocols and features
======================================
Supported Low level protocols:
* PPP over serial using HDLC-like framing, such as wired dialup modems
or mobile telecommunications GPRS/EDGE/UMTS/HSPA+/LTE modems
* PPP over Ethernet, such as xDSL modems
* PPP over L2TP (Layer 2 Tunneling Protocol) LAC (L2TP Access Concentrator),
IP tunnel over UDP, such as VPN access
Supported auth protocols:
* PAP, Password Authentication Protocol
* CHAP, Challenge-Handshake Authentication Protocol, also known as CHAP-MD5
* MSCHAPv1, Microsoft version of CHAP, version 1
* MSCHAPv2, Microsoft version of CHAP, version 2
* EAP, Extensible Authentication Protocol
Supported address protocols:
* IPCP, IP Control Protocol, IPv4 addresses negotiation
* IP6CP, IPv6 Control Protocol, IPv6 link-local addresses negotiation
Supported encryption protocols:
* MPPE, Microsoft Point-to-Point Encryption
Supported compression or miscellaneous protocols, for serial links only:
* PFC, Protocol Field Compression
* ACFC, Address-and-Control-Field-Compression
* ACCM, Asynchronous-Control-Character-Map
* VJ, Van Jacobson TCP/IP Header Compression
2 Raw API PPP example for all protocols
=======================================
As usual, raw API for lwIP means the lightweight API which *MUST* only be used
for NO_SYS=1 systems or called inside lwIP core thread for NO_SYS=0 systems.
/*
* Globals
* =======
*/
/* The PPP control block */
ppp_pcb *ppp;
/* The PPP IP interface */
struct netif ppp_netif;
/*
* PPP status callback
* ===================
*
* PPP status callback is called on PPP status change (up, down, …) from lwIP
* core thread
*/
/* PPP status callback example */
static void status_cb(ppp_pcb *pcb, int err_code, void *ctx) {
struct netif *pppif = ppp_netif(pcb);
LWIP_UNUSED_ARG(ctx);
switch(err_code) {
case PPPERR_NONE: {
#if LWIP_DNS
const ip_addr_t *ns;
#endif /* LWIP_DNS */
printf("status_cb: Connected\n");
#if PPP_IPV4_SUPPORT
printf(" our_ipaddr = %s\n", ipaddr_ntoa(&pppif->ip_addr));
printf(" his_ipaddr = %s\n", ipaddr_ntoa(&pppif->gw));
printf(" netmask = %s\n", ipaddr_ntoa(&pppif->netmask));
#if LWIP_DNS
ns = dns_getserver(0);
printf(" dns1 = %s\n", ipaddr_ntoa(ns));
ns = dns_getserver(1);
printf(" dns2 = %s\n", ipaddr_ntoa(ns));
#endif /* LWIP_DNS */
#endif /* PPP_IPV4_SUPPORT */
#if PPP_IPV6_SUPPORT
printf(" our6_ipaddr = %s\n", ip6addr_ntoa(netif_ip6_addr(pppif, 0)));
#endif /* PPP_IPV6_SUPPORT */
break;
}
case PPPERR_PARAM: {
printf("status_cb: Invalid parameter\n");
break;
}
case PPPERR_OPEN: {
printf("status_cb: Unable to open PPP session\n");
break;
}
case PPPERR_DEVICE: {
printf("status_cb: Invalid I/O device for PPP\n");
break;
}
case PPPERR_ALLOC: {
printf("status_cb: Unable to allocate resources\n");
break;
}
case PPPERR_USER: {
printf("status_cb: User interrupt\n");
break;
}
case PPPERR_CONNECT: {
printf("status_cb: Connection lost\n");
break;
}
case PPPERR_AUTHFAIL: {
printf("status_cb: Failed authentication challenge\n");
break;
}
case PPPERR_PROTOCOL: {
printf("status_cb: Failed to meet protocol\n");
break;
}
case PPPERR_PEERDEAD: {
printf("status_cb: Connection timeout\n");
break;
}
case PPPERR_IDLETIMEOUT: {
printf("status_cb: Idle Timeout\n");
break;
}
case PPPERR_CONNECTTIME: {
printf("status_cb: Max connect time reached\n");
break;
}
case PPPERR_LOOPBACK: {
printf("status_cb: Loopback detected\n");
break;
}
default: {
printf("status_cb: Unknown error code %d\n", err_code);
break;
}
}
/*
* This should be in the switch case, this is put outside of the switch
* case for example readability.
*/
if (err_code == PPPERR_NONE) {
return;
}
/* ppp_close() was previously called, don't reconnect */
if (err_code == PPPERR_USER) {
/* ppp_free(); -- can be called here */
return;
}
/*
* Try to reconnect in 30 seconds, if you need a modem chatscript you have
* to do a much better signaling here ;-)
*/
ppp_connect(pcb, 30);
/* OR ppp_listen(pcb); */
}
/*
* Creating a new PPPoS session
* ============================
*
* In lwIP, PPPoS is not PPPoSONET, in lwIP PPPoS is PPPoSerial.
*/
#include "netif/ppp/pppos.h"
/*
* PPPoS serial output callback
*
* ppp_pcb, PPP control block
* data, buffer to write to serial port
* len, length of the data buffer
* ctx, optional user-provided callback context pointer
*
* Return value: len if write succeed
*/
static u32_t output_cb(ppp_pcb *pcb, u8_t *data, u32_t len, void *ctx) {
return uart_write(UART, data, len);
}
/*
* Create a new PPPoS interface
*
* ppp_netif, netif to use for this PPP link, i.e. PPP IP interface
* output_cb, PPPoS serial output callback
* status_cb, PPP status callback, called on PPP status change (up, down, …)
* ctx_cb, optional user-provided callback context pointer
*/
ppp = pppos_create(&ppp_netif,
output_cb, status_cb, ctx_cb);
/*
* Creating a new PPPoE session
* ============================
*/
#include "netif/ppp/pppoe.h"
/*
* Create a new PPPoE interface
*
* ppp_netif, netif to use for this PPP link, i.e. PPP IP interface
* ethif, already existing and setup Ethernet interface to use
* service_name, PPPoE service name discriminator (not supported yet)
* concentrator_name, PPPoE concentrator name discriminator (not supported yet)
* status_cb, PPP status callback, called on PPP status change (up, down, …)
* ctx_cb, optional user-provided callback context pointer
*/
ppp = pppoe_create(&ppp_netif,
&ethif,
service_name, concentrator_name,
status_cb, ctx_cb);
/*
* Creating a new PPPoL2TP session
* ===============================
*/
#include "netif/ppp/pppol2tp.h"
/*
* Create a new PPPoL2TP interface
*
* ppp_netif, netif to use for this PPP link, i.e. PPP IP interface
* netif, optional already existing and setup output netif, necessary if you
* want to set this interface as default route to settle the chicken
* and egg problem with VPN links
* ipaddr, IP to connect to
* port, UDP port to connect to (usually 1701)
* secret, L2TP secret to use
* secret_len, size in bytes of the L2TP secret
* status_cb, PPP status callback, called on PPP status change (up, down, …)
* ctx_cb, optional user-provided callback context pointer
*/
ppp = pppol2tp_create(&ppp_netif,
struct netif *netif, ip_addr_t *ipaddr, u16_t port,
u8_t *secret, u8_t secret_len,
ppp_link_status_cb_fn link_status_cb, void *ctx_cb);
/*
* Initiate PPP client connection
* ==============================
*/
/* Set this interface as default route */
ppp_set_default(ppp);
/*
* Basic PPP client configuration. Can only be set if PPP session is in the
* dead state (i.e. disconnected). We don't need to provide thread-safe
* equivalents through PPPAPI because those helpers are only changing
* structure members while session is inactive for lwIP core. Configuration
* only need to be done once.
*/
/* Ask the peer for up to 2 DNS server addresses. */
ppp_set_usepeerdns(ppp, 1);
/* Auth configuration, this is pretty self-explanatory */
ppp_set_auth(ppp, PPPAUTHTYPE_ANY, "login", "password");
/*
* Initiate PPP negotiation, without waiting (holdoff=0), can only be called
* if PPP session is in the dead state (i.e. disconnected).
*/
u16_t holdoff = 0;
ppp_connect(ppp, holdoff);
/*
* Initiate PPP server listener
* ============================
*/
/*
* Basic PPP server configuration. Can only be set if PPP session is in the
* dead state (i.e. disconnected). We don't need to provide thread-safe
* equivalents through PPPAPI because those helpers are only changing
* structure members while session is inactive for lwIP core. Configuration
* only need to be done once.
*/
ip4_addr_t addr;
/* Set our address */
IP4_ADDR(&addr, 192,168,0,1);
ppp_set_ipcp_ouraddr(ppp, &addr);
/* Set peer(his) address */
IP4_ADDR(&addr, 192,168,0,2);
ppp_set_ipcp_hisaddr(ppp, &addr);
/* Set primary DNS server */
IP4_ADDR(&addr, 192,168,10,20);
ppp_set_ipcp_dnsaddr(ppp, 0, &addr);
/* Set secondary DNS server */
IP4_ADDR(&addr, 192,168,10,21);
ppp_set_ipcp_dnsaddr(ppp, 1, &addr);
/* Auth configuration, this is pretty self-explanatory */
ppp_set_auth(ppp, PPPAUTHTYPE_ANY, "login", "password");
/* Require peer to authenticate */
ppp_set_auth_required(ppp, 1);
/*
* Only for PPPoS, the PPP session should be up and waiting for input.
*
* Note: for PPPoS, ppp_connect() and ppp_listen() are actually the same thing.
* The listen call is meant for future support of PPPoE and PPPoL2TP server
* mode, where we will need to negotiate the incoming PPPoE session or L2TP
* session before initiating PPP itself. We need this call because there is
* two passive modes for PPPoS, ppp_set_passive and ppp_set_silent.
*/
ppp_set_silent(pppos, 1);
/*
* Initiate PPP listener (i.e. wait for an incoming connection), can only
* be called if PPP session is in the dead state (i.e. disconnected).
*/
ppp_listen(ppp);
/*
* Closing PPP connection
* ======================
*/
/*
* Initiate the end of the PPP session, without carrier lost signal
* (nocarrier=0), meaning a clean shutdown of PPP protocols.
* You can call this function at anytime.
*/
u8_t nocarrier = 0;
ppp_close(ppp, nocarrier);
/*
* Then you must wait your status_cb() to be called, it may takes from a few
* seconds to several tens of seconds depending on the current PPP state.
*/
/*
* Freeing a PPP connection
* ========================
*/
/*
* Free the PPP control block, can only be called if PPP session is in the
* dead state (i.e. disconnected). You need to call ppp_close() before.
*/
ppp_free(ppp);
3 PPPoS input path (raw API, IRQ safe API, TCPIP API)
=====================================================
Received data on serial port should be sent to lwIP using the pppos_input()
function or the pppos_input_tcpip() function.
If NO_SYS is 1 and if PPP_INPROC_IRQ_SAFE is 0 (the default), pppos_input()
is not IRQ safe and then *MUST* only be called inside your main loop.
Whatever the NO_SYS value, if PPP_INPROC_IRQ_SAFE is 1, pppos_input() is IRQ
safe and can be safely called from an interrupt context, using that is going
to reduce your need of buffer if pppos_input() is called byte after byte in
your rx serial interrupt.
if NO_SYS is 0, the thread safe way outside an interrupt context is to use
the pppos_input_tcpip() function to pass input data to the lwIP core thread
using the TCPIP API. This is thread safe in all cases but you should avoid
passing data byte after byte because it uses heavy locking (mailbox) and it
allocates pbuf, better fill them !
if NO_SYS is 0 and if PPP_INPROC_IRQ_SAFE is 1, you may also use pppos_input()
from an RX thread, however pppos_input() is not thread safe by itself. You can
do that *BUT* you should NEVER call pppos_connect(), pppos_listen() and
ppp_free() if pppos_input() can still be running, doing this is NOT thread safe
at all. Using PPP_INPROC_IRQ_SAFE from an RX thread is discouraged unless you
really know what you are doing, your move ;-)
/*
* Fonction to call for received data
*
* ppp, PPP control block
* buffer, input buffer
* buffer_len, buffer length in bytes
*/
void pppos_input(ppp, buffer, buffer_len);
or
void pppos_input_tcpip(ppp, buffer, buffer_len);
4 Thread safe PPP API (PPPAPI)
==============================
There is a thread safe API for all corresponding ppp_* functions, you have to
enable LWIP_PPP_API in your lwipopts.h file, then see
include/netif/ppp/pppapi.h, this is actually pretty obvious.
5 Notify phase callback (PPP_NOTIFY_PHASE)
==========================================
Notify phase callback, enabled using the PPP_NOTIFY_PHASE config option, let
you configure a callback that is called on each PPP internal state change.
This is different from the status callback which only warns you about
up(running) and down(dead) events.
Notify phase callback can be used, for example, to set a LED pattern depending
on the current phase of the PPP session. Here is a callback example which
tries to mimic what we usually see on xDSL modems while they are negotiating
the link, which should be self-explanatory:
static void ppp_notify_phase_cb(ppp_pcb *pcb, u8_t phase, void *ctx) {
switch (phase) {
/* Session is down (either permanently or briefly) */
case PPP_PHASE_DEAD:
led_set(PPP_LED, LED_OFF);
break;
/* We are between two sessions */
case PPP_PHASE_HOLDOFF:
led_set(PPP_LED, LED_SLOW_BLINK);
break;
/* Session just started */
case PPP_PHASE_INITIALIZE:
led_set(PPP_LED, LED_FAST_BLINK);
break;
/* Session is running */
case PPP_PHASE_RUNNING:
led_set(PPP_LED, LED_ON);
break;
default:
break;
}
}
6 Upgrading from lwIP <= 1.4.x to lwIP >= 2.0.x
===============================================
PPP API was fully reworked between 1.4.x and 2.0.x releases. However porting
from previous lwIP version is pretty easy:
* Previous PPP API used an integer to identify PPP sessions, we are now
using ppp_pcb* control block, therefore all functions changed from "int ppp"
to "ppp_pcb *ppp"
* struct netif was moved outside the PPP structure, you have to provide a netif
for PPP interface in pppoX_create() functions
* PPP session are not started automatically after you created them anymore,
you have to call ppp_connect(), this way you can configure the session before
starting it.
* Previous PPP API used CamelCase, we are now using snake_case.
* Previous PPP API mixed PPPoS and PPPoE calls, this isn't the case anymore,
PPPoS functions are now prefixed pppos_ and PPPoE functions are now prefixed
pppoe_, common functions are now prefixed ppp_.
* New PPPERR_ error codes added, check you have all of them in your status
callback function
* Only the following include files should now be used in user application:
#include "netif/ppp/pppapi.h"
#include "netif/ppp/pppos.h"
#include "netif/ppp/pppoe.h"
#include "netif/ppp/pppol2tp.h"
Functions from ppp.h can be used, but you don't need to include this header
file as it is already included by above header files.
* PPP_INPROC_OWNTHREAD was broken by design and was removed, you have to create
your own serial rx thread
* PPP_INPROC_MULTITHREADED option was misnamed and confusing and was renamed
PPP_INPROC_IRQ_SAFE, please read the "PPPoS input path" documentation above
because you might have been fooled by that
* If you used tcpip_callback_with_block() on ppp_ functions you may wish to use
the PPPAPI API instead.
* ppp_sighup and ppp_close functions were merged using an optional argument
"nocarrier" on ppp_close.
* DNS servers are now only remotely asked if LWIP_DNS is set and if
ppp_set_usepeerdns() is set to true, they are now automatically registered
using the dns_setserver() function so you don't need to do that in the PPP
callback anymore.
* PPPoS does not use the SIO API anymore, as such it now requires a serial
output callback in place of sio_write
* PPP_MAXIDLEFLAG is now in ms instead of jiffies

View file

@ -0,0 +1,499 @@
Raw TCP/IP interface for lwIP
Authors: Adam Dunkels, Leon Woestenberg, Christiaan Simons
lwIP provides three Application Program's Interfaces (APIs) for programs
to use for communication with the TCP/IP code:
* low-level "core" / "callback" or "raw" API.
* higher-level "sequential" API.
* BSD-style socket API.
The raw API (sometimes called native API) is an event-driven API designed
to be used without an operating system that implements zero-copy send and
receive. This API is also used by the core stack for interaction between
the various protocols. It is the only API available when running lwIP
without an operating system.
The sequential API provides a way for ordinary, sequential, programs
to use the lwIP stack. It is quite similar to the BSD socket API. The
model of execution is based on the blocking open-read-write-close
paradigm. Since the TCP/IP stack is event based by nature, the TCP/IP
code and the application program must reside in different execution
contexts (threads).
The socket API is a compatibility API for existing applications,
currently it is built on top of the sequential API. It is meant to
provide all functions needed to run socket API applications running
on other platforms (e.g. unix / windows etc.). However, due to limitations
in the specification of this API, there might be incompatibilities
that require small modifications of existing programs.
** Multithreading
lwIP started targeting single-threaded environments. When adding multi-
threading support, instead of making the core thread-safe, another
approach was chosen: there is one main thread running the lwIP core
(also known as the "tcpip_thread"). When running in a multithreaded
environment, raw API functions MUST only be called from the core thread
since raw API functions are not protected from concurrent access (aside
from pbuf- and memory management functions). Application threads using
the sequential- or socket API communicate with this main thread through
message passing.
As such, the list of functions that may be called from
other threads or an ISR is very limited! Only functions
from these API header files are thread-safe:
- api.h
- netbuf.h
- netdb.h
- netifapi.h
- pppapi.h
- sockets.h
- sys.h
Additionaly, memory (de-)allocation functions may be
called from multiple threads (not ISR!) with NO_SYS=0
since they are protected by SYS_LIGHTWEIGHT_PROT and/or
semaphores.
Netconn or Socket API functions are thread safe against the
core thread but they are not reentrant at the control block
granularity level. That is, a UDP or TCP control block must
not be shared among multiple threads without proper locking.
If SYS_LIGHTWEIGHT_PROT is set to 1 and
LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT is set to 1,
pbuf_free() may also be called from another thread or
an ISR (since only then, mem_free - for PBUF_RAM - may
be called from an ISR: otherwise, the HEAP is only
protected by semaphores).
** The remainder of this document discusses the "raw" API. **
The raw TCP/IP interface allows the application program to integrate
better with the TCP/IP code. Program execution is event based by
having callback functions being called from within the TCP/IP
code. The TCP/IP code and the application program both run in the same
thread. The sequential API has a much higher overhead and is not very
well suited for small systems since it forces a multithreaded paradigm
on the application.
The raw TCP/IP interface is not only faster in terms of code execution
time but is also less memory intensive. The drawback is that program
development is somewhat harder and application programs written for
the raw TCP/IP interface are more difficult to understand. Still, this
is the preferred way of writing applications that should be small in
code size and memory usage.
All APIs can be used simultaneously by different application
programs. In fact, the sequential API is implemented as an application
program using the raw TCP/IP interface.
Do not confuse the lwIP raw API with raw Ethernet or IP sockets.
The former is a way of interfacing the lwIP network stack (including
TCP and UDP), the later refers to processing raw Ethernet or IP data
instead of TCP connections or UDP packets.
Raw API applications may never block since all packet processing
(input and output) as well as timer processing (TCP mainly) is done
in a single execution context.
--- Callbacks
Program execution is driven by callbacks functions, which are then
invoked by the lwIP core when activity related to that application
occurs. A particular application may register to be notified via a
callback function for events such as incoming data available, outgoing
data sent, error notifications, poll timer expiration, connection
closed, etc. An application can provide a callback function to perform
processing for any or all of these events. Each callback is an ordinary
C function that is called from within the TCP/IP code. Every callback
function is passed the current TCP or UDP connection state as an
argument. Also, in order to be able to keep program specific state,
the callback functions are called with a program specified argument
that is independent of the TCP/IP state.
The function for setting the application connection state is:
- void tcp_arg(struct tcp_pcb *pcb, void *arg)
Specifies the program specific state that should be passed to all
other callback functions. The "pcb" argument is the current TCP
connection control block, and the "arg" argument is the argument
that will be passed to the callbacks.
--- TCP connection setup
The functions used for setting up connections is similar to that of
the sequential API and of the BSD socket API. A new TCP connection
identifier (i.e., a protocol control block - PCB) is created with the
tcp_new() function. This PCB can then be either set to listen for new
incoming connections or be explicitly connected to another host.
- struct tcp_pcb *tcp_new(void)
Creates a new connection identifier (PCB). If memory is not
available for creating the new pcb, NULL is returned.
- err_t tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr,
u16_t port)
Binds the pcb to a local IP address and port number. The IP address
can be specified as IP_ADDR_ANY in order to bind the connection to
all local IP addresses.
If another connection is bound to the same port, the function will
return ERR_USE, otherwise ERR_OK is returned.
- struct tcp_pcb *tcp_listen(struct tcp_pcb *pcb)
Commands a pcb to start listening for incoming connections. When an
incoming connection is accepted, the function specified with the
tcp_accept() function will be called. The pcb will have to be bound
to a local port with the tcp_bind() function.
The tcp_listen() function returns a new connection identifier, and
the one passed as an argument to the function will be
deallocated. The reason for this behavior is that less memory is
needed for a connection that is listening, so tcp_listen() will
reclaim the memory needed for the original connection and allocate a
new smaller memory block for the listening connection.
tcp_listen() may return NULL if no memory was available for the
listening connection. If so, the memory associated with the pcb
passed as an argument to tcp_listen() will not be deallocated.
- struct tcp_pcb *tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)
Same as tcp_listen, but limits the number of outstanding connections
in the listen queue to the value specified by the backlog argument.
To use it, your need to set TCP_LISTEN_BACKLOG=1 in your lwipopts.h.
- void tcp_accept(struct tcp_pcb *pcb,
err_t (* accept)(void *arg, struct tcp_pcb *newpcb,
err_t err))
Specified the callback function that should be called when a new
connection arrives on a listening connection.
- err_t tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr,
u16_t port, err_t (* connected)(void *arg,
struct tcp_pcb *tpcb,
err_t err));
Sets up the pcb to connect to the remote host and sends the
initial SYN segment which opens the connection.
The tcp_connect() function returns immediately; it does not wait for
the connection to be properly setup. Instead, it will call the
function specified as the fourth argument (the "connected" argument)
when the connection is established. If the connection could not be
properly established, either because the other host refused the
connection or because the other host didn't answer, the "err"
callback function of this pcb (registered with tcp_err, see below)
will be called.
The tcp_connect() function can return ERR_MEM if no memory is
available for enqueueing the SYN segment. If the SYN indeed was
enqueued successfully, the tcp_connect() function returns ERR_OK.
--- Sending TCP data
TCP data is sent by enqueueing the data with a call to
tcp_write(). When the data is successfully transmitted to the remote
host, the application will be notified with a call to a specified
callback function.
- err_t tcp_write(struct tcp_pcb *pcb, const void *dataptr, u16_t len,
u8_t apiflags)
Enqueues the data pointed to by the argument dataptr. The length of
the data is passed as the len parameter. The apiflags can be one or more of:
- TCP_WRITE_FLAG_COPY: indicates whether the new memory should be allocated
for the data to be copied into. If this flag is not given, no new memory
should be allocated and the data should only be referenced by pointer. This
also means that the memory behind dataptr must not change until the data is
ACKed by the remote host
- TCP_WRITE_FLAG_MORE: indicates that more data follows. If this is omitted,
the PSH flag is set in the last segment created by this call to tcp_write.
If this flag is given, the PSH flag is not set.
The tcp_write() function will fail and return ERR_MEM if the length
of the data exceeds the current send buffer size or if the length of
the queue of outgoing segment is larger than the upper limit defined
in lwipopts.h. The number of bytes available in the output queue can
be retrieved with the tcp_sndbuf() function.
The proper way to use this function is to call the function with at
most tcp_sndbuf() bytes of data. If the function returns ERR_MEM,
the application should wait until some of the currently enqueued
data has been successfully received by the other host and try again.
- void tcp_sent(struct tcp_pcb *pcb,
err_t (* sent)(void *arg, struct tcp_pcb *tpcb,
u16_t len))
Specifies the callback function that should be called when data has
successfully been received (i.e., acknowledged) by the remote
host. The len argument passed to the callback function gives the
amount bytes that was acknowledged by the last acknowledgment.
--- Receiving TCP data
TCP data reception is callback based - an application specified
callback function is called when new data arrives. When the
application has taken the data, it has to call the tcp_recved()
function to indicate that TCP can advertise increase the receive
window.
- void tcp_recv(struct tcp_pcb *pcb,
err_t (* recv)(void *arg, struct tcp_pcb *tpcb,
struct pbuf *p, err_t err))
Sets the callback function that will be called when new data
arrives. The callback function will be passed a NULL pbuf to
indicate that the remote host has closed the connection. If
there are no errors and the callback function is to return
ERR_OK, then it must free the pbuf. Otherwise, it must not
free the pbuf so that lwIP core code can store it.
- void tcp_recved(struct tcp_pcb *pcb, u16_t len)
Must be called when the application has received the data. The len
argument indicates the length of the received data.
--- Application polling
When a connection is idle (i.e., no data is either transmitted or
received), lwIP will repeatedly poll the application by calling a
specified callback function. This can be used either as a watchdog
timer for killing connections that have stayed idle for too long, or
as a method of waiting for memory to become available. For instance,
if a call to tcp_write() has failed because memory wasn't available,
the application may use the polling functionality to call tcp_write()
again when the connection has been idle for a while.
- void tcp_poll(struct tcp_pcb *pcb,
err_t (* poll)(void *arg, struct tcp_pcb *tpcb),
u8_t interval)
Specifies the polling interval and the callback function that should
be called to poll the application. The interval is specified in
number of TCP coarse grained timer shots, which typically occurs
twice a second. An interval of 10 means that the application would
be polled every 5 seconds.
--- Closing and aborting connections
- err_t tcp_close(struct tcp_pcb *pcb)
Closes the connection. The function may return ERR_MEM if no memory
was available for closing the connection. If so, the application
should wait and try again either by using the acknowledgment
callback or the polling functionality. If the close succeeds, the
function returns ERR_OK.
The pcb is deallocated by the TCP code after a call to tcp_close().
- void tcp_abort(struct tcp_pcb *pcb)
Aborts the connection by sending a RST (reset) segment to the remote
host. The pcb is deallocated. This function never fails.
ATTENTION: When calling this from one of the TCP callbacks, make
sure you always return ERR_ABRT (and never return ERR_ABRT otherwise
or you will risk accessing deallocated memory or memory leaks!
If a connection is aborted because of an error, the application is
alerted of this event by the err callback. Errors that might abort a
connection are when there is a shortage of memory. The callback
function to be called is set using the tcp_err() function.
- void tcp_err(struct tcp_pcb *pcb, void (* err)(void *arg,
err_t err))
The error callback function does not get the pcb passed to it as a
parameter since the pcb may already have been deallocated.
--- UDP interface
The UDP interface is similar to that of TCP, but due to the lower
level of complexity of UDP, the interface is significantly simpler.
- struct udp_pcb *udp_new(void)
Creates a new UDP pcb which can be used for UDP communication. The
pcb is not active until it has either been bound to a local address
or connected to a remote address.
- void udp_remove(struct udp_pcb *pcb)
Removes and deallocates the pcb.
- err_t udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr,
u16_t port)
Binds the pcb to a local address. The IP-address argument "ipaddr"
can be IP_ADDR_ANY to indicate that it should listen to any local IP
address. The function currently always return ERR_OK.
- err_t udp_connect(struct udp_pcb *pcb, ip_addr_t *ipaddr,
u16_t port)
Sets the remote end of the pcb. This function does not generate any
network traffic, but only set the remote address of the pcb.
- err_t udp_disconnect(struct udp_pcb *pcb)
Remove the remote end of the pcb. This function does not generate
any network traffic, but only removes the remote address of the pcb.
- err_t udp_send(struct udp_pcb *pcb, struct pbuf *p)
Sends the pbuf p. The pbuf is not deallocated.
- void udp_recv(struct udp_pcb *pcb,
void (* recv)(void *arg, struct udp_pcb *upcb,
struct pbuf *p,
ip_addr_t *addr,
u16_t port),
void *recv_arg)
Specifies a callback function that should be called when a UDP
datagram is received.
--- System initalization
A truly complete and generic sequence for initializing the lwIP stack
cannot be given because it depends on additional initializations for
your runtime environment (e.g. timers).
We can give you some idea on how to proceed when using the raw API.
We assume a configuration using a single Ethernet netif and the
UDP and TCP transport layers, IPv4 and the DHCP client.
Call these functions in the order of appearance:
- lwip_init()
Initialize the lwIP stack and all of its subsystems.
- netif_add(struct netif *netif, const ip4_addr_t *ipaddr,
const ip4_addr_t *netmask, const ip4_addr_t *gw,
void *state, netif_init_fn init, netif_input_fn input)
Adds your network interface to the netif_list. Allocate a struct
netif and pass a pointer to this structure as the first argument.
Give pointers to cleared ip_addr structures when using DHCP,
or fill them with sane numbers otherwise. The state pointer may be NULL.
The init function pointer must point to a initialization function for
your Ethernet netif interface. The following code illustrates its use.
err_t netif_if_init(struct netif *netif)
{
u8_t i;
for (i = 0; i < ETHARP_HWADDR_LEN; i++) {
netif->hwaddr[i] = some_eth_addr[i];
}
init_my_eth_device();
return ERR_OK;
}
For Ethernet drivers, the input function pointer must point to the lwIP
function ethernet_input() declared in "netif/etharp.h". Other drivers
must use ip_input() declared in "lwip/ip.h".
- netif_set_default(struct netif *netif)
Registers the default network interface.
- netif_set_link_up(struct netif *netif)
This is the hardware link state; e.g. whether cable is plugged for wired
Ethernet interface. This function must be called even if you don't know
the current state. Having link up and link down events is optional but
DHCP and IPv6 discover benefit well from those events.
- netif_set_up(struct netif *netif)
This is the administrative (= software) state of the netif, when the
netif is fully configured this function must be called.
- dhcp_start(struct netif *netif)
Creates a new DHCP client for this interface on the first call.
You can peek in the netif->dhcp struct for the actual DHCP status.
- sys_check_timeouts()
When the system is running, you have to periodically call
sys_check_timeouts() which will handle all timers for all protocols in
the stack; add this to your main loop or equivalent.
--- Optimalization hints
The first thing you want to optimize is the lwip_standard_checksum()
routine from src/core/inet.c. You can override this standard
function with the #define LWIP_CHKSUM <your_checksum_routine>.
There are C examples given in inet.c or you might want to
craft an assembly function for this. RFC1071 is a good
introduction to this subject.
Other significant improvements can be made by supplying
assembly or inline replacements for htons() and htonl()
if you're using a little-endian architecture.
#define lwip_htons(x) <your_htons>
#define lwip_htonl(x) <your_htonl>
If you #define them to htons() and htonl(), you should
#define LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS to prevent lwIP from
defining hton*/ntoh* compatibility macros.
Check your network interface driver if it reads at
a higher speed than the maximum wire-speed. If the
hardware isn't serviced frequently and fast enough
buffer overflows are likely to occur.
E.g. when using the cs8900 driver, call cs8900if_service(ethif)
as frequently as possible. When using an RTOS let the cs8900 interrupt
wake a high priority task that services your driver using a binary
semaphore or event flag. Some drivers might allow additional tuning
to match your application and network.
For a production release it is recommended to set LWIP_STATS to 0.
Note that speed performance isn't influenced much by simply setting
high values to the memory options.
For more optimization hints take a look at the lwIP wiki.
--- Zero-copy MACs
To achieve zero-copy on transmit, the data passed to the raw API must
remain unchanged until sent. Because the send- (or write-)functions return
when the packets have been enqueued for sending, data must be kept stable
after that, too.
This implies that PBUF_RAM/PBUF_POOL pbufs passed to raw-API send functions
must *not* be reused by the application unless their ref-count is 1.
For no-copy pbufs (PBUF_ROM/PBUF_REF), data must be kept unchanged, too,
but the stack/driver will/must copy PBUF_REF'ed data when enqueueing, while
PBUF_ROM-pbufs are just enqueued (as ROM-data is expected to never change).
Also, data passed to tcp_write without the copy-flag must not be changed!
Therefore, be careful which type of PBUF you use and if you copy TCP data
or not!

View file

@ -0,0 +1,120 @@
Daily Use Guide for using Savannah for lwIP
Table of Contents:
1 - Obtaining lwIP from the Git repository
2 - Committers/developers Git access using SSH
3 - Merging a development branch to master branch
4 - How to release lwIP
1 Obtaining lwIP from the Git repository
----------------------------------------
To perform an anonymous Git clone of the master branch (this is where
bug fixes and incremental enhancements occur), do this:
git clone git://git.savannah.nongnu.org/lwip.git
Or, obtain a stable branch (updated with bug fixes only) as follows:
git clone --branch DEVEL-1_4_1 git://git.savannah.nongnu.org/lwip.git
Or, obtain a specific (fixed) release as follows:
git clone --branch STABLE-1_4_1 git://git.savannah.nongnu.org/lwip.git
2 Committers/developers Git access using SSH
--------------------------------------------
The Savannah server uses SSH (Secure Shell) protocol 2 authentication and encryption.
As such, Git commits to the server occur through a SSH tunnel for project members.
To create a SSH2 key pair in UNIX-like environments, do this:
ssh-keygen -t dsa
Under Windows, a recommended SSH client is "PuTTY", freely available with good
documentation and a graphic user interface. Use its key generator.
Now paste the id_dsa.pub contents into your Savannah account public key list. Wait
a while so that Savannah can update its configuration (This can take minutes).
Try to login using SSH:
ssh -v your_login@git.sv.gnu.org
If it tells you:
Linux vcs.savannah.gnu.org 2.6.32-5-xen-686 #1 SMP Wed Jun 17 17:10:03 UTC 2015 i686
Interactive shell login is not possible for security reasons.
VCS commands are allowed.
Last login: Tue May 15 23:10:12 2012 from 82.245.102.129
You tried to execute:
Sorry, you are not allowed to execute that command.
Shared connection to git.sv.gnu.org closed.
then you could login; Savannah refuses to give you a shell - which is OK, as we
are allowed to use SSH for Git only. Now, you should be able to do this:
git clone your_login@git.sv.gnu.org:/srv/git/lwip.git
After which you can edit your local files with bug fixes or new features and
commit them. Make sure you know what you are doing when using Git to make
changes on the repository. If in doubt, ask on the lwip-members mailing list.
(If SSH asks about authenticity of the host, you can check the key
fingerprint against https://savannah.nongnu.org/git/?group=lwip
3 - Merging a development branch to master branch
-------------------------------------------------
Merging is a straightforward process in Git. How to merge all changes in a
development branch since our last merge from main:
Checkout the master branch:
git checkout master
Merge the development branch to master:
git merge your-development-branch
Resolve any conflict.
Commit the merge result.
git commit -a
Push your commits:
git push
4 How to release lwIP
---------------------
First, tag the release using Git: (I use release number 1.4.1 throughout
this example).
git tag -a STABLE-1_4_1
Share the tag reference by pushing it to remote:
git push origin STABLE-1_4_1
Prepare the release:
cp -r lwip lwip-1.4.1
rm -rf lwip-1.4.1/.git lwip-1.4.1/.gitattributes
Archive the current directory using tar, gzip'd, bzip2'd and zip'd.
tar czvf lwip-1.4.1.tar.gz lwip-1.4.1
tar cjvf lwip-1.4.1.tar.bz2 lwip-1.4.1
zip -r lwip-1.4.1.zip lwip-1.4.1
Now, sign the archives with a detached GPG binary signature as follows:
gpg -b lwip-1.4.1.tar.gz
gpg -b lwip-1.4.1.tar.bz2
gpg -b lwip-1.4.1.zip
Upload these files using anonymous FTP:
ncftp ftp://savannah.gnu.org/incoming/savannah/lwip
ncftp> mput *1.4.1.*
Additionally, you may post a news item on Savannah, like this:
A new 1.4.1 release is now available here:
http://savannah.nongnu.org/files/?group=lwip&highlight=1.4.1
You will have to submit this via the user News interface, then approve
this via the Administrator News interface.

View file

@ -0,0 +1,303 @@
sys_arch interface for lwIP
Author: Adam Dunkels
Simon Goldschmidt
The operating system emulation layer provides a common interface
between the lwIP code and the underlying operating system kernel. The
general idea is that porting lwIP to new architectures requires only
small changes to a few header files and a new sys_arch
implementation. It is also possible to do a sys_arch implementation
that does not rely on any underlying operating system.
The sys_arch provides semaphores, mailboxes and mutexes to lwIP. For the full
lwIP functionality, multiple threads support can be implemented in the
sys_arch, but this is not required for the basic lwIP
functionality. Timer scheduling is implemented in lwIP, but can be implemented
by the sys_arch port (LWIP_TIMERS_CUSTOM==1).
In addition to the source file providing the functionality of sys_arch,
the OS emulation layer must provide several header files defining
macros used throughout lwip. The files required and the macros they
must define are listed below the sys_arch description.
Semaphores can be either counting or binary - lwIP works with both
kinds. Mailboxes should be implemented as a queue which allows multiple messages
to be posted (implementing as a rendez-vous point where only one message can be
posted at a time can have a highly negative impact on performance). A message
in a mailbox is just a pointer, nothing more.
Semaphores are represented by the type "sys_sem_t" which is typedef'd
in the sys_arch.h file. Mailboxes are equivalently represented by the
type "sys_mbox_t". Mutexes are represented by the type "sys_mutex_t".
lwIP does not place any restrictions on how these types are represented
internally.
Since lwIP 1.4.0, semaphore, mutexes and mailbox functions are prototyped in a way that
allows both using pointers or actual OS structures to be used. This way, memory
required for such types can be either allocated in place (globally or on the
stack) or on the heap (allocated internally in the "*_new()" functions).
The following functions must be implemented by the sys_arch:
- void sys_init(void)
Is called to initialize the sys_arch layer.
- err_t sys_sem_new(sys_sem_t *sem, u8_t count)
Creates a new semaphore. The semaphore is allocated to the memory that 'sem'
points to (which can be both a pointer or the actual OS structure).
The "count" argument specifies the initial state of the semaphore (which is
either 0 or 1).
If the semaphore has been created, ERR_OK should be returned. Returning any
other error will provide a hint what went wrong, but except for assertions,
no real error handling is implemented.
- void sys_sem_free(sys_sem_t *sem)
Deallocates a semaphore.
- void sys_sem_signal(sys_sem_t *sem)
Signals a semaphore.
- u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout)
Blocks the thread while waiting for the semaphore to be
signaled. If the "timeout" argument is non-zero, the thread should
only be blocked for the specified time (measured in
milliseconds). If the "timeout" argument is zero, the thread should be
blocked until the semaphore is signalled.
If the timeout argument is non-zero, the return value is the number of
milliseconds spent waiting for the semaphore to be signaled. If the
semaphore wasn't signaled within the specified time, the return value is
SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore
(i.e., it was already signaled), the function may return zero.
Notice that lwIP implements a function with a similar name,
sys_sem_wait(), that uses the sys_arch_sem_wait() function.
- int sys_sem_valid(sys_sem_t *sem)
Returns 1 if the semaphore is valid, 0 if it is not valid.
When using pointers, a simple way is to check the pointer for != NULL.
When directly using OS structures, implementing this may be more complex.
This may also be a define, in which case the function is not prototyped.
- void sys_sem_set_invalid(sys_sem_t *sem)
Invalidate a semaphore so that sys_sem_valid() returns 0.
ATTENTION: This does NOT mean that the semaphore shall be deallocated:
sys_sem_free() is always called before calling this function!
This may also be a define, in which case the function is not prototyped.
- void sys_mutex_new(sys_mutex_t *mutex)
Creates a new mutex. The mutex is allocated to the memory that 'mutex'
points to (which can be both a pointer or the actual OS structure).
If the mutex has been created, ERR_OK should be returned. Returning any
other error will provide a hint what went wrong, but except for assertions,
no real error handling is implemented.
- void sys_mutex_free(sys_mutex_t *mutex)
Deallocates a mutex.
- void sys_mutex_lock(sys_mutex_t *mutex)
Blocks the thread until the mutex can be grabbed.
- void sys_mutex_unlock(sys_mutex_t *mutex)
Releases the mutex previously locked through 'sys_mutex_lock()'.
- void sys_mutex_valid(sys_mutex_t *mutex)
Returns 1 if the mutes is valid, 0 if it is not valid.
When using pointers, a simple way is to check the pointer for != NULL.
When directly using OS structures, implementing this may be more complex.
This may also be a define, in which case the function is not prototyped.
- void sys_mutex_set_invalid(sys_mutex_t *mutex)
Invalidate a mutex so that sys_mutex_valid() returns 0.
ATTENTION: This does NOT mean that the mutex shall be deallocated:
sys_mutex_free() is always called before calling this function!
This may also be a define, in which case the function is not prototyped.
- err_t sys_mbox_new(sys_mbox_t *mbox, int size)
Creates an empty mailbox for maximum "size" elements. Elements stored
in mailboxes are pointers. You have to define macros "_MBOX_SIZE"
in your lwipopts.h, or ignore this parameter in your implementation
and use a default size.
If the mailbox has been created, ERR_OK should be returned. Returning any
other error will provide a hint what went wrong, but except for assertions,
no real error handling is implemented.
- void sys_mbox_free(sys_mbox_t *mbox)
Deallocates a mailbox. If there are messages still present in the
mailbox when the mailbox is deallocated, it is an indication of a
programming error in lwIP and the developer should be notified.
- void sys_mbox_post(sys_mbox_t *mbox, void *msg)
Posts the "msg" to the mailbox. This function have to block until
the "msg" is really posted.
- err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
Try to post the "msg" to the mailbox. Returns ERR_MEM if this one
is full, else, ERR_OK if the "msg" is posted.
- u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout)
Blocks the thread until a message arrives in the mailbox, but does
not block the thread longer than "timeout" milliseconds (similar to
the sys_arch_sem_wait() function). If "timeout" is 0, the thread should
be blocked until a message arrives. The "msg" argument is a result
parameter that is set by the function (i.e., by doing "*msg =
ptr"). The "msg" parameter maybe NULL to indicate that the message
should be dropped.
The return values are the same as for the sys_arch_sem_wait() function:
Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a
timeout.
Note that a function with a similar name, sys_mbox_fetch(), is
implemented by lwIP.
- u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg)
This is similar to sys_arch_mbox_fetch, however if a message is not
present in the mailbox, it immediately returns with the code
SYS_MBOX_EMPTY. On success 0 is returned.
To allow for efficient implementations, this can be defined as a
function-like macro in sys_arch.h instead of a normal function. For
example, a naive implementation could be:
#define sys_arch_mbox_tryfetch(mbox,msg) \
sys_arch_mbox_fetch(mbox,msg,1)
although this would introduce unnecessary delays.
- int sys_mbox_valid(sys_mbox_t *mbox)
Returns 1 if the mailbox is valid, 0 if it is not valid.
When using pointers, a simple way is to check the pointer for != NULL.
When directly using OS structures, implementing this may be more complex.
This may also be a define, in which case the function is not prototyped.
- void sys_mbox_set_invalid(sys_mbox_t *mbox)
Invalidate a mailbox so that sys_mbox_valid() returns 0.
ATTENTION: This does NOT mean that the mailbox shall be deallocated:
sys_mbox_free() is always called before calling this function!
This may also be a define, in which case the function is not prototyped.
If threads are supported by the underlying operating system and if
such functionality is needed in lwIP, the following function will have
to be implemented as well:
- sys_thread_t sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio)
Starts a new thread named "name" with priority "prio" that will begin its
execution in the function "thread()". The "arg" argument will be passed as an
argument to the thread() function. The stack size to used for this thread is
the "stacksize" parameter. The id of the new thread is returned. Both the id
and the priority are system dependent.
When lwIP is used from more than one context (e.g. from multiple threads OR from
main-loop and from interrupts), the SYS_LIGHTWEIGHT_PROT protection SHOULD be enabled!
- sys_prot_t sys_arch_protect(void)
This optional function does a "fast" critical region protection and returns
the previous protection level. This function is only called during very short
critical regions. An embedded system which supports ISR-based drivers might
want to implement this function by disabling interrupts. Task-based systems
might want to implement this by using a mutex or disabling tasking. This
function should support recursive calls from the same task or interrupt. In
other words, sys_arch_protect() could be called while already protected. In
that case the return value indicates that it is already protected.
sys_arch_protect() is only required if your port is supporting an operating
system.
- void sys_arch_unprotect(sys_prot_t pval)
This optional function does a "fast" set of critical region protection to the
value specified by pval. See the documentation for sys_arch_protect() for
more information. This function is only required if your port is supporting
an operating system.
For some configurations, you also need:
- u32_t sys_now(void)
This optional function returns the current time in milliseconds (don't care
for wraparound, this is only used for time diffs).
Not implementing this function means you cannot use some modules (e.g. TCP
timestamps, internal timeouts for NO_SYS==1).
Note:
Be careful with using mem_malloc() in sys_arch. When malloc() refers to
mem_malloc() you can run into a circular function call problem. In mem.c
mem_init() tries to allcate a semaphore using mem_malloc, which of course
can't be performed when sys_arch uses mem_malloc.
-------------------------------------------------------------------------------
Additional files required for the "OS support" emulation layer:
-------------------------------------------------------------------------------
cc.h - Architecture environment, some compiler specific, some
environment specific (probably should move env stuff
to sys_arch.h.)
Typedefs for the types used by lwip -
u8_t, s8_t, u16_t, s16_t, u32_t, s32_t, mem_ptr_t
Compiler hints for packing lwip's structures -
PACK_STRUCT_FIELD(x)
PACK_STRUCT_STRUCT
PACK_STRUCT_BEGIN
PACK_STRUCT_END
Platform specific diagnostic output -
LWIP_PLATFORM_DIAG(x) - non-fatal, print a message.
LWIP_PLATFORM_ASSERT(x) - fatal, print message and abandon execution.
Portability defines for printf formatters:
U16_F, S16_F, X16_F, U32_F, S32_F, X32_F, SZT_F
"lightweight" synchronization mechanisms -
SYS_ARCH_DECL_PROTECT(x) - declare a protection state variable.
SYS_ARCH_PROTECT(x) - enter protection mode.
SYS_ARCH_UNPROTECT(x) - leave protection mode.
If the compiler does not provide memset() this file must include a
definition of it, or include a file which defines it.
This file must either include a system-local <errno.h> which defines
the standard *nix error codes, or it should #define LWIP_PROVIDE_ERRNO
to make lwip/arch.h define the codes which are used throughout.
perf.h - Architecture specific performance measurement.
Measurement calls made throughout lwip, these can be defined to nothing.
PERF_START - start measuring something.
PERF_STOP(x) - stop measuring something, and record the result.
sys_arch.h - Tied to sys_arch.c
Arch dependent types for the following objects:
sys_sem_t, sys_mbox_t, sys_thread_t,
And, optionally:
sys_prot_t
Defines to set vars of sys_mbox_t and sys_sem_t to NULL.
SYS_MBOX_NULL NULL
SYS_SEM_NULL NULL

View file

@ -0,0 +1,36 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#if defined(__IAR_SYSTEMS_ICC__) || defined (__GNUC__)
#pragma pack(1)
#endif

View file

@ -0,0 +1,108 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __CC_H__
#define __CC_H__
#include "cpu.h"
typedef unsigned char u8_t;
typedef signed char s8_t;
typedef unsigned short u16_t;
typedef signed short s16_t;
typedef unsigned int u32_t;
typedef signed long s32_t;
typedef u32_t mem_ptr_t;
typedef int sys_prot_t;
#define U16_F "d"
#define S16_F "d"
#define X16_F "x"
#define U32_F "d"
#define S32_F "d"
#define X32_F "x"
#define SZT_F "uz"
/* define compiler specific symbols */
#if defined (__ICCARM__)
#if !defined (__IARSTDLIB__) && !defined(CONFIG_PLATFORM_8195BHP)&& !defined(CONFIG_PLATFORM_8710C)
#define _STRING
#ifndef memcmp
#define memcmp(dst, src, sz) _memcmp(dst, src, sz)
#endif
#ifndef memset
#define memset(dst, val, sz) _memset(dst, val, sz)
#endif
#ifndef memcpy
#define memcpy(dst, src, sz) _memcpy(dst, src, sz)
#endif
#endif // __IARSTDLIB__
#define PACK_STRUCT_BEGIN
#define PACK_STRUCT_STRUCT
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x
#define PACK_STRUCT_USE_INCLUDES
#elif defined (__CC_ARM)
#define PACK_STRUCT_BEGIN __packed
#define PACK_STRUCT_STRUCT
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x
#elif defined (__GNUC__)
#define PACK_STRUCT_BEGIN
#define PACK_STRUCT_STRUCT __attribute__ ((__packed__))
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x
#define PACK_STRUCT_USE_INCLUDES
#elif defined (__TASKING__)
#define PACK_STRUCT_BEGIN
#define PACK_STRUCT_STRUCT
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x
#endif
#define LWIP_PLATFORM_ASSERT(x) //do { if(!(x)) while(1); } while(0)
#define LWIP_NO_STDINT_H 1
#if (defined (CONFIG_PLATFORM_8710C)||defined(CONFIG_PLATFORM_8721D)) && defined (__GNUC__) && (__GNUC__ >= 6)
#define LWIP_TIMEVAL_PRIVATE 0
#define IN_ADDR_T_DEFINED 1
#endif
#endif /* __CC_H__ */

View file

@ -0,0 +1,39 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __CPU_H__
#define __CPU_H__
#if !defined(BYTE_ORDER)
#define BYTE_ORDER LITTLE_ENDIAN
#endif
#endif /* __CPU_H__ */

View file

@ -0,0 +1,38 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#if defined(__IAR_SYSTEMS_ICC__)
#pragma pack()
#elif defined (__GNUC__)
#pragma pack()
#endif

View file

@ -0,0 +1,44 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __ARCH_INIT_H__
#define __ARCH_INIT_H__
#define TCPIP_INIT_DONE(arg) tcpip_init_done(arg)
void tcpip_init_done(void *);
int wait_for_tcpip_init(void);
#endif /* __ARCH_INIT_H__ */

View file

@ -0,0 +1,38 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LIB_H__
#define __LIB_H__
#include <string.h>
#endif /* __LIB_H__ */

View file

@ -0,0 +1,38 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __PERF_H__
#define __PERF_H__
#define PERF_START /* null definition */
#define PERF_STOP(x) /* null definition */
#endif /* __PERF_H__ */

View file

@ -0,0 +1,67 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __SYS_RTXC_H__
#define __SYS_RTXC_H__
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
#define SYS_MBOX_NULL (xQueueHandle)0
#define SYS_SEM_NULL (xSemaphoreHandle)0
#define SYS_DEFAULT_THREAD_STACK_DEPTH configMINIMAL_STACK_SIZE
typedef xSemaphoreHandle sys_sem_t;
typedef xSemaphoreHandle sys_mutex_t;
typedef xQueueHandle sys_mbox_t;
typedef xTaskHandle sys_thread_t;
typedef struct _sys_arch_state_t
{
// Task creation data.
char cTaskName[configMAX_TASK_NAME_LEN];
unsigned short nStackDepth;
unsigned short nTaskCount;
} sys_arch_state_t;
//extern sys_arch_state_t s_sys_arch_state;
//void sys_set_default_state();
//void sys_set_state(signed char *pTaskName, unsigned short nStackSize);
/* Message queue constants. */
#define archMESG_QUEUE_LENGTH ( 6 )
#endif /* __SYS_RTXC_H__ */

View file

@ -0,0 +1,25 @@
#ifndef __ETHERNETIF_H__
#define __ETHERNETIF_H__
#include "lwip/err.h"
#include "lwip/netif.h"
//----- ------------------------------------------------------------------
// Ethernet Buffer
//----- ------------------------------------------------------------------
struct eth_drv_sg {
unsigned int buf;
unsigned int len;
};
#define MAX_ETH_DRV_SG 32
#define MAX_ETH_MSG 1540
void ethernetif_recv(struct netif *netif, int total_len);
err_t ethernetif_init(struct netif *netif);
err_t ethernetif_mii_init(struct netif *netif);
void lwip_PRE_SLEEP_PROCESSING(void);
void lwip_POST_SLEEP_PROCESSING(void);
#endif

View file

@ -0,0 +1,66 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __SYS_RTXC_H__
#define __SYS_RTXC_H__
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
#define SYS_MBOX_NULL (xQueueHandle)0
#define SYS_SEM_NULL (xSemaphoreHandle)0
#define SYS_DEFAULT_THREAD_STACK_DEPTH configMINIMAL_STACK_SIZE
typedef xSemaphoreHandle sys_sem_t;
typedef xQueueHandle sys_mbox_t;
typedef xTaskHandle sys_thread_t;
typedef struct _sys_arch_state_t
{
// Task creation data.
char cTaskName[configMAX_TASK_NAME_LEN];
unsigned short nStackDepth;
unsigned short nTaskCount;
} sys_arch_state_t;
//extern sys_arch_state_t s_sys_arch_state;
//void sys_set_default_state();
//void sys_set_state(signed char *pTaskName, unsigned short nStackSize);
/* Message queue constants. */
#define archMESG_QUEUE_LENGTH ( 6 )
#endif /* __SYS_RTXC_H__ */

View file

@ -0,0 +1,15 @@
api/ - The code for the high-level wrapper API. Not needed if
you use the lowel-level call-back/raw API.
apps/ - Higher layer applications that are specifically programmed
with the lwIP low-level raw API.
core/ - The core of the TPC/IP stack; protocol implementations,
memory and buffer management, and the low-level raw API.
include/ - lwIP include files.
netif/ - Generic network interface device drivers are kept here.
For more information on the various subdirectories, check the FILES
file in each directory.

View file

@ -0,0 +1,181 @@
#
# Copyright (c) 2001, 2002 Swedish Institute of Computer Science.
# 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. The name of the author may not be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 lwIP TCP/IP stack.
#
# Author: Adam Dunkels <adam@sics.se>
#
# COREFILES, CORE4FILES: The minimum set of files needed for lwIP.
COREFILES=$(LWIPDIR)/core/init.c \
$(LWIPDIR)/core/def.c \
$(LWIPDIR)/core/dns.c \
$(LWIPDIR)/core/inet_chksum.c \
$(LWIPDIR)/core/ip.c \
$(LWIPDIR)/core/mem.c \
$(LWIPDIR)/core/memp.c \
$(LWIPDIR)/core/netif.c \
$(LWIPDIR)/core/pbuf.c \
$(LWIPDIR)/core/raw.c \
$(LWIPDIR)/core/stats.c \
$(LWIPDIR)/core/sys.c \
$(LWIPDIR)/core/tcp.c \
$(LWIPDIR)/core/tcp_in.c \
$(LWIPDIR)/core/tcp_out.c \
$(LWIPDIR)/core/timeouts.c \
$(LWIPDIR)/core/udp.c
CORE4FILES=$(LWIPDIR)/core/ipv4/autoip.c \
$(LWIPDIR)/core/ipv4/dhcp.c \
$(LWIPDIR)/core/ipv4/etharp.c \
$(LWIPDIR)/core/ipv4/icmp.c \
$(LWIPDIR)/core/ipv4/igmp.c \
$(LWIPDIR)/core/ipv4/ip4_frag.c \
$(LWIPDIR)/core/ipv4/ip4.c \
$(LWIPDIR)/core/ipv4/ip4_addr.c
CORE6FILES=$(LWIPDIR)/core/ipv6/dhcp6.c \
$(LWIPDIR)/core/ipv6/ethip6.c \
$(LWIPDIR)/core/ipv6/icmp6.c \
$(LWIPDIR)/core/ipv6/inet6.c \
$(LWIPDIR)/core/ipv6/ip6.c \
$(LWIPDIR)/core/ipv6/ip6_addr.c \
$(LWIPDIR)/core/ipv6/ip6_frag.c \
$(LWIPDIR)/core/ipv6/mld6.c \
$(LWIPDIR)/core/ipv6/nd6.c
# APIFILES: The files which implement the sequential and socket APIs.
APIFILES=$(LWIPDIR)/api/api_lib.c \
$(LWIPDIR)/api/api_msg.c \
$(LWIPDIR)/api/err.c \
$(LWIPDIR)/api/netbuf.c \
$(LWIPDIR)/api/netdb.c \
$(LWIPDIR)/api/netifapi.c \
$(LWIPDIR)/api/sockets.c \
$(LWIPDIR)/api/tcpip.c
# NETIFFILES: Files implementing various generic network interface functions
NETIFFILES=$(LWIPDIR)/netif/ethernet.c \
$(LWIPDIR)/netif/slipif.c
# SIXLOWPAN: 6LoWPAN
SIXLOWPAN=$(LWIPDIR)/netif/lowpan6.c \
# PPPFILES: PPP
PPPFILES=$(LWIPDIR)/netif/ppp/auth.c \
$(LWIPDIR)/netif/ppp/ccp.c \
$(LWIPDIR)/netif/ppp/chap-md5.c \
$(LWIPDIR)/netif/ppp/chap_ms.c \
$(LWIPDIR)/netif/ppp/chap-new.c \
$(LWIPDIR)/netif/ppp/demand.c \
$(LWIPDIR)/netif/ppp/eap.c \
$(LWIPDIR)/netif/ppp/ecp.c \
$(LWIPDIR)/netif/ppp/eui64.c \
$(LWIPDIR)/netif/ppp/fsm.c \
$(LWIPDIR)/netif/ppp/ipcp.c \
$(LWIPDIR)/netif/ppp/ipv6cp.c \
$(LWIPDIR)/netif/ppp/lcp.c \
$(LWIPDIR)/netif/ppp/magic.c \
$(LWIPDIR)/netif/ppp/mppe.c \
$(LWIPDIR)/netif/ppp/multilink.c \
$(LWIPDIR)/netif/ppp/ppp.c \
$(LWIPDIR)/netif/ppp/pppapi.c \
$(LWIPDIR)/netif/ppp/pppcrypt.c \
$(LWIPDIR)/netif/ppp/pppoe.c \
$(LWIPDIR)/netif/ppp/pppol2tp.c \
$(LWIPDIR)/netif/ppp/pppos.c \
$(LWIPDIR)/netif/ppp/upap.c \
$(LWIPDIR)/netif/ppp/utils.c \
$(LWIPDIR)/netif/ppp/vj.c \
$(LWIPDIR)/netif/ppp/polarssl/arc4.c \
$(LWIPDIR)/netif/ppp/polarssl/des.c \
$(LWIPDIR)/netif/ppp/polarssl/md4.c \
$(LWIPDIR)/netif/ppp/polarssl/md5.c \
$(LWIPDIR)/netif/ppp/polarssl/sha1.c
# LWIPNOAPPSFILES: All LWIP files without apps
LWIPNOAPPSFILES=$(COREFILES) \
$(CORE4FILES) \
$(CORE6FILES) \
$(APIFILES) \
$(NETIFFILES) \
$(PPPFILES) \
$(SIXLOWPAN)
# SNMPFILES: SNMPv2c agent
SNMPFILES=$(LWIPDIR)/apps/snmp/snmp_asn1.c \
$(LWIPDIR)/apps/snmp/snmp_core.c \
$(LWIPDIR)/apps/snmp/snmp_mib2.c \
$(LWIPDIR)/apps/snmp/snmp_mib2_icmp.c \
$(LWIPDIR)/apps/snmp/snmp_mib2_interfaces.c \
$(LWIPDIR)/apps/snmp/snmp_mib2_ip.c \
$(LWIPDIR)/apps/snmp/snmp_mib2_snmp.c \
$(LWIPDIR)/apps/snmp/snmp_mib2_system.c \
$(LWIPDIR)/apps/snmp/snmp_mib2_tcp.c \
$(LWIPDIR)/apps/snmp/snmp_mib2_udp.c \
$(LWIPDIR)/apps/snmp/snmp_msg.c \
$(LWIPDIR)/apps/snmp/snmpv3.c \
$(LWIPDIR)/apps/snmp/snmp_netconn.c \
$(LWIPDIR)/apps/snmp/snmp_pbuf_stream.c \
$(LWIPDIR)/apps/snmp/snmp_raw.c \
$(LWIPDIR)/apps/snmp/snmp_scalar.c \
$(LWIPDIR)/apps/snmp/snmp_table.c \
$(LWIPDIR)/apps/snmp/snmp_threadsync.c \
$(LWIPDIR)/apps/snmp/snmp_traps.c \
$(LWIPDIR)/apps/snmp/snmpv3_mbedtls.c \
$(LWIPDIR)/apps/snmp/snmpv3_dummy.c
# HTTPDFILES: HTTP server
HTTPDFILES=$(LWIPDIR)/apps/httpd/fs.c \
$(LWIPDIR)/apps/httpd/httpd.c
# LWIPERFFILES: IPERF server
LWIPERFFILES=$(LWIPDIR)/apps/lwiperf/lwiperf.c
# SNTPFILES: SNTP client
SNTPFILES=$(LWIPDIR)/apps/sntp/sntp.c
# MDNSFILES: MDNS responder
MDNSFILES=$(LWIPDIR)/apps/mdns/mdns.c
# NETBIOSNSFILES: NetBIOS name server
NETBIOSNSFILES=$(LWIPDIR)/apps/netbiosns/netbiosns.c
# TFTPFILES: TFTP server files
TFTPFILES=$(LWIPDIR)/apps/tftp/tftp_server.c
# MQTTFILES: MQTT client files
MQTTFILES=$(LWIPDIR)/apps/mqtt/mqtt.c
# LWIPAPPFILES: All LWIP APPs
LWIPAPPFILES=$(SNMPFILES) \
$(HTTPDFILES) \
$(LWIPERFFILES) \
$(SNTPFILES) \
$(MDNSFILES) \
$(NETBIOSNSFILES) \
$(TFTPFILES) \
$(MQTTFILES)

View file

@ -0,0 +1,21 @@
<html>
<head><title>lwIP - A Lightweight TCP/IP Stack</title></head>
<body bgcolor="white" text="black">
<table width="100%">
<tr valign="top"><td width="80">
<a href="http://www.sics.se/"><img src="/img/sics.gif"
border="0" alt="SICS logo" title="SICS logo"></a>
</td><td width="500">
<h1>lwIP - A Lightweight TCP/IP Stack</h1>
<h2>404 - Page not found</h2>
<p>
Sorry, the page you are requesting was not found on this
server.
</p>
</td><td>
&nbsp;
</td></tr>
</table>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 724 B

View file

@ -0,0 +1,47 @@
<html>
<head><title>lwIP - A Lightweight TCP/IP Stack</title></head>
<body bgcolor="white" text="black">
<table width="100%">
<tr valign="top"><td width="80">
<a href="http://www.sics.se/"><img src="/img/sics.gif"
border="0" alt="SICS logo" title="SICS logo"></a>
</td><td width="500">
<h1>lwIP - A Lightweight TCP/IP Stack</h1>
<p>
The web page you are watching was served by a simple web
server running on top of the lightweight TCP/IP stack <a
href="http://www.sics.se/~adam/lwip/">lwIP</a>.
</p>
<p>
lwIP is an open source implementation of the TCP/IP
protocol suite that was originally written by <a
href="http://www.sics.se/~adam/lwip/">Adam Dunkels
of the Swedish Institute of Computer Science</a> but now is
being actively developed by a team of developers
distributed world-wide. Since it's release, lwIP has
spurred a lot of interest and has been ported to several
platforms and operating systems. lwIP can be used either
with or without an underlying OS.
</p>
<p>
The focus of the lwIP TCP/IP implementation is to reduce
the RAM usage while still having a full scale TCP. This
makes lwIP suitable for use in embedded systems with tens
of kilobytes of free RAM and room for around 40 kilobytes
of code ROM.
</p>
<p>
More information about lwIP can be found at the lwIP
homepage at <a
href="http://savannah.nongnu.org/projects/lwip/">http://savannah.nongnu.org/projects/lwip/</a>
or at the lwIP wiki at <a
href="http://lwip.wikia.com/">http://lwip.wikia.com/</a>.
</p>
</td><td>
&nbsp;
</td></tr>
</table>
</body>
</html>

View file

@ -0,0 +1,50 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef LWIP_FSDATA_H
#define LWIP_FSDATA_H
#include "lwip/apps/httpd_opts.h"
#include "lwip/apps/fs.h"
struct fsdata_file {
const struct fsdata_file *next;
const unsigned char *name;
const unsigned char *data;
int len;
u8_t flags;
#if HTTPD_PRECALCULATED_CHECKSUM
u16_t chksum_count;
const struct fsdata_chksum *chksum;
#endif /* HTTPD_PRECALCULATED_CHECKSUM */
};
#endif /* LWIP_FSDATA_H */

View file

@ -0,0 +1,114 @@
#ifndef LWIP_HTTPD_STRUCTS_H
#define LWIP_HTTPD_STRUCTS_H
#include "lwip/apps/httpd.h"
#if LWIP_HTTPD_DYNAMIC_HEADERS
/** This struct is used for a list of HTTP header strings for various
* filename extensions. */
typedef struct
{
const char *extension;
const char *content_type;
} tHTTPHeader;
/** A list of strings used in HTTP headers (see RFC 1945 HTTP/1.0 and
* RFC 2616 HTTP/1.1 for header field definitions) */
static const char * const g_psHTTPHeaderStrings[] =
{
"HTTP/1.0 200 OK\r\n",
"HTTP/1.0 404 File not found\r\n",
"HTTP/1.0 400 Bad Request\r\n",
"HTTP/1.0 501 Not Implemented\r\n",
"HTTP/1.1 200 OK\r\n",
"HTTP/1.1 404 File not found\r\n",
"HTTP/1.1 400 Bad Request\r\n",
"HTTP/1.1 501 Not Implemented\r\n",
"Content-Length: ",
"Connection: Close\r\n",
"Connection: keep-alive\r\n",
"Connection: keep-alive\r\nContent-Length: ",
"Server: "HTTPD_SERVER_AGENT"\r\n",
"\r\n<html><body><h2>404: The requested file cannot be found.</h2></body></html>\r\n"
#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
,"Connection: keep-alive\r\nContent-Length: 77\r\n\r\n<html><body><h2>404: The requested file cannot be found.</h2></body></html>\r\n"
#endif
};
/* Indexes into the g_psHTTPHeaderStrings array */
#define HTTP_HDR_OK 0 /* 200 OK */
#define HTTP_HDR_NOT_FOUND 1 /* 404 File not found */
#define HTTP_HDR_BAD_REQUEST 2 /* 400 Bad request */
#define HTTP_HDR_NOT_IMPL 3 /* 501 Not Implemented */
#define HTTP_HDR_OK_11 4 /* 200 OK */
#define HTTP_HDR_NOT_FOUND_11 5 /* 404 File not found */
#define HTTP_HDR_BAD_REQUEST_11 6 /* 400 Bad request */
#define HTTP_HDR_NOT_IMPL_11 7 /* 501 Not Implemented */
#define HTTP_HDR_CONTENT_LENGTH 8 /* Content-Length: (HTTP 1.0)*/
#define HTTP_HDR_CONN_CLOSE 9 /* Connection: Close (HTTP 1.1) */
#define HTTP_HDR_CONN_KEEPALIVE 10 /* Connection: keep-alive (HTTP 1.1) */
#define HTTP_HDR_KEEPALIVE_LEN 11 /* Connection: keep-alive + Content-Length: (HTTP 1.1)*/
#define HTTP_HDR_SERVER 12 /* Server: HTTPD_SERVER_AGENT */
#define DEFAULT_404_HTML 13 /* default 404 body */
#if LWIP_HTTPD_SUPPORT_11_KEEPALIVE
#define DEFAULT_404_HTML_PERSISTENT 14 /* default 404 body, but including Connection: keep-alive */
#endif
#define HTTP_HDR_HTML "Content-type: text/html\r\n\r\n"
#define HTTP_HDR_SSI "Content-type: text/html\r\nExpires: Fri, 10 Apr 2008 14:00:00 GMT\r\nPragma: no-cache\r\n\r\n"
#define HTTP_HDR_GIF "Content-type: image/gif\r\n\r\n"
#define HTTP_HDR_PNG "Content-type: image/png\r\n\r\n"
#define HTTP_HDR_JPG "Content-type: image/jpeg\r\n\r\n"
#define HTTP_HDR_BMP "Content-type: image/bmp\r\n\r\n"
#define HTTP_HDR_ICO "Content-type: image/x-icon\r\n\r\n"
#define HTTP_HDR_APP "Content-type: application/octet-stream\r\n\r\n"
#define HTTP_HDR_JS "Content-type: application/javascript\r\n\r\n"
#define HTTP_HDR_RA "Content-type: application/javascript\r\n\r\n"
#define HTTP_HDR_CSS "Content-type: text/css\r\n\r\n"
#define HTTP_HDR_SWF "Content-type: application/x-shockwave-flash\r\n\r\n"
#define HTTP_HDR_XML "Content-type: text/xml\r\n\r\n"
#define HTTP_HDR_PDF "Content-type: application/pdf\r\n\r\n"
#define HTTP_HDR_JSON "Content-type: application/json\r\n\r\n"
#define HTTP_HDR_DEFAULT_TYPE "Content-type: text/plain\r\n\r\n"
/** A list of extension-to-HTTP header strings (see outdated RFC 1700 MEDIA TYPES
* and http://www.iana.org/assignments/media-types for registered content types
* and subtypes) */
static const tHTTPHeader g_psHTTPHeaders[] =
{
{ "html", HTTP_HDR_HTML},
{ "htm", HTTP_HDR_HTML},
{ "shtml",HTTP_HDR_SSI},
{ "shtm", HTTP_HDR_SSI},
{ "ssi", HTTP_HDR_SSI},
{ "gif", HTTP_HDR_GIF},
{ "png", HTTP_HDR_PNG},
{ "jpg", HTTP_HDR_JPG},
{ "bmp", HTTP_HDR_BMP},
{ "ico", HTTP_HDR_ICO},
{ "class",HTTP_HDR_APP},
{ "cls", HTTP_HDR_APP},
{ "js", HTTP_HDR_JS},
{ "ram", HTTP_HDR_RA},
{ "css", HTTP_HDR_CSS},
{ "swf", HTTP_HDR_SWF},
{ "xml", HTTP_HDR_XML},
{ "xsl", HTTP_HDR_XML},
{ "pdf", HTTP_HDR_PDF},
{ "json", HTTP_HDR_JSON}
};
#define NUM_HTTP_HEADERS (sizeof(g_psHTTPHeaders) / sizeof(tHTTPHeader))
#endif /* LWIP_HTTPD_DYNAMIC_HEADERS */
#if LWIP_HTTPD_SSI
static const char * const g_pcSSIExtensions[] = {
".shtml", ".shtm", ".ssi", ".xml"
};
#define NUM_SHTML_EXTENSIONS (sizeof(g_pcSSIExtensions) / sizeof(const char *))
#endif /* LWIP_HTTPD_SSI */
#endif /* LWIP_HTTPD_STRUCTS_H */

View file

@ -0,0 +1,97 @@
#!/usr/bin/perl
open(OUTPUT, "> fsdata.c");
chdir("fs");
open(FILES, "find . -type f |");
while($file = <FILES>) {
# Do not include files in CVS directories nor backup files.
if($file =~ /(CVS|~)/) {
next;
}
chop($file);
open(HEADER, "> /tmp/header") || die $!;
if($file =~ /404/) {
print(HEADER "HTTP/1.0 404 File not found\r\n");
} else {
print(HEADER "HTTP/1.0 200 OK\r\n");
}
print(HEADER "Server: lwIP/pre-0.6 (http://www.sics.se/~adam/lwip/)\r\n");
if($file =~ /\.html$/) {
print(HEADER "Content-type: text/html\r\n");
} elsif($file =~ /\.gif$/) {
print(HEADER "Content-type: image/gif\r\n");
} elsif($file =~ /\.png$/) {
print(HEADER "Content-type: image/png\r\n");
} elsif($file =~ /\.jpg$/) {
print(HEADER "Content-type: image/jpeg\r\n");
} elsif($file =~ /\.class$/) {
print(HEADER "Content-type: application/octet-stream\r\n");
} elsif($file =~ /\.ram$/) {
print(HEADER "Content-type: audio/x-pn-realaudio\r\n");
} else {
print(HEADER "Content-type: text/plain\r\n");
}
print(HEADER "\r\n");
close(HEADER);
unless($file =~ /\.plain$/ || $file =~ /cgi/) {
system("cat /tmp/header $file > /tmp/file");
} else {
system("cp $file /tmp/file");
}
open(FILE, "/tmp/file");
unlink("/tmp/file");
unlink("/tmp/header");
$file =~ s/\.//;
$fvar = $file;
$fvar =~ s-/-_-g;
$fvar =~ s-\.-_-g;
print(OUTPUT "static const unsigned char data".$fvar."[] = {\n");
print(OUTPUT "\t/* $file */\n\t");
for($j = 0; $j < length($file); $j++) {
printf(OUTPUT "%#02x, ", unpack("C", substr($file, $j, 1)));
}
printf(OUTPUT "0,\n");
$i = 0;
while(read(FILE, $data, 1)) {
if($i == 0) {
print(OUTPUT "\t");
}
printf(OUTPUT "%#02x, ", unpack("C", $data));
$i++;
if($i == 10) {
print(OUTPUT "\n");
$i = 0;
}
}
print(OUTPUT "};\n\n");
close(FILE);
push(@fvars, $fvar);
push(@files, $file);
}
for($i = 0; $i < @fvars; $i++) {
$file = $files[$i];
$fvar = $fvars[$i];
if($i == 0) {
$prevfile = "NULL";
} else {
$prevfile = "file" . $fvars[$i - 1];
}
print(OUTPUT "const struct fsdata_file file".$fvar."[] = {{$prevfile, data$fvar, ");
print(OUTPUT "data$fvar + ". (length($file) + 1) .", ");
print(OUTPUT "sizeof(data$fvar) - ". (length($file) + 1) ."}};\n\n");
}
print(OUTPUT "#define FS_ROOT file$fvars[$i - 1]\n\n");
print(OUTPUT "#define FS_NUMFILES $i\n");

View file

@ -0,0 +1,13 @@
This directory contains a script ('makefsdata') to create C code suitable for
httpd for given html pages (or other files) in a directory.
There is also a plain C console application doing the same and extended a bit.
Usage: htmlgen [targetdir] [-s] [-i]s
targetdir: relative or absolute path to files to convert
switch -s: toggle processing of subdirectories (default is on)
switch -e: exclude HTTP header from file (header is created at runtime, default is on)
switch -11: include HTTP 1.1 header (1.0 is default)
if targetdir not specified, makefsdata will attempt to
process files in subdirectory 'fs'.

Some files were not shown because too many files have changed in this diff Show more