smcp_status_t resend_get_request(void* context) { ThingMLCOAPContext * thingml_context = (ThingMLCOAPContext*) context; smcp_status_t status = 0; status = smcp_outbound_begin(smcp_get_current_instance(),COAP_METHOD_GET, get_tt); require_noerr(status,bail); status = smcp_outbound_set_uri(thingml_context->url, 0); require_noerr(status,bail); if(request_accept_type!=COAP_CONTENT_TYPE_UNKNOWN) { status = smcp_outbound_add_option_uint(COAP_OPTION_ACCEPT, request_accept_type); require_noerr(status,bail); } status = smcp_outbound_send(); if(status) { check_noerr(status); fprintf(stderr, "smcp_outbound_send() returned error %d(%s).\n", status, smcp_status_to_cstr(status)); goto bail; } bail: return status; }
smcp_status_t resend_async_response(void* context) { smcp_status_t ret = 0; struct smcp_async_response_s* async_response = (void*)context; ret = smcp_outbound_begin_async_response(COAP_RESULT_205_CONTENT,async_response); require_noerr(ret,bail); ret = smcp_outbound_add_option_uint(COAP_OPTION_CONTENT_TYPE, COAP_CONTENT_TYPE_TEXT_PLAIN); require_noerr(ret,bail); ret = smcp_outbound_set_content_formatted("This was an asynchronous response!"); require_noerr(ret,bail); ret = smcp_outbound_send(); require_noerr(ret,bail); if(ret) { assert_printf( "smcp_outbound_send() returned error %d(%s).\n", ret, smcp_status_to_cstr(ret) ); goto bail; } bail: return ret; }
static smcp_status_t delete_response_handler( int statuscode, void* context ) { if (statuscode >= 0) { char* content = (char*)smcp_inbound_get_content_ptr(); coap_size_t content_length = smcp_inbound_get_content_len(); if(content_length>(smcp_inbound_get_packet_length()-4)) { fprintf(stderr, "INTERNAL ERROR: CONTENT_LENGTH LARGER THAN PACKET_LENGTH-4! (content_length=%u, packet_length=%u)\n",content_length,smcp_inbound_get_packet_length()); gRet = ERRORCODE_UNKNOWN; goto bail; } if (delete_show_headers) { coap_dump_header( stdout, NULL, smcp_inbound_get_packet(), smcp_inbound_get_packet_length() ); } if(!coap_verify_packet((void*)smcp_inbound_get_packet(), smcp_inbound_get_packet_length())) { fprintf(stderr, "INTERNAL ERROR: CALLBACK GIVEN INVALID PACKET!\n"); gRet = ERRORCODE_UNKNOWN; goto bail; } if (statuscode != COAP_RESULT_202_DELETED) { fprintf(stderr, "delete: Result code = %d (%s)\n", statuscode, (statuscode < 0) ? smcp_status_to_cstr( statuscode) : coap_code_to_cstr(statuscode)); } if(content && content_length) { char contentBuffer[500]; content_length = ((content_length > sizeof(contentBuffer) - 2) ? sizeof(contentBuffer) - 2 : content_length); memcpy(contentBuffer, content, content_length); contentBuffer[content_length] = 0; if(content_length && (contentBuffer[content_length - 1] == '\n')) contentBuffer[--content_length] = 0; printf("%s\n", contentBuffer); } } bail: if (gRet == ERRORCODE_INPROGRESS) { gRet = 0; } return SMCP_STATUS_OK; }
static void async_response_ack_handler(int statuscode, void* context) { struct smcp_async_response_s* async_response = (void*)context; printf(" *** Finished sending async response.\n"); printf(" * RESULT CODE = %d (%s)\n", statuscode, (statuscode>0)?coap_code_to_cstr(statuscode):smcp_status_to_cstr(statuscode)); smcp_finish_async_response(async_response); }
static smcp_status_t resend_async_response(void* context) { smcp_status_t ret = 0; smcp_curl_request_t request = (smcp_curl_request_t)context; struct smcp_async_response_s* async_response = &request->async_response; coap_size_t len = (coap_size_t)request->content_len; if(len>512) { len = 512; } { uint16_t code; curl_easy_getinfo(request->curl, CURLINFO_RESPONSE_CODE,&code); code = http_to_coap_code(code); ret = smcp_outbound_begin_async_response(code,async_response); require_noerr(ret,bail); } { const char* content_type_string; curl_easy_getinfo(request->curl, CURLINFO_CONTENT_TYPE,&content_type_string); coap_content_type_t content_type = coap_content_type_from_cstr(content_type_string); if(content_type!=COAP_CONTENT_TYPE_UNKNOWN) { ret = smcp_outbound_add_option_uint(COAP_OPTION_CONTENT_TYPE, content_type); check_noerr(ret); } else { DEBUG_PRINTF("Unrecognised content-type: %s",content_type_string); } } ret = smcp_outbound_append_content(request->content, len); require_noerr(ret,bail); ret = smcp_outbound_send(); require_noerr(ret,bail); if(ret) { assert_printf( "smcp_outbound_send() returned error %d(%s).\n", ret, smcp_status_to_cstr(ret) ); goto bail; } bail: return ret; }
static smcp_status_t list_response_handler( int statuscode, void* context ) { // smcp_t const self = smcp_get_current_instance(); const char* content = smcp_inbound_get_content_ptr(); printf(" *** GOT LIST RESPONSE!!! ***\n"); printf(" * RESULT CODE = %d (%s)\n", statuscode, (statuscode>0)?coap_code_to_cstr(statuscode):smcp_status_to_cstr(statuscode)); if(content) { printf(" * CONTENT = \"%s\"\n", content); } return SMCP_STATUS_OK; }
static smcp_status_t pair_response_handler( int statuscode, void* context ) { // smcp_t const self = smcp_get_current_instance(); char* content = (char*)smcp_inbound_get_content_ptr(); coap_size_t content_length = smcp_inbound_get_content_len(); if((statuscode >= COAP_RESULT_100) && show_headers) { fprintf(stdout, "\n"); coap_dump_header( stdout, "NULL", smcp_inbound_get_packet(), 0 ); } if(((statuscode < COAP_RESULT_200) || (statuscode >= COAP_RESULT_300)) && (statuscode != SMCP_STATUS_TRANSACTION_INVALIDATED)) fprintf(stderr, "pair: Result code = %d (%s)\n", statuscode, (statuscode < 0) ? smcp_status_to_cstr( statuscode) : coap_code_to_cstr(statuscode)); if(content && content_length) { char contentBuffer[500]; content_length = ((content_length > sizeof(contentBuffer) - 2) ? sizeof(contentBuffer) - 2 : content_length); memcpy(contentBuffer, content, content_length); contentBuffer[content_length] = 0; if(content_length && (contentBuffer[content_length - 1] == '\n')) contentBuffer[--content_length] = 0; printf("%s\n", contentBuffer); } if(gRet == ERRORCODE_INPROGRESS) gRet = ERRORCODE_OK; free(context); return SMCP_STATUS_OK; }
void dump_test_results(const test_data_s *test_data) { printf("\tURL: %s\n",test_data->url); if(test_data->inbound_code) printf("\tinbound_code: %s (%d)\n", coap_code_to_cstr(test_data->inbound_code), COAP_TO_HTTP_CODE(test_data->inbound_code)); if(test_data->error || test_data->failed) { if(test_data->error) printf("\terror: %s (%d)\n", smcp_status_to_cstr(test_data->error), test_data->error); } { smcp_cms_t duration = smcp_plat_timestamp_diff(test_data->stop_time,test_data->start_time); printf("\tduration: %dms\n", (int)duration); } if(test_data->has_block1_option) { struct coap_block_info_s block_info; coap_decode_block(&block_info, test_data->block1_option); printf("\tblock1: %d/%d/%d\n", block_info.block_offset,block_info.block_m,block_info.block_size); } if(test_data->has_block2_option) { struct coap_block_info_s block_info; coap_decode_block(&block_info, test_data->block2_option); printf("\tblock2: %d/%d/%d\n", block_info.block_offset,block_info.block_m,block_info.block_size); } printf("\tlast_msg_id: 0x%04X\n", (int)test_data->msg_id); printf("\tinbound_content_len: %d\n", (int)test_data->inbound_content_len); if(test_data->inbound_packets!=1) { printf("\tinbound_packets: %d\n", test_data->inbound_packets); } if(test_data->inbound_dupe_packets!=0) { printf("\tinbound_dupes: %d\n", test_data->inbound_dupe_packets); } if(test_data->outbound_attempts!=1) { printf("\toutbound_attempts: %d\n", test_data->outbound_attempts); } if(test_data->response[0]!=0) { printf("\tresponse: \"%s\"\n", test_data->response); } }
bool send_get_request(smcp_t smcp, const char* next, coap_size_t nextlen, void *thingML_context) { bool ret = false; smcp_status_t status = 0; int flags = SMCP_TRANSACTION_ALWAYS_INVALIDATE; gRet = ERRORCODE_INPROGRESS; retries = 0; if(get_observe) flags |= SMCP_TRANSACTION_OBSERVE; if(get_keep_alive) flags |= SMCP_TRANSACTION_KEEPALIVE; smcp_transaction_end(smcp,&transaction); smcp_transaction_init( &transaction, flags, // Flags (void*)&resend_get_request, (void*)&get_response_handler, thingML_context ); status = smcp_transaction_begin(smcp, &transaction, get_timeout); if(status) { check(!status); fprintf(stderr, "smcp_begin_transaction_old() returned %d(%s).\n", status, smcp_status_to_cstr(status)); goto bail; } ret = true; bail: return ret; }
smcp_status_t resend_test_request(void* context) { test_data_s* test_data = context; smcp_status_t status = 0; status = smcp_outbound_begin(smcp_get_current_instance(),test_data->outbound_code, test_data->outbound_tt); require_noerr(status,bail); status = smcp_outbound_set_uri(test_data->url, 0); require_noerr(status,bail); if (test_data->outbound_content_type != COAP_CONTENT_TYPE_UNKNOWN) { status = smcp_outbound_add_option_uint(COAP_OPTION_CONTENT_TYPE, test_data->outbound_content_type); require_noerr(status,bail); } if (test_data->extra & EXT_BLOCK_01) { struct coap_block_info_s block1_info; uint32_t resource_length = 200; uint32_t block_stop; coap_decode_block(&block1_info, test_data->block1_option + (1<<4)); block_stop = block1_info.block_offset+block1_info.block_size; if (block1_info.block_offset < resource_length) { if (block_stop >= resource_length) { test_data->block1_option &= ~(1<<3); } else { test_data->block1_option |= (1<<3); } if (test_data->has_block1_option) { test_data->block1_option += (1<<4); } smcp_outbound_add_option_uint(COAP_OPTION_BLOCK1, test_data->block1_option); if (block1_info.block_m) { coap_size_t max_len = 0; uint32_t i; uint32_t block_stop; char* content = NULL; content = smcp_outbound_get_content_ptr(&max_len); if (!content) { status = SMCP_STATUS_FAILURE; goto bail; } block_stop = block1_info.block_offset+block1_info.block_size; for (i = block1_info.block_offset; i < block_stop; i++) { if (!((i + 1) % 64)) { content[i-block1_info.block_offset] = '\n'; } else { content[i-block1_info.block_offset] = '0'+(i%10); } } status = smcp_outbound_set_content_len(MIN((coap_code_t)(block_stop-block1_info.block_offset),(coap_code_t)(resource_length-block1_info.block_offset))); require_noerr(status,bail); } } } if(test_data->extra & EXT_BLOCK_02) { smcp_outbound_add_option_uint(COAP_OPTION_BLOCK2, 1); // 32 byte block size. } status = smcp_outbound_send(); if(status) { check_noerr(status); fprintf(stderr, "smcp_outbound_send() returned error %d(%s).\n", status, smcp_status_to_cstr(status)); goto bail; } else { test_data->outbound_attempts++; } bail: return status; }
smcp_status_t smcp_variable_node_request_handler( smcp_variable_node_t node ) { // TODO: Make this function use less stack space! smcp_method_t method = smcp_inbound_get_code(); smcp_status_t ret = SMCP_STATUS_NOT_FOUND; SMCP_NON_RECURSIVE coap_content_type_t content_type; SMCP_NON_RECURSIVE char* content_ptr; SMCP_NON_RECURSIVE size_t content_len; SMCP_NON_RECURSIVE char buffer[SMCP_VARIABLE_MAX_VALUE_LENGTH+1]; SMCP_NON_RECURSIVE coap_content_type_t reply_content_type; uint8_t key_index = BAD_KEY_INDEX; size_t value_len; bool needs_prefix = true; char* prefix_name = ""; content_type = smcp_inbound_get_content_type(); content_ptr = (char*)smcp_inbound_get_content_ptr(); content_len = smcp_inbound_get_content_len(); reply_content_type = SMCP_CONTENT_TYPE_APPLICATION_FORM_URLENCODED; require(node, bail); // Look up the key index. if(smcp_inbound_peek_option(NULL,&value_len)==COAP_OPTION_URI_PATH) { if(!value_len) { needs_prefix = false; smcp_inbound_next_option(NULL,NULL); } else for(key_index=0;key_index<BAD_KEY_INDEX;key_index++) { ret = node->func(node,SMCP_VAR_GET_KEY,key_index,buffer); require_action(ret==0,bail,ret=SMCP_STATUS_NOT_FOUND); if(smcp_inbound_option_strequal(COAP_OPTION_URI_PATH, buffer)) { smcp_inbound_next_option(NULL,NULL); break; } } } { coap_option_key_t key; const uint8_t* value; while((key=smcp_inbound_next_option(&value, &value_len))!=COAP_OPTION_INVALID) { require_action(key!=COAP_OPTION_URI_PATH,bail,ret=SMCP_STATUS_NOT_FOUND); if(key==COAP_OPTION_URI_QUERY) { if( method == COAP_METHOD_POST && value_len>=2 && strhasprefix_const((const char*)value,"v=") ) { DEBUG_PRINTF("variable-node: value is in the query."); content_type = COAP_CONTENT_TYPE_TEXT_PLAIN; content_ptr = (char*)value+2; content_len = value_len-2; } // } else if(key==COAP_OPTION_ETAG) { // } else if(key==COAP_OPTION_IF_MATCH) { // } else if(key==COAP_OPTION_IF_NONE_MATCH) { } else if(key==COAP_OPTION_ACCEPT) { reply_content_type = 0; if(value_len==1) reply_content_type = value[0]; else { // Unsupported type. } } else if(COAP_OPTION_IS_CRITICAL(key)) { ret=SMCP_STATUS_BAD_OPTION; assert_printf("Unrecognized option %d, \"%s\"", key, coap_option_key_to_cstr(key, false) ); goto bail; } } } // TODO: Implement me! if(method == COAP_METHOD_PUT) method = COAP_METHOD_POST; if(method == COAP_METHOD_POST) { require_action(!smcp_inbound_is_dupe(),bail,ret=0); require_action( key_index!=BAD_KEY_INDEX, bail, ret=SMCP_STATUS_NOT_ALLOWED ); if(content_type==SMCP_CONTENT_TYPE_APPLICATION_FORM_URLENCODED) { char* key = NULL; char* value = NULL; content_len = 0; while( url_form_next_value( (char**)&content_ptr, &key, &value ) && key && value ) { if(strequal_const(key, "v")) { content_ptr = value; content_len = strlen(value); break; } } } // Make sure our content is zero terminated. ((char*)content_ptr)[content_len] = 0; ret = node->func(node,SMCP_VAR_SET_VALUE,key_index,(char*)content_ptr); require_noerr(ret,bail); ret = smcp_outbound_begin_response(COAP_RESULT_204_CHANGED); require_noerr(ret,bail); ret = smcp_outbound_send(); require_noerr(ret,bail); } else if(method == COAP_METHOD_GET) { if(key_index==BAD_KEY_INDEX) { char* content_end_ptr; ret = smcp_outbound_begin_response(COAP_RESULT_205_CONTENT); require_noerr(ret,bail); smcp_outbound_add_option_uint(COAP_OPTION_CONTENT_TYPE, COAP_CONTENT_TYPE_APPLICATION_LINK_FORMAT); ret = smcp_observable_update(&node->observable, SMCP_OBSERVABLE_BROADCAST_KEY); check_string(ret==0,smcp_status_to_cstr(ret)); content_ptr = smcp_outbound_get_content_ptr(&content_len); content_end_ptr = content_ptr+content_len; for(key_index=0;key_index<BAD_KEY_INDEX;key_index++) { ret = node->func(node,SMCP_VAR_GET_KEY,key_index,buffer); if(ret) break; if(content_ptr+2>=content_end_ptr) { // No more room for content. break; } *content_ptr++ = '<'; if(needs_prefix) { content_ptr += url_encode_cstr(content_ptr, prefix_name, (content_end_ptr-content_ptr)-1); content_ptr = stpncpy(content_ptr,"/",MIN(1,(content_end_ptr-content_ptr)-1)); } content_ptr += url_encode_cstr(content_ptr, buffer, (content_end_ptr-content_ptr)-1); *content_ptr++ = '>'; ret = node->func(node,SMCP_VAR_GET_VALUE,key_index,buffer); if(content_ptr+4>=content_end_ptr) { // No more room for content. break; } if(!ret) { strcpy(content_ptr,";v="); content_ptr += 3; content_ptr += quoted_cstr(content_ptr, buffer, (content_end_ptr-content_ptr)-1); } ret = node->func(node,SMCP_VAR_GET_LF_TITLE,key_index,buffer); if(content_ptr+8>=content_end_ptr) { // No more room for content. break; } if(!ret) { strcpy(content_ptr,";title="); content_ptr += 7; content_ptr += quoted_cstr(content_ptr, buffer, (content_end_ptr-content_ptr)-1); } // Observation flag if(0==node->func(node,SMCP_VAR_GET_OBSERVABLE,key_index,NULL)) { content_ptr = stpncpy(content_ptr,";obs",MIN(4,(content_end_ptr-content_ptr)-1)); } *content_ptr++ = ','; } ret = smcp_outbound_set_content_len(content_len-(content_end_ptr-content_ptr)); require_noerr(ret,bail); ret = smcp_outbound_send(); } else { size_t replyContentLength = 0; char *replyContent; ret = smcp_outbound_begin_response(COAP_RESULT_205_CONTENT); require_noerr(ret,bail); if(0==node->func(node,SMCP_VAR_GET_OBSERVABLE,key_index,buffer)) { ret = smcp_observable_update(&node->observable, key_index); check_string(ret==0,smcp_status_to_cstr(ret)); } if(reply_content_type == SMCP_CONTENT_TYPE_APPLICATION_FORM_URLENCODED) { uint32_t etag; if(0==node->func(node,SMCP_VAR_GET_MAX_AGE,key_index,buffer)) { #if HAVE_STRTOL uint32_t max_age = strtol(buffer,NULL,0)&0xFFFFFF; #else uint32_t max_age = atoi(buffer)&0xFFFFFF; #endif smcp_outbound_add_option_uint(COAP_OPTION_MAX_AGE, max_age); } ret = node->func(node,SMCP_VAR_GET_VALUE,key_index,buffer); require_noerr(ret,bail); fasthash_start(0); fasthash_feed((const uint8_t*)buffer,strlen(buffer)); etag = fasthash_finish_uint32(); smcp_outbound_add_option_uint(COAP_OPTION_CONTENT_TYPE, SMCP_CONTENT_TYPE_APPLICATION_FORM_URLENCODED); smcp_outbound_add_option_uint(COAP_OPTION_ETAG, etag); replyContent = smcp_outbound_get_content_ptr(&replyContentLength); *replyContent++ = 'v'; *replyContent++ = '='; replyContentLength -= 2; replyContentLength = url_encode_cstr( replyContent, buffer, replyContentLength ); ret = smcp_outbound_set_content_len(replyContentLength+2); } else { ret = node->func(node,SMCP_VAR_GET_VALUE,key_index,buffer); require_noerr(ret,bail); ret = smcp_outbound_append_content(buffer, SMCP_CSTR_LEN); } require_noerr(ret,bail); ret = smcp_outbound_send(); } } else { ret = smcp_default_request_handler( (void*)node ); check_string(ret == SMCP_STATUS_OK, smcp_status_to_cstr(ret)); } bail: check_string(ret == SMCP_STATUS_OK, smcp_status_to_cstr(ret)); return ret; }
static smcp_status_t get_response_handler(int statuscode, void* context) { ThingMLCOAPContext * thingml_context = (ThingMLCOAPContext *) context; const char* content = (const char*)smcp_inbound_get_content_ptr(); coap_size_t content_length = smcp_inbound_get_content_len(); if(statuscode>=0) { if(content_length>(smcp_inbound_get_packet_length()-4)) { fprintf(stderr, "INTERNAL ERROR: CONTENT_LENGTH LARGER THAN PACKET_LENGTH-4! (content_length=%u, packet_length=%u)\n",content_length,smcp_inbound_get_packet_length()); gRet = ERRORCODE_UNKNOWN; thingml_context->fn_onerror_callback(thingml_context->thing_instance, gRet); goto bail; } if((statuscode >= 0) && get_show_headers) { if(next_len != ((coap_size_t)(-1))) fprintf(stdout, "\n\n"); coap_dump_header( stdout, NULL, smcp_inbound_get_packet(), smcp_inbound_get_packet_length() ); } if(!coap_verify_packet((void*)smcp_inbound_get_packet(), smcp_inbound_get_packet_length())) { fprintf(stderr, "INTERNAL ERROR: CALLBACK GIVEN INVALID PACKET!\n"); gRet = ERRORCODE_UNKNOWN; thingml_context->fn_onerror_callback(thingml_context->thing_instance, gRet); goto bail; } } if(statuscode == SMCP_STATUS_TRANSACTION_INVALIDATED) { gRet = 0; } if(observe_ignore_first) { observe_ignore_first = false; goto bail; } if( ((statuscode < COAP_RESULT_200) ||(statuscode >= COAP_RESULT_400)) && (statuscode != SMCP_STATUS_TRANSACTION_INVALIDATED) && (statuscode != HTTP_TO_COAP_CODE(HTTP_RESULT_CODE_PARTIAL_CONTENT)) ) { if(get_observe && statuscode == SMCP_STATUS_TIMEOUT) { gRet = 0; } else { gRet = (statuscode == SMCP_STATUS_TIMEOUT)?ERRORCODE_TIMEOUT:ERRORCODE_COAP_ERROR; fprintf(stderr, "get: Result code = %d (%s)\n", statuscode, (statuscode < 0) ? smcp_status_to_cstr( statuscode) : coap_code_to_cstr(statuscode)); thingml_context->fn_onerror_callback(thingml_context->thing_instance, gRet); } } if((statuscode>0) && content && content_length) { coap_option_key_t key; const uint8_t* value; coap_size_t value_len; bool last_block = true; int32_t observe_value = -1; while((key=smcp_inbound_next_option(&value, &value_len))!=COAP_OPTION_INVALID) { if(key == COAP_OPTION_BLOCK2) { last_block = !(value[value_len-1]&(1<<3)); } else if(key == COAP_OPTION_OBSERVE) { if(value_len) observe_value = value[0]; else observe_value = 0; } } thingml_context->fn_onmsgrcv_callback(thingml_context->thing_instance, content, content_length); last_observe_value = observe_value; } if(observe_once) { gRet = 0; goto bail; } bail: return SMCP_STATUS_OK; }