Exemple #1
0
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;
}
Exemple #2
0
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;
}