int coap_parse_option(struct option_context *context, uint8_t **value, uint16_t *vlen) { uint16_t delta, len; uint8_t start; int r; if (context->buf->used - context->pos < 1) return 0; start = ((uint8_t *)sol_buffer_at(context->buf, context->pos))[0]; /* This indicates that options have ended */ if (start == COAP_MARKER) return 0; delta = coap_option_header_get_delta(start); len = coap_option_header_get_len(start); context->pos += 1; context->used += 1; /* In case 'delta' doesn't fit the option fixed header. */ r = decode_delta(delta, sol_buffer_at(context->buf, context->pos), context->buf->used - context->pos, &delta); if (r < 0) return r; context->pos += r; context->used += r; /* In case 'len' doesn't fit the option fixed header. */ r = decode_delta(len, sol_buffer_at(context->buf, context->pos), context->buf->used - context->pos, &len); if (r < 0) return r; if (context->buf->used - context->pos < (size_t)(r + len)) return -EINVAL; if (value) *value = sol_buffer_at(context->buf, context->pos + r); if (vlen) *vlen = len; context->pos += r + len; context->used += r + len; context->delta += delta; return context->used; }
SOL_API int sol_buffer_insert_char(struct sol_buffer *buf, size_t pos, const char c) { char *p; size_t new_size; int err; SOL_NULL_CHECK(buf, -EINVAL); SOL_INT_CHECK(pos, > buf->used, -EINVAL); if (pos == buf->used) return sol_buffer_append_char(buf, c); err = sol_util_size_add(buf->used, 1, &new_size); if (err < 0) return err; err = sol_buffer_ensure(buf, new_size); if (err < 0) return err; p = sol_buffer_at(buf, pos); memmove(p + 1, p, buf->used - pos); *p = c; buf->used++; if (nul_byte_size(buf)) return sol_buffer_ensure_nul_byte(buf); return 0; }
SOL_API void sol_oic_payload_debug(struct sol_coap_packet *pkt) { SOL_NULL_CHECK(pkt); #ifdef HAVE_STDOUT struct sol_buffer *buf; CborParser parser; CborValue root; CborError err; size_t offset; if (!sol_oic_pkt_has_cbor_content(pkt) || !sol_coap_packet_has_payload(pkt)) { return; } if (sol_coap_packet_get_payload(pkt, &buf, &offset) < 0) { SOL_DBG("Failed to get packet payload"); return; } err = cbor_parser_init(sol_buffer_at(buf, offset), buf->used - offset, 0, &parser, &root); if (err != CborNoError) { SOL_DBG("Failed to get cbor payload"); return; } cbor_value_to_pretty(stdout, &root); fprintf(stdout, "\n"); #else SOL_DBG("Failed to log oic payload: stdout not available"); #endif }
static bool reply_cb(struct sol_coap_server *server, struct sol_coap_packet *req, const struct sol_network_link_addr *cliaddr, void *data) { struct sol_str_slice *path = data; static int count; struct sol_buffer *buf; size_t offset; SOL_BUFFER_DECLARE_STATIC(addr, SOL_INET_ADDR_STRLEN); if (!req || !cliaddr) //timeout return false; sol_network_link_addr_to_str(cliaddr, &addr); SOL_INF("Got response from %.*s\n", SOL_STR_SLICE_PRINT(sol_buffer_get_slice(&addr))); sol_coap_packet_get_payload(req, &buf, &offset); SOL_INF("Payload: %.*s\n", (int)(buf->used - offset), (char *)sol_buffer_at(buf, offset)); if (++count == 10) disable_observing(req, server, path, cliaddr); return true; }
SOL_API int sol_buffer_insert_from_base16(struct sol_buffer *buf, size_t pos, const struct sol_str_slice slice, enum sol_decode_case decode_case) { char *p; size_t new_size; ssize_t decoded_size, r; const size_t nul_size = nul_byte_size(buf); int err; SOL_NULL_CHECK(buf, -EINVAL); SOL_INT_CHECK(pos, > buf->used, -EINVAL); if (slice.len == 0) return 0; if (pos == buf->used) return sol_buffer_append_from_base16(buf, slice, decode_case); decoded_size = sol_util_base16_calculate_decoded_len(slice); if (decoded_size < 0) return decoded_size; err = sol_util_size_add(buf->used, decoded_size, &new_size); if (err < 0) return err; if (nul_size) { err = sol_util_size_add(new_size, nul_size, &new_size); if (err < 0) return err; } err = sol_buffer_ensure(buf, new_size); if (err < 0) return err; p = sol_buffer_at(buf, pos); memmove(p + decoded_size, p, buf->used - pos); r = sol_util_base16_decode(p, decoded_size, slice, decode_case); if (r != decoded_size) { memmove(p, p + decoded_size, buf->used - pos); if (nul_size) sol_buffer_ensure_nul_byte(buf); if (r < 0) return r; else return -EINVAL; } buf->used += decoded_size; if (nul_size) return sol_buffer_ensure_nul_byte(buf); return 0; }
SOL_API int sol_buffer_insert_as_base64(struct sol_buffer *buf, size_t pos, const struct sol_str_slice slice, const char base64_map[SOL_STATIC_ARRAY_SIZE(65)]) { char *p; size_t new_size; ssize_t encoded_size, r; const size_t nul_size = nul_byte_size(buf); int err; SOL_NULL_CHECK(buf, -EINVAL); SOL_INT_CHECK(pos, > buf->used, -EINVAL); if (slice.len == 0) return 0; if (pos == buf->used) return sol_buffer_append_as_base64(buf, slice, base64_map); encoded_size = sol_util_base64_calculate_encoded_len(slice, base64_map); if (encoded_size < 0) return encoded_size; err = sol_util_size_add(buf->used, encoded_size, &new_size); if (err < 0) return err; if (nul_size) { err = sol_util_size_add(new_size, nul_size, &new_size); if (err < 0) return err; } err = sol_buffer_ensure(buf, new_size); if (err < 0) return err; p = sol_buffer_at(buf, pos); memmove(p + encoded_size, p, buf->used - pos); r = sol_util_base64_encode(p, encoded_size, slice, base64_map); if (r != encoded_size) { memmove(p, p + encoded_size, buf->used - pos); if (nul_size) sol_buffer_ensure_nul_byte(buf); if (r < 0) return r; else return -EINVAL; } buf->used += encoded_size; if (nul_size) return sol_buffer_ensure_nul_byte(buf); return 0; }
static int light_method_put(struct sol_coap_server *server, const struct sol_coap_resource *resource, struct sol_coap_packet *req, const struct sol_network_link_addr *cliaddr, void *data) { sol_coap_responsecode_t code = SOL_COAP_RSPCODE_CONTENT; struct sol_coap_packet *resp; struct sol_buffer *buf; char *sub = NULL; size_t offset; bool value; int r; sol_coap_packet_get_payload(req, &buf, &offset); if (buf) sub = strstr((char *)sol_buffer_at(buf, offset), "state\":"); if (!sub) { code = SOL_COAP_RSPCODE_BAD_REQUEST; goto done; } value = !memcmp(sub + strlen("state\":"), "true", sizeof("true") - 1); SOL_INF("Changing light state to %s", value ? "on" : "off"); set_scrolllock_led(value); done: resp = sol_coap_packet_new(req); if (!resp) { SOL_WRN("Could not build response packet"); return -1; } r = sol_coap_header_set_type(resp, SOL_COAP_TYPE_ACK); SOL_INT_CHECK_GOTO(r, < 0, err); r = sol_coap_header_set_code(resp, code); SOL_INT_CHECK_GOTO(r, < 0, err); return sol_coap_send_packet(server, resp, cliaddr); err: sol_coap_packet_unref(resp); return r; }
SOL_API int sol_buffer_insert_slice(struct sol_buffer *buf, size_t pos, const struct sol_str_slice slice) { const size_t nul_size = nul_byte_size(buf); char *p; size_t new_size; int err; SOL_NULL_CHECK(buf, -EINVAL); SOL_INT_CHECK(pos, > buf->used, -EINVAL); if (pos == buf->used) return sol_buffer_append_slice(buf, slice); err = sol_util_size_add(buf->used, slice.len, &new_size); if (err < 0) return err; /* Extra room for the ending NUL-byte. */ if (new_size >= SIZE_MAX - nul_size) return -EOVERFLOW; err = sol_buffer_ensure(buf, new_size + nul_size); if (err < 0) return err; p = sol_buffer_at(buf, pos); memmove(p + slice.len, p, buf->used - pos); memcpy(p, slice.data, slice.len); buf->used += slice.len; if (nul_size) { p = sol_buffer_at_end(buf); p[0] = '\0'; } return 0; }
static int coap_parse_options(struct sol_coap_packet *pkt, unsigned int offset) { struct option_context context = { .delta = 0, .used = 0, .buf = &pkt->buf, .pos = offset }; while (true) { int r = coap_parse_option(&context, NULL, NULL); if (r < 0) return -EINVAL; if (r == 0) break; } return context.used; } int coap_get_header_len(const struct sol_coap_packet *pkt) { struct coap_header *hdr; unsigned int hdrlen; uint8_t tkl; hdrlen = sizeof(struct coap_header); if (pkt->buf.used < hdrlen) return -EINVAL; hdr = (struct coap_header *)sol_buffer_at(&pkt->buf, 0); tkl = hdr->tkl; // Token lenghts 9-15 are reserved. if (tkl > 8) return -EINVAL; if (pkt->buf.used < hdrlen + tkl) return -EINVAL; return hdrlen + tkl; } int coap_packet_parse(struct sol_coap_packet *pkt) { int optlen, hdrlen; SOL_NULL_CHECK(pkt, -EINVAL); hdrlen = coap_get_header_len(pkt); if (hdrlen < 0) return hdrlen; optlen = coap_parse_options(pkt, hdrlen); if (optlen < 0) return optlen; if (pkt->buf.used < (size_t)(hdrlen + optlen)) return -EINVAL; /* +1 for COAP_MARKER */ if (pkt->buf.used <= (size_t)(hdrlen + optlen + 1)) { pkt->payload_start = 0; return 0; } pkt->payload_start = hdrlen + optlen + 1; return 0; }