smcp_status_t plugtest_separate_async_resend_response(void* context) { smcp_status_t ret = 0; struct smcp_async_response_s* async_response = (void*)context; #if !SMCP_AVOID_PRINTF || VERBOSE_DEBUG printf("Resending async response. . . %p\n",async_response); #endif 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_append_content("This was an asynchronous response!",SMCP_CSTR_LEN); require_noerr(ret,bail); ret = smcp_outbound_send(); require_noerr(ret,bail); bail: return ret; }
static smcp_status_t request_handler(void* context) { /* This will respond to every GET request to `/hello-world' with ** "Hello world!". Everyone else gets a 4.04 Not Found. */ printf("Got a request!\n"); if(smcp_inbound_get_code() != COAP_METHOD_GET) { return SMCP_STATUS_NOT_IMPLEMENTED; } while(smcp_inbound_peek_option(NULL, NULL) != COAP_OPTION_URI_PATH) if(smcp_inbound_next_option(NULL, NULL) == COAP_OPTION_INVALID) break; if(smcp_inbound_option_strequal(COAP_OPTION_URI_PATH, "hello-world")) { smcp_outbound_begin_response(COAP_RESULT_205_CONTENT); smcp_outbound_add_option_uint( COAP_OPTION_CONTENT_TYPE, COAP_CONTENT_TYPE_TEXT_PLAIN ); smcp_outbound_append_content("Hello world!", SMCP_CSTR_LEN); return smcp_outbound_send(); } return SMCP_STATUS_NOT_FOUND; }
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 request_handler(void* context) { /* This request handler will respond to every GET request with "Hello world!". * It isn't usually a good idea to (almost) completely ignore the actual * request, but since this is just an example we can get away with it. * We do more processing on the request in the other examples. */ printf("Got a request!\n"); // Only handle GET requests for now. Returning SMCP_STATUS_NOT_IMPLEMENTED // here without sending a response will cause us to automatically // send a METHOD_NOT_IMPLEMENTED response. if(smcp_inbound_get_code() != COAP_METHOD_GET) { return SMCP_STATUS_NOT_IMPLEMENTED; } // Begin describing the response message. (2.05 CONTENT, // in this case) smcp_outbound_begin_response(COAP_RESULT_205_CONTENT); // Add an option describing the content type as plaintext. smcp_outbound_add_option_uint( COAP_OPTION_CONTENT_TYPE, COAP_CONTENT_TYPE_TEXT_PLAIN ); // Set the content of our response to be "Hello world!". smcp_outbound_append_content("Hello world!", SMCP_CSTR_LEN); // Send the response we hae created, passing the return value // to our caller. return smcp_outbound_send(); }
smcp_status_t plugtest_separate_handler( smcp_node_t node ) { struct smcp_async_response_s* async_response = NULL; smcp_transaction_t transaction = NULL; smcp_status_t ret = SMCP_STATUS_NOT_ALLOWED; smcp_method_t method = smcp_inbound_get_code(); if(method==COAP_METHOD_GET) { if(smcp_inbound_is_dupe()) { smcp_outbound_begin_response(COAP_CODE_EMPTY); smcp_outbound_send(); ret = SMCP_STATUS_OK; goto bail; } async_response = calloc(sizeof(struct smcp_async_response_s),1); if(!async_response) { ret = SMCP_STATUS_MALLOC_FAILURE; goto bail; } #if !SMCP_AVOID_PRINTF || VERBOSE_DEBUG printf("This request needs an async response. %p\n",async_response); #endif transaction = smcp_transaction_init( NULL, SMCP_TRANSACTION_DELAY_START|SMCP_TRANSACTION_ALWAYS_INVALIDATE, &plugtest_separate_async_resend_response, &plugtest_separate_async_ack_handler, (void*)async_response ); if(!transaction) { free(async_response); // TODO: Consider dropping instead...? ret = SMCP_STATUS_MALLOC_FAILURE; goto bail; } ret = smcp_transaction_begin( smcp_get_current_instance(), transaction, (smcp_inbound_get_packet()->tt==COAP_TRANS_TYPE_CONFIRMABLE)?(smcp_cms_t)(COAP_MAX_TRANSMIT_WAIT*MSEC_PER_SEC):1 ); if(SMCP_STATUS_OK != ret) { smcp_transaction_end(smcp_get_current_instance(),transaction); goto bail; } ret = smcp_start_async_response(async_response,0); if(ret) { goto bail; } async_response = NULL; } bail: return ret; }
smcp_status_t smcp_outbound_quick_response(coap_code_t code, const char* body) { smcp_outbound_begin_response(code); if (body) { smcp_outbound_append_content(body, SMCP_CSTR_LEN); } return smcp_outbound_send(); }
smcp_status_t plugtest_test_handler(smcp_node_t node) { smcp_status_t ret = SMCP_STATUS_NOT_ALLOWED; char* content = NULL; coap_size_t max_len = 0; smcp_method_t method = smcp_inbound_get_code(); if(method==COAP_METHOD_GET) { ret = smcp_outbound_begin_response(COAP_RESULT_205_CONTENT); } else if(method==COAP_METHOD_POST) { ret = smcp_outbound_begin_response(COAP_RESULT_201_CREATED); } else if(method==COAP_METHOD_PUT) { ret = smcp_outbound_begin_response(COAP_RESULT_204_CHANGED); } else if(method==COAP_METHOD_DELETE) { ret = smcp_outbound_begin_response(COAP_RESULT_202_DELETED); } if(ret) goto bail; smcp_outbound_add_option_uint(COAP_OPTION_CONTENT_TYPE, COAP_CONTENT_TYPE_TEXT_PLAIN); content = smcp_outbound_get_content_ptr(&max_len); if(!content) { ret = SMCP_STATUS_FAILURE; goto bail; } smcp_inbound_get_path(content, SMCP_GET_PATH_LEADING_SLASH|SMCP_GET_PATH_INCLUDE_QUERY); strlcat(content,"\nPlugtest!\nMethod = ",max_len); strlcat(content,coap_code_to_cstr(method),max_len); strlcat(content,"\n",max_len); { const uint8_t* value; coap_size_t value_len; coap_option_key_t key; while((key=smcp_inbound_next_option(&value, &value_len))!=COAP_OPTION_INVALID) { strlcat(content,coap_option_key_to_cstr(key,1),max_len); strlcat(content,": ",max_len); if(coap_option_value_is_string(key)) { int argh = strlen(content)+value_len; strlcat(content,(char*)value,MIN(max_len,argh+1)); content[argh] = 0; } else { strlcat(content,"<binary>",max_len); } strlcat(content,"\n",max_len); } } smcp_outbound_set_content_len((coap_size_t)strlen(content)); ret = smcp_outbound_send(); bail: return ret; }
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; }
smcp_status_t resend_pair_request(char* url[2]) { smcp_status_t status; #if SMCP_ENABLE_PAIRING coap_size_t len = 8; bool did_mutate = false; while(url[0][len] && url[0][len]!='/') { len++; } // Temporarily mutate the input url because I'm lazy. if(url[0][len]) { did_mutate = true; url[0][len] = 0; } status = smcp_outbound_begin( smcp_get_current_instance(), COAP_METHOD_PUT, COAP_TRANS_TYPE_CONFIRMABLE ); require_noerr(status,bail); status = smcp_outbound_set_uri(url[0],0); require_noerr(status,bail); // Root pairings object path status = smcp_outbound_add_option(COAP_OPTION_URI_PATH,SMCP_PAIRING_DEFAULT_ROOT_PATH,SMCP_CSTR_LEN); require_noerr(status,bail); // Path to pair with status = smcp_outbound_add_option(COAP_OPTION_URI_PATH,url[0]+len+1,SMCP_CSTR_LEN); require_noerr(status,bail); // Remote target status = smcp_outbound_add_option(COAP_OPTION_URI_PATH,url[1],SMCP_CSTR_LEN); require_noerr(status,bail); status = smcp_outbound_send(); require_noerr(status,bail); bail: if(did_mutate) { url[0][len] = '/'; } #else status = SMCP_STATUS_NOT_IMPLEMENTED; #endif return status; }
smcp_status_t cgi_node_async_resend_response(void* context) { smcp_status_t ret = 0; cgi_node_request_t request = context; coap_size_t block_len = (1<<((request->block2&0x7)+4)); coap_size_t max_len; syslog(LOG_INFO, "cgi-node: Resending async response. . ."); ret = smcp_outbound_begin_async_response(COAP_RESULT_205_CONTENT,&request->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); if(request->block1!=BLOCK_OPTION_UNSPECIFIED) { ret = smcp_outbound_add_option_uint(COAP_OPTION_BLOCK1,request->block1); require_noerr(ret,bail); } if(request->state == CGI_NODE_STATE_ACTIVE_BLOCK2_WAIT_ACK) { if(request->stdout_buffer_len>block_len || request->fd_cmd_stdout>=0 || ((request->block2>>4)!=0)) { if(request->stdout_buffer_len>block_len || request->fd_cmd_stdout>=0) request->block2 |= (1<<3); else request->block2 &= ~(1<<3); ret = smcp_outbound_add_option_uint(COAP_OPTION_BLOCK2,request->block2); require_noerr(ret,bail); } char *content = smcp_outbound_get_content_ptr(&max_len); require_noerr(ret,bail); memcpy(content,request->stdout_buffer,MIN(request->stdout_buffer_len,block_len)); ret = smcp_outbound_set_content_len(MIN(request->stdout_buffer_len,block_len)); require_noerr(ret,bail); } ret = smcp_outbound_send(); require_noerr(ret,bail); bail: return ret; }
static smcp_status_t retry_sending_event(struct smcp_observer_s* observer) { smcp_status_t status; smcp_t const self = smcp_get_current_instance(); status = smcp_outbound_begin_response(COAP_RESULT_205_CONTENT); require_noerr(status,bail); status = smcp_outbound_set_async_response(&observer->async_response); require_noerr(status,bail); status = smcp_outbound_add_option_uint(COAP_OPTION_OBSERVE,observer->seq); require_noerr(status,bail); self->outbound.packet->tt = SHOULD_CONFIRM_EVENT_FOR_OBSERVER(observer)?COAP_TRANS_TYPE_CONFIRMABLE:COAP_TRANS_TYPE_NONCONFIRMABLE; self->inbound.has_observe_option = true; self->is_responding = true; self->force_current_outbound_code = true; self->is_processing_message = true; self->did_respond = false; #if VERBOSE_DEBUG coap_dump_header( SMCP_DEBUG_OUT_FILE, "FAKE Inbound:\t", self->inbound.packet, self->inbound.packet_len ); #endif status = smcp_handle_request(self); require(!status||status==SMCP_STATUS_NOT_FOUND||status==SMCP_STATUS_NOT_ALLOWED,bail); if(status) { smcp_outbound_set_content_len(0); smcp_outbound_send(); } bail: self->is_processing_message = false; self->did_respond = false; return status; }
smcp_status_t resend_delete_request(const char* url) { smcp_status_t status = 0; status = smcp_outbound_begin(smcp_get_current_instance(), COAP_METHOD_DELETE, COAP_TRANS_TYPE_CONFIRMABLE); require_noerr(status,bail); status = smcp_outbound_set_uri(url, 0); require_noerr(status,bail); status = smcp_outbound_send(); require_noerr(status,bail); gRet = ERRORCODE_INPROGRESS; bail: return status; }
static smcp_status_t request_handler(void* context) { smcp_status_t ret = SMCP_STATUS_OK; char* content = (char*)smcp_inbound_get_content_ptr(); size_t content_length = smcp_inbound_get_content_len(); char *path = NULL; FILE * pFile; path = smcp_inbound_get_path(NULL,0); // path must be free()'d after this! //require_action_string(path && path[0], (free((void*)path),ret = SMCP_STATUS_INVALID_ARGUMENT)); if(smcp_inbound_get_code() != COAP_METHOD_POST) { return SMCP_STATUS_NOT_IMPLEMENTED; } // Skip to the URI path option while(smcp_inbound_peek_option(NULL, NULL) != COAP_OPTION_URI_PATH) if(smcp_inbound_next_option(NULL, NULL) == COAP_OPTION_INVALID) break; smcp_outbound_begin_response(COAP_RESULT_205_CONTENT); smcp_outbound_add_option_uint( COAP_OPTION_CONTENT_TYPE, COAP_CONTENT_TYPE_TEXT_PLAIN); if(content && content_length) { // if content exist then print and write on .txt file with "a" being append feature. pFile = fopen ("data-collect.txt","a"); printf("%s", content); if (pFile!=NULL) { fputs (content,pFile); fclose (pFile); } /* Only print a newline if the content doesn't already print one. */ if((content[content_length - 1] != '\n')) printf("\n"); } ret = smcp_outbound_send(); free((void*)path); bail: return ret; }
smcp_status_t plugtest_obs_handler( struct plugtest_server_s *self ) { smcp_status_t ret = SMCP_STATUS_NOT_ALLOWED; smcp_method_t method = smcp_inbound_get_code(); if(method==COAP_METHOD_GET) { char* content = NULL; coap_size_t max_len = 0; ret = smcp_outbound_begin_response(COAP_RESULT_205_CONTENT); require_noerr(ret, bail); ret = smcp_outbound_add_option_uint(COAP_OPTION_CONTENT_TYPE, COAP_CONTENT_TYPE_TEXT_PLAIN); require_noerr(ret, bail); if(!smcp_timer_is_scheduled(smcp_get_current_instance(), &self->obs_timer)) plugtest_obs_timer_callback(smcp_get_current_instance(),self); ret = smcp_observable_update(&self->observable,PLUGTEST_OBS_KEY); check_noerr(ret); ret = smcp_outbound_add_option_uint(COAP_OPTION_MAX_AGE,10); require_noerr(ret, bail); content = smcp_outbound_get_content_ptr(&max_len); require_action(content!=NULL, bail, ret = SMCP_STATUS_FAILURE); require_action(max_len>11, bail, ret = SMCP_STATUS_MESSAGE_TOO_BIG); ret = smcp_outbound_set_content_len( (coap_size_t)strlen(uint32_to_dec_cstr(content, (uint32_t)time(NULL))) ); require_noerr(ret, bail); ret = smcp_outbound_send(); require_noerr(ret, bail); } bail: return ret; }
static smcp_status_t request_handler(void* context) { /* This will respond to every GET request to `/hello-world' with ** "Hello world!". Everyone else gets a 4.04 Not Found. */ printf("Got a request!\n"); // Only handle GET requests for now. Returning SMCP_STATUS_NOT_IMPLEMENTED // here without sending a response will cause us to automatically // send a METHOD_NOT_IMPLEMENTED response. if(smcp_inbound_get_code() != COAP_METHOD_GET) { return SMCP_STATUS_NOT_IMPLEMENTED; } // Skip to the URI path option while(smcp_inbound_peek_option(NULL, NULL) != COAP_OPTION_URI_PATH) if(smcp_inbound_next_option(NULL, NULL) == COAP_OPTION_INVALID) break; // If our URI path matches what we are looking for... if(smcp_inbound_option_strequal(COAP_OPTION_URI_PATH, "hello-world")) { // Begin describing the response message. (2.05 CONTENT, // in this case) smcp_outbound_begin_response(COAP_RESULT_205_CONTENT); // Add an option describing the content type as plaintext. smcp_outbound_add_option_uint( COAP_OPTION_CONTENT_TYPE, COAP_CONTENT_TYPE_TEXT_PLAIN ); // Set the content of our response to be "Hello world!". smcp_outbound_append_content("Hello world!", SMCP_CSTR_LEN); // Send the response we hae created, passing the return value // to our caller. return smcp_outbound_send(); } return SMCP_STATUS_NOT_FOUND; }
smcp_status_t smcp_auth_verify_request() { smcp_status_t ret = SMCP_STATUS_OK; coap_option_key_t key; const uint8_t* authvalue; size_t authvalue_len; // For testing purposes only! if(smcp_inbound_get_code() >1 && smcp_inbound_get_code()<COAP_RESULT_100) { ret = SMCP_STATUS_UNAUTHORIZED; } smcp_inbound_reset_next_option(); while((key = smcp_inbound_next_option(&authvalue,&authvalue_len))!=COAP_OPTION_INVALID) { if(key==COAP_OPTION_PROXY_URI) { // For testing purposes only! ret = SMCP_STATUS_OK; } if(key==COAP_OPTION_AUTHENTICATE) { // For testing purposes only! ret = SMCP_STATUS_OK; // writeme! } } if(smcp_inbound_origin_is_local()) { ret = SMCP_STATUS_OK; } ret = SMCP_STATUS_OK; // For testing purposes only! if(ret==SMCP_STATUS_UNAUTHORIZED) { smcp_outbound_begin_response(COAP_RESULT_401_UNAUTHORIZED); smcp_outbound_add_option(COAP_OPTION_AUTHENTICATE,NULL,0); smcp_outbound_send(); } return ret; }
static smcp_status_t request_handler_get_listing_( smcp_group_mgr_t self ) { smcp_status_t ret = 0; int i; char name_str[3] = { }; // Fetching the group table. ret = smcp_outbound_begin_response(COAP_RESULT_205_CONTENT); require_noerr(ret, bail); ret = smcp_outbound_add_option_uint(COAP_OPTION_CONTENT_TYPE, COAP_CONTENT_TYPE_APPLICATION_LINK_FORMAT); require_noerr(ret, bail); for (i = 0; i < SMCP_CONF_MAX_GROUPS; i++) { if (!self->group_table[i].in_use) { continue; } name_str[0] = get_hex_char(i >> 4); name_str[1] = get_hex_char(i >> 0); smcp_outbound_append_content("<", SMCP_CSTR_LEN); smcp_outbound_append_content(name_str, SMCP_CSTR_LEN); smcp_outbound_append_content("/>;ct=40;obs,", SMCP_CSTR_LEN); #if SMCP_ADD_NEWLINES_TO_LIST_OUTPUT smcp_outbound_append_content("\n", SMCP_CSTR_LEN); #endif } ret = smcp_outbound_send(); 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; }
int tool_cmd_test( smcp_t smcp_instance, int argc, char* argv[] ) { if((2 == argc) && (0 == strcmp(argv[1], "--help"))) { printf("Help not yet implemented for this command.\n"); return ERRORCODE_HELP; } smcp_t smcp; smcp_t smcp2; struct smcp_timer_node_s timer_node = {}; struct smcp_variable_node_s device_node = {}; struct smcp_node_s async_response_node = {}; smcp2 = smcp_create(12345); if(smcp_get_port(smcp_instance) == SMCP_DEFAULT_PORT) smcp = smcp_instance; else smcp = smcp_create(SMCP_DEFAULT_PORT); //printf(__FILE__":%d: root node child count = %d\n",__LINE__,(int)bt_count(&smcp_get_root_node(smcp)->children)); #if HAVE_LIBCURL struct smcp_curl_proxy_node_s proxy_node = {}; // curl_global_init(CURL_GLOBAL_ALL); // CURLM* curl_multi_handle = curl_multi_init(); smcp_curl_proxy_node_init( &proxy_node, smcp_get_root_node(smcp), "proxy" ); #endif //printf(__FILE__":%d: root node child count = %d\n",__LINE__,(int)bt_count(&smcp_get_root_node(smcp)->children)); // smcp_pairing_init( // smcp_get_root_node(smcp), // SMCP_PAIRING_DEFAULT_ROOT_PATH // ); // // smcp_pairing_init( // smcp_get_root_node(smcp2), // SMCP_PAIRING_DEFAULT_ROOT_PATH // ); //printf(__FILE__":%d: root node child count = %d\n",__LINE__,(int)bt_count(&smcp_get_root_node(smcp)->children)); smcp_variable_node_init( &device_node, smcp_get_root_node(smcp), "device" ); device_node.func = device_func; //printf(__FILE__":%d: root node child count = %d\n",__LINE__,(int)bt_count(&smcp_get_root_node(smcp)->children)); smcp_variable_node_init( NULL, smcp_get_root_node(smcp2), "device" )->func = device_func; //printf(__FILE__":%d: root node child count = %d\n",__LINE__,(int)bt_count(&smcp_get_root_node(smcp)->children)); smcp_timer_node_init( &timer_node, smcp_get_root_node(smcp), "timer" ); //printf(__FILE__":%d: root node child count = %d\n",__LINE__,(int)bt_count(&smcp_get_root_node(smcp)->children)); smcp_node_init((smcp_node_t)&async_response_node, smcp_get_root_node(smcp), "async_response" ); async_response_node.request_handler = &async_request_handler; //printf(__FILE__":%d: root node child count = %d\n",__LINE__,(int)bt_count(&smcp_get_root_node(smcp)->children)); #if !SMCP_CONF_OBSERVING_ONLY { char url[256]; snprintf(url, sizeof(url), "smcp://127.0.0.1:%d/device/action", smcp_get_port(smcp2)); smcp_pair_with_uri(smcp, "device/loadavg", url, 0, NULL); printf("EVENT_NODE PAIRED WITH %s\n", url); } { char url[256]; snprintf(url, sizeof(url), "smcp://[::1]:%d/device/loadavg", smcp_get_port(smcp)); smcp_pair_with_uri(smcp2, "device/action", url, 0, NULL); printf("ACTION_NODE PAIRED WITH %s\n", url); } #endif //printf(__FILE__":%d: root node child count = %d\n",__LINE__,(int)bt_count(&smcp_get_root_node(smcp)->children)); // Just adding some random nodes so we can browse thru them with another process... { smcp_node_t subdevice = smcp_node_init(NULL, smcp_get_root_node(smcp), "lots_of_devices"); unsigned char i = 0; #if 1 for(i = i * 97 + 101; i; i = i * 97 + 101) { #else for(i = 0; i != 255; i++) { #endif char *name = NULL; asprintf(&name, "subdevice_%d", i); // Will leak, but we don't care. smcp_node_init(NULL, (smcp_node_t)subdevice, name); } // { // unsigned int i = bt_rebalance( // (void**)&((smcp_node_t)subdevice)->children); // printf("Balance operation took %u rotations\n", i); // } // { // unsigned int i = bt_rebalance( // (void**)&((smcp_node_t)subdevice)->children); // printf("Second balance operation took %u rotations\n", i); // } // { // unsigned int i = bt_rebalance( // (void**)&((smcp_node_t)subdevice)->children); // printf("Third balance operation took %u rotations\n", i); // } // { // unsigned int i = bt_rebalance( // (void**)&((smcp_node_t)subdevice)->children); // printf("Fourth balance operation took %u rotations\n", i); // } } //printf(__FILE__":%d: root node child count = %d\n",__LINE__,(int)bt_count(&smcp_get_root_node(smcp)->children)); { coap_msg_id_t tid = smcp_get_next_msg_id(smcp2); char url[256]; #if 0 snprintf(url, sizeof(url), "smcp://["COAP_MULTICAST_IP6_ALLDEVICES"]:%d/device/", smcp_get_port(smcp)); #else snprintf(url, sizeof(url), "smcp://[::1]:%d/device/", smcp_get_port(smcp)); #endif smcp_begin_transaction_old( smcp2, tid, 5 * MSEC_PER_SEC, 0, // Flags NULL, &list_response_handler, NULL ); smcp_outbound_begin(smcp2,COAP_METHOD_GET,COAP_TRANS_TYPE_CONFIRMABLE); smcp_outbound_set_msg_id(tid); smcp_outbound_set_uri(url, 0); smcp_outbound_send(); fprintf(stderr, " *** Sent LIST request...\n"); } //printf(__FILE__":%d: root node child count = %d\n",__LINE__,(int)bt_count(&smcp_get_root_node(smcp)->children)); int i; for(i = 0; 1/*i < 3000000*/; i++) { #if 1 if((i - 1) % 250 == 0) { fprintf(stderr, " *** Forcing variable refresh...\n"); smcp_variable_node_did_change(&device_node,0,NULL); } #endif smcp_process(smcp); smcp_process(smcp2); #if HAVE_LIBCURL smcp_curl_proxy_node_process(&proxy_node); #endif } bail: return 0; }
smcp_status_t plugtest_large_handler( smcp_node_t node ) { smcp_status_t ret = SMCP_STATUS_NOT_ALLOWED; char* content = NULL; coap_size_t max_len = 0; smcp_method_t method = smcp_inbound_get_code(); uint32_t block_option = 0x03; uint32_t block_start = 0; uint32_t block_stop = 0; uint32_t resource_length = 2000; if(method==COAP_METHOD_GET) { ret = 0; } require_noerr(ret,bail); { const uint8_t* value; coap_size_t value_len; coap_option_key_t key; while((key=smcp_inbound_next_option(&value, &value_len))!=COAP_OPTION_INVALID) { if(key == COAP_OPTION_BLOCK2) { uint8_t i; block_option = 0; for(i = 0; i < value_len; i++) block_option = (block_option << 8) + value[i]; } } } ret = smcp_outbound_begin_response(COAP_RESULT_205_CONTENT); 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_add_option_uint(COAP_OPTION_MAX_AGE,60*60); require_noerr(ret,bail); max_len = smcp_outbound_get_space_remaining()-2; // Here we are making sure our data will fit, // and adjusting our block-option size accordingly. do { struct coap_block_info_s block_info; coap_decode_block(&block_info, block_option); block_start = block_info.block_offset; block_stop = block_info.block_offset + block_info.block_size; if(max_len<(block_stop-block_start) && block_option!=0 && !block_info.block_offset) { block_option--; block_stop = 0; continue; } } while(0==block_stop); require_action(block_start<resource_length,bail,ret=SMCP_STATUS_INVALID_ARGUMENT); if(block_stop>=resource_length) block_option &= ~(1<<3); else block_option |= (1<<3); ret = smcp_outbound_add_option_uint(COAP_OPTION_BLOCK2,block_option); require_noerr(ret,bail); content = smcp_outbound_get_content_ptr(&max_len); require_action(NULL!=content, bail, ret = SMCP_STATUS_FAILURE); require_action(max_len>(block_stop-block_start), bail, ret = SMCP_STATUS_MESSAGE_TOO_BIG); { uint32_t i; for(i=block_start;i<block_stop;i++) { if(!((i+1)%64)) content[i-block_start] = '\n'; else content[i-block_start] = '0'+(i%10); } } ret = smcp_outbound_set_content_len((coap_size_t)MIN(block_stop-block_start,resource_length-block_start)); if(ret) goto bail; ret = smcp_outbound_send(); bail: return ret; }
static smcp_status_t request_handler_new_group_( smcp_group_mgr_t self ) { smcp_status_t ret = SMCP_STATUS_OK; coap_content_type_t content_type; coap_size_t content_len; char* fqdn = NULL; char* addr_cstr = NULL; smcp_sockaddr_t saddr = { }; char* content_ptr = NULL; char* key = NULL; char* value = NULL; smcp_group_t group = NULL; char name_str[3] = { }; content_type = smcp_inbound_get_content_type(); content_ptr = (char*)smcp_inbound_get_content_ptr(); content_len = smcp_inbound_get_content_len(); switch (content_type) { case COAP_CONTENT_TYPE_UNKNOWN: case COAP_CONTENT_TYPE_TEXT_PLAIN: case SMCP_CONTENT_TYPE_APPLICATION_FORM_URLENCODED: content_len = 0; while( url_form_next_value( (char**)&content_ptr, &key, &value ) && key && value ) { if (strequal_const(key, names[I_FQDN])) { fqdn = value; DEBUG_PRINTF("new_group: fqdn=\"%s\"", value); } else if (strequal_const(key, names[I_ADDR])) { addr_cstr = value; DEBUG_PRINTF("new_group: addr=\"%s\"", value); } } break; default: return smcp_outbound_quick_response(HTTP_RESULT_CODE_UNSUPPORTED_MEDIA_TYPE, NULL); break; } if (NULL == addr_cstr) { require_action(NULL != fqdn, bail, ret = SMCP_STATUS_INVALID_ARGUMENT); addr_cstr = fqdn; } else if (NULL == fqdn) { fqdn = addr_cstr; } smcp_plat_lookup_hostname(addr_cstr, &saddr, SMCP_LOOKUP_HOSTNAME_FLAG_DEFAULT); group = smcp_group_mgr_new_group( self, fqdn, &saddr.smcp_addr, 0 ); if (!group) { return smcp_outbound_quick_response(COAP_RESULT_400_BAD_REQUEST, "(400) Failed to create group"); } // Default to enabled. smcp_group_set_enabled(group, true); name_str[0] = get_hex_char(group->index >> 4); name_str[1] = get_hex_char(group->index >> 0); smcp_outbound_begin_response(COAP_RESULT_201_CREATED); smcp_outbound_add_option(COAP_OPTION_LOCATION_PATH, name_str, SMCP_CSTR_LEN); smcp_outbound_append_content(name_str, SMCP_CSTR_LEN); smcp_outbound_send(); bail: return ret; }