static void disable_observing(struct sol_coap_packet *req, struct sol_coap_server *server, struct sol_str_slice path[], const struct sol_network_link_addr *cliaddr) { struct sol_coap_packet *pkt = sol_coap_packet_new(req); uint8_t observe = 1; int i, r; if (!pkt) return; r = sol_coap_header_set_code(pkt, SOL_COAP_METHOD_GET); SOL_INT_CHECK_GOTO(r, < 0, err); r = sol_coap_header_set_type(pkt, SOL_COAP_TYPE_CON); SOL_INT_CHECK_GOTO(r, < 0, err); r = sol_coap_add_option(pkt, SOL_COAP_OPTION_OBSERVE, &observe, sizeof(observe)); SOL_INT_CHECK_GOTO(r, < 0, err); for (i = 0; path[i].data; i++) sol_coap_add_option(pkt, SOL_COAP_OPTION_URI_PATH, path[i].data, path[i].len); sol_coap_send_packet(server, pkt, cliaddr); SOL_INF("Disabled observing"); return; err: sol_coap_packet_unref(pkt); }
static void test_coap_parse_illegal_token_length(void) { uint8_t pdu[] = { 0x59, 0x69, 0x12, 0x34, 't', 'o', 'k', 'e', 'n', '1', '2', '3', '4' }; struct sol_coap_packet *pkt; struct sol_buffer *buf; size_t offset; pkt = sol_coap_packet_new(NULL); ASSERT(pkt); ASSERT(!sol_coap_packet_get_payload(pkt, &buf, &offset)); ASSERT(!sol_buffer_remove_data(buf, 0, offset)); ASSERT(!sol_buffer_insert_bytes(buf, 0, pdu, sizeof(pdu))); ASSERT(coap_packet_parse(pkt)); pdu[0] = 0x5f; ASSERT(!sol_buffer_remove_data(buf, 0, offset)); ASSERT(!sol_buffer_insert_bytes(buf, 0, pdu, sizeof(pdu))); ASSERT(coap_packet_parse(pkt)); sol_coap_packet_unref(pkt); }
static int light_method_get(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) { struct sol_coap_packet *resp; struct sol_buffer *buf; int r; 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, SOL_COAP_RSPCODE_CONTENT); SOL_INT_CHECK_GOTO(r, < 0, err); r = sol_coap_packet_get_payload(resp, &buf, NULL); SOL_INT_CHECK_GOTO(r, < 0, err); r = light_resource_to_rep(resource, get_scrolllock_led(), buf); SOL_INT_CHECK_GOTO(r, < 0, err); return sol_coap_send_packet(server, resp, cliaddr); err: sol_coap_packet_unref(resp); return r; }
static void test_coap_find_options(void) { uint8_t pdu[] = { 0x55, 0xA5, 0x12, 0x34, 't', 'o', 'k', 'e', 'n', 0x00, 0xC1, 0x00, 0xff, 'p', 'a', 'y', 'l', 'o', 'a', 'd', 0x00 }; struct sol_coap_packet *pkt; struct sol_str_slice options[16]; int count = 16; pkt = sol_coap_packet_new(NULL); ASSERT(pkt); memcpy(pkt->buf, pdu, sizeof(pdu)); pkt->payload.size = sizeof(pdu); ASSERT(!coap_packet_parse(pkt)); count = sol_coap_find_options(pkt, SOL_COAP_OPTION_CONTENT_FORMAT, options, count); ASSERT_INT_EQ(count, 1); ASSERT_INT_EQ(options[0].len, 1); ASSERT_INT_EQ((uint8_t)options[0].data[0], 0); count = sol_coap_find_options(pkt, SOL_COAP_OPTION_IF_MATCH, options, count); ASSERT_INT_EQ(count, 0); sol_coap_packet_unref(pkt); }
static bool update_light(void *data) { struct light_context *context = data; struct sol_coap_server *server = context->server; struct sol_coap_resource *resource = context->resource; struct sol_coap_packet *pkt; struct sol_buffer *buf; int r; SOL_INF("Emitting notification"); pkt = sol_coap_packet_notification_new(server, resource); SOL_NULL_CHECK(pkt, false); r = sol_coap_header_set_code(pkt, SOL_COAP_RSPCODE_CONTENT); SOL_INT_CHECK_GOTO(r, < 0, err); r = sol_coap_packet_get_payload(pkt, &buf, NULL); SOL_INT_CHECK_GOTO(r, < 0, err); r = light_resource_to_rep(resource, get_scrolllock_led(), buf); SOL_INT_CHECK_GOTO(r, < 0, err); return !sol_coap_packet_send_notification(server, resource, pkt); err: sol_coap_packet_unref(pkt); return false; }
static void test_coap_parse_empty_pdu(void) { uint8_t pdu[] = { 0x40, 0x01, 0, 0 }; struct sol_coap_packet *pkt; struct sol_buffer *buf; size_t offset; uint8_t ver, type, code; uint16_t id; pkt = sol_coap_packet_new(NULL); ASSERT(pkt); ASSERT(!sol_coap_packet_get_payload(pkt, &buf, &offset)); ASSERT(!sol_buffer_remove_data(buf, 0, offset)); ASSERT(!sol_buffer_insert_bytes(buf, 0, pdu, sizeof(pdu))); ASSERT(!coap_packet_parse(pkt)); sol_coap_header_get_version(pkt, &ver); sol_coap_header_get_type(pkt, &type); sol_coap_header_get_code(pkt, &code); sol_coap_header_get_id(pkt, &id); ASSERT_INT_EQ(ver, 1); ASSERT_INT_EQ(type, SOL_COAP_MESSAGE_TYPE_CON); ASSERT_INT_EQ(code, SOL_COAP_METHOD_GET); ASSERT_INT_EQ(id, 0); sol_coap_packet_unref(pkt); }
static void test_coap_find_options(void) { uint8_t pdu[] = { 0x55, 0xA5, 0x12, 0x34, 't', 'o', 'k', 'e', 'n', 0x00, 0xC1, 0x00, 0xff, 'p', 'a', 'y', 'l', 'o', 'a', 'd', 0x00 }; struct sol_str_slice options[16]; struct sol_coap_packet *pkt; struct sol_buffer *buf; int count = 16; size_t offset; pkt = sol_coap_packet_new(NULL); ASSERT(pkt); ASSERT(!sol_coap_packet_get_payload(pkt, &buf, &offset)); ASSERT(!sol_buffer_remove_data(buf, 0, offset)); ASSERT(!sol_buffer_insert_bytes(buf, 0, pdu, sizeof(pdu))); ASSERT(!coap_packet_parse(pkt)); count = sol_coap_find_options(pkt, SOL_COAP_OPTION_CONTENT_FORMAT, options, count); ASSERT_INT_EQ(count, 1); ASSERT_INT_EQ(options[0].len, 1); ASSERT_INT_EQ((uint8_t)options[0].data[0], 0); count = sol_coap_find_options(pkt, SOL_COAP_OPTION_IF_MATCH, options, count); ASSERT_INT_EQ(count, 0); sol_coap_packet_unref(pkt); }
static void test_coap_parse_simple_pdu(void) { uint8_t pdu[] = { 0x55, 0xA5, 0x12, 0x34, 't', 'o', 'k', 'e', 'n', 0x00, 0xc1, 0x00, 0xff, 'p', 'a', 'y', 'l', 'o', 'a', 'd', 0x00 }; struct sol_str_slice options[16]; struct sol_coap_packet *pkt; struct sol_buffer *buf; uint8_t *token; int count = 16; size_t offset; uint8_t tkl, code, ver, type; uint16_t id; pkt = sol_coap_packet_new(NULL); ASSERT(pkt); ASSERT(!sol_coap_packet_get_payload(pkt, &buf, &offset)); ASSERT(!sol_buffer_remove_data(buf, 0, offset)); ASSERT(!sol_buffer_insert_bytes(buf, 0, pdu, sizeof(pdu))); ASSERT(!coap_packet_parse(pkt)); sol_coap_header_get_version(pkt, &ver); sol_coap_header_get_type(pkt, &type); ASSERT_INT_EQ(ver, 1); ASSERT_INT_EQ(type, SOL_COAP_MESSAGE_TYPE_NON_CON); token = sol_coap_header_get_token(pkt, &tkl); ASSERT(token); ASSERT_INT_EQ(tkl, 5); ASSERT(!strcmp((char *)token, "token")); sol_coap_header_get_code(pkt, &code); sol_coap_header_get_id(pkt, &id); ASSERT_INT_EQ(code, SOL_COAP_RESPONSE_CODE_PROXYING_NOT_SUPPORTED); ASSERT_INT_EQ(id, 0x1234); count = sol_coap_find_options(pkt, SOL_COAP_OPTION_CONTENT_FORMAT, options, count); ASSERT_INT_EQ(count, 1); ASSERT_INT_EQ(options[0].len, 1); ASSERT_INT_EQ((uint8_t)options[0].data[0], 0); /* Not existent. */ count = sol_coap_find_options(pkt, SOL_COAP_OPTION_ETAG, options, count); ASSERT_INT_EQ(count, 0); ASSERT(!sol_coap_packet_get_payload(pkt, &buf, &offset)); ASSERT_INT_EQ(offset + sizeof("payload"), buf->used); ASSERT(!strcmp((char *)buf->data + offset, "payload")); sol_coap_packet_unref(pkt); }
static void test_coap_parse_options_that_exceed_pdu(void) { uint8_t pdu[] = { 0x55, 0x73, 0x12, 0x34, 't', 'o', 'k', 'e', 'n', 0x00, 0xc1, 0x00, 0xae, 0xf0, 0x03 }; struct sol_coap_packet *pkt; pkt = sol_coap_packet_new(NULL); ASSERT(pkt); memcpy(pkt->buf, pdu, sizeof(pdu)); pkt->payload.size = sizeof(pdu); ASSERT(coap_packet_parse(pkt)); sol_coap_packet_unref(pkt); }
static void test_coap_parse_without_options_with_payload(void) { uint8_t pdu[] = { 0x50, 0x73, 0x12, 0x34, 0xff, 'p', 'a', 'y', 'l', 'o', 'a', 'd' }; struct sol_coap_packet *pkt; pkt = sol_coap_packet_new(NULL); ASSERT(pkt); memcpy(pkt->buf, pdu, sizeof(pdu)); pkt->payload.size = sizeof(pdu); ASSERT(!coap_packet_parse(pkt)); sol_coap_packet_unref(pkt); }
static void test_coap_parse_simple_pdu(void) { uint8_t pdu[] = { 0x55, 0xA5, 0x12, 0x34, 't', 'o', 'k', 'e', 'n', 0x00, 0xc1, 0x00, 0xff, 'p', 'a', 'y', 'l', 'o', 'a', 'd', 0x00 }; struct sol_coap_packet *pkt; struct sol_str_slice options[16]; uint8_t *payload, *token; uint16_t len; int count = 16; uint8_t tkl; pkt = sol_coap_packet_new(NULL); ASSERT(pkt); memcpy(pkt->buf, pdu, sizeof(pdu)); pkt->payload.size = sizeof(pdu); ASSERT(!coap_packet_parse(pkt)); ASSERT_INT_EQ(sol_coap_header_get_ver(pkt), 1); ASSERT_INT_EQ(sol_coap_header_get_type(pkt), SOL_COAP_TYPE_NONCON); token = sol_coap_header_get_token(pkt, &tkl); ASSERT(token); ASSERT_INT_EQ(tkl, 5); ASSERT(!strcmp((char *)token, "token")); ASSERT_INT_EQ(sol_coap_header_get_code(pkt), SOL_COAP_RSPCODE_PROXYING_NOT_SUPPORTED); ASSERT_INT_EQ(sol_coap_header_get_id(pkt), 0x1234); count = sol_coap_find_options(pkt, SOL_COAP_OPTION_CONTENT_FORMAT, options, count); ASSERT_INT_EQ(count, 1); ASSERT_INT_EQ(options[0].len, 1); ASSERT_INT_EQ((uint8_t)options[0].data[0], 0); /* Not existent. */ count = sol_coap_find_options(pkt, SOL_COAP_OPTION_ETAG, options, count); ASSERT_INT_EQ(count, 0); ASSERT(!sol_coap_packet_get_payload(pkt, &payload, &len)); ASSERT_INT_EQ(len, sizeof("payload")); ASSERT(!strcmp((char *)payload, "payload")); sol_coap_packet_unref(pkt); }
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; }
static void test_coap_parse_options_that_exceed_pdu(void) { uint8_t pdu[] = { 0x55, 0x73, 0x12, 0x34, 't', 'o', 'k', 'e', 'n', 0x00, 0xc1, 0x00, 0xae, 0xf0, 0x03 }; struct sol_coap_packet *pkt; struct sol_buffer *buf; size_t offset; pkt = sol_coap_packet_new(NULL); ASSERT(pkt); ASSERT(!sol_coap_packet_get_payload(pkt, &buf, &offset)); ASSERT(!sol_buffer_remove_data(buf, 0, offset)); ASSERT(!sol_buffer_insert_bytes(buf, 0, pdu, sizeof(pdu))); ASSERT(coap_packet_parse(pkt)); sol_coap_packet_unref(pkt); }
static void test_coap_parse_without_options_with_payload(void) { uint8_t pdu[] = { 0x50, 0x73, 0x12, 0x34, 0xff, 'p', 'a', 'y', 'l', 'o', 'a', 'd' }; struct sol_coap_packet *pkt; struct sol_buffer *buf; size_t offset; pkt = sol_coap_packet_new(NULL); ASSERT(pkt); ASSERT(!sol_coap_packet_get_payload(pkt, &buf, &offset)); ASSERT(!sol_buffer_remove_data(buf, 0, offset)); ASSERT(!sol_buffer_insert_bytes(buf, 0, pdu, sizeof(pdu))); ASSERT(!coap_packet_parse(pkt)); sol_coap_packet_unref(pkt); }
static void test_coap_parse_empty_pdu(void) { uint8_t pdu[] = { 0x40, 0x01, 0, 0 }; struct sol_coap_packet *pkt; pkt = sol_coap_packet_new(NULL); ASSERT(pkt); memcpy(pkt->buf, pdu, sizeof(pdu)); pkt->payload.size = sizeof(pdu); ASSERT(!coap_packet_parse(pkt)); ASSERT_INT_EQ(sol_coap_header_get_ver(pkt), 1); ASSERT_INT_EQ(sol_coap_header_get_type(pkt), SOL_COAP_TYPE_CON); ASSERT_INT_EQ(sol_coap_header_get_code(pkt), SOL_COAP_METHOD_GET); ASSERT_INT_EQ(sol_coap_header_get_id(pkt), 0); sol_coap_packet_unref(pkt); }
static void test_coap_parse_illegal_token_length(void) { uint8_t pdu[] = { 0x59, 0x69, 0x12, 0x34, 't', 'o', 'k', 'e', 'n', '1', '2', '3', '4' }; struct sol_coap_packet *pkt; pkt = sol_coap_packet_new(NULL); ASSERT(pkt); memcpy(pkt->buf, pdu, sizeof(pdu)); pkt->payload.size = sizeof(pdu); ASSERT(coap_packet_parse(pkt)); pdu[0] = 0x5f; memcpy(pkt->buf, pdu, sizeof(pdu)); ASSERT(coap_packet_parse(pkt)); sol_coap_packet_unref(pkt); }
static void test_coap_payload_simple(void) { uint8_t pdu[] = { 0x50, 0x73, 0x12, 0x34, 0xff, 'p', 'a', 'y', 'l', 'o', 'a', 'd', 0x00 }; struct sol_coap_packet *pkt; struct sol_buffer *buf; size_t offset; pkt = sol_coap_packet_new(NULL); ASSERT(pkt); ASSERT(!sol_coap_packet_get_payload(pkt, &buf, &offset)); ASSERT(!sol_buffer_remove_data(buf, 0, offset)); ASSERT(!sol_buffer_insert_bytes(buf, 0, pdu, sizeof(pdu))); ASSERT_INT_EQ(buf->used - offset, sizeof("payload")); ASSERT(streq((char *)buf->data + offset, "payload")); ASSERT(!coap_packet_parse(pkt)); sol_coap_packet_unref(pkt); }
static void test_coap_token_simple(void) { uint8_t token[] = { 't', 'o', 'k', 'e', 'n' }; uint8_t token_length; uint8_t *token_ptr; struct sol_coap_packet *pkt; pkt = sol_coap_packet_new(NULL); ASSERT(pkt); ASSERT(!sol_coap_header_set_token(pkt, token, sizeof(token))); token_ptr = sol_coap_header_get_token(pkt, &token_length); ASSERT(token_ptr); ASSERT_INT_EQ(token_length, sizeof(token)); ASSERT(streqn((char *)token_ptr, (char *)token, sizeof(token))); ASSERT(!coap_packet_parse(pkt)); sol_coap_packet_unref(pkt); }
static void test_coap_payload_simple(void) { uint8_t pdu[] = { 0x50, 0x73, 0x12, 0x34, 0xff, 'p', 'a', 'y', 'l', 'o', 'a', 'd', 0x00 }; uint16_t payload_length; uint8_t *payload_ptr; struct sol_coap_packet *pkt; pkt = sol_coap_packet_new(NULL); ASSERT(pkt); memcpy(pkt->buf, pdu, sizeof(pdu)); pkt->payload.size = sizeof(pdu); ASSERT(!sol_coap_packet_get_payload(pkt, &payload_ptr, &payload_length)); ASSERT(payload_ptr); ASSERT_INT_EQ(payload_length, sizeof("payload")); ASSERT(streq((char *)payload_ptr, "payload")); ASSERT(!coap_packet_parse(pkt)); sol_coap_packet_unref(pkt); }
int main(int argc, char *argv[]) { struct sol_coap_server *server; struct sol_str_slice *path; struct sol_network_link_addr cliaddr = { }; struct sol_coap_packet *req; uint8_t observe = 0; int i, r; struct sol_network_link_addr servaddr = { .family = SOL_NETWORK_FAMILY_INET6, .port = 0 }; uint8_t token[4] = { 0x41, 0x42, 0x43, 0x44 }; sol_init(); if (argc < 3) { printf("Usage: %s <address> <path> [path]\n", argv[0]); return 0; } server = sol_coap_server_new(&servaddr); if (!server) { SOL_WRN("Could not create a coap server."); return -1; } req = sol_coap_packet_request_new(SOL_COAP_METHOD_GET, SOL_COAP_TYPE_CON); if (!req) { SOL_WRN("Could not make a GET request to resource %s", argv[2]); return -1; } r = sol_coap_header_set_token(req, token, sizeof(token)); if (r < 0) { SOL_WRN("Could not set coap header token."); return -1; } path = calloc(argc - 1, sizeof(*path)); if (!path) { sol_coap_packet_unref(req); return -1; } for (i = 2; i < argc; i++) { path[i - 2] = sol_str_slice_from_str(argv[i]); } sol_coap_add_option(req, SOL_COAP_OPTION_OBSERVE, &observe, sizeof(observe)); for (i = 0; path[i].data; i++) sol_coap_add_option(req, SOL_COAP_OPTION_URI_PATH, path[i].data, path[i].len); cliaddr.family = SOL_NETWORK_FAMILY_INET6; if (!sol_network_link_addr_from_str(&cliaddr, argv[1])) { SOL_WRN("%s is an invalid IPv6 address", argv[1]); free(path); sol_coap_packet_unref(req); return -1; } cliaddr.port = DEFAULT_UDP_PORT; /* Takes the ownership of 'req'. */ sol_coap_send_packet_with_reply(server, req, &cliaddr, reply_cb, path); sol_run(); sol_coap_server_unref(server); free(path); return 0; }