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;
}
Esempio n. 2
0
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;
}
Esempio n. 3
0
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();
}
Esempio n. 4
0
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;
}
Esempio n. 5
0
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;
}
Esempio n. 6
0
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;
}
Esempio n. 7
0
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;
}
Esempio n. 8
0
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;
}
Esempio n. 9
0
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;
}
Esempio n. 10
0
smcp_status_t
smcp_outbound_set_var_content_unsigned_long_int(unsigned long int v) {
	smcp_outbound_add_option_uint(
		COAP_OPTION_CONTENT_TYPE,
		SMCP_CONTENT_TYPE_APPLICATION_FORM_URLENCODED
	);
#if SMCP_AVOID_PRINTF
{
		char nstr[12];
		smcp_outbound_append_content("v=", SMCP_CSTR_LEN);
		return smcp_outbound_append_content(uint32_to_dec_cstr(nstr,v), SMCP_CSTR_LEN);
	}
#else
	return smcp_outbound_set_content_formatted_const("v=%ul",v);
#endif
}
Esempio n. 11
0
smcp_status_t
smcp_observable_update(smcp_observable_t context, uint8_t key) {
	smcp_status_t ret = SMCP_STATUS_OK;
	smcp_t const interface = smcp_get_current_instance();
	int8_t i;

#if !SMCP_EMBEDDED
	context->interface = interface;
#endif

	if(interface->inbound.is_fake || interface->inbound.is_dupe) {
		goto bail;
	}

	for(i = context->first_observer-1; i >= 0; i = observer_table[i].next - 1) {
		if(observer_table[i].key != key)
			continue;
		if(smcp_inbound_is_related_to_async_response(&observer_table[i].async_response))
			break;
	}

	if(interface->inbound.has_observe_option) {
		if(i == -1) {
			i = get_unused_observer_index();
			if(i == -1)
				goto bail;
			if(context->last_observer == 0) {
				context->first_observer = context->last_observer = i + 1;
			} else {
				observer_table[context->last_observer-1].next = i +1;
				context->last_observer = i + 1;
			}
			observer_table[i].key = key;
			observer_table[i].seq = 0;
			observer_table[i].observable = context;
		}

		smcp_start_async_response(&observer_table[i].async_response,SMCP_ASYNC_RESPONSE_FLAG_DONT_ACK);

		ret = smcp_outbound_add_option_uint(COAP_OPTION_OBSERVE,observer_table[i].seq);
	} else if(i != -1) {
		free_observer(&observer_table[i]);
	}

bail:
	return ret;
}
Esempio n. 12
0
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;
}
Esempio n. 13
0
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;
}
Esempio n. 14
0
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;
}
Esempio n. 15
0
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;
}
Esempio n. 16
0
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;
}
Esempio n. 17
0
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;
}
Esempio n. 18
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;
}
Esempio n. 19
0
smcp_status_t
smcp_outbound_set_uri(
	const char* uri, char flags
) {
	smcp_status_t ret = SMCP_STATUS_OK;
	smcp_t const self = smcp_get_current_instance();
	SMCP_NON_RECURSIVE struct url_components_s components;
	SMCP_NON_RECURSIVE uint16_t toport;
	SMCP_NON_RECURSIVE char* uri_copy;

	memset((void*)&components, 0, sizeof(components));
	toport = COAP_DEFAULT_PORT;
	smcp_plat_set_session_type(SMCP_SESSION_TYPE_UDP);
	uri_copy = NULL;

	require_action(uri, bail, ret = SMCP_STATUS_INVALID_ARGUMENT);

	{
#if HAVE_ALLOCA
		uri_copy = alloca(strlen(uri) + 1);
		strcpy(uri_copy, uri);
#elif SMCP_AVOID_MALLOC
		// Well, we can't use the stack and we can't
		// use malloc. Let's use what room we have left
		// in the packet buffer, since this is temporary anyway...
		// It helps a bunch that we know the user hasn't written
		// any content yet (because that would be an API violation)
		if (smcp_outbound_get_space_remaining() > strlen(uri) + 8) {
			uri_copy = self->outbound.content_ptr + self->outbound.content_len;

			// The options section may be expanding as we parse this, so
			// we should move ahead by a few bytes. We are helped out
			// by the fact that we will be writing the options in the
			// same order they appear in the URL.
			uri_copy += 8;

			strcpy(uri_copy, uri);
		}
#else
		uri_copy = strdup(uri);
#endif

		require_action(uri_copy != NULL, bail, ret = SMCP_STATUS_MALLOC_FAILURE);

		// Parse the URI.
		require_action_string(
			url_parse(
				uri_copy,
				&components
			),
			bail,
			ret = SMCP_STATUS_URI_PARSE_FAILURE,
			"Unable to parse URL"
		);

		if(!components.protocol && !components.host) {
			// Talking to ourself.
			components.protocol = "coap";
			components.host = "::1";
			toport = smcp_plat_get_port(smcp_get_current_instance());
			flags |= SMCP_MSG_SKIP_AUTHORITY;
		} else if(components.port) {
			toport = (uint16_t)atoi(components.port);
		}

		DEBUG_PRINTF(
			"URI Parse: \"%s\" -> host=\"%s\" port=\"%u\" path=\"%s\"",
			uri,
			components.host,
			toport,
			components.path
		);
	}

	if (components.protocol) {
		smcp_session_type_t session_type = smcp_session_type_from_uri_scheme(components.protocol);
		smcp_plat_set_session_type(session_type);

		if (NULL == components.port) {
			toport = smcp_default_port_from_session_type(session_type);
		}

		if (session_type == SMCP_SESSION_TYPE_NIL) {
			require_action_string(
				self->proxy_url,
				bail,
				ret=SMCP_STATUS_INVALID_ARGUMENT,
				"No proxy URL configured"
			);
			require_action(uri != self->proxy_url,bail,ret = SMCP_STATUS_INVALID_ARGUMENT);

			ret = smcp_outbound_add_option(COAP_OPTION_PROXY_URI, uri, SMCP_CSTR_LEN);
			require_noerr(ret, bail);
			ret = smcp_outbound_set_uri(self->proxy_url,flags);
			goto bail;
		}
	}

	if (!(flags & SMCP_MSG_SKIP_AUTHORITY)) {
		if(components.host && !string_contains_colons(components.host)) {
			ret = smcp_outbound_add_option(COAP_OPTION_URI_HOST, components.host, SMCP_CSTR_LEN);
			require_noerr(ret, bail);
		}
		if(components.port) {
			ret = smcp_outbound_add_option_uint(COAP_OPTION_URI_PORT, toport);
			require_noerr(ret, bail);
		}
	}


	if ( !(flags & SMCP_MSG_SKIP_DESTADDR)
	  && components.host && components.host[0]!=0
	) {
		ret = smcp_set_remote_sockaddr_from_host_and_port(
			components.host,
			toport
		);
		require_noerr(ret, bail);
	}

	if (components.path) {
		SMCP_NON_RECURSIVE char* component;
		const bool has_trailing_slash = components.path[0]?('/' == components.path[strlen(components.path)-1]):false;

		// Move past any preceding slashes.
		while (components.path[0] == '/') {
			components.path++;
		}

		while (url_path_next_component(&components.path,&component)) {
			ret = smcp_outbound_add_option(COAP_OPTION_URI_PATH, component, SMCP_CSTR_LEN);
			require_noerr(ret,bail);
		}

		if (has_trailing_slash) {
			ret = smcp_outbound_add_option(COAP_OPTION_URI_PATH, NULL, 0);
			require_noerr(ret,bail);
		}
	}

	if (components.query) {
		SMCP_NON_RECURSIVE char* key;

		while (url_form_next_value(&components.query, &key, NULL)) {
			coap_size_t len = (coap_size_t)strlen(key);

			if (len) {
				ret = smcp_outbound_add_option(COAP_OPTION_URI_QUERY, key, len);
			}
			require_noerr(ret,bail);
		}
	}

bail:
	if(ret) {
		DEBUG_PRINTF("URI Parse failed for URI: \"%s\"",uri);
	}

#if !HAVE_ALLOCA && !SMCP_AVOID_MALLOC
	free(uri_copy);
#endif

	return ret;
}