CoAP server ported from Arduino microcoap
Dependencies: EthernetInterface Socket mbed-rtos mbed
main.cpp@0:64df7fc091da, 2017-03-23 (annotated)
- 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?
User | Revision | Line number | New 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 |