/* * Function: _wilddog_coap_send. * Description: send out and coap package. * * Input: p_coap : point to an coap package. * Output: N/A. * Return: Wilddog_Return_T type. */ Wilddog_Return_T WD_SYSTEM _wilddog_coap_send(void *p_arg,int flag) { coap_pdu_t *p_coap = (coap_pdu_t*)p_arg; if( p_coap == NULL) return WILDDOG_ERR_INVALID; #ifdef DEBUG_LEVEL if(DEBUG_LEVEL <= WD_DEBUG_LOG ) coap_show_pdu(p_coap); #endif return _wilddog_sec_send(p_coap->hdr, p_coap->length); }
// When we receive the CoAP response we build and send the HTTP response void coap_response_handler(struct coap_context_t *ctx, const coap_endpoint_t *local_interface, const coap_address_t *remote, coap_pdu_t *sent, coap_pdu_t *received, const coap_tid_t id) { printf("COAP %13s:%-5u -> ", inet_ntoa((&remote->addr.sin)->sin_addr), ntohs((&remote->addr.sin)->sin_port)); coap_show_pdu(received); for(int i = 0; i < MAX_HTTP_CONNECTIONS; i++) { if(http_coap_pairs[i].message_id == received->hdr->id) { struct MHD_Connection *connection = http_coap_pairs[i].connection; size_t len = 0; unsigned char *databuf = NULL; struct MHD_Response *response = MHD_create_response_from_buffer(len, databuf, MHD_RESPMEM_MUST_COPY); int read_result = coap_get_data(received, &len, &databuf); if(received->hdr->code == COAP_RESPONSE_CODE(205) && read_result == 0) { coap_abort_to_http(connection, "coap_get_data: cannot read CoAP response data\n"); } static char tid_str[8]; snprintf(tid_str, sizeof(tid_str), "%u", ntohs(received->hdr->id)); MHD_add_response_header(response, "X-CoAP-Message-Id", tid_str); MHD_add_response_header(response, "X-CoAP-Response-Code", msg_code_string(received->hdr->code)); // HTTP Content-Type const char *http_content_type; int coap_content_format; coap_opt_iterator_t opt_iter; coap_opt_t *option; coap_option_iterator_init(received, &opt_iter, COAP_OPT_ALL); while((option = coap_option_next(&opt_iter))) { switch(opt_iter.type) { case COAP_OPTION_CONTENT_FORMAT: coap_content_format = (int)coap_decode_var_bytes(COAP_OPT_VALUE(option), COAP_OPT_LENGTH(option)); break; default: continue; } } switch(coap_content_format) { case COAP_MEDIATYPE_TEXT_PLAIN: http_content_type = "text/plain"; break; case COAP_MEDIATYPE_APPLICATION_LINK_FORMAT: http_content_type = "application/link-format"; break; case COAP_MEDIATYPE_APPLICATION_XML: http_content_type = "application/xml"; break; case COAP_MEDIATYPE_APPLICATION_OCTET_STREAM: http_content_type = "application/octet-stream"; break; case COAP_MEDIATYPE_APPLICATION_EXI: http_content_type = "application/exi"; break; case COAP_MEDIATYPE_APPLICATION_JSON: http_content_type = "application/json"; break; case COAP_MEDIATYPE_APPLICATION_CBOR: http_content_type = "application/cbor"; break; default: http_content_type = "unknown"; break; } MHD_add_response_header(response, MHD_HTTP_HEADER_CONTENT_TYPE, http_content_type); // HTTP Code unsigned int http_code; switch(received->hdr->code) { case COAP_RESPONSE_200: http_code = MHD_HTTP_NO_CONTENT; break; /* 2.00 OK */ case COAP_RESPONSE_201: http_code = MHD_HTTP_CREATED; break; /* 2.01 Created */ case COAP_RESPONSE_CODE(205): http_code = MHD_HTTP_OK; break; case COAP_RESPONSE_304: http_code = MHD_HTTP_ACCEPTED; break; /* 2.03 Valid */ case COAP_RESPONSE_400: http_code = MHD_HTTP_BAD_REQUEST; break; /* 4.00 Bad Request */ case COAP_RESPONSE_404: http_code = MHD_HTTP_NOT_FOUND; break; /* 4.04 Not Found */ case COAP_RESPONSE_405: http_code = MHD_HTTP_NOT_ACCEPTABLE; break; /* 4.05 Method Not Allowed */ case COAP_RESPONSE_415: http_code = MHD_HTTP_UNSUPPORTED_MEDIA_TYPE;break; /* 4.15 Unsupported Media Type */ case COAP_RESPONSE_500: http_code = MHD_HTTP_INTERNAL_SERVER_ERROR; break; /* 5.00 Internal Server Error */ case COAP_RESPONSE_501: http_code = MHD_HTTP_NOT_IMPLEMENTED; break; /* 5.01 Not Implemented */ case COAP_RESPONSE_503: http_code = MHD_HTTP_SERVICE_UNAVAILABLE; break; /* 5.03 Service Unavailable */ case COAP_RESPONSE_504: http_code = MHD_HTTP_GATEWAY_TIMEOUT; break; /* 5.04 Gateway Timeout */ default: http_code = MHD_HTTP_INTERNAL_SERVER_ERROR; break; } // Send the response MHD_queue_response(connection, http_code, response); MHD_destroy_response(response); const struct sockaddr_in *client_addr = (const struct sockaddr_in *) MHD_get_connection_info(connection, MHD_CONNECTION_INFO_CLIENT_ADDRESS)->client_addr; printf("HTTP %13s:%-5u <- %u %s [ %s, %zu bytes, \"%s\" ]\n", inet_ntoa(client_addr->sin_addr), ntohs(client_addr->sin_port), http_code, http_reason_phrase_for(http_code), http_content_type, len, (databuf != NULL) ? (char *)databuf : ""); } // clear the association http_coap_pairs[i].connection = NULL; return; } }
int coap_read(coap_context_t *ctx, struct sockaddr_in6 *src, void *buf, uint16_t bytes_read, struct ip6_metadata *meta) { coap_queue_t *node; coap_opt_t *opt; if ( bytes_read < 0 ) { return -1; } if ( bytes_read < sizeof(coap_hdr_t) || ((coap_hdr_t *)buf)->version != COAP_DEFAULT_VERSION ) { #ifndef NDEBUG //fprintf(stderr, "coap_read: discarded invalid frame\n" ); #endif return -1; } node = coap_new_node(); if ( !node ) return -1; node->pdu = coap_new_pdu(); if ( !node->pdu ) { coap_delete_node( node ); return -1; } /*printf("** coap: coap_read pointers %p %p, %p %p\n", &node->remote, node->remote, src, *src, sizeof(src), sizeof(*src));*/ memcpy( &node->remote, src, sizeof( *src ) ); /* "parse" received PDU by filling pdu structure */ memcpy( node->pdu->hdr, buf, bytes_read ); node->pdu->length = bytes_read; /* finally calculate beginning of data block */ options_end( node->pdu, &opt ); if ( (unsigned char *)node->pdu->hdr + node->pdu->length < (unsigned char *)opt ) node->pdu->data = (unsigned char *)node->pdu->hdr + node->pdu->length; else node->pdu->data = (unsigned char *)opt; /* and add new node to receive queue */ coap_insert_node( &ctx->recvqueue, node, order_transaction_id ); #ifndef NDEBUG if ( inet_ntop(src.sin6_family, &src.sin6_addr, addr, INET6_ADDRSTRLEN) == 0 ) { //perror("coap_read: inet_ntop"); } else { printf( "** received from [%s]:%d:\n ",addr,ntohs(src.sin6_port)); } coap_show_pdu( node->pdu ); #endif return 0; }
//This function is called back by libcoap when a request is received static void HandleCoAPRequests(struct coap_context_t *ctx, const coap_queue_t * rcvdRequest) { // silence warnings (void) ctx; OCServerProtocolRequest protocolRequest = {(OCMethod)0}; coap_block_t rcvdBlock1; coap_block_t rcvdBlock2; memset(&rcvdBlock1, COAP_BLOCK_FILL_VALUE, sizeof(coap_block_t)); memset(&rcvdBlock2, COAP_BLOCK_FILL_VALUE, sizeof(coap_block_t)); uint16_t rcvdSize1 = 0; coap_pdu_t * rcvdPdu = rcvdRequest->pdu; coap_pdu_t * sendPdu = NULL; coap_send_flags_t sendFlag; OCStackResult result = OC_STACK_ERROR; OCStackResult requestResult = OC_STACK_ERROR; if(myStackMode == OC_CLIENT) { //TODO: should the client be responding to requests? return; } protocolRequest.observationOption = OC_OBSERVE_NO_OPTION; protocolRequest.qos = (rcvdPdu->hdr->type == COAP_MESSAGE_CON) ? OC_HIGH_QOS : OC_LOW_QOS; protocolRequest.coapID = rcvdPdu->hdr->id; protocolRequest.delayedResNeeded = rcvdRequest->delayedResNeeded; protocolRequest.secured = rcvdRequest->secure; // fill OCCoAPToken structure RetrieveOCCoAPToken(rcvdPdu, &protocolRequest.requestToken); OC_LOG_V(INFO, TAG, " Token received %d bytes", protocolRequest.requestToken.tokenLength); OC_LOG_BUFFER(INFO, TAG, protocolRequest.requestToken.token, protocolRequest.requestToken.tokenLength); // fill OCDevAddr memcpy(&protocolRequest.requesterAddr, (OCDevAddr *) &rcvdRequest->remote, sizeof(OCDevAddr)); // Retrieve Uri and Query from received coap pdu result = ParseCoAPPdu(rcvdPdu, protocolRequest.resourceUrl, protocolRequest.query, &(protocolRequest.observationOption), NULL, &(protocolRequest.numRcvdVendorSpecificHeaderOptions), protocolRequest.rcvdVendorSpecificHeaderOptions, &rcvdBlock1, &rcvdBlock2, &rcvdSize1, NULL, protocolRequest.reqJSONPayload); VERIFY_SUCCESS(result, OC_STACK_OK); switch (rcvdPdu->hdr->code) { case COAP_REQUEST_GET: { protocolRequest.method = OC_REST_GET; break; } case COAP_REQUEST_POST: { protocolRequest.method = OC_REST_POST; break; } case COAP_REQUEST_DELETE: { protocolRequest.method = OC_REST_DELETE; break; } case COAP_REQUEST_PUT: { protocolRequest.method = OC_REST_PUT; break; } default: { OC_LOG_V(ERROR, TAG, "Received CoAP method %d not supported", rcvdPdu->hdr->code); goto exit; } } if(rcvdBlock1.szx != 7) { protocolRequest.reqPacketSize = 1 << (rcvdBlock1.szx + 4); protocolRequest.reqMorePacket = rcvdBlock1.m; protocolRequest.reqPacketNum = rcvdBlock1.num; } else { // No block1 received rcvdSize1 = strlen((const char *)protocolRequest.reqJSONPayload)+1; protocolRequest.reqTotalSize = rcvdSize1; } if(rcvdBlock2.szx != 7) { protocolRequest.resPacketSize = 1 << (rcvdBlock2.szx + 4); protocolRequest.resPacketNum = rcvdBlock2.num; } requestResult = HandleStackRequests(&protocolRequest); if(requestResult == OC_STACK_VIRTUAL_DO_NOT_HANDLE || requestResult == OC_STACK_OK || requestResult == OC_STACK_RESOURCE_CREATED || requestResult == OC_STACK_RESOURCE_DELETED || requestResult == OC_STACK_INVALID_DEVICE_INFO) { goto exit; } else if(requestResult == OC_STACK_NO_MEMORY || requestResult == OC_STACK_ERROR || requestResult == OC_STACK_NOTIMPL || requestResult == OC_STACK_NO_RESOURCE || requestResult == OC_STACK_RESOURCE_ERROR) { // TODO: should we send an error also when we receive a non-secured request to a secure resource? // TODO: should we consider some sort of error response OC_LOG(DEBUG, TAG, PCF("We should send some sort of error message")); // generate the pdu, if the request was CON, then the response is ACK, otherwire NON sendPdu = GenerateCoAPPdu((rcvdPdu->hdr->type == COAP_MESSAGE_CON)? COAP_MESSAGE_ACK : COAP_MESSAGE_NON, OCToCoAPResponseCode(requestResult), rcvdPdu->hdr->id, &protocolRequest.requestToken, NULL, NULL); VERIFY_NON_NULL(sendPdu); coap_show_pdu(sendPdu); sendFlag = (coap_send_flags_t)(rcvdRequest->secure ? SEND_SECURE_PORT : 0); if(SendCoAPPdu(gCoAPCtx, (coap_address_t*) &(rcvdRequest->remote), sendPdu, sendFlag) != OC_STACK_OK){ OC_LOG(DEBUG, TAG, PCF("A problem occurred in sending a pdu")); } goto exit; } else if(requestResult == OC_STACK_SLOW_RESOURCE) { if(rcvdPdu->hdr->type == COAP_MESSAGE_CON) { // generate the pdu, if the request was CON, then the response is ACK, otherwire NON sendPdu = GenerateCoAPPdu(COAP_MESSAGE_ACK, 0, rcvdPdu->hdr->id, NULL, NULL, NULL); VERIFY_NON_NULL(sendPdu); coap_show_pdu(sendPdu); sendFlag = (coap_send_flags_t)(rcvdRequest->secure ? SEND_SECURE_PORT : 0); if(SendCoAPPdu(gCoAPCtx, (coap_address_t*) &(rcvdRequest->remote), sendPdu, sendFlag) != OC_STACK_OK){ OC_LOG(DEBUG, TAG, PCF("A problem occurred in sending a pdu")); } } else { goto exit; } } exit: return; }
/* to do * Function: _wilddog_coap_receive. * Description: recv coap packet and handle it. * * Input: N/A. * Output: N/A. * Return: Wilddog_Return_T type */ Wilddog_Return_T WD_SYSTEM _wilddog_coap_receive(void *p_arg,int flag) { int res =0; u32 recv_type = 0; u32 ack_type = COAP_MESSAGE_ACK; u32 tmp_tokenLen = 0; u32 tmp_token = 0; u32 tmp_mid = 0; Protocol_recvArg_T recvArg; coap_pdu_t *p_pdu = NULL; memset(&recvArg,0,sizeof(Protocol_recvArg_T)); recvArg.p_recvData = _wilddog_coap_mallocRecvBuffer(); if( recvArg.p_recvData == NULL) { wilddog_debug_level(WD_DEBUG_ERROR, "malloc failed!"); return WILDDOG_ERR_NULL; } res = _wilddog_sec_recv((void*)recvArg.p_recvData,(s32)WILDDOG_PROTO_MAXSIZE); /*@ NO enougth space */ if( res <= 0 || res > WILDDOG_PROTO_MAXSIZE ) goto _COAPRECV_ERR; recvArg.d_recvDataLen = res; /* distinguish recv an coap packet. */ p_pdu = _wilddog_recvCoap(recvArg.p_recvData,recvArg.d_recvDataLen); if(p_pdu == NULL) goto _COAPRECV_ERR; #ifdef WILDDOG_SELFTEST ramtest_caculate_peakRam(); performtest_getHandleRecvDtlsTime(); #endif #ifdef WILDDOG_DEBUG #if DEBUG_LEVEL <= WD_DEBUG_LOG printf("recv:\n"); coap_show_pdu(p_pdu); #endif #endif /* dispatch .*/ recvArg.d_recvDataLen = WILDDOG_PROTO_MAXSIZE; if( _wilddog_recv_dispatch(p_pdu,&recvArg) < 0) { coap_delete_pdu(p_pdu); goto _COAPRECV_ERR; } tmp_mid = p_pdu->hdr->id; recv_type = p_pdu->hdr->type; tmp_tokenLen = p_pdu->hdr->token_length; memcpy(&tmp_token,p_pdu->hdr->token,p_pdu->hdr->token_length); coap_delete_pdu(p_pdu); /* call back.*/ if( _wilddog_coap_findRespondNode(&recvArg) != TRUE) ack_type = COAP_MESSAGE_RST; /* ack */ _wilddog_coap_ackSend(recv_type,ack_type,tmp_mid,tmp_tokenLen,tmp_token); _wilddog_coap_freeRecvBuffer( recvArg.p_recvData ); return WILDDOG_ERR_NOERR; _COAPRECV_ERR: _wilddog_coap_freeRecvBuffer( recvArg.p_recvData ); return WILDDOG_ERR_NULL; }