libcoap  4.1.1
 All Data Structures Files Functions Variables Typedefs Macros Groups Pages
server.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 
43 
44 #ifndef WITHOUT_ASYNC
45 /* This variable is used to mimic long-running tasks that require
46  * asynchronous responses. */
47 static coap_async_state_t *async = NULL;
48 #endif /* WITHOUT_ASYNC */
49 
50 /* SIGINT handler: set quit to 1 for graceful termination */
51 void
52 handle_sigint(int signum) {
53  quit = 1;
54 }
55 
56 #define INDEX "This is a test server made with libcoap (see http://libcoap.sf.net)\n" \
57  "Copyright (C) 2010--2013 Olaf Bergmann <bergmann@tzi.org>\n\n"
58 
59 void
61  coap_address_t *peer, coap_pdu_t *request, str *token,
62  coap_pdu_t *response) {
63  unsigned char buf[3];
64 
65  response->hdr->code = COAP_RESPONSE_CODE(205);
66 
69 
71  coap_encode_var_bytes(buf, 0x2ffff), buf);
72 
73  coap_add_data(response, strlen(INDEX), (unsigned char *)INDEX);
74 }
75 
76 void
78  coap_address_t *peer, coap_pdu_t *request, str *token,
79  coap_pdu_t *response) {
80  coap_opt_iterator_t opt_iter;
81  coap_opt_t *option;
82  unsigned char buf[40];
83  size_t len;
84  time_t now;
85  coap_tick_t t;
86  coap_subscription_t *subscription;
87 
88  /* FIXME: return time, e.g. in human-readable by default and ticks
89  * when query ?ticks is given. */
90 
91  /* if my_clock_base was deleted, we pretend to have no such resource */
92  response->hdr->code =
94 
95  if (request != NULL &&
96  coap_check_option(request, COAP_OPTION_OBSERVE, &opt_iter)) {
97  subscription = coap_add_observer(resource, peer, token);
98  if (subscription) {
99  subscription->non = request->hdr->type == COAP_MESSAGE_NON;
100  coap_add_option(response, COAP_OPTION_OBSERVE, 0, NULL);
101  }
102  }
103  if (resource->dirty == 1)
105  coap_encode_var_bytes(buf, ctx->observe), buf);
106 
107 
108  if (my_clock_base)
111 
113  coap_encode_var_bytes(buf, 0x01), buf);
114 
115  if (my_clock_base) {
116 
117  /* calculate current time */
118  coap_ticks(&t);
119  now = my_clock_base + (t / COAP_TICKS_PER_SECOND);
120 
121  if (request != NULL
122  && (option = coap_check_option(request, COAP_OPTION_URI_QUERY, &opt_iter))
123  && memcmp(COAP_OPT_VALUE(option), "ticks",
124  min(5, COAP_OPT_LENGTH(option))) == 0) {
125  /* output ticks */
126  len = snprintf((char *)buf,
127  min(sizeof(buf), response->max_size - response->length),
128  "%u", (unsigned int)now);
129  coap_add_data(response, len, buf);
130 
131  } else { /* output human-readable time */
132  struct tm *tmp;
133  tmp = gmtime(&now);
134  len = strftime((char *)buf,
135  min(sizeof(buf), response->max_size - response->length),
136  "%b %d %H:%M:%S", tmp);
137  coap_add_data(response, len, buf);
138  }
139  }
140 }
141 
142 void
144  coap_address_t *peer, coap_pdu_t *request, str *token,
145  coap_pdu_t *response) {
146  coap_tick_t t;
147  size_t size;
148  unsigned char *data;
149 
150  /* FIXME: re-set my_clock_base to clock_offset if my_clock_base == 0
151  * and request is empty. When not empty, set to value in request payload
152  * (insist on query ?ticks). Return Created or Ok.
153  */
154 
155  /* if my_clock_base was deleted, we pretend to have no such resource */
156  response->hdr->code =
158 
159  resource->dirty = 1;
160 
161  coap_get_data(request, &size, &data);
162 
163  if (size == 0) /* re-init */
164  my_clock_base = clock_offset;
165  else {
166  my_clock_base = 0;
167  coap_ticks(&t);
168  while(size--)
169  my_clock_base = my_clock_base * 10 + *data++;
170  my_clock_base -= t / COAP_TICKS_PER_SECOND;
171  }
172 }
173 
174 void
176  coap_address_t *peer, coap_pdu_t *request, str *token,
177  coap_pdu_t *response) {
178  my_clock_base = 0; /* mark clock as "deleted" */
179 
180  /* type = request->hdr->type == COAP_MESSAGE_CON */
181  /* ? COAP_MESSAGE_ACK : COAP_MESSAGE_NON; */
182 }
183 
184 #ifndef WITHOUT_ASYNC
185 void
187  coap_address_t *peer, coap_pdu_t *request, str *token,
188  coap_pdu_t *response) {
189  coap_opt_iterator_t opt_iter;
190  coap_opt_t *option;
191  unsigned long delay = 5;
192  size_t size;
193 
194  if (async) {
195  if (async->id != request->hdr->id) {
198  response->hdr->code = COAP_RESPONSE_CODE(503);
199  }
200  return;
201  }
202 
203  option = coap_check_option(request, COAP_OPTION_URI_QUERY, &opt_iter);
204  if (option) {
205  unsigned char *p = COAP_OPT_VALUE(option);
206 
207  delay = 0;
208  for (size = COAP_OPT_LENGTH(option); size; --size, ++p)
209  delay = delay * 10 + (*p - '0');
210  }
211 
212  async = coap_register_async(ctx, peer, request,
214  (void *)(COAP_TICKS_PER_SECOND * delay));
215 }
216 
217 void
218 check_async(coap_context_t *ctx, coap_tick_t now) {
219  coap_pdu_t *response;
220  coap_async_state_t *tmp;
221 
222  size_t size = sizeof(coap_hdr_t) + 8;
223 
224  if (!async || now < async->created + (unsigned long)async->appdata)
225  return;
226 
227  response = coap_pdu_init(async->flags & COAP_ASYNC_CONFIRM
230  COAP_RESPONSE_CODE(205), 0, size);
231  if (!response) {
232  debug("check_async: insufficient memory, we'll try later\n");
233  async->appdata =
234  (void *)((unsigned long)async->appdata + 15 * COAP_TICKS_PER_SECOND);
235  return;
236  }
237 
238  response->hdr->id = coap_new_message_id(ctx);
239 
240  if (async->tokenlen)
241  coap_add_token(response, async->tokenlen, async->token);
242 
243  coap_add_data(response, 4, (unsigned char *)"done");
244 
245  if (coap_send(ctx, &async->peer, response) == COAP_INVALID_TID) {
246  debug("check_async: cannot send response for message %d\n",
247  response->hdr->id);
248  }
249  coap_delete_pdu(response);
250  coap_remove_async(ctx, async->id, &tmp);
251  coap_free_async(async);
252  async = NULL;
253 }
254 #endif /* WITHOUT_ASYNC */
255 
256 void
258  coap_resource_t *r;
259 
260  r = coap_resource_init(NULL, 0, 0);
262 
263  coap_add_attr(r, (unsigned char *)"ct", 2, (unsigned char *)"0", 1, 0);
264  coap_add_attr(r, (unsigned char *)"title", 5, (unsigned char *)"\"General Info\"", 14, 0);
265  coap_add_resource(ctx, r);
266 
267  /* store clock base to use in /time */
268  my_clock_base = clock_offset;
269 
270  r = coap_resource_init((unsigned char *)"time", 4, 0);
274 
275  coap_add_attr(r, (unsigned char *)"ct", 2, (unsigned char *)"0", 1, 0);
276  coap_add_attr(r, (unsigned char *)"title", 5, (unsigned char *)"\"Internal Clock\"", 16, 0);
277  coap_add_attr(r, (unsigned char *)"rt", 2, (unsigned char *)"\"Ticks\"", 7, 0);
278  r->observable = 1;
279  coap_add_attr(r, (unsigned char *)"if", 2, (unsigned char *)"\"clock\"", 7, 0);
280 
281  coap_add_resource(ctx, r);
282  time_resource = r;
283 
284 #ifndef WITHOUT_ASYNC
285  r = coap_resource_init((unsigned char *)"async", 5, 0);
287 
288  coap_add_attr(r, (unsigned char *)"ct", 2, (unsigned char *)"0", 1, 0);
289  coap_add_resource(ctx, r);
290 #endif /* WITHOUT_ASYNC */
291 }
292 
293 void
294 usage( const char *program, const char *version) {
295  const char *p;
296 
297  p = strrchr( program, '/' );
298  if ( p )
299  program = ++p;
300 
301  fprintf( stderr, "%s v%s -- a small CoAP implementation\n"
302  "(c) 2010,2011 Olaf Bergmann <bergmann@tzi.org>\n\n"
303  "usage: %s [-A address] [-p port]\n\n"
304  "\t-A address\tinterface address to bind to\n"
305  "\t-p port\t\tlisten on specified port\n"
306  "\t-v num\t\tverbosity level (default: 3)\n",
307  program, version, program );
308 }
309 
311 get_context(const char *node, const char *port) {
312  coap_context_t *ctx = NULL;
313  int s;
314  struct addrinfo hints;
315  struct addrinfo *result, *rp;
316 
317  memset(&hints, 0, sizeof(struct addrinfo));
318  hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
319  hints.ai_socktype = SOCK_DGRAM; /* Coap uses UDP */
320  hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
321 
322  s = getaddrinfo(node, port, &hints, &result);
323  if ( s != 0 ) {
324  fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
325  return NULL;
326  }
327 
328  /* iterate through results until success */
329  for (rp = result; rp != NULL; rp = rp->ai_next) {
330  coap_address_t addr;
331 
332  if (rp->ai_addrlen <= sizeof(addr.addr)) {
333  coap_address_init(&addr);
334  addr.size = rp->ai_addrlen;
335  memcpy(&addr.addr, rp->ai_addr, rp->ai_addrlen);
336 
337  ctx = coap_new_context(&addr);
338  if (ctx) {
339  /* TODO: output address:port for successful binding */
340  goto finish;
341  }
342  }
343  }
344 
345  fprintf(stderr, "no context available for interface '%s'\n", node);
346 
347  finish:
348  freeaddrinfo(result);
349  return ctx;
350 }
351 
352 int
353 main(int argc, char **argv) {
354  coap_context_t *ctx;
355  fd_set readfds;
356  struct timeval tv, *timeout;
357  int result;
358  coap_tick_t now;
359  coap_queue_t *nextpdu;
360  char addr_str[NI_MAXHOST] = "::";
361  char port_str[NI_MAXSERV] = "5683";
362  int opt;
363  coap_log_t log_level = LOG_WARNING;
364 
365  while ((opt = getopt(argc, argv, "A:p:v:")) != -1) {
366  switch (opt) {
367  case 'A' :
368  strncpy(addr_str, optarg, NI_MAXHOST-1);
369  addr_str[NI_MAXHOST - 1] = '\0';
370  break;
371  case 'p' :
372  strncpy(port_str, optarg, NI_MAXSERV-1);
373  port_str[NI_MAXSERV - 1] = '\0';
374  break;
375  case 'v' :
376  log_level = strtol(optarg, NULL, 10);
377  break;
378  default:
379  usage( argv[0], PACKAGE_VERSION );
380  exit( 1 );
381  }
382  }
383 
384  coap_set_log_level(log_level);
385 
386  ctx = get_context(addr_str, port_str);
387  if (!ctx)
388  return -1;
389 
390  init_resources(ctx);
391 
392  signal(SIGINT, handle_sigint);
393 
394  while ( !quit ) {
395  FD_ZERO(&readfds);
396  FD_SET( ctx->sockfd, &readfds );
397 
398  nextpdu = coap_peek_next( ctx );
399 
400  coap_ticks(&now);
401  while (nextpdu && nextpdu->t <= now - ctx->sendqueue_basetime) {
402  coap_retransmit( ctx, coap_pop_next( ctx ) );
403  nextpdu = coap_peek_next( ctx );
404  }
405 
406  if ( nextpdu && nextpdu->t <= COAP_RESOURCE_CHECK_TIME ) {
407  /* set timeout if there is a pdu to send before our automatic timeout occurs */
408  tv.tv_usec = ((nextpdu->t) % COAP_TICKS_PER_SECOND) * 1000000 / COAP_TICKS_PER_SECOND;
409  tv.tv_sec = (nextpdu->t) / COAP_TICKS_PER_SECOND;
410  timeout = &tv;
411  } else {
412  tv.tv_usec = 0;
413  tv.tv_sec = COAP_RESOURCE_CHECK_TIME;
414  timeout = &tv;
415  }
416  result = select( FD_SETSIZE, &readfds, 0, 0, timeout );
417 
418  if ( result < 0 ) { /* error */
419  if (errno != EINTR)
420  perror("select");
421  } else if ( result > 0 ) { /* read from socket */
422  if ( FD_ISSET( ctx->sockfd, &readfds ) ) {
423  coap_read( ctx ); /* read received data */
424  coap_dispatch( ctx ); /* and dispatch PDUs from receivequeue */
425  }
426  } else { /* timeout */
427  if (time_resource) {
428  time_resource->dirty = 1;
429  }
430  }
431 
432 #ifndef WITHOUT_ASYNC
433  /* check if we have to send asynchronous responses */
434  check_async(ctx, now);
435 #endif /* WITHOUT_ASYNC */
436 
437 #ifndef WITHOUT_OBSERVE
438  /* check if we have to send observe notifications */
439  coap_check_notify(ctx);
440 #endif /* WITHOUT_OBSERVE */
441  }
442 
443  coap_free_context( ctx );
444 
445  return 0;
446 }
unsigned int observe
The next value to be used for Observe.
Definition: net.h:141
coap_subscription_t * coap_add_observer(coap_resource_t *resource, const coap_address_t *observer, const str *token)
Adds the specified peer as observer for resource.
Definition: resource.c:607
int main(int argc, char **argv)
Definition: server.c:353
void * appdata
This field can be used to register opaque application data with the asynchronous state object...
Definition: async.h:45
void coap_check_notify(coap_context_t *context)
Checks for all known resources, if they are dirty and notifies subscribed observers.
Definition: resource.c:764
#define COAP_RESPONSE_CODE(N)
Definition: pdu.h:92
void coap_dispatch(coap_context_t *context)
Dispatches the PDUs from the receive queue in given context.
Definition: net.c:1452
#define COAP_OPTION_CONTENT_FORMAT
Definition: pdu.h:64
#define COAP_RESOURCE_CHECK_TIME
Definition: server.c:30
unsigned short id
Definition: pdu.h:173
static int quit
Definition: server.c:37
#define COAP_REQUEST_GET
Definition: pdu.h:50
unsigned short length
PDU length (including header, options, data)
Definition: pdu.h:211
int coap_add_token(coap_pdu_t *pdu, size_t len, const unsigned char *data)
Adds token of length len to pdu.
Definition: pdu.c:157
unsigned char flags
holds the flags to control behaviour
Definition: async.h:33
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.
Definition: option.c:207
#define COAP_MESSAGE_NON
Definition: pdu.h:44
#define COAP_OPTION_OBSERVE
Definition: pdu.h:76
short coap_log_t
Definition: debug.h:24
coap_address_t peer
the peer to notify
Definition: async.h:52
int coap_get_data(coap_pdu_t *pdu, size_t *len, unsigned char **data)
Retrieves the length and data pointer of specified PDU.
Definition: pdu.c:261
void init_resources(coap_context_t *ctx)
Definition: server.c:257
#define COAP_OPTION_MAXAGE
Definition: pdu.h:66
static time_t my_clock_base
Definition: server.c:40
#define COAP_OPTION_CONTENT_TYPE
Definition: pdu.h:65
coap_hdr_t * hdr
Definition: pdu.h:209
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.
Definition: net.c:296
coap_queue_t * coap_peek_next(coap_context_t *context)
Returns the next pdu to send without removing from sendqeue.
Definition: net.c:253
coap_tick_t sendqueue_basetime
The time stamp in the first element of the sendqeue is relative to sendqueue_basetime.
Definition: net.h:109
#define debug(...)
Definition: debug.h:55
static coap_async_state_t * async
Definition: server.c:47
coap_tick_t t
when to send PDU for the next time
Definition: net.h:54
coap_tid_t id
transaction id
Definition: async.h:48
#define COAP_INVALID_TID
Definition: pdu.h:156
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.
Definition: resource.c:341
void coap_ticks(coap_tick_t *)
Returns the current value of an internal tick counter.
unsigned int code
Definition: pdu.h:172
Header structure for CoAP PDUs.
Definition: pdu.h:206
void hnd_delete_time(coap_context_t *ctx, struct coap_resource_t *resource, coap_address_t *peer, coap_pdu_t *request, str *token, coap_pdu_t *response)
Definition: server.c:175
unsigned int dirty
set to 1 if resource has changed
Definition: resource.h:62
coap_async_state_t * coap_register_async(coap_context_t *context, coap_address_t *peer, coap_pdu_t *request, unsigned char flags, void *data)
Allocates a new coap_async_state_t object and fills its fields according to the given request...
Definition: async.c:25
unsigned int observable
can be observed
Definition: resource.h:64
#define INDEX
Definition: server.c:56
unsigned int coap_encode_var_bytes(unsigned char *buf, unsigned int val)
Encodes multiple-length byte sequences.
Definition: encode.c:34
coap_context_t * get_context(const char *node, const char *port)
Definition: server.c:311
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.
Definition: resource.h:227
#define COAP_ASYNC_CONFIRM
send confirmable response
Definition: async.h:59
size_t max_size
allocated storage for options and data
Definition: pdu.h:207
void coap_add_resource(coap_context_t *context, coap_resource_t *resource)
Registers the given resource for context.
Definition: resource.c:440
void hnd_get_index(coap_context_t *ctx, struct coap_resource_t *resource, coap_address_t *peer, coap_pdu_t *request, str *token, coap_pdu_t *response)
Definition: server.c:60
Iterator to run through PDU options.
Definition: option.h:169
#define COAP_MESSAGE_CON
Definition: pdu.h:43
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
Definition: pdu.c:175
generic resource handling
void hnd_put_time(coap_context_t *ctx, struct coap_resource_t *resource, coap_address_t *peer, coap_pdu_t *request, str *token, coap_pdu_t *response)
Definition: server.c:143
unsigned char coap_opt_filter_t[(COAP_MAX_OPT >> 3)+1]
Fixed-size bit-vector we use for option filtering.
Definition: option.h:93
void check_async(coap_context_t *ctx, coap_tick_t now)
Definition: server.c:218
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.
Definition: pdu.c:238
void hnd_get_async(coap_context_t *ctx, struct coap_resource_t *resource, coap_address_t *peer, coap_pdu_t *request, str *token, coap_pdu_t *response)
Definition: server.c:186
void usage(const char *program, const char *version)
Definition: server.c:294
#define COAP_ASYNC_SEPARATE
send separate response
Definition: async.h:60
#define COAP_REQUEST_DELETE
Definition: pdu.h:53
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.
Definition: net.c:653
void handle_sigint(int signum)
Definition: server.c:52
Subscriber information.
Definition: subscribe.h:41
void coap_delete_pdu(coap_pdu_t *pdu)
Definition: pdu.c:143
static void coap_address_init(coap_address_t *addr)
Resets the given coap_address_t object addr to its default values.
Definition: address.h:134
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...
Definition: pdu.c:82
static void coap_option_filter_clear(coap_opt_filter_t f)
Clears filter f.
Definition: option.h:104
int coap_remove_async(coap_context_t *context, coap_tid_t id, coap_async_state_t **s)
Removes the state object identified by id from context.
Definition: async.c:81
Definition: str.h:14
void coap_free_async(coap_async_state_t *s)
Releases the memory that was allocated by coap_async_state_init() for the object s.
Definition: async.c:93
void coap_free_context(coap_context_t *context)
Definition: net.c:419
#define COAP_OPT_LENGTH(opt)
Definition: option.h:305
size_t tokenlen
length of the token
Definition: async.h:53
static unsigned short coap_new_message_id(coap_context_t *context)
Returns a new message id and updates context->message_id accordingly.
Definition: net.h:197
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...
Definition: resource.c:307
#define COAP_MEDIATYPE_TEXT_PLAIN
Definition: pdu.h:141
void coap_set_log_level(coap_log_t level)
Sets the log level to the specified value.
Definition: debug.c:46
unsigned char token[]
the token to use in a response
Definition: async.h:54
#define COAP_OPTION_URI_QUERY
Definition: pdu.h:67
unsigned int type
Definition: pdu.h:170
unsigned char coap_opt_t
Use byte-oriented access methods here because sliding a complex struct coap_opt_t over the data buffe...
Definition: option.h:26
#define COAP_REQUEST_PUT
Definition: pdu.h:52
#define PACKAGE_VERSION
Definition: config.h:108
int coap_read(coap_context_t *ctx)
Reads data from the network and tries to parse as CoAP PDU.
Definition: net.c:831
void hnd_get_time(coap_context_t *ctx, struct coap_resource_t *resource, coap_address_t *peer, coap_pdu_t *request, str *token, coap_pdu_t *response)
Definition: server.c:77
coap_tid_t coap_retransmit(coap_context_t *context, coap_queue_t *node)
Handles retransmissions of confirmable messages.
Definition: net.c:771
coap_queue_t * coap_pop_next(coap_context_t *context)
Returns the next pdu to send and removes it from the sendqeue.
Definition: net.c:261
#define min(a, b)
Definition: server.c:33
unsigned int non
send non-confirmable notifies if 1
Definition: subscribe.h:45
#define COAP_OPT_VALUE(opt)
Definition: option.h:318
The CoAP stack's global state is stored in a coap_context_t object.
Definition: net.h:97
struct coap_resource_t * time_resource
Definition: server.c:42