libcoap  4.1.1
 All Data Structures Files Functions Variables Typedefs Macros Groups Pages
examples/block.c
Go to the documentation of this file.
1 /* coap -- simple implementation of the Constrained Application Protocol (CoAP)
2  * as defined in draft-ietf-core-coap
3  *
4  * Copyright (C) 2010--2013 Olaf Bergmann <bergmann@tzi.org>
5  *
6  * This file is part of the CoAP library libcoap. Please see
7  * README for terms of use.
8  */
9 
10 #include <string.h>
11 #include <stdlib.h>
12 #include <unistd.h>
13 #include <stdio.h>
14 #include <ctype.h>
15 #include <sys/select.h>
16 #include <sys/types.h>
17 #include <sys/socket.h>
18 #include <netinet/in.h>
19 #include <arpa/inet.h>
20 #include <netdb.h>
21 #include <sys/stat.h>
22 #include <dirent.h>
23 #include <errno.h>
24 #include <signal.h>
25 
26 #include "config.h"
27 #include "resource.h"
28 #include "coap.h"
29 
30 #define COAP_RESOURCE_CHECK_TIME 2
31 
32 #ifndef min
33 #define min(a,b) ((a) < (b) ? (a) : (b))
34 #endif
35 
36 /* temporary storage for dynamic resource representations */
37 static int quit = 0;
38 
39 /* changeable clock base (see handle_put_time()) */
40 static time_t my_clock_base = 0;
41 
42 #ifndef WITHOUT_ASYNC
43 /* This variable is used to mimic long-running tasks that require
44  * asynchronous responses. */
45 static coap_async_state_t *async = NULL;
46 #endif /* WITHOUT_ASYNC */
47 
48 /* SIGINT handler: set quit to 1 for graceful termination */
49 void
50 handle_sigint(int signum) {
51  quit = 1;
52 }
53 
54 #define INDEX "This is a test server made with libcoap (see http://libcoap.sf.net)\n" \
55  "Copyright (C) 2010--2013 Olaf Bergmann <bergmann@tzi.org>\n\n"
56 
57 void
59  coap_address_t *peer, coap_pdu_t *request, str *token,
60  coap_pdu_t *response) {
61  unsigned char buf[3];
62 
63  response->hdr->code = COAP_RESPONSE_CODE(205);
64 
67 
69  coap_encode_var_bytes(buf, 0x2ffff), buf);
70 
71  coap_add_data(response, strlen(INDEX), (unsigned char *)INDEX);
72 }
73 
74 void
76  coap_address_t *peer, coap_pdu_t *request, str *token,
77  coap_pdu_t *response) {
78  coap_opt_iterator_t opt_iter;
79  coap_opt_t *option;
80  unsigned char buf[40];
81  size_t len;
82  time_t now;
83  coap_tick_t t;
84 
85  /* FIXME: return time, e.g. in human-readable by default and ticks
86  * when query ?ticks is given. */
87 
88  /* if my_clock_base was deleted, we pretend to have no such resource */
89  response->hdr->code =
91 
92  if (request != NULL &&
93  coap_check_option(request, COAP_OPTION_OBSERVE, &opt_iter)) {
94  coap_add_observer(resource,
95  peer,
96  token);
97  coap_add_option(response, COAP_OPTION_OBSERVE, 0, NULL);
98  }
99  if (resource->dirty == 1)
101  coap_encode_var_bytes(buf, ctx->observe), buf);
102 
103 
104  if (my_clock_base)
107 
109  coap_encode_var_bytes(buf, 0x01), buf);
110 
111  if (my_clock_base) {
112 
113  /* calculate current time */
114  coap_ticks(&t);
115  now = my_clock_base + (t / COAP_TICKS_PER_SECOND);
116 
117  if (request != NULL
118  && (option = coap_check_option(request, COAP_OPTION_URI_QUERY, &opt_iter))
119  && memcmp(COAP_OPT_VALUE(option), "ticks",
120  min(5, COAP_OPT_LENGTH(option))) == 0) {
121  /* output ticks */
122  len = snprintf((char *)buf,
123  min(sizeof(buf), response->max_size - response->length),
124  "%u", (unsigned int)now);
125  coap_add_data(response, len, buf);
126 
127  } else { /* output human-readable time */
128  struct tm *tmp;
129  tmp = gmtime(&now);
130  len = strftime((char *)buf,
131  min(sizeof(buf), response->max_size - response->length),
132  "%b %d %H:%M:%S", tmp);
133  coap_add_data(response, len, buf);
134  }
135  }
136 }
137 
138 void
140  coap_address_t *peer, coap_pdu_t *request, str *token,
141  coap_pdu_t *response) {
142  coap_tick_t t;
143  size_t size;
144  unsigned char *data;
145 
146  /* FIXME: re-set my_clock_base to clock_offset if my_clock_base == 0
147  * and request is empty. When not empty, set to value in request payload
148  * (insist on query ?ticks). Return Created or Ok.
149  */
150 
151  /* if my_clock_base was deleted, we pretend to have no such resource */
152  response->hdr->code =
154 
155  resource->dirty = 1;
156 
157  coap_get_data(request, &size, &data);
158 
159  if (size == 0) /* re-init */
160  my_clock_base = clock_offset;
161  else {
162  my_clock_base = 0;
163  coap_ticks(&t);
164  while(size--)
165  my_clock_base = my_clock_base * 10 + *data++;
166  my_clock_base -= t / COAP_TICKS_PER_SECOND;
167  }
168 }
169 
170 void
172  coap_address_t *peer, coap_pdu_t *request, str *token,
173  coap_pdu_t *response) {
174  my_clock_base = 0; /* mark clock as "deleted" */
175 
176  /* type = request->hdr->type == COAP_MESSAGE_CON */
177  /* ? COAP_MESSAGE_ACK : COAP_MESSAGE_NON; */
178 }
179 
180 #ifndef WITHOUT_ASYNC
181 void
183  coap_address_t *peer, coap_pdu_t *request, str *token,
184  coap_pdu_t *response) {
185  coap_opt_iterator_t opt_iter;
186  coap_opt_t *option;
187  unsigned long delay = 5;
188  size_t size;
189 
190  if (async) {
191  if (async->id != request->hdr->id) {
194  response->hdr->code = COAP_RESPONSE_CODE(503);
195  }
196  return;
197  }
198 
199  option = coap_check_option(request, COAP_OPTION_URI_QUERY, &opt_iter);
200  if (option) {
201  unsigned char *p = COAP_OPT_VALUE(option);
202 
203  delay = 0;
204  for (size = COAP_OPT_LENGTH(option); size; --size, ++p)
205  delay = delay * 10 + (*p - '0');
206  }
207 
208  async = coap_register_async(ctx, peer, request,
210  (void *)(COAP_TICKS_PER_SECOND * delay));
211 }
212 
213 void
214 check_async(coap_context_t *ctx, coap_tick_t now) {
215  coap_pdu_t *response;
216  coap_async_state_t *tmp;
217 
218  size_t size = sizeof(coap_hdr_t) + 8;
219 
220  if (!async || now < async->created + (unsigned long)async->appdata)
221  return;
222 
223  response = coap_pdu_init(async->flags & COAP_ASYNC_CONFIRM
226  COAP_RESPONSE_CODE(205), 0, size);
227  if (!response) {
228  debug("check_async: insufficient memory, we'll try later\n");
229  async->appdata =
230  (void *)((unsigned long)async->appdata + 15 * COAP_TICKS_PER_SECOND);
231  return;
232  }
233 
234  response->hdr->id = coap_new_message_id(ctx);
235 
236  if (async->tokenlen)
237  coap_add_token(response, async->tokenlen, async->token);
238 
239  coap_add_data(response, 4, (unsigned char *)"done");
240 
241  if (coap_send(ctx, &async->peer, response) == COAP_INVALID_TID) {
242  debug("check_async: cannot send response for message %d\n",
243  response->hdr->id);
244  }
245  coap_delete_pdu(response);
246  coap_remove_async(ctx, async->id, &tmp);
247  coap_free_async(async);
248  async = NULL;
249 }
250 #endif /* WITHOUT_ASYNC */
251 
252 void
254  coap_resource_t *r;
255 
256  r = coap_resource_init(NULL, 0, 0);
258 
259  coap_add_attr(r, (unsigned char *)"ct", 2, (unsigned char *)"0", 1, 0);
260  coap_add_attr(r, (unsigned char *)"title", 5, (unsigned char *)"\"General Info\"", 14, 0);
261  coap_add_resource(ctx, r);
262 
263  /* store clock base to use in /time */
264  my_clock_base = clock_offset;
265 
266  r = coap_resource_init((unsigned char *)"time", 4, 0);
270 
271  coap_add_attr(r, (unsigned char *)"ct", 2, (unsigned char *)"0", 1, 0);
272  coap_add_attr(r, (unsigned char *)"title", 5, (unsigned char *)"\"Internal Clock\"", 16, 0);
273  coap_add_attr(r, (unsigned char *)"rt", 2, (unsigned char *)"\"Ticks\"", 7, 0);
274  r->observable = 1;
275  coap_add_attr(r, (unsigned char *)"if", 2, (unsigned char *)"\"clock\"", 7, 0);
276 
277  coap_add_resource(ctx, r);
278 
279 #ifndef WITHOUT_ASYNC
280  r = coap_resource_init((unsigned char *)"async", 5, 0);
282 
283  coap_add_attr(r, (unsigned char *)"ct", 2, (unsigned char *)"0", 1, 0);
284  coap_add_resource(ctx, r);
285 #endif /* WITHOUT_ASYNC */
286 }
287 
288 void
289 usage( const char *program, const char *version) {
290  const char *p;
291 
292  p = strrchr( program, '/' );
293  if ( p )
294  program = ++p;
295 
296  fprintf( stderr, "%s v%s -- a small CoAP implementation\n"
297  "(c) 2010,2011 Olaf Bergmann <bergmann@tzi.org>\n\n"
298  "usage: %s [-A address] [-p port]\n\n"
299  "\t-A address\tinterface address to bind to\n"
300  "\t-p port\t\tlisten on specified port\n"
301  "\t-v num\t\tverbosity level (default: 3)\n",
302  program, version, program );
303 }
304 
306 get_context(const char *node, const char *port) {
307  coap_context_t *ctx = NULL;
308  int s;
309  struct addrinfo hints;
310  struct addrinfo *result, *rp;
311 
312  memset(&hints, 0, sizeof(struct addrinfo));
313  hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
314  hints.ai_socktype = SOCK_DGRAM; /* Coap uses UDP */
315  hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
316 
317  s = getaddrinfo(node, port, &hints, &result);
318  if ( s != 0 ) {
319  fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
320  return NULL;
321  }
322 
323  /* iterate through results until success */
324  for (rp = result; rp != NULL; rp = rp->ai_next) {
325  coap_address_t addr;
326 
327  if (rp->ai_addrlen <= sizeof(addr.addr)) {
328  coap_address_init(&addr);
329  addr.size = rp->ai_addrlen;
330  memcpy(&addr.addr, rp->ai_addr, rp->ai_addrlen);
331 
332  ctx = coap_new_context(&addr);
333  if (ctx) {
334  /* TODO: output address:port for successful binding */
335  goto finish;
336  }
337  }
338  }
339 
340  fprintf(stderr, "no context available for interface '%s'\n", node);
341 
342  finish:
343  freeaddrinfo(result);
344  return ctx;
345 }
346 
347 int
348 main(int argc, char **argv) {
349  coap_context_t *ctx;
350  fd_set readfds;
351  struct timeval tv, *timeout;
352  int result;
353  coap_tick_t now;
354  coap_queue_t *nextpdu;
355  char addr_str[NI_MAXHOST] = "::";
356  char port_str[NI_MAXSERV] = "5683";
357  int opt;
358  coap_log_t log_level = LOG_WARN;
359 
360  while ((opt = getopt(argc, argv, "A:p:v:")) != -1) {
361  switch (opt) {
362  case 'A' :
363  strncpy(addr_str, optarg, NI_MAXHOST-1);
364  addr_str[NI_MAXHOST - 1] = '\0';
365  break;
366  case 'p' :
367  strncpy(port_str, optarg, NI_MAXSERV-1);
368  port_str[NI_MAXSERV - 1] = '\0';
369  break;
370  case 'v' :
371  log_level = strtol(optarg, NULL, 10);
372  break;
373  default:
374  usage( argv[0], PACKAGE_VERSION );
375  exit( 1 );
376  }
377  }
378 
379  coap_set_log_level(log_level);
380 
381  ctx = get_context(addr_str, port_str);
382  if (!ctx)
383  return -1;
384 
385  init_resources(ctx);
386 
387  signal(SIGINT, handle_sigint);
388 
389  while ( !quit ) {
390  FD_ZERO(&readfds);
391  FD_SET( ctx->sockfd, &readfds );
392 
393  nextpdu = coap_peek_next( ctx );
394 
395  coap_ticks(&now);
396  while ( nextpdu && nextpdu->t <= now ) {
397  coap_retransmit( ctx, coap_pop_next( ctx ) );
398  nextpdu = coap_peek_next( ctx );
399  }
400 
401  if ( nextpdu && nextpdu->t <= now + COAP_RESOURCE_CHECK_TIME ) {
402  /* set timeout if there is a pdu to send before our automatic timeout occurs */
403  tv.tv_usec = ((nextpdu->t - now) % COAP_TICKS_PER_SECOND) * 1000000 / COAP_TICKS_PER_SECOND;
404  tv.tv_sec = (nextpdu->t - now) / COAP_TICKS_PER_SECOND;
405  timeout = &tv;
406  } else {
407  tv.tv_usec = 0;
408  tv.tv_sec = COAP_RESOURCE_CHECK_TIME;
409  timeout = &tv;
410  }
411  result = select( FD_SETSIZE, &readfds, 0, 0, timeout );
412 
413  if ( result < 0 ) { /* error */
414  if (errno != EINTR)
415  perror("select");
416  } else if ( result > 0 ) { /* read from socket */
417  if ( FD_ISSET( ctx->sockfd, &readfds ) ) {
418  coap_read( ctx ); /* read received data */
419  coap_dispatch( ctx ); /* and dispatch PDUs from receivequeue */
420  }
421  } else { /* timeout */
422  /* coap_check_resource_list( ctx ); */
423  }
424 
425 #ifndef WITHOUT_ASYNC
426  /* check if we have to send asynchronous responses */
427  check_async(ctx, now);
428 #endif /* WITHOUT_ASYNC */
429 
430 #ifndef WITHOUT_OBSERVE
431  /* check if we have to send observe notifications */
432  coap_check_notify(ctx);
433 #endif /* WITHOUT_OBSERVE */
434  }
435 
436  coap_free_context( ctx );
437 
438  return 0;
439 }