16 #include <sys/select.h>
17 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <netinet/in.h>
21 #include <arpa/inet.h>
31 #define FLAGS_BLOCK 0x01
61 #define min(a,b) ((a) < (b) ? (a) : (b))
66 *timer += seconds * COAP_TICKS_PER_SECOND;
74 if (!output_file.
s || (output_file.
length && output_file.
s[0] ==
'-'))
77 if (!(
file = fopen((
char *)output_file.
s,
"w"))) {
85 written = fwrite(data, 1, len,
file);
88 }
while ( written && len );
99 if (!output_file.
s || (output_file.
length && output_file.
s[0] ==
'-'))
100 fwrite(
"\n", 1, 1,
file);
144 debug(
"cannot add token to request\n");
149 for (opt = options; opt; opt = opt->
next) {
177 for (option = optlist; option; option = option->
next ) {
198 debug(
"clear_obs: error sending new request");
209 struct addrinfo *res, *ainfo;
210 struct addrinfo hints;
211 static char addrstr[256];
214 memset(addrstr, 0,
sizeof(addrstr));
216 memcpy(addrstr, server->
s, server->
length);
218 memcpy(addrstr,
"localhost", 9);
220 memset ((
char *)&hints, 0,
sizeof(hints));
221 hints.ai_socktype = SOCK_DGRAM;
222 hints.ai_family = AF_UNSPEC;
224 error = getaddrinfo(addrstr,
"", &hints, &res);
227 fprintf(stderr,
"getaddrinfo: %s\n", gai_strerror(error));
231 for (ainfo = res; ainfo != NULL; ainfo = ainfo->ai_next) {
232 switch (ainfo->ai_family) {
235 len = ainfo->ai_addrlen;
236 memcpy(dst, ainfo->ai_addr, len);
262 #define HANDLE_BLOCK1(Pdu) \
263 ((method == COAP_REQUEST_PUT || method == COAP_REQUEST_POST) && \
264 ((flags & FLAGS_BLOCK) == 0) && \
265 ((Pdu)->hdr->code == COAP_RESPONSE_CODE(201) || \
266 (Pdu)->hdr->code == COAP_RESPONSE_CODE(204)))
276 const coap_address_t *remote,
284 unsigned char buf[4];
287 unsigned char *databuf;
292 debug(
"** process incoming %d.%02d response:\n",
324 debug(
"observation relationship established, set timeout to %d\n",
obs_seconds);
330 block_opt =
get_block(received, &opt_iter);
336 unsigned short blktype = opt_iter.
type;
344 debug(
"found the M bit, block size is %u, block nr. %u\n",
351 for (option = optlist; option; option = option->
next ) {
379 debug(
"message_handler: error sending new request");
395 fprintf(stderr,
"%d.%02d",
398 fprintf(stderr,
" ");
400 fprintf(stderr,
"%c", *databuf++);
402 fprintf(stderr,
"\n");
409 debug(
"message_handler: error sending response");
418 usage(
const char *program,
const char *version) {
421 p = strrchr( program,
'/' );
425 fprintf( stderr,
"%s v%s -- a small CoAP implementation\n"
426 "(c) 2010-2013 Olaf Bergmann <bergmann@tzi.org>\n\n"
427 "usage: %s [-A type...] [-t type] [-b [num,]size] [-B seconds] [-e text]\n"
428 "\t\t[-g group] [-m method] [-N] [-o file] [-P addr[:port]] [-p port]\n"
429 "\t\t[-s duration] [-O num,text] [-T string] [-v num] URI\n\n"
430 "\tURI can be an absolute or relative coap URI,\n"
431 "\t-A type...\taccepted media types as comma-separated list of\n"
432 "\t\t\tsymbolic or numeric values\n"
433 "\t-t type\t\tcontent type for given resource for PUT/POST\n"
434 "\t-b [num,]size\tblock size to be used in GET/PUT/POST requests\n"
435 "\t \t\t(value must be a multiple of 16 not larger than 1024)\n"
436 "\t \t\tIf num is present, the request chain will start at\n"
438 "\t-B seconds\tbreak operation after waiting given seconds\n"
439 "\t\t\t(default is %d)\n"
440 "\t-e text\t\tinclude text as payload (use percent-encoding for\n"
441 "\t\t\tnon-ASCII characters)\n"
442 "\t-f file\t\tfile to send with PUT/POST (use '-' for STDIN)\n"
443 "\t-g group\tjoin the given multicast group\n"
444 "\t-m method\trequest method (get|put|post|delete), default is 'get'\n"
445 "\t-N\t\tsend NON-confirmable message\n"
446 "\t-o file\t\toutput received data to this file (use '-' for STDOUT)\n"
447 "\t-p port\t\tlisten on specified port\n"
448 "\t-s duration\tsubscribe for given duration [s]\n"
449 "\t-v num\t\tverbosity level (default: 3)\n"
450 "\t-O num,text\tadd option num with contents text to request\n"
451 "\t-P addr[:port]\tuse proxy (automatically adds Proxy-Uri option to\n"
453 "\t-T token\tinclude specified token\n"
456 "\tcoap-client -m get coap://[::1]/\n"
457 "\tcoap-client -m get coap://[::1]/.well-known/core\n"
458 "\tcoap-client -m get -T cafe coap://[::1]/time\n"
459 "\techo 1000 | coap-client -m put -T cafe coap://[::1]/time -f -\n"
465 struct ipv6_mreq mreq;
466 struct addrinfo *reslocal = NULL, *resmulti = NULL, hints, *ainfo;
470 memset(&hints, 0,
sizeof(hints));
471 hints.ai_family = AF_INET6;
472 hints.ai_socktype = SOCK_DGRAM;
474 result = getaddrinfo(
"::", NULL, &hints, &reslocal);
476 fprintf(stderr,
"join: cannot resolve link-local interface: %s\n",
477 gai_strerror(result));
482 for (ainfo = reslocal; ainfo != NULL; ainfo = ainfo->ai_next) {
483 if ( ainfo->ai_family == AF_INET6 ) {
484 mreq.ipv6mr_interface =
485 ((
struct sockaddr_in6 *)ainfo->ai_addr)->sin6_scope_id;
490 memset(&hints, 0,
sizeof(hints));
491 hints.ai_family = AF_INET6;
492 hints.ai_socktype = SOCK_DGRAM;
495 result = getaddrinfo(group_name, NULL, &hints, &resmulti);
498 fprintf(stderr,
"join: cannot resolve multicast address: %s\n",
499 gai_strerror(result));
503 for (ainfo = resmulti; ainfo != NULL; ainfo = ainfo->ai_next) {
504 if ( ainfo->ai_family == AF_INET6 ) {
505 mreq.ipv6mr_multiaddr =
506 ((
struct sockaddr_in6 *)ainfo->ai_addr)->sin6_addr;
511 result = setsockopt( ctx->sockfd, IPPROTO_IPV6, IPV6_JOIN_GROUP,
512 (
char *)&mreq,
sizeof(mreq) );
514 perror(
"join: setsockopt");
517 freeaddrinfo(resmulti);
518 freeaddrinfo(reslocal);
526 return a < b ? -1 : 1;
555 perror(
"new_option_node: malloc");
571 { 40,
"link-format" },
572 { 40,
"application/link-format" },
575 { 42,
"octet-stream" },
576 { 42,
"application/octet-stream" },
578 { 47,
"application/exi" },
580 { 50,
"application/json" },
584 unsigned char i, value[10];
586 unsigned char buf[2];
595 value[valcnt++] = atoi(q);
598 strncmp(q,content_types[i].media_type, p ? p-q : strlen(q)) != 0 ;
602 if (content_types[i].media_type) {
603 value[valcnt] = content_types[i].
code;
606 warn(
"W: unknown content-type '%s'\n",arg);
616 for (i = 0; i < valcnt; ++i) {
625 unsigned char portbuf[2];
628 unsigned char *buf = _buf;
633 size_t len = strlen(arg);
637 270, (
unsigned char *)arg),
645 len, (
unsigned char *)arg),
695 while(*arg && *arg !=
',')
696 size = size * 10 + (*arg++ -
'0');
715 static unsigned char buf[4];
736 char *proxy_port_str = strrchr((
const char *)arg,
':');
737 if (proxy_port_str) {
738 char *ipv6_delimiter = strrchr((
const char *)arg,
']');
739 if (!ipv6_delimiter) {
740 if (proxy_port_str == strchr((
const char *)arg,
':')) {
742 *proxy_port_str++ =
'\0';
746 arg = strchr((
const char *)arg,
'[');
749 *ipv6_delimiter =
'\0';
750 if (ipv6_delimiter + 1 == proxy_port_str++) {
757 proxy.
length = strlen(arg);
763 memcpy(proxy.
s, arg, proxy.
length+1);
769 strncpy((
char *)the_token.
s, arg,
min(
sizeof(
_token_data), strlen(arg)));
770 the_token.
length = strlen(arg);
775 unsigned int num = 0;
777 while (*arg && *arg !=
',') {
778 num = num * 10 + (*arg -
'0');
789 extern int check_segment(
const unsigned char *s,
size_t length);
790 extern void decode_segment(
const unsigned char *seg,
size_t length,
unsigned char *buf);
811 FILE *inputfile = NULL;
816 if (!filename || !buf)
819 if (filename[0] ==
'-' && !filename[1]) {
828 if (stat(filename, &statbuf) < 0) {
829 perror(
"cmdline_input_from_file: stat");
833 buf->
length = statbuf.st_size;
838 inputfile = fopen(filename,
"r");
840 perror(
"cmdline_input_from_file: fopen");
846 len = fread(buf->
s, 1, buf->
length, inputfile);
848 if (len < buf->length) {
849 if (ferror(inputfile) != 0) {
850 perror(
"cmdline_input_from_file: fread");
860 if (inputfile != stdin)
868 static char *methods[] =
869 { 0,
"get",
"post",
"put",
"delete", 0};
872 for (i=1; methods[i] && strcasecmp(arg,methods[i]) != 0 ; ++i)
882 struct addrinfo hints;
883 struct addrinfo *result, *rp;
885 memset(&hints, 0,
sizeof(
struct addrinfo));
886 hints.ai_family = AF_UNSPEC;
887 hints.ai_socktype = SOCK_DGRAM;
888 hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST | AI_NUMERICSERV | AI_ALL;
890 s = getaddrinfo(node, port, &hints, &result);
892 fprintf(stderr,
"getaddrinfo: %s\n", gai_strerror(s));
897 for (rp = result; rp != NULL; rp = rp->ai_next) {
900 if (rp->ai_addrlen <=
sizeof(addr.addr)) {
902 addr.size = rp->ai_addrlen;
903 memcpy(&addr.addr, rp->ai_addr, rp->ai_addrlen);
913 fprintf(stderr,
"no context available for interface '%s'\n", node);
916 freeaddrinfo(result);
925 void *addrptr = NULL;
934 char port_str[NI_MAXSERV] =
"0";
940 while ((opt = getopt(argc, argv,
"Nb:e:f:g:m:p:s:t:o:v:A:B:O:P:T:")) != -1) {
960 strncpy(port_str, optarg, NI_MAXSERV-1);
961 port_str[NI_MAXSERV - 1] =
'\0';
973 output_file.
length = strlen(optarg);
976 if (!output_file.
s) {
977 fprintf(stderr,
"cannot set output file: insufficient memory\n");
981 memcpy(output_file.
s, optarg, output_file.
length + 1);
995 fprintf(stderr,
"error specifying proxy address\n");
1003 log_level = strtol(optarg, NULL, 10);
1013 if ( optind < argc )
1032 fprintf(stderr,
"failed to resolve address\n");
1037 dst.addr.sin.sin_port = htons(port);
1041 switch (dst.addr.sa.sa_family) {
1043 addrptr = &dst.addr.sin.sin_addr;
1049 addrptr = &dst.addr.sin6.sin6_addr;
1059 coap_log(LOG_EMERG,
"cannot create context\n");
1072 if (!proxy.
length && addrptr
1073 && (inet_ntop(dst.addr.sa.sa_family, addrptr, addr,
sizeof(addr)) != 0)
1092 debug(
"sending CoAP request:\n");
1110 FD_SET( ctx->sockfd, &readfds );
1122 tv.tv_usec = ((nextpdu->
t) % COAP_TICKS_PER_SECOND) * 1000000 / COAP_TICKS_PER_SECOND;
1123 tv.tv_sec = (nextpdu->
t) / COAP_TICKS_PER_SECOND;
1127 tv.tv_usec = ((
obs_wait - now) % COAP_TICKS_PER_SECOND) * 1000000 / COAP_TICKS_PER_SECOND;
1128 tv.tv_sec = (
obs_wait - now) / COAP_TICKS_PER_SECOND;
1130 tv.tv_usec = ((max_wait - now) % COAP_TICKS_PER_SECOND) * 1000000 / COAP_TICKS_PER_SECOND;
1131 tv.tv_sec = (max_wait - now) / COAP_TICKS_PER_SECOND;
1135 result = select(ctx->sockfd + 1, &readfds, 0, 0, &tv);
1139 }
else if ( result > 0 ) {
1140 if ( FD_ISSET( ctx->sockfd, &readfds ) ) {
1146 if (max_wait <= now) {
1151 debug(
"clear observation relationship\n");
Representation of parsed URI.
Structures for more convenient handling of options.
int coap_split_uri(unsigned char *str_var, size_t len, coap_uri_t *uri)
Parses a given string into URI components.
int check_token(coap_pdu_t *received)
int append_to_output(const unsigned char *data, size_t len)
unsigned int coap_opt_block_num(const coap_opt_t *block_opt)
Returns the value of field num in the given block option block_opt.
str query
The query part if present.
int cmdline_blocksize(char *arg)
#define COAP_RESPONSE_CODE(N)
void coap_dispatch(coap_context_t *context)
Dispatches the PDUs from the receive queue in given context.
#define COAP_OPTION_PROXY_URI
int coap_insert(coap_list_t **queue, coap_list_t *node, int(*order)(void *, void *node))
void cmdline_subscribe(char *arg)
int main(int argc, char **argv)
void coap_show_pdu(const coap_pdu_t *pdu)
static coap_list_t * optlist
str host
host part of the URI
coap_tid_t coap_send_confirmed(coap_context_t *context, const coap_address_t *dst, coap_pdu_t *pdu)
Sends a confirmed CoAP message to given destination.
void usage(const char *program, const char *version)
int check_segment(const unsigned char *s, size_t length)
Runs through the given path (or query) segment and checks if percent-encodings are correct...
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.
struct coap_linkedlistnode * next
static void coap_register_option(coap_context_t *ctx, unsigned char type)
Registers the option type type with the given context object ctx.
str path
Beginning of the first path segment.
#define COAP_OPTION_BLOCK1
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_malloc(size)
coap_opt_t * coap_option_next(coap_opt_iterator_t *oi)
Updates the iterator oi to point to the next option.
void message_handler(struct coap_context_t *ctx, const coap_address_t *remote, coap_pdu_t *sent, coap_pdu_t *received, const coap_tid_t id)
coap_log_t coap_get_log_level()
Returns the current log level.
#define COAP_OPTION_CONTENT_TYPE
int coap_fls(unsigned int i)
unsigned short port
The port in host byte order.
static int coap_option_setb(coap_opt_filter_t filter, unsigned short type)
Sets the corresponding bit for type in filter.
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.
int resolve_address(const str *server, struct sockaddr *dst)
coap_pdu_t * new_ack(coap_context_t *ctx, coap_queue_t *node)
coap_queue_t * coap_peek_next(coap_context_t *context)
Returns the next pdu to send without removing from sendqeue.
static unsigned char _token_data[8]
static void coap_register_response_handler(coap_context_t *context, coap_response_handler_t handler)
Registers a new message handler that is called whenever a response was received that matches an ongoi...
coap_tick_t sendqueue_basetime
The time stamp in the first element of the sendqeue is relative to sendqueue_basetime.
#define COAP_OPTION_SUBSCRIPTION
coap_pdu_t * pdu
the CoAP PDU to send
method_t cmdline_method(char *arg)
coap_tick_t t
when to send PDU for the next time
unsigned int wait_seconds
coap_tid_t clear_obs(coap_context_t *ctx, const coap_address_t *remote)
void coap_ticks(coap_tick_t *)
Returns the current value of an internal tick counter.
coap_list_t * new_option_node(unsigned short key, unsigned int length, unsigned char *data)
Header structure for CoAP PDUs.
void cmdline_uri(char *arg)
int coap_can_exit(coap_context_t *context)
Returns 1 if there are no messages to send or to dispatch in the context's queues.
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 oi to point to the beginning of the pdu's option list...
#define COAP_OPTION_URI_PORT
int order_opts(void *a, void *b)
#define COAP_OPTION_DATA(option)
void cmdline_token(char *arg)
coap_context_t * get_context(const char *node, const char *port)
unsigned int coap_encode_var_bytes(unsigned char *buf, unsigned int val)
Encodes multiple-length byte sequences.
int join(coap_context_t *ctx, char *group_name)
static unsigned short proxy_port
int coap_add_block(coap_pdu_t *pdu, unsigned int len, const unsigned char *data, unsigned int block_num, unsigned char block_szx)
Adds the block_num block of size 1 << (block_szx + 4) from source data to pdu.
#define COAP_RESPONSE_CLASS(C)
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.
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
#define COAP_OPT_SIZE(opt)
unsigned char coap_opt_filter_t[(COAP_MAX_OPT >> 3)+1]
Fixed-size bit-vector we use for option filtering.
int cmdline_input(char *text, str *buf)
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_OPTION_LENGTH(option)
int cmdline_proxy(char *arg)
#define COAP_DEFAULT_PORT
coap_list_t * coap_new_listnode(void *data, void(*delete_func)(void *))
Creates a new list node and adds the given data object.
unsigned short type
decoded option type
void decode_segment(const unsigned char *seg, size_t length, unsigned char *buf)
Decodes percent-encoded characters while copying the string seg of size length to buf...
void cmdline_content_type(char *arg, unsigned short key)
#define COAP_OPTION_KEY(option)
coap_tid_t coap_send_ack(coap_context_t *context, const coap_address_t *dst, coap_pdu_t *request)
Sends an ACK message with code 0 for the specified request to dst.
#define COAP_OPTION_BLOCK2
void coap_delete_pdu(coap_pdu_t *pdu)
static coap_tid_t coap_send_rst(coap_context_t *context, const coap_address_t *dst, coap_pdu_t *request)
Sends an RST message with code 0 for the specified request to dst.
static void coap_address_init(coap_address_t *addr)
Resets the given coap_address_t object addr to its default values.
Structure of Block options.
void coap_free_context(coap_context_t *context)
int coap_split_query(const unsigned char *s, size_t length, unsigned char *buf, size_t *buflen)
Splits the given URI query into segments.
static void set_timeout(coap_tick_t *timer, const unsigned int seconds)
#define COAP_OPT_LENGTH(opt)
unsigned int token_length
static unsigned short coap_new_message_id(coap_context_t *context)
Returns a new message id and updates context->message_id accordingly.
#define COAP_OPT_BLOCK_SZX(opt)
Returns the value of the SZX-field of a Block option opt.
#define COAP_OPTION_URI_PATH
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...
coap_pdu_t * new_response(coap_context_t *ctx, coap_queue_t *node, unsigned int code)
#define COAP_OPTION_ACCEPT
void cmdline_option(char *arg)
int coap_read(coap_context_t *ctx)
Reads data from the network and tries to parse as CoAP PDU.
coap_pdu_t * coap_new_request(coap_context_t *ctx, method_t m, coap_list_t *options)
coap_pdu_t * coap_new_pdu()
Creates a new CoAP PDU.
int cmdline_input_from_file(char *filename, str *buf)
#define COAP_OPT_BLOCK_MORE(opt)
Returns the value of the More-bit of a Block option opt.
static coap_opt_t * get_block(coap_pdu_t *pdu, coap_opt_iterator_t *opt_iter)
coap_tid_t coap_retransmit(coap_context_t *context, coap_queue_t *node)
Handles retransmissions of confirmable messages.
#define COAP_OPTION_URI_HOST
coap_queue_t * coap_pop_next(coap_context_t *context)
Returns the next pdu to send and removes it from the sendqeue.
#define COAP_OPT_VALUE(opt)
The CoAP stack's global state is stored in a coap_context_t object.
unsigned int szx
block size
unsigned int num
block number