1COAP_OBSERVE(3) libcoap Manual COAP_OBSERVE(3)
2
3
4
6 coap_observe, coap_resource_set_get_observable,
7 coap_resource_notify_observers, coap_resource_get_uri_path,
8 coap_find_observer, coap_delete_observer, coap_delete_observers - work
9 with CoAP observe
10
12 #include <coap2/coap.h>
13
14 void coap_resource_set_get_observable(coap_resource_t *resource, int
15 mode);
16
17 int coap_resource_notify_observers(coap_resource_t *resource, const
18 const_string_t *query);
19
20 const coap_string_t *coap_resource_get_uri_path(coap_resource_t
21 *resource);
22
23 coap_subscription_t *coap_find_observer(coap_resource_t *resource,
24 coap_session_t *session, const const_string_t *token);
25
26 int coap_delete_observer(coap_resource_t *resource, coap_session_t
27 *session, const coap_binary_t *token);
28
29 void coap_delete_observers(coap_context_t *context, coap_session_t
30 *session);
31
32 Link with -lcoap-2, -lcoap-2-gnutls, -lcoap-2-openssl or
33 -lcoap-2-tinydtls depending on your (D)TLS library type.
34
36 RFC 7641 extends the CoAP protocol to be able to monitor the state of a
37 resource over time.
38
39 This enables clients to "observe" resources with a defined query, i.e.,
40 to retrieve a representation of a resource and keep this representation
41 updated by the server over a period of time.
42
43 The server has to flag a resource as "observable", and then the client
44 has to request in a GET request that it wants to observe this resource
45 by the use of the COAP_OPTION_OBSERVE Option with a value of
46 COAP_OBSERVE_ESTABLISH. Optionally, the client can specify query
47 options for the resource.
48
49 To remove the "observe" subscription, the client has to issue a GET
50 request with the COAP_OPTION_OBSERVE Option with a value of
51 COAP_OBSERVE_CANCEL. Alternatively, the server can remove a
52 subscription by calling coap_delete_observer() or
53 coap_delete_observers(), but this does not notify the client that the
54 subscription has been removed.
55
56 The underlying library adds in and removes "subscribers" to the
57 resource as appropriate in the server side logic.
58
59 Within the server application, it needs to determine that there is a
60 change of state of the resource under observation, and then cause the
61 CoAP library layer to initiate a "fake GET request" so that an observe
62 GET response gets sent back to all the clients that are observing the
63 resource. The appropriate GET handler within the server application is
64 called to fill in the response packet with the appropriate information.
65 This "fake GET request" is triggered by a call to
66 coap_resource_notify_observers().
67
68 The call to coap_run_once() in the main server application i/o loop
69 will do all the necessary processing of sending any outstanding "fake
70 GET requests".
71
72 Whenever the server sends a copy of the state of the "observed"
73 resource to the client, it will use the same token used by the client
74 when the client requested the "observe". The client will receive this
75 observe response in the handler defined by
76 coap_register_response_handler(3). It is the responsibility of the
77 client application to match the supplied token and update the
78 appropriate internal information.
79
80 The coap_resource_set_get_observable() function enables or disables the
81 observable status of the resource by the setting of mode. If mode is 1,
82 then the resource is observable. If mode is 0, then the resource is no
83 longer observable.
84
85 NOTE: It is not possible for the Unknown Resource, created by
86 coap_resource_unknown_init(3), to be observable as the Uri-Path is not
87 known when libcoap creates a "fake GET request". The Unknown Resource
88 PUT handler must create a new resource and mark the resource as
89 "observable" if a specific resource needs to be observable. The
90 application must then manage the deleteion of the resource at the
91 appropriate time.
92
93 NOTE: The type (confirmable or non-confirmable) of the triggered
94 observe GET response is determined not by the initial GET request, but
95 independently by the server as per RFC 7641 3.5. Transmission. This is
96 controlled by the flags (one of COAP_RESOURCE_FLAGS_NOTIFY_NON or
97 COAP_RESOURCE_FLAGS_NOTIFY_CON) used when creating the resource using
98 coap_resource_init(3). Furthermore, the server must send at least one
99 "observe" response as confirmable, when generally sending
100 non-confirmable, every 24 hours. libcoap handles this by sending every
101 fifth (COAP_OBS_MAX_NON) response as a confirmable response for
102 detection that the client is still responding.
103
104 The coap_resource_notify_observers() function needs to be called
105 whenever the server application determines that there has been a change
106 to the state of resource, possibly only matching a specific query if
107 query is not NULL.
108
109 The coap_resource_get_uri_path() function is used to obtain the UriPath
110 of the resource definion.
111
112 The coap_find_observer() function is used to check whether the current
113 GET request as determined from resource, session and token is currently
114 being observed or not.
115
116 The coap_delete_observer() function deletes the specific observer
117 associated with resource, session and has token.
118
119 The coap_delete_observers() function is used to delete all observers
120 associated with the session that is a part of the context.
121
123 The coap_resource_get_uri_path() function returns the uri_path or NULL
124 if there was a failure.
125
126 The coap_find_observer() function returns the subscription or NULL if
127 there was a failure.
128
129 The coap_resource_set_get_observable() function return 0 on failure, 1
130 on success.
131
132 The coap_delete_observer() function return 0 on failure, 1 on success.
133
135 Simple Time Server
136
137 #include <coap2/coap.h>
138
139 coap_resource_t *time_resource = NULL;
140
141 static int check_if_time_resource_has_changed(coap_resource_t *resource) {
142 return 1;
143 }
144
145 /* specific GET "time" handler, called from hnd_get_generic() */
146
147 static void
148 hnd_get_time(coap_context_t *context, coap_resource_t *resource,
149 coap_session_t *session, coap_pdu_t *request, coap_string_t *token,
150 coap_string_t *query, coap_pdu_t *response) {
151
152 unsigned char buf[40];
153 size_t len;
154 time_t now;
155
156 /* ... Additional analysis code for resource, request pdu etc. ... */
157
158 /* After analysis, generate a suitable response */
159
160 /* Note that token, if set, is already in the response pdu */
161
162 now = time(NULL);
163
164 if (query != NULL && coap_string_equal(query, coap_make_str_const("secs"))) {
165 /* Output secs since Jan 1 1970 */
166 len = snprintf((char *)buf, sizeof(buf), "%lu", now);
167 }
168 else {
169 /* Output human-readable time */
170 struct tm *tmp;
171 tmp = gmtime(&now);
172 if (!tmp) {
173 /* If 'now' is not valid */
174 response->code = COAP_RESPONSE_CODE(404);
175 return;
176 }
177 len = strftime((char *)buf, sizeof(buf), "%b %d %H:%M:%S", tmp);
178 }
179 /*
180 * Invoke coap_add_data_blocked_response() to do all the hard work.
181 *
182 * Define the format - COAP_MEDIATYPE_TEXT_PLAIN - to add in
183 * Define how long this response is valid for (secs) - 1 - to add in.
184 *
185 * OBSERVE Option added internally if needed within the function
186 * BLOCK2 Option added internally if output too large
187 * ETAG Option added internally
188 */
189 coap_add_data_blocked_response(resource, session, request, response, token,
190 COAP_MEDIATYPE_TEXT_PLAIN, 1,
191 len,
192 buf);
193
194 /*
195 * As resource->code has been updated in coap_add_data_blocked_response(),
196 * the response pdu will be transmitted by the underlying library.
197 */
198
199 }
200
201 /* Generic GET handler */
202
203 static void
204 hnd_get_generic(coap_context_t *ctx, coap_resource_t *resource,
205 coap_session_t *session, coap_pdu_t *request, coap_string_t *token,
206 coap_string_t *query, coap_pdu_t *response) {
207
208 coap_str_const_t *uri_path = coap_resource_get_uri_path(resource);
209
210 if (!uri_path) {
211 /* Unexpected Failure */
212 response->code = COAP_RESPONSE_CODE(400);
213 return;
214 }
215
216 /* Is this the "time" resource" ? */
217 if (coap_string_equal(uri_path, coap_make_str_const("time"))) {
218 hnd_get_time(ctx, resource, session, request, token, query,
219 response);
220 return;
221 }
222
223 /* Other resources code */
224
225 /* Failure response */
226 response->code = COAP_RESPONSE_CODE(400);
227 }
228
229 /* Initialize generic GET handler */
230
231 static void
232 init_resources(coap_context_t *ctx)
233 {
234
235 coap_resource_t *r;
236
237 /* Create a resource to return return or update time */
238 r = coap_resource_init(coap_make_str_const("time"),
239 COAP_RESOURCE_FLAGS_NOTIFY_CON);
240
241 /* We are using a generic GET handler here */
242 coap_register_handler(r, COAP_REQUEST_GET, hnd_get_generic);
243
244 coap_resource_set_get_observable(r, 1);
245
246 coap_add_resource(ctx, r);
247 time_resource = r;
248
249 }
250
251 int main(int argc, char *argv[]){
252
253 coap_context_t *ctx = NULL;
254 coap_endpoint_t *ep = NULL;
255 coap_address_t addr;
256 unsigned wait_ms;
257
258 /* Create the libcoap context */
259 ctx = coap_new_context(NULL);
260 if (!ctx) {
261 exit(1);
262 }
263 coap_address_init(&addr);
264 addr.addr.sa.sa_family = AF_INET;
265 addr.addr.sin.sin_port = ntohs(COAP_DEFAULT_PORT);
266 ep = coap_new_endpoint(ctx, &addr, COAP_PROTO_UDP);
267
268 /* Other Set up Code */
269
270 init_resources(ctx);
271
272 wait_ms = COAP_RESOURCE_CHECK_TIME * 1000;
273
274 while (1) {
275 int result = coap_run_once( ctx, wait_ms );
276 if ( result < 0 ) {
277 break;
278 } else if ( result && (unsigned)result < wait_ms ) {
279 /* decrement if there is a result wait time returned */
280 wait_ms -= result;
281 } else {
282 /*
283 * result == 0, or result >= wait_ms
284 * (wait_ms could have decremented to a small value, below
285 * the granularity of the timer in coap_run_once() and hence
286 * result == 0)
287 */
288 time_t t_now = time(NULL);
289 if (t_last != t_now) {
290 /* Happens once per second */
291 int i;
292 t_last = t_now;
293 if (time_resource) {
294 coap_resource_notify_observers(time_resource, NULL);
295 }
296 }
297 if (result) {
298 /* result must have been >= wait_ms, so reset wait_ms */
299 wait_ms = COAP_RESOURCE_CHECK_TIME * 1000;
300 }
301 }
302 }
303 exit(0);
304
305 }
306
307 Client Observe Request Setup
308
309 #include <coap2/coap.h>
310
311 /* Usually, requests are sent confirmable */
312
313 static unsigned char msgtype = COAP_MESSAGE_CON;
314
315 static unsigned int token = 0;
316
317 static coap_pdu_t *
318 coap_new_request(coap_context_t *context, coap_session_t *session, char request_code,
319 coap_optlist_t **options, unsigned char *data, size_t length, int observe) {
320
321 coap_pdu_t *pdu;
322 coap_optlist_t *opt;
323 (void)context;
324
325 /* Create the pdu with the appropriate options */
326 pdu = coap_pdu_init(msgtype, request_code, coap_new_message_id(session),
327 coap_session_max_pdu_size(session));
328 if (!pdu)
329 return NULL;
330
331 /*
332 * Create uniqueness token for this request for handling unsolicited /
333 * delayed responses
334 */
335 token++;
336 if (!coap_add_token(pdu, sizeof(token), (unsigned char*)&token)) {
337 coap_log(LOG_DEBUG, "cannot add token to request\n");
338 goto error;
339 }
340
341 if (request_code == COAP_REQUEST_GET && observe) {
342 /* Indicate that we want to observe this resource */
343 if (!coap_insert_optlist(options,
344 coap_new_optlist(COAP_OPTION_OBSERVE,
345 COAP_OBSERVE_ESTABLISH, NULL)))
346 goto error;
347 }
348
349 /* ... Other code / options etc. ... */
350
351 /* Add in all the options (after internal sorting) to the pdu */
352 if (!coap_add_optlist_pdu(pdu, options))
353 goto error;
354
355 if (data && length) {
356 /* Add in the specified data */
357 if (!coap_add_data(pdu, length, data))
358 goto error;
359 }
360
361 return pdu;
362
363 error:
364
365 coap_delete_pdu(pdu);
366 return NULL;
367
368 }
369
371 coap_attribute(3), coap_context(3), coap_handler(3), coap_pdu_setup(3)
372 and coap_resource(3)
373
375 "RFC7252: The Constrained Application Protocol (CoAP)"
376
377 "RFC7641: Observing Resources in the Constrained Application Protocol
378 (CoAP)"
379
381 Please report bugs on the mailing list for libcoap:
382 libcoap-developers@lists.sourceforge.net
383
385 The libcoap project <libcoap-developers@lists.sourceforge.net>
386
387
388
389coap_observe 4.2.1 02/24/2020 COAP_OBSERVE(3)