void coap_SendNotify(AddressType * addr, const char * path, const char * token, int tokenSize, ContentType contentType, const char * payload, int payloadLen, int sequence) { // TODO - FIXME: if path is not full uri then map addr to Network address + append path(?) coap_packet_t notify; coap_transaction_t *transaction; NetworkAddress * remoteAddress = NetworkAddress_New(path, strlen(path)); Lwm2m_Debug("Coap notify: %s\n", path); //Lwm2m_Debug("Coap IPv6 request address: " PRINT6ADDR(&addr->Addr)); //Lwm2m_Debug("Coap request port: %d\n", addr->Port); coap_init_message(¬ify, COAP_TYPE_NON, CONTENT_2_05, coap_get_mid()); if (contentType != ContentType_None) { coap_set_header_content_format(¬ify, contentType); coap_set_payload(¬ify, payload, payloadLen); } coap_set_token(¬ify, token, tokenSize); coap_set_header_observe(¬ify, sequence); if ((transaction = coap_new_transaction(networkSocket, notify.mid, remoteAddress))) { transaction->packet_len = coap_serialize_message(¬ify, transaction->packet); coap_send_transaction(transaction); // for NON confirmable messages this will call coap_clear_transaction(); } }
void coap_SendNotify(AddressType * addr, const char * path, const char * token, int tokenSize, ContentType contentType, const char * payload, int payloadLen, int sequence) { coap_packet_t notify; coap_transaction_t *transaction; Lwm2m_Debug("Coap notify: %s\n", path); Lwm2m_Debug("Coap IPv6 request address: " PRINT6ADDR(&addr->Addr)); Lwm2m_Debug("Coap request port: %d\n", addr->Port); coap_init_message(¬ify, COAP_TYPE_NON, CONTENT_2_05, coap_get_mid()); if (contentType != ContentType_None) { coap_set_header_content_format(¬ify, contentType); coap_set_payload(¬ify, payload, payloadLen); } coap_set_token(¬ify, token, tokenSize); coap_set_header_observe(¬ify, sequence); if ((transaction = coap_new_transaction(notify.mid, &addr->Addr, uip_htons(addr->Port)))) { transaction->packet_len = coap_serialize_message(¬ify, transaction->packet); coap_send_transaction(transaction); // for NON confirmable messages this will call coap_clear_transaction(); } }
/*---------------------------------------------------------------------------*/ void coap_notify_observers(resource_t *resource) { /* build notification */ coap_packet_t notification[1]; /* this way the packet can be treated as pointer as usual */ coap_init_message(notification, COAP_TYPE_NON, CONTENT_2_05, 0); coap_observer_t *obs = NULL; PRINTF("Observe: Notification from %s\n", resource->url); /* iterate over observers */ for(obs = (coap_observer_t *)list_head(observers_list); obs; obs = obs->next) { if(obs->url == resource->url) { /* using RESOURCE url pointer as handle */ coap_transaction_t *transaction = NULL; /*TODO implement special transaction for CON, sharing the same buffer to allow for more observers */ if((transaction = coap_new_transaction(coap_get_mid(), &obs->addr, obs->port))) { if(obs->obs_counter % COAP_OBSERVE_REFRESH_INTERVAL == 0) { PRINTF(" Force Confirmable for\n"); notification->type = COAP_TYPE_CON; } PRINTF(" Observer "); PRINT6ADDR(&obs->addr); PRINTF(":%u\n", obs->port); /* update last MID for RST matching */ obs->last_mid = transaction->mid; /* prepare response */ notification->mid = transaction->mid; resource->get_handler(NULL, notification, transaction->packet + COAP_MAX_HEADER_SIZE, REST_MAX_CHUNK_SIZE, NULL); if(notification->code < BAD_REQUEST_4_00) { coap_set_header_observe(notification, (obs->obs_counter)++); } coap_set_token(notification, obs->token, obs->token_len); transaction->packet_len = coap_serialize_message(notification, transaction->packet); coap_send_transaction(transaction); } } } }
/*----------------------------------------------------------------------------*/ void coap_separate_resume(void *response, coap_separate_t *separate_store, uint8_t code) { coap_init_message(response, separate_store->type, code, separate_store->mid); if(separate_store->token_len) { coap_set_token(response, separate_store->token, separate_store->token_len); } if(separate_store->block1_size) { coap_set_header_block1(response, separate_store->block1_num, 0, separate_store->block1_size); } }
int main(void) { char alias[] = "temp"; char cik[] = "a32c85ba9dda45823be416246cf8b433baa068d7"; char host[] = "coap.exosite.com"; char port[] = "5683"; srand(time(NULL)); // CoAP Message Setup #define MSG_BUF_LEN 64 uint8_t msg_send_buf[MSG_BUF_LEN]; coap_pdu msg_send = {msg_send_buf, 0, 64}; uint8_t msg_recv_buf[MSG_BUF_LEN]; coap_pdu msg_recv = {msg_recv_buf, 0, 64}; uint16_t message_id_counter = rand(); // Socket to Exosite int remotesock; size_t bytes_sent; ssize_t bytes_recv; int rv; struct addrinfo exohints, *servinfo, *q; memset(&exohints, 0, sizeof exohints); exohints.ai_family = AF_UNSPEC; exohints.ai_socktype = SOCK_DGRAM; exohints.ai_flags = AI_PASSIVE; if ((rv = getaddrinfo(host, port, &exohints, &servinfo)) != 0) { fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); return 1; } // loop through all the results and make a socket for(q = servinfo; q != NULL; q = q->ai_next) { if ((remotesock = socket(q->ai_family, q->ai_socktype, q->ai_protocol)) == -1) { perror("bad socket"); continue; } break; } if (q == NULL) { fprintf(stderr, "Failed to Bind Socket\n"); return 2; } for (;;) { printf("--------------------------------------------------------------------------------\n"); // Build Message coap_init_pdu(&msg_send); //memset(msg_send, 0, msg_send_len); coap_set_version(&msg_send, COAP_V1); coap_set_type(&msg_send, CT_CON); coap_set_code(&msg_send, CC_GET); // or POST to write coap_set_mid(&msg_send, message_id_counter++); coap_set_token(&msg_send, rand(), 2); coap_add_option(&msg_send, CON_URI_PATH, (uint8_t*)"1a", 2); coap_add_option(&msg_send, CON_URI_PATH, (uint8_t*)alias, strlen(alias)); coap_add_option(&msg_send, CON_URI_QUERY, (uint8_t*)cik, strlen(cik)); // to write, set payload: //coap_set_payload(msg_send, &msg_send_len, MSG_BUF_LEN, (uint8_t*)"99", 2); // Send Message if ((bytes_sent = sendto(remotesock, msg_send.buf, msg_send.len, 0, q->ai_addr, q->ai_addrlen)) == -1){ fprintf(stderr, "Failed to Send Message\n"); return 2; } printf("Sent.\n"); coap_pretty_print(&msg_send); // Wait for Response bytes_recv = recvfrom(remotesock, (void *)msg_recv.buf, msg_recv.max, 0, q->ai_addr, &q->ai_addrlen); if (bytes_recv < 0) { fprintf(stderr, "%s\n", strerror(errno)); exit(EXIT_FAILURE); } msg_recv.len = bytes_recv; if(coap_validate_pkt(&msg_recv) == CE_NONE) { printf("Got Valid CoAP Packet\n"); if(coap_get_mid(&msg_recv) == coap_get_mid(&msg_send) && coap_get_token(&msg_recv) == coap_get_token(&msg_send)) { printf("Is Response to Last Message\n"); coap_pretty_print(&msg_recv); } }else{ printf("Received %zi Bytes, Not Valid CoAP\n", msg_recv.len); hex_dump(msg_recv.buf, msg_recv.len); } sleep(1); // One Second } }
/*---------------------------------------------------------------------------*/ int coap_engine_receive(coap_context_t *coap_ctx) { erbium_status_code = NO_ERROR; coap_packet_t message[1]; /* this way the packet can be treated as pointer as usual */ coap_packet_t response[1]; coap_transaction_t *transaction = NULL; PRINTF("%s(): received data len %u\n", __FUNCTION__, (uint16_t)uip_appdatalen(coap_ctx->buf)); if(uip_newdata(coap_ctx->buf)) { PRINTF("receiving UDP datagram from: "); PRINT6ADDR(&UIP_IP_BUF(coap_ctx->buf)->srcipaddr); PRINTF(":%u\n Length: %u\n", uip_ntohs(UIP_UDP_BUF(coap_ctx->buf)->srcport), uip_appdatalen(coap_ctx->buf)); erbium_status_code = coap_parse_message(message, uip_appdata(coap_ctx->buf), uip_appdatalen(coap_ctx->buf)); coap_set_context(message, coap_ctx); if(erbium_status_code == NO_ERROR) { NET_COAP_STAT(recv++); /*TODO duplicates suppression, if required by application */ PRINTF(" Parsed: v %u, t %u, tkl %u, c %u, mid %u\n", message->version, message->type, message->token_len, message->code, message->mid); PRINTF(" URL[%d]: %.*s\n", message->uri_path_len, message->uri_path_len, message->uri_path); PRINTF(" Payload[%d]: %.*s\n", message->payload_len, message->payload_len, message->payload); /* handle requests */ if(message->code >= COAP_GET && message->code <= COAP_DELETE) { /* use transaction buffer for response to confirmable request */ if((transaction = coap_new_transaction(message->mid, coap_ctx, &UIP_IP_BUF(coap_ctx->buf)->srcipaddr, UIP_UDP_BUF(coap_ctx->buf)->srcport))) { uint32_t block_num = 0; uint16_t block_size = REST_MAX_CHUNK_SIZE; uint32_t block_offset = 0; int32_t new_offset = 0; /* prepare response */ if(message->type == COAP_TYPE_CON) { /* reliable CON requests are answered with an ACK */ coap_init_message(response, COAP_TYPE_ACK, CONTENT_2_05, message->mid); } else { /* unreliable NON requests are answered with a NON as well */ coap_init_message(response, COAP_TYPE_NON, CONTENT_2_05, coap_get_mid()); /* mirror token */ } if(message->token_len) { coap_set_token(response, message->token, message->token_len); /* get offset for blockwise transfers */ } if(coap_get_header_block2 (message, &block_num, NULL, &block_size, &block_offset)) { PRINTF("Blockwise: block request %lu (%u/%u) @ %lu bytes\n", (unsigned long)block_num, block_size, REST_MAX_CHUNK_SIZE, (unsigned long)block_offset); block_size = MIN(block_size, REST_MAX_CHUNK_SIZE); new_offset = block_offset; } /* invoke resource handler */ if(service_cbk) { /* call REST framework and check if found and allowed */ if(service_cbk (message, response, transaction->packet + COAP_MAX_HEADER_SIZE, block_size, &new_offset)) { if(erbium_status_code == NO_ERROR) { /* TODO coap_handle_blockwise(request, response, start_offset, end_offset); */ /* resource is unaware of Block1 */ if(IS_OPTION(message, COAP_OPTION_BLOCK1) && response->code < BAD_REQUEST_4_00 && !IS_OPTION(response, COAP_OPTION_BLOCK1)) { PRINTF("Block1 NOT IMPLEMENTED\n"); erbium_status_code = NOT_IMPLEMENTED_5_01; coap_error_message = "NoBlock1Support"; /* client requested Block2 transfer */ } else if(IS_OPTION(message, COAP_OPTION_BLOCK2)) { /* unchanged new_offset indicates that resource is unaware of blockwise transfer */ if(new_offset == block_offset) { PRINTF ("Blockwise: unaware resource with payload length %u/%u\n", response->payload_len, block_size); if(block_offset >= response->payload_len) { PRINTF ("handle_incoming_data(): block_offset >= response->payload_len\n"); response->code = BAD_OPTION_4_02; coap_set_payload(response, "BlockOutOfScope", 15); /* a const char str[] and sizeof(str) produces larger code size */ } else { coap_set_header_block2(response, block_num, response->payload_len - block_offset > block_size, block_size); coap_set_payload(response, response->payload + block_offset, MIN(response->payload_len - block_offset, block_size)); } /* if(valid offset) */ /* resource provides chunk-wise data */ } else { PRINTF("Blockwise: blockwise resource, new offset %ld\n", (long)new_offset); coap_set_header_block2(response, block_num, new_offset != -1 || response->payload_len > block_size, block_size); if(response->payload_len > block_size) { coap_set_payload(response, response->payload, block_size); } } /* if(resource aware of blockwise) */ /* Resource requested Block2 transfer */ } else if(new_offset != 0) { PRINTF ("Blockwise: no block option for blockwise resource, using block size %u\n", COAP_MAX_BLOCK_SIZE); coap_set_header_block2(response, 0, new_offset != -1, COAP_MAX_BLOCK_SIZE); coap_set_payload(response, response->payload, MIN(response->payload_len, COAP_MAX_BLOCK_SIZE)); } /* blockwise transfer handling */ } /* no errors/hooks */ /* successful service callback */ /* serialize response */ } if(erbium_status_code == NO_ERROR) { if((transaction->packet_len = coap_serialize_message(response, transaction-> packet)) == 0) { erbium_status_code = PACKET_SERIALIZATION_ERROR; } } } else { erbium_status_code = NOT_IMPLEMENTED_5_01; coap_error_message = "NoServiceCallbck"; /* no 'a' to fit into 16 bytes */ } /* if(service callback) */ } else { erbium_status_code = SERVICE_UNAVAILABLE_5_03; coap_error_message = "NoFreeTraBuffer"; } /* if(transaction buffer) */ /* handle responses */ } else { if(message->type == COAP_TYPE_CON && message->code == 0) { PRINTF("Received Ping\n"); erbium_status_code = PING_RESPONSE; } else if(message->type == COAP_TYPE_ACK) { /* transactions are closed through lookup below */ PRINTF("Received ACK\n"); } else if(message->type == COAP_TYPE_RST) { PRINTF("Received RST\n"); /* cancel possible subscriptions */ coap_remove_observer_by_mid(coap_ctx, &UIP_IP_BUF(coap_ctx->buf)->srcipaddr, UIP_UDP_BUF(coap_ctx->buf)->srcport, message->mid); } if((transaction = coap_get_transaction_by_mid(message->mid))) { /* free transaction memory before callback, as it may create a new transaction */ restful_response_handler callback = transaction->callback; void *callback_data = transaction->callback_data; coap_clear_transaction(transaction); /* check if someone registered for the response */ if(callback) { callback(callback_data, message); } } /* if(ACKed transaction) */ transaction = NULL; #if COAP_OBSERVE_CLIENT /* if observe notification */ if((message->type == COAP_TYPE_CON || message->type == COAP_TYPE_NON) && IS_OPTION(message, COAP_OPTION_OBSERVE)) { PRINTF("Observe [%u]\n", message->observe); coap_handle_notification(coap_ctx, &UIP_IP_BUF(coap_ctx->buf)->srcipaddr, UIP_UDP_BUF(coap_ctx->buf)->srcport, message); } #endif /* COAP_OBSERVE_CLIENT */ } /* request or response */ } else { /* parsed correctly */ NET_COAP_STAT(recv_err++); } /* if(parsed correctly) */ if(erbium_status_code == NO_ERROR) { if(transaction) { coap_send_transaction(transaction); } } else if(erbium_status_code == MANUAL_RESPONSE) { PRINTF("Clearing transaction for manual response"); coap_clear_transaction(transaction); } else { coap_message_type_t reply_type = COAP_TYPE_ACK; PRINTF("ERROR %u: %s\n", erbium_status_code, coap_error_message); coap_clear_transaction(transaction); if(erbium_status_code == PING_RESPONSE) { erbium_status_code = 0; reply_type = COAP_TYPE_RST; } else if(erbium_status_code >= 192) { /* set to sendable error code */ erbium_status_code = INTERNAL_SERVER_ERROR_5_00; /* reuse input buffer for error message */ } coap_init_message(message, reply_type, erbium_status_code, message->mid); coap_set_payload(message, coap_error_message, strlen(coap_error_message)); coap_send_message(coap_ctx, &UIP_IP_BUF(coap_ctx->buf)->srcipaddr, UIP_UDP_BUF(coap_ctx->buf)->srcport, uip_appdata(coap_ctx->buf), coap_serialize_message(message, uip_appdata(coap_ctx->buf))); } } /* if(new data) */ return erbium_status_code; }
void* CoapClient(void* parg) { socklen_t sin_size; struct sockaddr_in addr_remote; uint16_t message_id_counter; ssize_t bytes_sent; ssize_t bytes_recv; uint8_t msg_buf[MSG_BUF_LEN]; int msg_len; int fifo_fd; char fifo[64] = {'\0'}; struct timeval timeout; timeout.tv_sec = 3; timeout.tv_usec = 0; coapIP *ipdata = (coapIP *)parg; //注册信号 (void)signal(COAP_CLOSE_SIGNAL, Close_Sig); (void)signal(FIFO_CREATE_SIGNAL, Fifo_Create_Sig); // CoAP Message Setup uint8_t msg_send_buf[MSG_BUF_LEN]; coap_pdu msg_send = {msg_send_buf, 0, MSG_BUF_LEN}; uint8_t msg_recv_buf[MSG_BUF_LEN]; coap_pdu msg_recv = {msg_recv_buf, 0, MSG_BUF_LEN}; srand(time(NULL)); message_id_counter = rand(); //创建套接字 if( (ipdata->coapSocket = socket(AF_INET, SOCK_DGRAM, 0))==-1 ) { zlog_error(zc, "create socket error!"); exit(-1); } addr_remote.sin_family = AF_INET; addr_remote.sin_port = htons(COAP_PORT); addr_remote.sin_addr.s_addr = inet_addr( ipdata->ip ); memset(addr_remote.sin_zero, 0, 8); zlog_debug(zc, "coap client socket is %d, ip is %s,path is %s", ipdata->coapSocket, ipdata->ip, ipdata->path); //设置接收超时 setsockopt(ipdata->coapSocket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)); GetfifoName( fifo, sizeof(fifo), getpid() ); //等待fifo创建好的信号 //pause(); //以只读方式打开FIFO,返回文件描述符fd fifo_fd = open(fifo,O_RDONLY); if( fifo_fd == -1 ) { printf("Open fifo error!\n"); exit(1); } printf("coap client %d open fifo %s\r\n", getpid(), fifo); while(1) { //清空缓存 memset(msg_send.buf, '\0', MSG_BUF_LEN); msg_send.len = 0; //从管道读数据 msg_len = read(fifo_fd, msg_buf, MSG_BUF_LEN); //printf("fifo read is %s", msg_buf); // Build Message coap_init_pdu(&msg_send); coap_set_version(&msg_send, COAP_V1); coap_set_type(&msg_send, CT_CON); coap_set_code(&msg_send, CC_GET); // or POST to write coap_set_mid(&msg_send, message_id_counter++); coap_set_token(&msg_send, rand(), 2); coap_add_option(&msg_send, CON_URI_PATH, (uint8_t*)ipdata->path, strlen(ipdata->path)); // to write, set payload: coap_set_payload( &msg_send, (uint8_t *)msg_buf, msg_len ); // Send Message if ( (bytes_sent = sendto(ipdata->coapSocket, msg_send.buf, msg_send.len, 0, (struct sockaddr*)&addr_remote, sizeof(struct sockaddr_in))) == -1 ) zlog_error(zc, "Failed to Send Message!"); else { //发送成功 //printf("Sent.\n"); //coap_pretty_print(&msg_send); sin_size = sizeof(struct sockaddr); // Wait for Response bytes_recv = recvfrom(ipdata->coapSocket, (void *)msg_recv.buf, msg_recv.max, 0, (struct sockaddr*)&addr_remote, &sin_size); if (bytes_recv < 0) { zlog_error(zc, "Failed to socket recv Message!"); continue; } /* msg_recv.len = bytes_recv; if(coap_validate_pkt(&msg_recv) == CE_NONE) { printf("Got Valid CoAP Packet\n"); if(coap_get_mid(&msg_recv) == coap_get_mid(&msg_send) && coap_get_token(&msg_recv) == coap_get_token(&msg_send)) { printf("Is Response to Last Message\n"); coap_pretty_print(&msg_recv); } } else { printf("Received %zi Bytes, Not Valid CoAP\n", msg_recv.len); hex_dump(msg_recv.buf, msg_recv.len); } */ } } }
/*---------------------------------------------------------------------------*/ int coap_receive(oc_message_t *msg) { erbium_status_code = NO_ERROR; LOG("\n\nCoAP Engine: received datalen=%u \n", (unsigned int) msg->length); /* static declaration reduces stack peaks and program code size */ static coap_packet_t message[1]; /* this way the packet can be treated as pointer as usual */ static coap_packet_t response[1]; static coap_transaction_t *transaction = NULL; erbium_status_code = coap_parse_message(message, msg->data, msg->length); if (erbium_status_code == NO_ERROR) { /*TODO duplicates suppression, if required by application */ #if DEBUG LOG(" Parsed: CoAP version: %u, token: 0x%02X%02X, mid: %u\n", message->version, message->token[0], message->token[1], message->mid); switch (message->type) { case COAP_TYPE_CON: LOG(" type: CON\n"); break; case COAP_TYPE_NON: LOG(" type: NON\n"); break; case COAP_TYPE_ACK: LOG(" type: ACK\n"); break; case COAP_TYPE_RST: LOG(" type: RST\n"); break; default: break; } #endif /* handle requests */ if (message->code >= COAP_GET && message->code <= COAP_DELETE) { #if DEBUG switch (message->code) { case COAP_GET: LOG(" method: GET\n"); break; case COAP_PUT: LOG(" method: PUT\n"); break; case COAP_POST: LOG(" method: POST\n"); break; case COAP_DELETE: LOG(" method: DELETE\n"); break; } LOG(" URL: %.*s\n", (int) message->uri_path_len, message->uri_path); LOG(" Payload: %.*s\n", (int) message->payload_len, message->payload); #endif /* use transaction buffer for response to confirmable request */ if ((transaction = coap_new_transaction(message->mid, &msg->endpoint))) { uint32_t block_num = 0; uint16_t block_size = COAP_MAX_BLOCK_SIZE; uint32_t block_offset = 0; int32_t new_offset = 0; /* prepare response */ if (message->type == COAP_TYPE_CON) { /* reliable CON requests are answered with an ACK */ coap_init_message(response, COAP_TYPE_ACK, CONTENT_2_05, message->mid); } else { /* unreliable NON requests are answered with a NON as well */ coap_init_message(response, COAP_TYPE_NON, CONTENT_2_05, coap_get_mid()); /* mirror token */ } if (message->token_len) { coap_set_token(response, message->token, message->token_len); /* get offset for blockwise transfers */ } if (coap_get_header_block2(message, &block_num, NULL, &block_size, &block_offset)) { LOG("\tBlockwise: block request %u (%u/%u) @ %u bytes\n", (unsigned int) block_num, block_size, COAP_MAX_BLOCK_SIZE, (unsigned int) block_offset); block_size = MIN(block_size, COAP_MAX_BLOCK_SIZE); new_offset = block_offset; } /* invoke resource handler in RI layer */ if (oc_ri_invoke_coap_entity_handler( message, response, transaction->message->data + COAP_MAX_HEADER_SIZE, block_size, &new_offset, &msg->endpoint)) { if (erbium_status_code == NO_ERROR) { /* TODO coap_handle_blockwise(request, response, start_offset, * end_offset); */ /* resource is unaware of Block1 */ if (IS_OPTION(message, COAP_OPTION_BLOCK1) && response->code < BAD_REQUEST_4_00 && !IS_OPTION(response, COAP_OPTION_BLOCK1)) { LOG("\tBlock1 option NOT IMPLEMENTED\n"); erbium_status_code = NOT_IMPLEMENTED_5_01; coap_error_message = "NoBlock1Support"; /* client requested Block2 transfer */ } else if (IS_OPTION(message, COAP_OPTION_BLOCK2)) { /* unchanged new_offset indicates that resource is unaware of * blockwise transfer */ if (new_offset == block_offset) { LOG("\tBlockwise: unaware resource with payload length %u/%u\n", response->payload_len, block_size); if (block_offset >= response->payload_len) { LOG("\t\t: block_offset >= response->payload_len\n"); response->code = BAD_OPTION_4_02; coap_set_payload(response, "BlockOutOfScope", 15); /* a const char str[] and sizeof(str) produces larger code size */ } else { coap_set_header_block2(response, block_num, response->payload_len - block_offset > block_size, block_size); coap_set_payload( response, response->payload + block_offset, MIN(response->payload_len - block_offset, block_size)); } /* if(valid offset) */ /* resource provides chunk-wise data */ } else { LOG("\tBlockwise: blockwise resource, new offset %d\n", (int) new_offset); coap_set_header_block2(response, block_num, new_offset != -1 || response->payload_len > block_size, block_size); if (response->payload_len > block_size) { coap_set_payload(response, response->payload, block_size); } } /* if(resource aware of blockwise) */ /* Resource requested Block2 transfer */ } else if (new_offset != 0) { LOG("\tBlockwise: no block option for blockwise resource, using " "block size %u\n", COAP_MAX_BLOCK_SIZE); coap_set_header_block2(response, 0, new_offset != -1, COAP_MAX_BLOCK_SIZE); coap_set_payload(response, response->payload, MIN(response->payload_len, COAP_MAX_BLOCK_SIZE)); } /* blockwise transfer handling */ } /* no errors/hooks */ /* successful service callback */ /* serialize response */ } if (erbium_status_code == NO_ERROR) { if ((transaction->message->length = coap_serialize_message( response, transaction->message->data)) == 0) { erbium_status_code = PACKET_SERIALIZATION_ERROR; } } } else { erbium_status_code = SERVICE_UNAVAILABLE_5_03; coap_error_message = "NoFreeTraBuffer"; } /* if(transaction buffer) */ /* handle responses */ } else { // Fix this if (message->type == COAP_TYPE_CON) { erbium_status_code = EMPTY_ACK_RESPONSE; } else if (message->type == COAP_TYPE_ACK) { /* transactions are closed through lookup below */ } else if (message->type == COAP_TYPE_RST) { #ifdef OC_SERVER /* cancel possible subscriptions */ coap_remove_observer_by_mid(&msg->endpoint, message->mid); #endif } /* Open transaction now cleared for ACK since mid matches */ if ((transaction = coap_get_transaction_by_mid(message->mid))) { coap_clear_transaction(transaction); } /* if(ACKed transaction) */ transaction = NULL; #ifdef OC_CLIENT // ACKs and RSTs sent to oc_ri.. RSTs cleared, ACKs sent to // client oc_ri_invoke_client_cb(message, &msg->endpoint); #endif } /* request or response */ } /* parsed correctly */ /* if(parsed correctly) */ if (erbium_status_code == NO_ERROR) { if (transaction) { // Server transactions sent from here coap_send_transaction(transaction); } } else if (erbium_status_code == CLEAR_TRANSACTION) { LOG("Clearing transaction for manual response"); coap_clear_transaction(transaction); // used in server for separate response } #ifdef OC_CLIENT else if (erbium_status_code == EMPTY_ACK_RESPONSE) { coap_init_message(message, COAP_TYPE_ACK, 0, message->mid); oc_message_t *response = oc_allocate_message(); if (response) { memcpy(&response->endpoint, &msg->endpoint, sizeof(msg->endpoint)); response->length = coap_serialize_message(message, response->data); coap_send_message(response); } } #endif /* OC_CLIENT */ #ifdef OC_SERVER else { // framework errors handled here coap_message_type_t reply_type = COAP_TYPE_RST; coap_clear_transaction(transaction); coap_init_message(message, reply_type, SERVICE_UNAVAILABLE_5_03, message->mid); oc_message_t *response = oc_allocate_message(); if (response) { memcpy(&response->endpoint, &msg->endpoint, sizeof(msg->endpoint)); response->length = coap_serialize_message(message, response->data); coap_send_message(response); } } #endif /* OC_SERVER */ /* if(new data) */ return erbium_status_code; }
void coap_createCoapRequest(coap_method_t method, const char * uri, ContentType contentType, ObserveState observeState, const char * payload, int payloadLen, TransactionCallback callback, void * context) { coap_packet_t request; char path[MAX_COAP_PATH] = { 0 }; char query[128] = { 0 }; coap_transaction_t *transaction; NetworkAddress * remoteAddress = NetworkAddress_New(uri, strlen(uri)); coap_getPathQueryFromURI(uri, path, query); Lwm2m_Info("Coap request: %s\n", uri); //Lwm2m_Debug("Coap request path: %s\n", path); //Lwm2m_Debug("Coap request query: %s\n", query); coap_init_message(&request, COAP_TYPE_CON, method, coap_get_mid()); coap_set_header_uri_path(&request, path); if (strlen(query) > 0) coap_set_header_uri_query(&request, query); // TODO - REVIEW: Erbium must copy path/query from request - else mem out of scope if (contentType != ContentType_None) { if ((method == COAP_POST) || (method == COAP_PUT)) { coap_set_header_content_format(&request, contentType); coap_set_payload(&request, payload, payloadLen); } else { coap_set_header_accept(&request, contentType); } } if (method == COAP_GET) { if (observeState == ObserveState_Establish) { coap_set_header_observe(&request, 0); int token = addObserve(remoteAddress, path, callback, context); if (token != 0) coap_set_token(&request, (const uint8_t *) &token, sizeof(token)); } else if (observeState == ObserveState_Cancel) { coap_set_header_observe(&request, 1); int token = removeObserve(remoteAddress, path); if (token != 0) coap_set_token(&request, (const uint8_t *) &token, sizeof(token)); } } if (CurrentTransaction[CurrentTransactionIndex].TransactionUsed && CurrentTransaction[CurrentTransactionIndex].TransactionPtr) { Lwm2m_Warning("Canceled previous transaction [%d]: %p\n", CurrentTransactionIndex, CurrentTransaction[CurrentTransactionIndex].TransactionPtr); coap_clear_transaction(&CurrentTransaction[CurrentTransactionIndex].TransactionPtr); } //if ((transaction = coap_new_transaction(request.mid, remote_ipaddr, uip_htons(remote_port)))) if ((transaction = coap_new_transaction(networkSocket, request.mid, remoteAddress))) { transaction->callback = coap_CoapRequestCallback; memcpy(CurrentTransaction[CurrentTransactionIndex].Path, path, MAX_COAP_PATH); CurrentTransaction[CurrentTransactionIndex].Callback = callback; CurrentTransaction[CurrentTransactionIndex].Context = context; CurrentTransaction[CurrentTransactionIndex].TransactionUsed = true; CurrentTransaction[CurrentTransactionIndex].TransactionPtr = transaction; NetworkAddress_SetAddressType(remoteAddress, &CurrentTransaction[CurrentTransactionIndex].Address); transaction->callback_data = &CurrentTransaction[CurrentTransactionIndex]; transaction->packet_len = coap_serialize_message(&request, transaction->packet); Lwm2m_Debug("Sending transaction [%d]: %p\n", CurrentTransactionIndex, CurrentTransaction[CurrentTransactionIndex].TransactionPtr); coap_send_transaction(transaction); CurrentTransactionIndex++; if (CurrentTransactionIndex >= MAX_COAP_TRANSACTIONS) { CurrentTransactionIndex = 0; } } }