23 #include <sys/select.h>
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
39 #define COAP_RESOURCE_CHECK_TIME 2
41 #define RD_ROOT_STR ((unsigned char *)"rd")
42 #define RD_ROOT_SIZE 2
45 #define min(a,b) ((a) < (b) ? (a) : (b))
65 memset(rd, 0,
sizeof(
rd_t));
104 if (rd && rd->
data.
s)
137 debug(
"hnd_put_rd: cannot allocate storage for new rd\n");
167 debug(
"cannot create response for message %d\n", request->
hdr->
id);
175 debug(
"hnd_get_rd: cannot send response for message %d\n",
204 unsigned char buf[3];
217 unsigned char *data,
size_t data_len,
str *result) {
220 memset(result, 0,
sizeof(
str));
225 while (search_len <= data_len) {
228 if (memcmp(search, data, search_len) == 0) {
230 data_len -= search_len;
233 if (!data_len || *data ==
'=' || *data ==
'&') {
234 while (data_len && *data !=
'=') {
238 if (data_len > 1 && result) {
242 while (--data_len && *data !=
'&') {
252 while (--data_len && *data++ !=
'&')
271 switch(peer->addr.sa.sa_family) {
278 n += snprintf(buf + n,
BUFSIZE - n,
279 "[%02x%02x:%02x%02x:%02x%02x:%02x%02x" \
280 ":%02x%02x:%02x%02x:%02x%02x:%02x%02x]",
281 peer->addr.sin6.sin6_addr.s6_addr[0],
282 peer->addr.sin6.sin6_addr.s6_addr[1],
283 peer->addr.sin6.sin6_addr.s6_addr[2],
284 peer->addr.sin6.sin6_addr.s6_addr[3],
285 peer->addr.sin6.sin6_addr.s6_addr[4],
286 peer->addr.sin6.sin6_addr.s6_addr[5],
287 peer->addr.sin6.sin6_addr.s6_addr[6],
288 peer->addr.sin6.sin6_addr.s6_addr[7],
289 peer->addr.sin6.sin6_addr.s6_addr[8],
290 peer->addr.sin6.sin6_addr.s6_addr[9],
291 peer->addr.sin6.sin6_addr.s6_addr[10],
292 peer->addr.sin6.sin6_addr.s6_addr[11],
293 peer->addr.sin6.sin6_addr.s6_addr[12],
294 peer->addr.sin6.sin6_addr.s6_addr[13],
295 peer->addr.sin6.sin6_addr.s6_addr[14],
296 peer->addr.sin6.sin6_addr.s6_addr[15]);
300 snprintf(buf + n,
BUFSIZE - n,
":%d", peer->addr.sin6.sin6_port);
325 debug(
"hnd_get_rd: cannot allocate storage for rd\n");
332 debug(
"hnd_get_rd: cannot allocate storage for rd->data\n");
358 str h = {0, NULL}, ins = {0, NULL}, rt = {0, NULL}, lt = {0, NULL};
369 loc[loc_size++] =
'/';
388 if (ins.length && loc_size > 1) {
389 loc[loc_size++] =
'-';
390 memcpy((
char *)(loc + loc_size),
391 ins.s,
min(ins.length,
LOCSIZE - loc_size - 1));
392 loc_size +=
min(ins.length,
LOCSIZE - loc_size - 1);
397 snprintf((
char *)(loc + loc_size),
LOCSIZE - loc_size - 1,
398 "%x", request->
hdr->
id);
402 loc[loc_size++] =
'-';
403 memcpy((
char *)(loc + loc_size),
404 ins.s,
min(ins.length,
LOCSIZE - loc_size - 1));
405 loc_size +=
min(ins.length,
LOCSIZE - loc_size - 1);
411 snprintf((
char *)(loc + loc_size),
LOCSIZE - loc_size - 1,
427 buf = (
unsigned char *)
coap_malloc(ins.length + 2);
431 memcpy(buf + 1, ins.s, ins.length);
432 buf[ins.length + 1] =
'"';
442 memcpy(buf + 1, rt.s, rt.length);
443 buf[rt.length + 1] =
'"';
470 unsigned char *b = _b;
471 size_t buflen =
sizeof(_b);
491 coap_add_attr(r, (
unsigned char *)
"ct", 2, (
unsigned char *)
"40", 2, 0);
492 coap_add_attr(r, (
unsigned char *)
"rt", 2, (
unsigned char *)
"\"core-rd\"", 9, 0);
493 coap_add_attr(r, (
unsigned char *)
"ins", 2, (
unsigned char *)
"\"default\"", 9, 0);
500 usage(
const char *program,
const char *version) {
503 p = strrchr( program,
'/' );
507 fprintf( stderr,
"%s v%s -- CoRE Resource Directory implementation\n"
508 "(c) 2011-2012 Olaf Bergmann <bergmann@tzi.org>\n\n"
509 "usage: %s [-A address] [-p port]\n\n"
510 "\t-A address\tinterface address to bind to\n"
511 "\t-p port\t\tlisten on specified port\n"
512 "\t-v num\t\tverbosity level (default: 3)\n",
513 program, version, program );
520 struct addrinfo hints;
521 struct addrinfo *result, *rp;
523 memset(&hints, 0,
sizeof(
struct addrinfo));
524 hints.ai_family = AF_UNSPEC;
525 hints.ai_socktype = SOCK_DGRAM;
526 hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
528 s = getaddrinfo(node, port, &hints, &result);
530 fprintf(stderr,
"getaddrinfo: %s\n", gai_strerror(s));
535 for (rp = result; rp != NULL; rp = rp->ai_next) {
538 if (rp->ai_addrlen <=
sizeof(addr.addr)) {
540 addr.size = rp->ai_addrlen;
541 memcpy(&addr.addr, rp->ai_addr, rp->ai_addrlen);
551 fprintf(stderr,
"no context available for interface '%s'\n", node);
554 freeaddrinfo(result);
560 struct ipv6_mreq mreq;
561 struct addrinfo *reslocal = NULL, *resmulti = NULL, hints, *ainfo;
565 memset(&hints, 0,
sizeof(hints));
566 hints.ai_family = AF_INET6;
567 hints.ai_socktype = SOCK_DGRAM;
569 result = getaddrinfo(
"::", NULL, &hints, &reslocal);
571 perror(
"join: cannot resolve link-local interface");
576 for (ainfo = reslocal; ainfo != NULL; ainfo = ainfo->ai_next) {
577 if ( ainfo->ai_family == AF_INET6 ) {
578 mreq.ipv6mr_interface =
579 ((
struct sockaddr_in6 *)ainfo->ai_addr)->sin6_scope_id;
584 memset(&hints, 0,
sizeof(hints));
585 hints.ai_family = AF_INET6;
586 hints.ai_socktype = SOCK_DGRAM;
589 result = getaddrinfo(group_name, NULL, &hints, &resmulti);
592 perror(
"join: cannot resolve multicast address");
596 for (ainfo = resmulti; ainfo != NULL; ainfo = ainfo->ai_next) {
597 if ( ainfo->ai_family == AF_INET6 ) {
598 mreq.ipv6mr_multiaddr =
599 ((
struct sockaddr_in6 *)ainfo->ai_addr)->sin6_addr;
604 result = setsockopt( ctx->sockfd, IPPROTO_IPV6, IPV6_JOIN_GROUP,
605 (
char *)&mreq,
sizeof(mreq) );
607 perror(
"join: setsockopt");
610 freeaddrinfo(resmulti);
611 freeaddrinfo(reslocal);
620 struct timeval tv, *timeout;
624 char addr_str[NI_MAXHOST] =
"::";
625 char port_str[NI_MAXSERV] =
"5683";
630 while ((opt = getopt(argc, argv,
"A:g:p:v:")) != -1) {
633 strncpy(addr_str, optarg, NI_MAXHOST-1);
634 addr_str[NI_MAXHOST - 1] =
'\0';
640 strncpy(port_str, optarg, NI_MAXSERV-1);
641 port_str[NI_MAXSERV - 1] =
'\0';
644 log_level = strtol(optarg, NULL, 10);
667 FD_SET( ctx->sockfd, &readfds );
672 while ( nextpdu && nextpdu->
t <= now ) {
679 tv.tv_usec = ((nextpdu->
t - now) % COAP_TICKS_PER_SECOND) * 1000000 / COAP_TICKS_PER_SECOND;
680 tv.tv_sec = (nextpdu->
t - now) / COAP_TICKS_PER_SECOND;
687 result = select( FD_SETSIZE, &readfds, 0, 0, timeout );
692 }
else if ( result > 0 ) {
693 if ( FD_ISSET( ctx->sockfd, &readfds ) ) {
void hnd_get_resource(coap_context_t *ctx, struct coap_resource_t *resource, coap_address_t *peer, coap_pdu_t *request, str *token, coap_pdu_t *response)
#define COAP_REQUEST_POST
unsigned char coap_key_t[4]
#define COAP_RESPONSE_CODE(N)
void coap_dispatch(coap_context_t *context)
Dispatches the PDUs from the receive queue in given context.
int main(int argc, char **argv)
void hnd_post_rd(coap_context_t *ctx, struct coap_resource_t *resource, coap_address_t *peer, coap_pdu_t *request, str *token, coap_pdu_t *response)
coap_context_t * get_context(const char *node, const char *port)
coap_key_t key
the actual key bytes for this resource
int coap_delete_resource(coap_context_t *context, coap_key_t key)
Deletes a resource identified by key.
int coap_add_token(coap_pdu_t *pdu, size_t len, const unsigned char *data)
Adds token of length len to pdu.
coap_opt_t * coap_check_option(coap_pdu_t *pdu, unsigned char type, coap_opt_iterator_t *oi)
Retrieves the first option of type type from pdu.
size_t etag_len
actual length of etag
int coap_get_data(coap_pdu_t *pdu, size_t *len, unsigned char **data)
Retrieves the length and data pointer of specified PDU.
#define COAP_OPTION_MAXAGE
#define coap_malloc(size)
rd_t * make_rd(coap_address_t *peer, coap_pdu_t *pdu)
#define COAP_OPTION_CONTENT_TYPE
str data
points to the resource description
coap_context_t * coap_new_context(const coap_address_t *listen_addr)
Creates a new coap_context_t object that will hold the CoAP stack status.
coap_queue_t * coap_peek_next(coap_context_t *context)
Returns the next pdu to send without removing from sendqeue.
void hnd_delete_resource(coap_context_t *ctx, struct coap_resource_t *resource, coap_address_t *peer, coap_pdu_t *request, str *token, coap_pdu_t *response)
coap_tick_t t
when to send PDU for the next time
#define HASH_DELETE(hh, head, delptr)
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)
Registers a new attribute with the given resource.
void coap_ticks(coap_tick_t *)
Returns the current value of an internal tick counter.
Header structure for CoAP PDUs.
coap_key_t key
the actual key bytes for this resource
#define COAP_ATTR_FLAGS_RELEASE_VALUE
void usage(const char *program, const char *version)
unsigned int coap_encode_var_bytes(unsigned char *buf, unsigned int val)
Encodes multiple-length byte sequences.
static void coap_register_handler(coap_resource_t *resource, unsigned char method, coap_method_handler_t handler)
Registers the specified handler as message handler for the request type method.
void coap_add_resource(coap_context_t *context, coap_resource_t *resource)
Registers the given resource for context.
int coap_split_path(const unsigned char *s, size_t length, unsigned char *buf, size_t *buflen)
Splits the given URI path into segments.
Iterator to run through PDU options.
#define COAP_MEDIATYPE_APPLICATION_LINK_FORMAT
size_t coap_add_option(coap_pdu_t *pdu, unsigned short type, unsigned int len, const unsigned char *data)
de-duplicate code with coap_add_option_later
generic resource handling
void add_source_address(struct coap_resource_t *resource, coap_address_t *peer)
void hnd_put_resource(coap_context_t *ctx, struct coap_resource_t *resource, coap_address_t *peer, coap_pdu_t *request, str *token, coap_pdu_t *response)
#define COAP_OPT_SIZE(opt)
int coap_add_data(coap_pdu_t *pdu, unsigned int len, const unsigned char *data)
Adds given data to the pdu that is passed as first parameter.
#define COAP_REQUEST_DELETE
coap_tid_t coap_send(coap_context_t *context, const coap_address_t *dst, coap_pdu_t *pdu)
Sends a non-confirmed CoAP message to given destination.
#define COAP_DEFAULT_PORT
int join(coap_context_t *ctx, char *group_name)
int parse_param(unsigned char *search, size_t search_len, unsigned char *data, size_t data_len, str *result)
#define COAP_OPTION_LOCATION_PATH
void coap_delete_pdu(coap_pdu_t *pdu)
static void coap_address_init(coap_address_t *addr)
Resets the given coap_address_t object addr to its default values.
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 size (must be large enough to hold the basic CoAP message header (coa...
int coap_hash_path(const unsigned char *path, size_t len, coap_key_t key)
Calculates a hash over the given path and stores the result in key.
void coap_free_context(coap_context_t *context)
#define COAP_OPT_LENGTH(opt)
unsigned int token_length
coap_resource_t * coap_resource_init(const unsigned char *uri, size_t len, int flags)
Creates a new resource object and initializes the link field to the string of length len...
void hnd_get_rd(coap_context_t *ctx, struct coap_resource_t *resource, coap_address_t *peer, coap_pdu_t *request, str *token, coap_pdu_t *response)
#define HASH_ADD(hh, head, fieldname, keylen_in, add)
void coap_set_log_level(coap_log_t level)
Sets the log level to the specified value.
#define COAP_OPTION_URI_QUERY
unsigned char coap_opt_t
Use byte-oriented access methods here because sliding a complex struct coap_opt_t over the data buffe...
unsigned char etag[8]
ETag for current description.
int coap_read(coap_context_t *ctx)
Reads data from the network and tries to parse as CoAP PDU.
void handle_sigint(int signum)
#define HASH_FIND(hh, head, keyptr, keylen, out)
UT_hash_handle hh
hash handle (for internal use only)
#define COAP_RESOURCE_FLAGS_RELEASE_URI
coap_tid_t coap_retransmit(coap_context_t *context, coap_queue_t *node)
Handles retransmissions of confirmable messages.
coap_queue_t * coap_pop_next(coap_context_t *context)
Returns the next pdu to send and removes it from the sendqeue.
void init_resources(coap_context_t *ctx)
#define COAP_OPT_VALUE(opt)
The CoAP stack's global state is stored in a coap_context_t object.
#define COAP_RESOURCE_CHECK_TIME