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 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 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; }
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 response_test_handler(int statuscode, void* context) { test_data_s * const test_data = context; smcp_t interface = smcp_get_current_instance(); bool has_observe_option = false; smcp_status_t status = 0; if(!test_data->finished) { if (statuscode < 0) { test_data->finished = true; if (statuscode != SMCP_STATUS_TRANSACTION_INVALIDATED) { test_data->error = statuscode; } } else { const uint8_t* value; coap_size_t value_len; coap_option_key_t key; test_data->msg_id = smcp_inbound_get_packet()->msg_id; if (smcp_inbound_is_dupe()) { test_data->inbound_dupe_packets++; } else { test_data->inbound_packets++; } while ((key=smcp_inbound_next_option(&value, &value_len))!=COAP_OPTION_INVALID) { if (key == COAP_OPTION_BLOCK1) { test_data->block1_option = 0; test_data->has_block1_option = 1; test_data->block1_option = coap_decode_uint32(value,(uint8_t)value_len); if ( statuscode == COAP_RESULT_231_CONTINUE) { smcp_transaction_new_msg_id(interface, test_data->transaction, smcp_get_next_msg_id(interface)); smcp_transaction_tickle(interface, test_data->transaction); } } if (key == COAP_OPTION_BLOCK2) { test_data->block2_option = 0; test_data->has_block2_option = 1; test_data->block2_option = coap_decode_uint32(value,(uint8_t)value_len); if (!(test_data->block2_option & (1<<3))) { test_data->finished = true; } } if (key == COAP_OPTION_OBSERVE) { if (test_data->inbound_packets > 2) { test_data->finished = true; } has_observe_option = true; printf("\tobs-response: \"%s\"\n", smcp_inbound_get_content_ptr()); } } if ( !has_observe_option && !test_data->has_block2_option && statuscode != COAP_RESULT_231_CONTINUE ) { test_data->finished = true; } test_data->inbound_content_len += smcp_inbound_get_content_len(); test_data->inbound_code = (coap_code_t)statuscode; if (test_data->has_block2_option) { strncat(test_data->response, smcp_inbound_get_content_ptr(), smcp_inbound_get_content_len()); } else { strncpy(test_data->response, smcp_inbound_get_content_ptr(), smcp_inbound_get_content_len()); } } } 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; }
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; }
smcp_status_t smcp_node_route(smcp_node_t node, smcp_request_handler_func* func, void** context) { smcp_status_t ret = 0; smcp_t const self = smcp_get_current_instance(); smcp_inbound_reset_next_option(); { // TODO: Rewrite this to be more efficient. const uint8_t* prev_option_ptr = self->inbound.this_option; coap_option_key_t prev_key = 0; coap_option_key_t key; const uint8_t* value; coap_size_t value_len; while ((key = smcp_inbound_next_option(&value, &value_len)) != COAP_OPTION_INVALID) { if (key > COAP_OPTION_URI_PATH) { self->inbound.this_option = prev_option_ptr; self->inbound.last_option_key = prev_key; break; } else if (key == COAP_OPTION_URI_PATH) { smcp_node_t next = smcp_node_find( node, (const char*)value, (int)value_len ); if (next) { node = next; } else { self->inbound.this_option = prev_option_ptr; self->inbound.last_option_key = prev_key; break; } } else if(key==COAP_OPTION_URI_HOST) { // Skip host at the moment, // because we don't do virtual hosting yet. } else if(key==COAP_OPTION_URI_PORT) { // Skip port at the moment, // because we don't do virtual hosting yet. } else if(key==COAP_OPTION_PROXY_URI) { // Skip the proxy URI for now. } else if(key==COAP_OPTION_CONTENT_TYPE) { // Skip. } 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; } } prev_option_ptr = self->inbound.this_option; prev_key = self->inbound.last_option_key; } } *func = (void*)node->request_handler; if(node->context) { *context = node->context; } else { *context = (void*)node; } bail: return ret; }
smcp_status_t smcp_group_mgr_request_handler( smcp_group_mgr_t self ) { smcp_status_t ret = 0; const smcp_method_t method = smcp_inbound_get_code(); coap_option_key_t key; const uint8_t* value; coap_size_t value_len; smcp_group_t group; bool missing_trailing_slash = false; if (smcp_inbound_next_option(&value, &value_len) != COAP_OPTION_URI_PATH) { missing_trailing_slash = true; } if (value_len == 0) { // listing groups if (method == COAP_METHOD_GET) { if (missing_trailing_slash) { return smcp_outbound_quick_response(COAP_RESULT_400_BAD_REQUEST, "(400) Needs trailing slash"); } return request_handler_get_listing_(self); } else if (method == COAP_METHOD_POST) { return request_handler_new_group_(self); } else { ret = SMCP_STATUS_NOT_ALLOWED; goto bail; } } else if (value_len == 2) { // Query on a specific group. const char str[3] = {value[0], value[1], 0}; int i; errno = 0; #if HAVE_STRTOL i = strtol(str, NULL, 16); #else i = atoi(str); // TODO: This isn't base16! #endif if (errno) { ret = SMCP_STATUS_NOT_FOUND; goto bail; } group = &self->group_table[i]; key = smcp_inbound_peek_option(&value, &value_len); if ( (i < 0) || (i >= SMCP_CONF_MAX_GROUPS) || (!group->in_use) ) { ret = SMCP_STATUS_NOT_FOUND; goto bail; } if (key != COAP_OPTION_URI_PATH) { value_len = 0; } if ( (method == COAP_METHOD_GET) || (method == COAP_METHOD_PUT) || (method == COAP_METHOD_POST) || ( (method == COAP_METHOD_DELETE) && (value_len > 0) ) ) { // hand off handling of this to variable node. return smcp_variable_handler_request_handler(&group->var_handler); } else if (method == COAP_METHOD_DELETE) { // Delete this group. smcp_group_mgr_delete(self, group); return smcp_outbound_quick_response(COAP_RESULT_202_DELETED, NULL); } } else { ret = SMCP_STATUS_NOT_FOUND; } bail: return ret; }
smcp_status_t smcp_curl_proxy_request_handler( smcp_curl_proxy_node_t node ) { smcp_status_t ret = SMCP_STATUS_NOT_ALLOWED; smcp_curl_request_t request = NULL; struct curl_slist *headerlist=NULL; smcp_method_t method = smcp_inbound_get_code(); //require_action(method<=COAP_METHOD_DELETE,bail,ret = SMCP_STATUS_NOT_ALLOWED); //require_action(COAP_OPTION_URI_PATH!=smcp_inbound_peek_option(NULL,NULL),bail,ret=SMCP_STATUS_NOT_FOUND); node->interface = smcp_get_current_instance(); smcp_inbound_reset_next_option(); request = smcp_curl_request_create(); request->proxy_node = node; require_action(request!=NULL,bail,ret = SMCP_STATUS_MALLOC_FAILURE); switch(method) { case COAP_METHOD_GET: curl_easy_setopt(request->curl, CURLOPT_CUSTOMREQUEST, "GET"); break; case COAP_METHOD_PUT: curl_easy_setopt(request->curl, CURLOPT_PUT, 1L); break; case COAP_METHOD_POST: curl_easy_setopt(request->curl, CURLOPT_POST, 1L); break; case COAP_METHOD_DELETE: curl_easy_setopt(request->curl, CURLOPT_CUSTOMREQUEST, "DELETE"); break; default: ret = SMCP_STATUS_NOT_ALLOWED; break; } { coap_option_key_t key; const uint8_t* value; coap_size_t value_len; while((key=smcp_inbound_next_option(&value, &value_len))!=COAP_OPTION_INVALID) { if(key==COAP_OPTION_PROXY_URI) { char uri[value_len+1]; memcpy(uri,value,value_len); uri[value_len] = 0; curl_easy_setopt(request->curl, CURLOPT_URL, uri); assert_printf("CuRL URL: \"%s\"",uri); ret = 0; } else if(key==COAP_OPTION_URI_HOST) { } else if(key==COAP_OPTION_URI_PORT) { } else if(key==COAP_OPTION_URI_PATH) { } else if(key==COAP_OPTION_URI_QUERY) { } else if(key==COAP_OPTION_CONTENT_TYPE || key==COAP_OPTION_ACCEPT) { const char* option_name = coap_option_key_to_cstr(key, false); const char* value_string = coap_content_type_to_cstr(value[1]); char header[strlen(option_name)+strlen(value_string)+3]; strcpy(header,option_name); strcat(header,": "); strcat(header,value_string); headerlist = curl_slist_append(headerlist, header); assert_printf("CuRL HEADER: \"%s\"",header); } else { if(coap_option_value_is_string(key)) { const char* option_name = coap_option_key_to_cstr(key, false); char header[strlen(option_name)+value_len+3]; strcpy(header,option_name); strcat(header,": "); strncat(header,(const char*)value,value_len); assert_printf("CuRL HEADER: \"%s\"",header); headerlist = curl_slist_append(headerlist, header); } } } } require_noerr(ret,bail); if(smcp_inbound_get_content_len()) { coap_size_t len = smcp_inbound_get_content_len(); request->output_content = calloc(1,len+1); request->output_content_len = len; memcpy(request->output_content,smcp_inbound_get_content_ptr(),len); curl_easy_setopt(request->curl, CURLOPT_READFUNCTION, ReadMemoryCallback); curl_easy_setopt(request->curl, CURLOPT_READDATA, (void *)request); } curl_easy_setopt(request->curl, CURLOPT_USERAGENT, "smcp-curl-proxy/1.0"); curl_easy_setopt(request->curl, CURLOPT_HTTPHEADER, headerlist),headerlist=NULL; curl_easy_setopt(request->curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); curl_easy_setopt(request->curl, CURLOPT_WRITEDATA, (void *)request); ret = smcp_start_async_response(&request->async_response,0); require_noerr(ret,bail); if(node->curl_multi_handle) curl_multi_add_handle(node->curl_multi_handle, request->curl); else curl_easy_perform(request->curl); bail: if(headerlist) curl_slist_free_all(headerlist); if(ret && request) smcp_curl_request_release(request); 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; }
smcp_status_t cgi_node_request_handler( cgi_node_t node ) { smcp_status_t ret = 0; cgi_node_request_t request = NULL; uint32_t block2_option = BLOCK_OPTION_DEFAULT; uint32_t block1_option = BLOCK_OPTION_UNSPECIFIED; smcp_method_t method = smcp_inbound_get_code(); require(node,bail); node->interface = smcp_get_current_instance(); 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; block2_option = 0; for (i = 0; i < value_len; i++) { block2_option = (block2_option << 8) + value[i]; } } if (key == COAP_OPTION_BLOCK1) { uint8_t i; block1_option = 0; for (i = 0; i < value_len; i++) { block1_option = (block1_option << 8) + value[i]; } } } } // Make sure this is a supported method. switch (method) { case COAP_METHOD_GET: case COAP_METHOD_PUT: case COAP_METHOD_POST: case COAP_METHOD_DELETE: break; default: ret = SMCP_STATUS_NOT_IMPLEMENTED; goto bail; break; } request = cgi_node_get_associated_request(node); if (request == NULL) { // Possibly new request. // Assume new for now, but we may need to do additional checks. // We don't support non-zero block indexes on the first packet. require_action((block2_option>>4) == 0, bail, ret = SMCP_STATUS_INVALID_ARGUMENT); request = cgi_node_create_request(node); require_action(request != NULL, bail, ret = SMCP_STATUS_FAILURE); request->block2 = block2_option; }