CoAP server ported from Arduino microcoap

Dependencies:   EthernetInterface Socket mbed-rtos mbed

Committer:
rfrenken
Date:
Thu Mar 23 16:29:41 2017 +0000
Revision:
0:64df7fc091da
Coap Server ported from Arduino microcoap

Who changed what in which revision?

UserRevisionLine numberNew contents of line
rfrenken 0:64df7fc091da 1 #include "mbed.h"
rfrenken 0:64df7fc091da 2 #include "EthernetInterface.h"
rfrenken 0:64df7fc091da 3 #include <stdio.h>
rfrenken 0:64df7fc091da 4 #include <stdlib.h>
rfrenken 0:64df7fc091da 5 #include <stdint.h>
rfrenken 0:64df7fc091da 6 #include <stdbool.h>
rfrenken 0:64df7fc091da 7 #include <string.h>
rfrenken 0:64df7fc091da 8 #include <stddef.h>
rfrenken 0:64df7fc091da 9 #include "coap.h"
rfrenken 0:64df7fc091da 10
rfrenken 0:64df7fc091da 11 #define PORT 5683
rfrenken 0:64df7fc091da 12
rfrenken 0:64df7fc091da 13 extern void endpoint_setup(void);
rfrenken 0:64df7fc091da 14 extern const coap_endpoint_t endpoints[];
rfrenken 0:64df7fc091da 15 #define UDP_TX_PACKET_MAX_SIZE 256
rfrenken 0:64df7fc091da 16
rfrenken 0:64df7fc091da 17
rfrenken 0:64df7fc091da 18
rfrenken 0:64df7fc091da 19 #ifdef DEBUG
rfrenken 0:64df7fc091da 20 void coap_dumpHeader(coap_header_t *hdr)
rfrenken 0:64df7fc091da 21 {
rfrenken 0:64df7fc091da 22 printf("Header:\n");
rfrenken 0:64df7fc091da 23 printf(" ver 0x%02X\n", hdr->ver);
rfrenken 0:64df7fc091da 24 printf(" t 0x%02X\n", hdr->t);
rfrenken 0:64df7fc091da 25 printf(" tkl 0x%02X\n", hdr->tkl);
rfrenken 0:64df7fc091da 26 printf(" code 0x%02X\n", hdr->code);
rfrenken 0:64df7fc091da 27 printf(" id 0x%02X%02X\n", hdr->id[0], hdr->id[1]);
rfrenken 0:64df7fc091da 28 }
rfrenken 0:64df7fc091da 29 #endif
rfrenken 0:64df7fc091da 30
rfrenken 0:64df7fc091da 31 #ifdef DEBUG
rfrenken 0:64df7fc091da 32 void coap_dump(const uint8_t *buf, size_t buflen, bool bare)
rfrenken 0:64df7fc091da 33 {
rfrenken 0:64df7fc091da 34 if (bare)
rfrenken 0:64df7fc091da 35 {
rfrenken 0:64df7fc091da 36 while(buflen--)
rfrenken 0:64df7fc091da 37 printf("%02X%s", *buf++, (buflen > 0) ? " " : "");
rfrenken 0:64df7fc091da 38 }
rfrenken 0:64df7fc091da 39 else
rfrenken 0:64df7fc091da 40 {
rfrenken 0:64df7fc091da 41 printf("Dump: ");
rfrenken 0:64df7fc091da 42 while(buflen--)
rfrenken 0:64df7fc091da 43 printf("%02X%s", *buf++, (buflen > 0) ? " " : "");
rfrenken 0:64df7fc091da 44 printf("\n");
rfrenken 0:64df7fc091da 45 }
rfrenken 0:64df7fc091da 46 }
rfrenken 0:64df7fc091da 47 #endif
rfrenken 0:64df7fc091da 48
rfrenken 0:64df7fc091da 49 int coap_parseHeader(coap_header_t *hdr, const uint8_t *buf, size_t buflen)
rfrenken 0:64df7fc091da 50 {
rfrenken 0:64df7fc091da 51 if (buflen < 4)
rfrenken 0:64df7fc091da 52 return COAP_ERR_HEADER_TOO_SHORT;
rfrenken 0:64df7fc091da 53 hdr->ver = (buf[0] & 0xC0) >> 6;
rfrenken 0:64df7fc091da 54 if (hdr->ver != 1)
rfrenken 0:64df7fc091da 55 {
rfrenken 0:64df7fc091da 56 printf("hdr versions is %d\n", hdr->ver);
rfrenken 0:64df7fc091da 57 return COAP_ERR_VERSION_NOT_1;
rfrenken 0:64df7fc091da 58 }
rfrenken 0:64df7fc091da 59 hdr->t = (buf[0] & 0x30) >> 4;
rfrenken 0:64df7fc091da 60 hdr->tkl = buf[0] & 0x0F;
rfrenken 0:64df7fc091da 61 hdr->code = buf[1];
rfrenken 0:64df7fc091da 62 hdr->id[0] = buf[2];
rfrenken 0:64df7fc091da 63 hdr->id[1] = buf[3];
rfrenken 0:64df7fc091da 64 return 0;
rfrenken 0:64df7fc091da 65 }
rfrenken 0:64df7fc091da 66
rfrenken 0:64df7fc091da 67 int coap_parseToken(coap_buffer_t *tokbuf, const coap_header_t *hdr, const uint8_t *buf, size_t buflen)
rfrenken 0:64df7fc091da 68 {
rfrenken 0:64df7fc091da 69 if (hdr->tkl == 0)
rfrenken 0:64df7fc091da 70 {
rfrenken 0:64df7fc091da 71 tokbuf->p = NULL;
rfrenken 0:64df7fc091da 72 tokbuf->len = 0;
rfrenken 0:64df7fc091da 73 return 0;
rfrenken 0:64df7fc091da 74 }
rfrenken 0:64df7fc091da 75 else
rfrenken 0:64df7fc091da 76 if (hdr->tkl <= 8)
rfrenken 0:64df7fc091da 77 {
rfrenken 0:64df7fc091da 78 if (4U + hdr->tkl > buflen)
rfrenken 0:64df7fc091da 79 return COAP_ERR_TOKEN_TOO_SHORT; // tok bigger than packet
rfrenken 0:64df7fc091da 80 tokbuf->p = buf+4; // past header
rfrenken 0:64df7fc091da 81 tokbuf->len = hdr->tkl;
rfrenken 0:64df7fc091da 82 return 0;
rfrenken 0:64df7fc091da 83 }
rfrenken 0:64df7fc091da 84 else
rfrenken 0:64df7fc091da 85 {
rfrenken 0:64df7fc091da 86 // invalid size
rfrenken 0:64df7fc091da 87 return COAP_ERR_TOKEN_TOO_SHORT;
rfrenken 0:64df7fc091da 88 }
rfrenken 0:64df7fc091da 89 }
rfrenken 0:64df7fc091da 90
rfrenken 0:64df7fc091da 91 // advances p
rfrenken 0:64df7fc091da 92 int coap_parseOption(coap_option_t *option, uint16_t *running_delta, const uint8_t **buf, size_t buflen)
rfrenken 0:64df7fc091da 93 {
rfrenken 0:64df7fc091da 94 const uint8_t *p = *buf;
rfrenken 0:64df7fc091da 95 uint8_t headlen = 1;
rfrenken 0:64df7fc091da 96 uint16_t len, delta;
rfrenken 0:64df7fc091da 97
rfrenken 0:64df7fc091da 98 if (buflen < headlen) // too small
rfrenken 0:64df7fc091da 99 return COAP_ERR_OPTION_TOO_SHORT_FOR_HEADER;
rfrenken 0:64df7fc091da 100
rfrenken 0:64df7fc091da 101 delta = (p[0] & 0xF0) >> 4;
rfrenken 0:64df7fc091da 102 len = p[0] & 0x0F;
rfrenken 0:64df7fc091da 103
rfrenken 0:64df7fc091da 104 // These are untested and may be buggy
rfrenken 0:64df7fc091da 105 if (delta == 13)
rfrenken 0:64df7fc091da 106 {
rfrenken 0:64df7fc091da 107 headlen++;
rfrenken 0:64df7fc091da 108 if (buflen < headlen)
rfrenken 0:64df7fc091da 109 return COAP_ERR_OPTION_TOO_SHORT_FOR_HEADER;
rfrenken 0:64df7fc091da 110 delta = p[1] + 13;
rfrenken 0:64df7fc091da 111 p++;
rfrenken 0:64df7fc091da 112 }
rfrenken 0:64df7fc091da 113 else
rfrenken 0:64df7fc091da 114 if (delta == 14)
rfrenken 0:64df7fc091da 115 {
rfrenken 0:64df7fc091da 116 headlen += 2;
rfrenken 0:64df7fc091da 117 if (buflen < headlen)
rfrenken 0:64df7fc091da 118 return COAP_ERR_OPTION_TOO_SHORT_FOR_HEADER;
rfrenken 0:64df7fc091da 119 delta = ((p[1] << 8) | p[2]) + 269;
rfrenken 0:64df7fc091da 120 p+=2;
rfrenken 0:64df7fc091da 121 }
rfrenken 0:64df7fc091da 122 else
rfrenken 0:64df7fc091da 123 if (delta == 15)
rfrenken 0:64df7fc091da 124 return COAP_ERR_OPTION_DELTA_INVALID;
rfrenken 0:64df7fc091da 125
rfrenken 0:64df7fc091da 126 if (len == 13)
rfrenken 0:64df7fc091da 127 {
rfrenken 0:64df7fc091da 128 headlen++;
rfrenken 0:64df7fc091da 129 if (buflen < headlen)
rfrenken 0:64df7fc091da 130 return COAP_ERR_OPTION_TOO_SHORT_FOR_HEADER;
rfrenken 0:64df7fc091da 131 len = p[1] + 13;
rfrenken 0:64df7fc091da 132 p++;
rfrenken 0:64df7fc091da 133 }
rfrenken 0:64df7fc091da 134 else
rfrenken 0:64df7fc091da 135 if (len == 14)
rfrenken 0:64df7fc091da 136 {
rfrenken 0:64df7fc091da 137 headlen += 2;
rfrenken 0:64df7fc091da 138 if (buflen < headlen)
rfrenken 0:64df7fc091da 139 return COAP_ERR_OPTION_TOO_SHORT_FOR_HEADER;
rfrenken 0:64df7fc091da 140 len = ((p[1] << 8) | p[2]) + 269;
rfrenken 0:64df7fc091da 141 p+=2;
rfrenken 0:64df7fc091da 142 }
rfrenken 0:64df7fc091da 143 else
rfrenken 0:64df7fc091da 144 if (len == 15)
rfrenken 0:64df7fc091da 145 return COAP_ERR_OPTION_LEN_INVALID;
rfrenken 0:64df7fc091da 146
rfrenken 0:64df7fc091da 147 if ((p + 1 + len) > (*buf + buflen))
rfrenken 0:64df7fc091da 148 return COAP_ERR_OPTION_TOO_BIG;
rfrenken 0:64df7fc091da 149
rfrenken 0:64df7fc091da 150 //printf("option num=%d\n", delta + *running_delta);
rfrenken 0:64df7fc091da 151 option->num = delta + *running_delta;
rfrenken 0:64df7fc091da 152 option->buf.p = p+1;
rfrenken 0:64df7fc091da 153 option->buf.len = len;
rfrenken 0:64df7fc091da 154 //coap_dump(p+1, len, false);
rfrenken 0:64df7fc091da 155
rfrenken 0:64df7fc091da 156 // advance buf
rfrenken 0:64df7fc091da 157 *buf = p + 1 + len;
rfrenken 0:64df7fc091da 158 *running_delta += delta;
rfrenken 0:64df7fc091da 159
rfrenken 0:64df7fc091da 160 return 0;
rfrenken 0:64df7fc091da 161 }
rfrenken 0:64df7fc091da 162
rfrenken 0:64df7fc091da 163 // http://tools.ietf.org/html/rfc7252#section-3.1
rfrenken 0:64df7fc091da 164 int coap_parseOptionsAndPayload(coap_option_t *options, uint8_t *numOptions, coap_buffer_t *payload, const coap_header_t *hdr, const uint8_t *buf, size_t buflen)
rfrenken 0:64df7fc091da 165 {
rfrenken 0:64df7fc091da 166 size_t optionIndex = 0;
rfrenken 0:64df7fc091da 167 uint16_t delta = 0;
rfrenken 0:64df7fc091da 168 const uint8_t *p = buf + 4 + hdr->tkl;
rfrenken 0:64df7fc091da 169 const uint8_t *end = buf + buflen;
rfrenken 0:64df7fc091da 170 int rc;
rfrenken 0:64df7fc091da 171 if (p > end)
rfrenken 0:64df7fc091da 172 return COAP_ERR_OPTION_OVERRUNS_PACKET; // out of bounds
rfrenken 0:64df7fc091da 173
rfrenken 0:64df7fc091da 174 //coap_dump(p, end - p);
rfrenken 0:64df7fc091da 175
rfrenken 0:64df7fc091da 176 // 0xFF is payload marker
rfrenken 0:64df7fc091da 177 while((optionIndex < *numOptions) && (p < end) && (*p != 0xFF))
rfrenken 0:64df7fc091da 178 {
rfrenken 0:64df7fc091da 179 if (0 != (rc = coap_parseOption(&options[optionIndex], &delta, &p, end-p)))
rfrenken 0:64df7fc091da 180 return rc;
rfrenken 0:64df7fc091da 181 optionIndex++;
rfrenken 0:64df7fc091da 182 }
rfrenken 0:64df7fc091da 183 *numOptions = optionIndex;
rfrenken 0:64df7fc091da 184
rfrenken 0:64df7fc091da 185 if (p+1 < end && *p == 0xFF) // payload marker
rfrenken 0:64df7fc091da 186 {
rfrenken 0:64df7fc091da 187 payload->p = p+1;
rfrenken 0:64df7fc091da 188 payload->len = end-(p+1);
rfrenken 0:64df7fc091da 189 }
rfrenken 0:64df7fc091da 190 else
rfrenken 0:64df7fc091da 191 {
rfrenken 0:64df7fc091da 192 payload->p = NULL;
rfrenken 0:64df7fc091da 193 payload->len = 0;
rfrenken 0:64df7fc091da 194 }
rfrenken 0:64df7fc091da 195
rfrenken 0:64df7fc091da 196 return 0;
rfrenken 0:64df7fc091da 197 }
rfrenken 0:64df7fc091da 198
rfrenken 0:64df7fc091da 199 #ifdef DEBUG
rfrenken 0:64df7fc091da 200 void coap_dumpOptions(coap_option_t *opts, size_t numopt)
rfrenken 0:64df7fc091da 201 {
rfrenken 0:64df7fc091da 202 size_t i;
rfrenken 0:64df7fc091da 203 printf(" Options:\n");
rfrenken 0:64df7fc091da 204 for (i=0;i<numopt;i++)
rfrenken 0:64df7fc091da 205 {
rfrenken 0:64df7fc091da 206 printf(" 0x%02X [ ", opts[i].num);
rfrenken 0:64df7fc091da 207 coap_dump(opts[i].buf.p, opts[i].buf.len, true);
rfrenken 0:64df7fc091da 208 printf(" ]\n");
rfrenken 0:64df7fc091da 209 }
rfrenken 0:64df7fc091da 210 }
rfrenken 0:64df7fc091da 211 #endif
rfrenken 0:64df7fc091da 212
rfrenken 0:64df7fc091da 213 #ifdef DEBUG
rfrenken 0:64df7fc091da 214 void coap_dumpPacket(coap_packet_t *pkt)
rfrenken 0:64df7fc091da 215 {
rfrenken 0:64df7fc091da 216 coap_dumpHeader(&pkt->hdr);
rfrenken 0:64df7fc091da 217 coap_dumpOptions(pkt->opts, pkt->numopts);
rfrenken 0:64df7fc091da 218 printf("Payload: ");
rfrenken 0:64df7fc091da 219 coap_dump(pkt->payload.p, pkt->payload.len, true);
rfrenken 0:64df7fc091da 220 printf("\n");
rfrenken 0:64df7fc091da 221 }
rfrenken 0:64df7fc091da 222 #endif
rfrenken 0:64df7fc091da 223
rfrenken 0:64df7fc091da 224 int coap_parse(coap_packet_t *pkt, const uint8_t *buf, size_t buflen)
rfrenken 0:64df7fc091da 225 {
rfrenken 0:64df7fc091da 226 int rc;
rfrenken 0:64df7fc091da 227
rfrenken 0:64df7fc091da 228 // coap_dump(buf, buflen, false);
rfrenken 0:64df7fc091da 229
rfrenken 0:64df7fc091da 230 if (0 != (rc = coap_parseHeader(&pkt->hdr, buf, buflen)))
rfrenken 0:64df7fc091da 231 return rc;
rfrenken 0:64df7fc091da 232 // coap_dumpHeader(&hdr);
rfrenken 0:64df7fc091da 233 if (0 != (rc = coap_parseToken(&pkt->tok, &pkt->hdr, buf, buflen)))
rfrenken 0:64df7fc091da 234 return rc;
rfrenken 0:64df7fc091da 235 pkt->numopts = MAXOPT;
rfrenken 0:64df7fc091da 236 if (0 != (rc = coap_parseOptionsAndPayload(pkt->opts, &(pkt->numopts), &(pkt->payload), &pkt->hdr, buf, buflen)))
rfrenken 0:64df7fc091da 237 return rc;
rfrenken 0:64df7fc091da 238 // coap_dumpOptions(opts, numopt);
rfrenken 0:64df7fc091da 239 return 0;
rfrenken 0:64df7fc091da 240 }
rfrenken 0:64df7fc091da 241
rfrenken 0:64df7fc091da 242 // options are always stored consecutively, so can return a block with same option num
rfrenken 0:64df7fc091da 243 const coap_option_t *coap_findOptions(const coap_packet_t *pkt, uint8_t num, uint8_t *count)
rfrenken 0:64df7fc091da 244 {
rfrenken 0:64df7fc091da 245 // FIXME, options is always sorted, can find faster than this
rfrenken 0:64df7fc091da 246 size_t i;
rfrenken 0:64df7fc091da 247 const coap_option_t *first = NULL;
rfrenken 0:64df7fc091da 248 *count = 0;
rfrenken 0:64df7fc091da 249 for (i=0;i<pkt->numopts;i++)
rfrenken 0:64df7fc091da 250 {
rfrenken 0:64df7fc091da 251 if (pkt->opts[i].num == num)
rfrenken 0:64df7fc091da 252 {
rfrenken 0:64df7fc091da 253 if (NULL == first)
rfrenken 0:64df7fc091da 254 first = &pkt->opts[i];
rfrenken 0:64df7fc091da 255 (*count)++;
rfrenken 0:64df7fc091da 256 }
rfrenken 0:64df7fc091da 257 else
rfrenken 0:64df7fc091da 258 {
rfrenken 0:64df7fc091da 259 if (NULL != first)
rfrenken 0:64df7fc091da 260 break;
rfrenken 0:64df7fc091da 261 }
rfrenken 0:64df7fc091da 262 }
rfrenken 0:64df7fc091da 263 return first;
rfrenken 0:64df7fc091da 264 }
rfrenken 0:64df7fc091da 265
rfrenken 0:64df7fc091da 266 int coap_buffer_to_string(char *strbuf, size_t strbuflen, const coap_buffer_t *buf)
rfrenken 0:64df7fc091da 267 {
rfrenken 0:64df7fc091da 268 if (buf->len+1 > strbuflen)
rfrenken 0:64df7fc091da 269 return COAP_ERR_BUFFER_TOO_SMALL;
rfrenken 0:64df7fc091da 270 memcpy(strbuf, buf->p, buf->len);
rfrenken 0:64df7fc091da 271 strbuf[buf->len] = 0;
rfrenken 0:64df7fc091da 272 return 0;
rfrenken 0:64df7fc091da 273 }
rfrenken 0:64df7fc091da 274
rfrenken 0:64df7fc091da 275 int coap_build(uint8_t *buf, size_t *buflen, const coap_packet_t *pkt)
rfrenken 0:64df7fc091da 276 {
rfrenken 0:64df7fc091da 277 size_t opts_len = 0;
rfrenken 0:64df7fc091da 278 size_t i;
rfrenken 0:64df7fc091da 279 uint8_t *p;
rfrenken 0:64df7fc091da 280 uint16_t running_delta = 0;
rfrenken 0:64df7fc091da 281
rfrenken 0:64df7fc091da 282 // build header
rfrenken 0:64df7fc091da 283 if (*buflen < (4U + pkt->hdr.tkl))
rfrenken 0:64df7fc091da 284 return COAP_ERR_BUFFER_TOO_SMALL;
rfrenken 0:64df7fc091da 285
rfrenken 0:64df7fc091da 286 buf[0] = (pkt->hdr.ver & 0x03) << 6;
rfrenken 0:64df7fc091da 287 buf[0] |= (pkt->hdr.t & 0x03) << 4;
rfrenken 0:64df7fc091da 288 buf[0] |= (pkt->hdr.tkl & 0x0F);
rfrenken 0:64df7fc091da 289 buf[1] = pkt->hdr.code;
rfrenken 0:64df7fc091da 290 buf[2] = pkt->hdr.id[0];
rfrenken 0:64df7fc091da 291 buf[3] = pkt->hdr.id[1];
rfrenken 0:64df7fc091da 292
rfrenken 0:64df7fc091da 293 // inject token
rfrenken 0:64df7fc091da 294 p = buf + 4;
rfrenken 0:64df7fc091da 295 if ((pkt->hdr.tkl > 0) && (pkt->hdr.tkl != pkt->tok.len))
rfrenken 0:64df7fc091da 296 return COAP_ERR_UNSUPPORTED;
rfrenken 0:64df7fc091da 297
rfrenken 0:64df7fc091da 298 if (pkt->hdr.tkl > 0)
rfrenken 0:64df7fc091da 299 memcpy(p, pkt->tok.p, pkt->hdr.tkl);
rfrenken 0:64df7fc091da 300
rfrenken 0:64df7fc091da 301 // // http://tools.ietf.org/html/rfc7252#section-3.1
rfrenken 0:64df7fc091da 302 // inject options
rfrenken 0:64df7fc091da 303 p += pkt->hdr.tkl;
rfrenken 0:64df7fc091da 304
rfrenken 0:64df7fc091da 305 for (i=0;i<pkt->numopts;i++)
rfrenken 0:64df7fc091da 306 {
rfrenken 0:64df7fc091da 307 uint32_t optDelta;
rfrenken 0:64df7fc091da 308 uint8_t len, delta = 0;
rfrenken 0:64df7fc091da 309
rfrenken 0:64df7fc091da 310 if (((size_t)(p-buf)) > *buflen)
rfrenken 0:64df7fc091da 311 return COAP_ERR_BUFFER_TOO_SMALL;
rfrenken 0:64df7fc091da 312 optDelta = pkt->opts[i].num - running_delta;
rfrenken 0:64df7fc091da 313 coap_option_nibble(optDelta, &delta);
rfrenken 0:64df7fc091da 314 coap_option_nibble((uint32_t)pkt->opts[i].buf.len, &len);
rfrenken 0:64df7fc091da 315
rfrenken 0:64df7fc091da 316 *p++ = (0xFF & (delta << 4 | len));
rfrenken 0:64df7fc091da 317 if (delta == 13)
rfrenken 0:64df7fc091da 318 {
rfrenken 0:64df7fc091da 319 *p++ = (optDelta - 13);
rfrenken 0:64df7fc091da 320 }
rfrenken 0:64df7fc091da 321 else
rfrenken 0:64df7fc091da 322 if (delta == 14)
rfrenken 0:64df7fc091da 323 {
rfrenken 0:64df7fc091da 324 *p++ = ((optDelta-269) >> 8);
rfrenken 0:64df7fc091da 325 *p++ = (0xFF & (optDelta-269));
rfrenken 0:64df7fc091da 326 }
rfrenken 0:64df7fc091da 327 if (len == 13)
rfrenken 0:64df7fc091da 328 {
rfrenken 0:64df7fc091da 329 *p++ = (pkt->opts[i].buf.len - 13);
rfrenken 0:64df7fc091da 330 }
rfrenken 0:64df7fc091da 331 else
rfrenken 0:64df7fc091da 332 if (len == 14)
rfrenken 0:64df7fc091da 333 {
rfrenken 0:64df7fc091da 334 *p++ = (pkt->opts[i].buf.len >> 8);
rfrenken 0:64df7fc091da 335 *p++ = (0xFF & (pkt->opts[i].buf.len-269));
rfrenken 0:64df7fc091da 336 }
rfrenken 0:64df7fc091da 337
rfrenken 0:64df7fc091da 338 memcpy(p, pkt->opts[i].buf.p, pkt->opts[i].buf.len);
rfrenken 0:64df7fc091da 339 p += pkt->opts[i].buf.len;
rfrenken 0:64df7fc091da 340 running_delta = pkt->opts[i].num;
rfrenken 0:64df7fc091da 341 }
rfrenken 0:64df7fc091da 342
rfrenken 0:64df7fc091da 343 opts_len = (p - buf) - 4; // number of bytes used by options
rfrenken 0:64df7fc091da 344
rfrenken 0:64df7fc091da 345 if (pkt->payload.len > 0)
rfrenken 0:64df7fc091da 346 {
rfrenken 0:64df7fc091da 347 if (*buflen < 4 + 1 + pkt->payload.len + opts_len)
rfrenken 0:64df7fc091da 348 return COAP_ERR_BUFFER_TOO_SMALL;
rfrenken 0:64df7fc091da 349 buf[4 + opts_len] = 0xFF; // payload marker
rfrenken 0:64df7fc091da 350 memcpy(buf+5 + opts_len, pkt->payload.p, pkt->payload.len);
rfrenken 0:64df7fc091da 351 *buflen = opts_len + 5 + pkt->payload.len;
rfrenken 0:64df7fc091da 352 }
rfrenken 0:64df7fc091da 353 else
rfrenken 0:64df7fc091da 354 *buflen = opts_len + 4;
rfrenken 0:64df7fc091da 355 return 0;
rfrenken 0:64df7fc091da 356 }
rfrenken 0:64df7fc091da 357
rfrenken 0:64df7fc091da 358 void coap_option_nibble(uint32_t value, uint8_t *nibble)
rfrenken 0:64df7fc091da 359 {
rfrenken 0:64df7fc091da 360 if (value<13)
rfrenken 0:64df7fc091da 361 {
rfrenken 0:64df7fc091da 362 *nibble = (0xFF & value);
rfrenken 0:64df7fc091da 363 }
rfrenken 0:64df7fc091da 364 else
rfrenken 0:64df7fc091da 365 if (value<=0xFF+13)
rfrenken 0:64df7fc091da 366 {
rfrenken 0:64df7fc091da 367 *nibble = 13;
rfrenken 0:64df7fc091da 368 } else if (value<=0xFFFF+269)
rfrenken 0:64df7fc091da 369 {
rfrenken 0:64df7fc091da 370 *nibble = 14;
rfrenken 0:64df7fc091da 371 }
rfrenken 0:64df7fc091da 372 }
rfrenken 0:64df7fc091da 373
rfrenken 0:64df7fc091da 374 int coap_make_response(coap_rw_buffer_t *scratch, coap_packet_t *pkt, const uint8_t *content, size_t content_len, uint8_t msgid_hi, uint8_t msgid_lo, const coap_buffer_t* tok, coap_responsecode_t rspcode, coap_content_type_t content_type)
rfrenken 0:64df7fc091da 375 {
rfrenken 0:64df7fc091da 376 pkt->hdr.ver = 0x01;
rfrenken 0:64df7fc091da 377 pkt->hdr.t = COAP_TYPE_ACK;
rfrenken 0:64df7fc091da 378 pkt->hdr.tkl = 0;
rfrenken 0:64df7fc091da 379 pkt->hdr.code = rspcode;
rfrenken 0:64df7fc091da 380 pkt->hdr.id[0] = msgid_hi;
rfrenken 0:64df7fc091da 381 pkt->hdr.id[1] = msgid_lo;
rfrenken 0:64df7fc091da 382 pkt->numopts = 1;
rfrenken 0:64df7fc091da 383
rfrenken 0:64df7fc091da 384 // need token in response
rfrenken 0:64df7fc091da 385 if (tok) {
rfrenken 0:64df7fc091da 386 pkt->hdr.tkl = tok->len;
rfrenken 0:64df7fc091da 387 pkt->tok = *tok;
rfrenken 0:64df7fc091da 388 }
rfrenken 0:64df7fc091da 389
rfrenken 0:64df7fc091da 390 // safe because 1 < MAXOPT
rfrenken 0:64df7fc091da 391 pkt->opts[0].num = COAP_OPTION_CONTENT_FORMAT;
rfrenken 0:64df7fc091da 392 pkt->opts[0].buf.p = scratch->p;
rfrenken 0:64df7fc091da 393 if (scratch->len < 2)
rfrenken 0:64df7fc091da 394 return COAP_ERR_BUFFER_TOO_SMALL;
rfrenken 0:64df7fc091da 395 scratch->p[0] = ((uint16_t)content_type & 0xFF00) >> 8;
rfrenken 0:64df7fc091da 396 scratch->p[1] = ((uint16_t)content_type & 0x00FF);
rfrenken 0:64df7fc091da 397 pkt->opts[0].buf.len = 2;
rfrenken 0:64df7fc091da 398 pkt->payload.p = content;
rfrenken 0:64df7fc091da 399 pkt->payload.len = content_len;
rfrenken 0:64df7fc091da 400 return 0;
rfrenken 0:64df7fc091da 401 }
rfrenken 0:64df7fc091da 402
rfrenken 0:64df7fc091da 403 // FIXME, if this looked in the table at the path before the method then
rfrenken 0:64df7fc091da 404 // it could more easily return 405 errors
rfrenken 0:64df7fc091da 405 int coap_handle_req(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt)
rfrenken 0:64df7fc091da 406 {
rfrenken 0:64df7fc091da 407 const coap_option_t *opt;
rfrenken 0:64df7fc091da 408 uint8_t count;
rfrenken 0:64df7fc091da 409 int i;
rfrenken 0:64df7fc091da 410 const coap_endpoint_t *ep = endpoints;
rfrenken 0:64df7fc091da 411
rfrenken 0:64df7fc091da 412 while(NULL != ep->handler)
rfrenken 0:64df7fc091da 413 {
rfrenken 0:64df7fc091da 414 if (ep->method != inpkt->hdr.code)
rfrenken 0:64df7fc091da 415 goto next;
rfrenken 0:64df7fc091da 416 if (NULL != (opt = coap_findOptions(inpkt, COAP_OPTION_URI_PATH, &count)))
rfrenken 0:64df7fc091da 417 {
rfrenken 0:64df7fc091da 418 if (count != ep->path->count)
rfrenken 0:64df7fc091da 419 goto next;
rfrenken 0:64df7fc091da 420 for (i=0;i<count;i++)
rfrenken 0:64df7fc091da 421 {
rfrenken 0:64df7fc091da 422 if (opt[i].buf.len != strlen(ep->path->elems[i]))
rfrenken 0:64df7fc091da 423 goto next;
rfrenken 0:64df7fc091da 424 if (0 != memcmp(ep->path->elems[i], opt[i].buf.p, opt[i].buf.len))
rfrenken 0:64df7fc091da 425 goto next;
rfrenken 0:64df7fc091da 426 }
rfrenken 0:64df7fc091da 427 // match!
rfrenken 0:64df7fc091da 428 return ep->handler(scratch, inpkt, outpkt, inpkt->hdr.id[0], inpkt->hdr.id[1]);
rfrenken 0:64df7fc091da 429 }
rfrenken 0:64df7fc091da 430 next:
rfrenken 0:64df7fc091da 431 ep++;
rfrenken 0:64df7fc091da 432 }
rfrenken 0:64df7fc091da 433
rfrenken 0:64df7fc091da 434 coap_make_response(scratch, outpkt, NULL, 0, inpkt->hdr.id[0], inpkt->hdr.id[1], &inpkt->tok, COAP_RSPCODE_NOT_FOUND, COAP_CONTENTTYPE_NONE);
rfrenken 0:64df7fc091da 435
rfrenken 0:64df7fc091da 436 return 0;
rfrenken 0:64df7fc091da 437 }
rfrenken 0:64df7fc091da 438
rfrenken 0:64df7fc091da 439 void coap_setup(void)
rfrenken 0:64df7fc091da 440 {
rfrenken 0:64df7fc091da 441 }
rfrenken 0:64df7fc091da 442
rfrenken 0:64df7fc091da 443 Serial pc(USBTX, USBRX);
rfrenken 0:64df7fc091da 444 static uint8_t scratch_raw[32];
rfrenken 0:64df7fc091da 445 static coap_rw_buffer_t scratch_buf = {scratch_raw, sizeof(scratch_raw)};
rfrenken 0:64df7fc091da 446
rfrenken 0:64df7fc091da 447 int main(void) {
rfrenken 0:64df7fc091da 448
rfrenken 0:64df7fc091da 449
rfrenken 0:64df7fc091da 450 EthernetInterface eth;
rfrenken 0:64df7fc091da 451 eth.init(); //Use DHCP
rfrenken 0:64df7fc091da 452 eth.connect();
rfrenken 0:64df7fc091da 453 printf("IP Address is %s\n", eth.getIPAddress());
rfrenken 0:64df7fc091da 454
rfrenken 0:64df7fc091da 455 UDPSocket coapServer;
rfrenken 0:64df7fc091da 456 coapServer.bind(PORT);
rfrenken 0:64df7fc091da 457
rfrenken 0:64df7fc091da 458 coap_setup();
rfrenken 0:64df7fc091da 459 endpoint_setup();
rfrenken 0:64df7fc091da 460 Endpoint client;
rfrenken 0:64df7fc091da 461 char buffer[256];
rfrenken 0:64df7fc091da 462 uint8_t packetbuf[256];
rfrenken 0:64df7fc091da 463 coap_packet_t pkt;
rfrenken 0:64df7fc091da 464
rfrenken 0:64df7fc091da 465 while (true) {
rfrenken 0:64df7fc091da 466 printf("\nWaiting for UDP packet...\n");
rfrenken 0:64df7fc091da 467 int sz = coapServer.receiveFrom(client, buffer, sizeof(buffer));
rfrenken 0:64df7fc091da 468 buffer[sz] = '\0';
rfrenken 0:64df7fc091da 469
rfrenken 0:64df7fc091da 470 printf("Received packet from: %s\n", client.get_address());
rfrenken 0:64df7fc091da 471
rfrenken 0:64df7fc091da 472 printf("Packet contents : '%s'\n",buffer);
rfrenken 0:64df7fc091da 473
rfrenken 0:64df7fc091da 474 #ifdef DEBUG
rfrenken 0:64df7fc091da 475 for (int i=0;i<sz;i++)
rfrenken 0:64df7fc091da 476 {
rfrenken 0:64df7fc091da 477 printf("%x",buffer[i]);
rfrenken 0:64df7fc091da 478 printf(" ");
rfrenken 0:64df7fc091da 479 }
rfrenken 0:64df7fc091da 480 printf("\n");
rfrenken 0:64df7fc091da 481 #endif
rfrenken 0:64df7fc091da 482 int rc;
rfrenken 0:64df7fc091da 483
rfrenken 0:64df7fc091da 484 if (0 != (rc = coap_parse(&pkt, (uint8_t *)buffer, sz)))
rfrenken 0:64df7fc091da 485 {
rfrenken 0:64df7fc091da 486 printf("Bad packet rc=%d\n", rc);
rfrenken 0:64df7fc091da 487 }
rfrenken 0:64df7fc091da 488 else
rfrenken 0:64df7fc091da 489 {
rfrenken 0:64df7fc091da 490 size_t rsplen = sizeof(buffer);
rfrenken 0:64df7fc091da 491 coap_packet_t rsppkt;
rfrenken 0:64df7fc091da 492 coap_handle_req(&scratch_buf, &pkt, &rsppkt);
rfrenken 0:64df7fc091da 493
rfrenken 0:64df7fc091da 494 memset(buffer, 0, UDP_TX_PACKET_MAX_SIZE);
rfrenken 0:64df7fc091da 495 if (0 != (rc = coap_build((uint8_t *)buffer, &rsplen, &rsppkt)))
rfrenken 0:64df7fc091da 496 {
rfrenken 0:64df7fc091da 497 printf("coap_build failed rc=%d\n", rc);
rfrenken 0:64df7fc091da 498 }
rfrenken 0:64df7fc091da 499 else
rfrenken 0:64df7fc091da 500 {
rfrenken 0:64df7fc091da 501 coapServer.sendTo(client, (char *) buffer, rsplen);
rfrenken 0:64df7fc091da 502 }
rfrenken 0:64df7fc091da 503 }
rfrenken 0:64df7fc091da 504 }
rfrenken 0:64df7fc091da 505 }
rfrenken 0:64df7fc091da 506
rfrenken 0:64df7fc091da 507
rfrenken 0:64df7fc091da 508 //coap_setup();
rfrenken 0:64df7fc091da 509 //endpoint_setup();
rfrenken 0:64df7fc091da 510 // override the default weak function to provide a specific mac address
rfrenken 0:64df7fc091da 511 /*extern "C" void mbed_mac_address(char *mac)
rfrenken 0:64df7fc091da 512 {
rfrenken 0:64df7fc091da 513 mac[0] = 0x01;
rfrenken 0:64df7fc091da 514 mac[1] = 0x23;
rfrenken 0:64df7fc091da 515 mac[2] = 0x45;
rfrenken 0:64df7fc091da 516 mac[3] = 0x67;
rfrenken 0:64df7fc091da 517 mac[4] = 0x89;
rfrenken 0:64df7fc091da 518 mac[5] = 0xAB;
rfrenken 0:64df7fc091da 519 };*/
rfrenken 0:64df7fc091da 520