1.. _coap_server_interface:
2
3CoAP server
4###########
5
6.. contents::
7    :local:
8    :depth: 2
9
10Overview
11********
12
13Zephyr comes with a batteries-included CoAP server, which uses services to listen for CoAP
14requests. The CoAP services handle communication over sockets and pass requests to registered
15CoAP resources.
16
17Setup
18*****
19
20Some configuration is required to make sure services can be started using the CoAP server. The
21:kconfig:option:`CONFIG_COAP_SERVER` option should be enabled in your project:
22
23.. code-block:: cfg
24    :caption: ``prj.conf``
25
26    CONFIG_COAP_SERVER=y
27
28All services are added to a predefined linker section and all resources for each service also get
29their respective linker sections. If you would have a service ``my_service`` it has to be
30prefixed with ``coap_resource_`` and added to a linker file:
31
32.. code-block:: c
33    :caption: ``sections-ram.ld``
34
35    #include <zephyr/linker/iterable_sections.h>
36
37    ITERABLE_SECTION_RAM(coap_resource_my_service, Z_LINK_ITERABLE_SUBALIGN)
38
39Add this linker file to your application using CMake:
40
41.. code-block:: cmake
42    :caption: ``CMakeLists.txt``
43
44    # Support LD linker template
45    zephyr_linker_sources(DATA_SECTIONS sections-ram.ld)
46
47    # Support CMake linker generator
48    zephyr_iterable_section(NAME coap_resource_my_service
49                            GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT}
50                            SUBALIGN ${CONFIG_LINKER_ITERABLE_SUBALIGN})
51
52You can now define your service as part of the application:
53
54.. code-block:: c
55
56    #include <zephyr/net/coap_service.h>
57
58    static const uint16_t my_service_port = 5683;
59
60    COAP_SERVICE_DEFINE(my_service, "0.0.0.0", &my_service_port, COAP_SERVICE_AUTOSTART);
61
62.. note::
63
64    Services defined with the ``COAP_SERVICE_AUTOSTART`` flag will be started together with the CoAP
65    server thread. Services can be manually started and stopped with ``coap_service_start`` and
66    ``coap_service_stop`` respectively.
67
68Sample Usage
69************
70
71The following is an example of a CoAP resource registered with our service:
72
73.. code-block:: c
74
75    #include <zephyr/net/coap_service.h>
76
77    static int my_get(struct coap_resource *resource, struct coap_packet *request,
78                      struct sockaddr *addr, socklen_t addr_len)
79    {
80        static const char *msg = "Hello, world!";
81        uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE];
82        struct coap_packet response;
83        uint16_t id;
84        uint8_t token[COAP_TOKEN_MAX_LEN];
85        uint8_t tkl, type;
86
87        type = coap_header_get_type(request);
88        id = coap_header_get_id(request);
89        tkl = coap_header_get_token(request, token);
90
91        /* Determine response type */
92        type = (type == COAP_TYPE_CON) ? COAP_TYPE_ACK : COAP_TYPE_NON_CON;
93
94        coap_packet_init(&response, data, sizeof(data), COAP_VERSION_1, type, tkl, token,
95                         COAP_RESPONSE_CODE_CONTENT, id);
96
97        /* Set content format */
98        coap_append_option_int(&response, COAP_OPTION_CONTENT_FORMAT,
99                               COAP_CONTENT_FORMAT_TEXT_PLAIN);
100
101        /* Append payload */
102        coap_packet_append_payload_marker(&response);
103        coap_packet_append_payload(&response, (uint8_t *)msg, sizeof(msg));
104
105        /* Send to response back to the client */
106        return coap_resource_send(resource, &response, addr, addr_len, NULL);
107    }
108
109    static int my_put(struct coap_resource *resource, struct coap_packet *request,
110                      struct sockaddr *addr, socklen_t addr_len)
111    {
112        /* ... Handle the incoming request ... */
113
114        /* Return a CoAP response code as a shortcut for an empty ACK message */
115        return COAP_RESPONSE_CODE_CHANGED;
116    }
117
118    static const char * const my_resource_path[] = { "test", NULL };
119    COAP_RESOURCE_DEFINE(my_resource, my_service, {
120        .path = my_resource_path,
121        .get = my_get,
122        .put = my_put,
123    });
124
125.. note::
126
127    As demonstrated in the example above, a CoAP resource handler can return response codes to let
128    the server respond with an empty ACK response.
129
130Observable resources
131********************
132
133The CoAP server provides logic for parsing observe requests and stores these using the runtime data
134of CoAP services. An example using a temperature sensor can look like:
135
136.. code-block:: c
137
138    #include <zephyr/kernel.h>
139    #include <zephyr/drivers/sensor.h>
140    #include <zephyr/net/coap_service.h>
141
142    static void notify_observers(struct k_work *work);
143    K_WORK_DELAYABLE_DEFINE(temp_work, notify_observers);
144
145    static int send_temperature(struct coap_resource *resource,
146                                const struct sockaddr *addr, socklen_t addr_len,
147                                uint16_t age, uint16_t id, const uint8_t *token, uint8_t tkl,
148                                bool is_response)
149    {
150        const struct device *dev = DEVICE_DT_GET(DT_ALIAS(ambient_temp0));
151        uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE];
152        struct coap_packet response;
153        char payload[14];
154        struct sensor_value value;
155        double temp;
156        uint8_t type;
157
158        /* Determine response type */
159        type = is_response ? COAP_TYPE_ACK : COAP_TYPE_CON;
160
161        if (!is_response) {
162            id = coap_next_id();
163        }
164
165        coap_packet_init(&response, data, sizeof(data), COAP_VERSION_1, type, tkl, token,
166                         COAP_RESPONSE_CODE_CONTENT, id);
167
168        if (age >= 2U) {
169            coap_append_option_int(&response, COAP_OPTION_OBSERVE, age);
170        }
171
172        /* Set content format */
173        coap_append_option_int(&response, COAP_OPTION_CONTENT_FORMAT,
174                               COAP_CONTENT_FORMAT_TEXT_PLAIN);
175
176        /* Get the sensor data */
177        sensor_sample_fetch_chan(dev, SENSOR_CHAN_AMBIENT_TEMP);
178        sensor_channel_get(dev, SENSOR_CHAN_AMBIENT_TEMP, &value);
179        temp = sensor_value_to_double(&value);
180
181        snprintk(payload, sizeof(payload), "%0.2f°C", temp);
182
183        /* Append payload */
184        coap_packet_append_payload_marker(&response);
185        coap_packet_append_payload(&response, (uint8_t *)payload, strlen(payload));
186
187        return coap_resource_send(resource, &response, addr, addr_len, NULL);
188    }
189
190    static int temp_get(struct coap_resource *resource, struct coap_packet *request,
191                        struct sockaddr *addr, socklen_t addr_len)
192    {
193        uint8_t token[COAP_TOKEN_MAX_LEN];
194        uint16_t id;
195        uint8_t tkl;
196        int r;
197
198        /* Let the CoAP server parse the request and add/remove observers if needed */
199        r = coap_resource_parse_observe(resource, request, addr);
200
201        id = coap_header_get_id(request);
202        tkl = coap_header_get_token(request, token);
203
204        return send_temperature(resource, addr, addr_len, r == 0 ? resource->age : 0,
205                                id, token, tkl, true);
206    }
207
208    static void temp_notify(struct coap_resource *resource, struct coap_observer *observer)
209    {
210        send_temperature(resource, &observer->addr, sizeof(observer->addr), resource->age, 0,
211                         observer->token, observer->tkl, false);
212    }
213
214    static const char * const temp_resource_path[] = { "sensors", "temp1", NULL };
215    COAP_RESOURCE_DEFINE(temp_resource, my_service, {
216        .path = temp_resource_path,
217        .get = temp_get,
218        .notify = temp_notify,
219    });
220
221    static void notify_observers(struct k_work *work)
222    {
223        if (sys_slist_is_empty(&temp_resource.observers)) {
224            return;
225        }
226
227        coap_resource_notify(&temp_resource);
228        k_work_reschedule(&temp_work, K_SECONDS(1));
229    }
230
231CoAP Events
232***********
233
234By enabling :kconfig:option:`CONFIG_NET_MGMT_EVENT` the user can register for CoAP events. The
235following example simply prints when an event occurs.
236
237.. code-block:: c
238
239    #include <zephyr/sys/printk.h>
240    #include <zephyr/net/coap_mgmt.h>
241    #include <zephyr/net/coap_service.h>
242
243    #define COAP_EVENTS_SET (NET_EVENT_COAP_OBSERVER_ADDED | NET_EVENT_COAP_OBSERVER_REMOVED | \
244                             NET_EVENT_COAP_SERVICE_STARTED | NET_EVENT_COAP_SERVICE_STOPPED)
245
246    void coap_event_handler(uint32_t mgmt_event, struct net_if *iface,
247                            void *info, size_t info_length, void *user_data)
248    {
249        switch (mgmt_event) {
250        case NET_EVENT_COAP_OBSERVER_ADDED:
251            printk("CoAP observer added");
252            break;
253        case NET_EVENT_COAP_OBSERVER_REMOVED:
254            printk("CoAP observer removed");
255            break;
256        case NET_EVENT_COAP_SERVICE_STARTED:
257            if (info != NULL && info_length == sizeof(struct net_event_coap_service)) {
258                struct net_event_coap_service *net_event = info;
259
260                printk("CoAP service %s started", net_event->service->name);
261            } else {
262                printk("CoAP service started");
263            }
264            break;
265        case NET_EVENT_COAP_SERVICE_STOPPED:
266            if (info != NULL && info_length == sizeof(struct net_event_coap_service)) {
267                struct net_event_coap_service *net_event = info;
268
269                printk("CoAP service %s stopped", net_event->service->name);
270            } else {
271                printk("CoAP service stopped");
272            }
273            break;
274        }
275    }
276
277    NET_MGMT_REGISTER_EVENT_HANDLER(coap_events, COAP_EVENTS_SET, coap_event_handler, NULL);
278
279CoRE Link Format
280****************
281
282The :kconfig:option:`CONFIG_COAP_SERVER_WELL_KNOWN_CORE` option enables handling the
283``.well-known/core`` GET requests by the server. This allows clients to get a list of hypermedia
284links to other resources hosted in that server.
285
286API Reference
287*************
288
289.. doxygengroup:: coap_service
290.. doxygengroup:: coap_mgmt
291