blob: 7ec25c0876f7f0fe31f080d9d83742ddbdb87698 [file] [log] [blame]
/**
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "coap_functions.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* Initialize the API access. Not thread safe.
*/
void init_coap_api(void *rcvr, callback_pointers *ptrs) {
global_ptrs.data_received = ptrs->data_received;
global_ptrs.received_error = ptrs->received_error;
receiver = rcvr;
}
int create_session(coap_context_t **ctx, coap_session_t **session, const char *node, const char *port, coap_address_t *dst_addr) {
int getaddrres;
struct addrinfo hints;
coap_proto_t proto = COAP_PROTO_UDP;
struct addrinfo *result, *interface_itr;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC; // ipv4 or ipv6
hints.ai_socktype = COAP_PROTO_RELIABLE(proto) ? SOCK_STREAM : SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST | AI_NUMERICSERV | AI_ALL;
if (node) {
getaddrres = getaddrinfo(node, port, &hints, &result);
if (getaddrres != 0) {
perror("getaddrinfo");
return -1;
}
int skip = 1, count = 0;
for (interface_itr = result; interface_itr != NULL; interface_itr = interface_itr->ai_next) {
coap_address_t addr;
if (interface_itr->ai_addrlen <= sizeof(addr.addr)) {
coap_address_init(&addr);
addr.size = interface_itr->ai_addrlen;
memcpy(&addr.addr, interface_itr->ai_addr, interface_itr->ai_addrlen);
*ctx = coap_new_context(0x00);
*session = coap_new_client_session(*ctx, &addr, dst_addr, proto);
if (*ctx && *session) {
freeaddrinfo(result);
return 0;
}
}
}
freeaddrinfo(result);
return -2;
} else {
*ctx = coap_new_context(0x00);
*session = coap_new_client_session(*ctx, 0x00, dst_addr, proto);
return 0;
}
}
int create_endpoint_context(coap_context_t **ctx, const char *node, const char *port) {
struct addrinfo hints;
coap_proto_t proto = COAP_PROTO_UDP;
struct addrinfo *result, *interface_itr;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC; // ipv4 or ipv6
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
int getaddrres = getaddrinfo(node, port, &hints, &result);
if (getaddrres != 0) {
perror("getaddrinfo");
return -1;
}
for (interface_itr = result; interface_itr != NULL; interface_itr = interface_itr->ai_next) {
coap_address_t addr;
if (interface_itr->ai_addrlen <= sizeof(addr.addr)) {
coap_address_init(&addr);
addr.size = interface_itr->ai_addrlen;
memcpy(&addr.addr, interface_itr->ai_addr, interface_itr->ai_addrlen);
*ctx = coap_new_context(0x00);
coap_endpoint_t * ep_udp = coap_new_endpoint(*ctx, &addr, COAP_PROTO_UDP);
if (*ctx && ep_udp) {
freeaddrinfo(result);
return 0;
}
}
}
freeaddrinfo(result);
return -2;
}
struct coap_pdu_t *create_request(struct coap_context_t *ctx, struct coap_session_t *session, coap_optlist_t **optlist, unsigned char code, coap_str_const_t *ptr) {
coap_pdu_t *pdu;
if (!(pdu = coap_new_pdu(session)))
return NULL;
pdu->type = COAP_MESSAGE_CON;
pdu->tid = coap_new_message_id(session);
pdu->code = code;
if (optlist) {
coap_add_optlist_pdu(pdu, optlist);
}
int flags = 0;
coap_add_data(pdu, ptr->length, ptr->s);
return pdu;
}
int coap_event(struct coap_context_t *ctx, coap_event_t event, struct coap_session_t *session) {
if (event == COAP_EVENT_SESSION_FAILED && global_ptrs.received_error) {
global_ptrs.received_error(receiver, ctx, -1);
}
return 0;
}
void no_acknowledgement(struct coap_context_t *ctx, coap_session_t *session, coap_pdu_t *sent, coap_nack_reason_t reason, const coap_tid_t id) {
if (global_ptrs.received_error) {
global_ptrs.received_error(receiver, ctx, -1);
}
}
void response_handler(struct coap_context_t *ctx, struct coap_session_t *session, coap_pdu_t *sent, coap_pdu_t *received, const coap_tid_t id) {
unsigned char* data;
size_t data_len;
coap_opt_iterator_t opt_iter;
coap_opt_t * block_opt = coap_check_option(received, COAP_OPTION_BLOCK1, &opt_iter);
if (block_opt) {
printf("Block option not currently supported");
} else {
if (!global_ptrs.data_received) {
return;
}
if (COAP_RESPONSE_CLASS(received->code) == 2 || received->code == COAP_RESPONSE_400) {
if (global_ptrs.data_received) {
CoapMessage * const msg = create_coap_message(received);
global_ptrs.data_received(receiver, ctx, msg);
}
} else {
if (global_ptrs.received_error)
global_ptrs.received_error(receiver, ctx, received->code);
}
}
}
int resolve_address(const struct coap_str_const_t *server, struct sockaddr *destination) {
struct addrinfo *result, *iterative_obj;
struct addrinfo hints;
static char addrstr[256];
int error, len = -1;
memset(addrstr, 0, sizeof(addrstr));
if (server->length)
memcpy(addrstr, server->s, server->length);
else
memcpy(addrstr, "127.0.0.1", 9);
memset((char *) &hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_DGRAM;
hints.ai_family = AF_UNSPEC;
error = getaddrinfo(addrstr, NULL, &hints, &result);
if (error != 0) {
perror("getaddrinfo");
return error;
}
for (iterative_obj = result; iterative_obj != NULL; iterative_obj = iterative_obj->ai_next) {
switch (iterative_obj->ai_family) {
case AF_INET6:
case AF_INET:
len = iterative_obj->ai_addrlen;
memcpy(destination, iterative_obj->ai_addr, len);
freeaddrinfo(result);
return len;
default:
;
}
}
freeaddrinfo(result);
return len;
}
#ifdef __cplusplus
}
#endif