Skip to content

Commit

Permalink
Merge pull request #1537 from particle-iot/feature/increase-limits
Browse files Browse the repository at this point in the history
[Electron/Photon/P1] Increase Device OS API argument lengths
  • Loading branch information
technobly authored May 4, 2018
2 parents 3dc9060 + e4f6c93 commit 612ee42
Show file tree
Hide file tree
Showing 15 changed files with 342 additions and 201 deletions.
1 change: 1 addition & 0 deletions communication/src/communication_dynalib.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ DYNALIB_FN(BASE_IDX2 + 0, communication, spark_protocol_set_connection_property,
DYNALIB_FN(BASE_IDX2 + 1, communication, spark_protocol_command, int(ProtocolFacade* protocol, ProtocolCommands::Enum cmd, uint32_t data, void* reserved))
DYNALIB_FN(BASE_IDX2 + 2, communication, spark_protocol_time_request_pending, bool(ProtocolFacade*, void*))
DYNALIB_FN(BASE_IDX2 + 3, communication, spark_protocol_time_last_synced, system_tick_t(ProtocolFacade*, time_t*, void*))
DYNALIB_FN(BASE_IDX2 + 4, communication, spark_protocol_get_describe_data, int(ProtocolFacade*, spark_protocol_describe_data*, void*))

DYNALIB_END(communication)

Expand Down
122 changes: 67 additions & 55 deletions communication/src/functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,67 +37,79 @@ class Functions

ProtocolError function_result(MessageChannel& channel, const void* result, SparkReturnType::Enum, token_t token)
{
Message message;
channel.create(message, Messages::function_return_size);
Message message;
channel.create(message, Messages::function_return_size);
size_t length = Messages::function_return(message.buf(), 0, token, long(result), channel.is_unreliable());
message.set_length(length);
return channel.send(message);
}

public:
ProtocolError handle_function_call(token_t token, message_id_t message_id, Message& message, MessageChannel& channel,
int (*call_function)(const char *function_key, const char *arg, SparkDescriptor::FunctionResultCallback callback, void* reserved))
{
// copy the function key
char function_key[13];
memset(function_key, 0, 13);
uint8_t* queue = message.buf();
size_t function_key_length = queue[7] & 0x0F;
memcpy(function_key, queue + 8, function_key_length);

// How long is the argument?
size_t q_index = 8 + function_key_length;
size_t query_length = queue[q_index] & 0x0F;
if (13 == query_length)
{
++q_index;
query_length = 13 + queue[q_index];
}
else if (14 == query_length)
{
++q_index;
query_length = queue[q_index] << 8;
++q_index;
query_length |= queue[q_index];
query_length += 269;
}

bool has_function = false;

// allocated memory bounds check
if (MAX_FUNCTION_ARG_LENGTH > query_length)
{
// save a copy of the argument
memcpy(function_arg, queue + q_index + 1, query_length);
function_arg[query_length] = 0; // null terminate string
has_function = true;
}

Message response;
channel.response(message, response, 16);
// send ACK
size_t response_length = Messages::coded_ack(response.buf(), has_function ? 0x00 : RESPONSE_CODE(4,00), 0, 0);
response.set_id(message_id);
response.set_length(response_length);
ProtocolError error = channel.send(response);
if (error) return error;

// call the given user function
auto callback = [=,&channel] (const void* result, SparkReturnType::Enum resultType )
{ return this->function_result(channel, result, resultType, token); };
call_function(function_key, function_arg, callback, NULL);
return NO_ERROR;
}
ProtocolError handle_function_call(token_t token, message_id_t message_id, Message& message, MessageChannel& channel,
int (*call_function)(const char *function_key, const char *arg, SparkDescriptor::FunctionResultCallback callback, void* reserved))
{
// copy the function key
char function_key[MAX_FUNCTION_KEY_LENGTH+1];
memset(function_key, 0, MAX_FUNCTION_KEY_LENGTH+1);
uint8_t* queue = message.buf();
uint8_t queue_offset = 8;
size_t function_key_length = queue[7] & 0x0F;
if (function_key_length == MAX_OPTION_DELTA_LENGTH+1)
{
function_key_length = MAX_OPTION_DELTA_LENGTH+1 + queue[8];
queue_offset++;
}
// else if (function_key_length == MAX_OPTION_DELTA_LENGTH+2)
// {
// // MAX_OPTION_DELTA_LENGTH+2 not supported and not required for function_key_length
// }
memcpy(function_key, queue + queue_offset, function_key_length);

// How long is the argument?
size_t q_index = queue_offset + function_key_length;
size_t function_arg_length = queue[q_index] & 0x0F;
if (function_arg_length == MAX_OPTION_DELTA_LENGTH+1)
{
++q_index;
function_arg_length = MAX_OPTION_DELTA_LENGTH+1 + queue[q_index];
}
else if (function_arg_length == MAX_OPTION_DELTA_LENGTH+2)
{
++q_index;
function_arg_length = queue[q_index] << 8;
++q_index;
function_arg_length |= queue[q_index];
function_arg_length += 269;
}

bool has_function = false;

// allocated memory bounds check
if (function_arg_length <= MAX_FUNCTION_ARG_LENGTH)
{
// save a copy of the argument
memcpy(function_arg, queue + q_index + 1, function_arg_length);
function_arg[function_arg_length] = 0; // null terminate string
has_function = true;
}

Message response;
channel.response(message, response, 16);
// send ACK
size_t response_length = Messages::coded_ack(response.buf(), has_function ? 0x00 : RESPONSE_CODE(4,00), 0, 0);
response.set_id(message_id);
response.set_length(response_length);
ProtocolError error = channel.send(response);
if (error) {
return error;
}

// call the given user function
auto callback = [=,&channel] (const void* result, SparkReturnType::Enum resultType )
{ return this->function_result(channel, result, resultType, token); };
call_function(function_key, function_arg, callback, NULL);
return NO_ERROR;
}
};


Expand Down
4 changes: 2 additions & 2 deletions communication/src/messages.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ size_t Messages::event(uint8_t buf[], uint16_t message_id, const char *event_nam
*p++ = 0xb1; // one-byte Uri-Path option
*p++ = event_type;

size_t name_data_len = strnlen(event_name, 63);
size_t name_data_len = strnlen(event_name, MAX_EVENT_NAME_LENGTH);
p += event_name_uri_path(p, event_name, name_data_len);

if (60 != ttl)
Expand All @@ -320,7 +320,7 @@ size_t Messages::event(uint8_t buf[], uint16_t message_id, const char *event_nam

if (NULL != data)
{
name_data_len = strnlen(data, 255);
name_data_len = strnlen(data, MAX_EVENT_DATA_LENGTH);

*p++ = 0xff;
memcpy(p, data, name_data_len);
Expand Down
44 changes: 29 additions & 15 deletions communication/src/protocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ ProtocolError Protocol::handle_received_message(Message& message,

case CoAPMessageType::VARIABLE_REQUEST:
{
char variable_key[13];
char variable_key[MAX_VARIABLE_KEY_LENGTH+1];
variables.decode_variable_request(variable_key, message);
return variables.handle_variable_request(variable_key, message,
channel, token, msg_id,
Expand Down Expand Up @@ -403,21 +403,8 @@ ProtocolError Protocol::event_loop(CoAPMessageType::Enum& message_type)
return error;
}


/**
* Produces and transmits a describe message.
* @param desc_flags Flags describing the information to provide. A combination of {@code DESCRIBE_APPLICATION) and {@code DESCRIBE_SYSTEM) flags.
*/
ProtocolError Protocol::send_description(token_t token, message_id_t msg_id, int desc_flags)
void Protocol::build_describe_message(Appender& appender, int desc_flags)
{
Message message;
channel.create(message);
uint8_t* buf = message.buf();
message.set_id(msg_id);
size_t desc = Messages::description(buf, msg_id, token);

BufferAppender appender(buf + desc, message.capacity());

// diagnostics must be requested in isolation to be a binary packet
if (descriptor.append_metrics && (desc_flags == DESCRIBE_METRICS))
{
Expand Down Expand Up @@ -490,6 +477,24 @@ ProtocolError Protocol::send_description(token_t token, message_id_t msg_id, int
}
appender.append('}');
}
}

/**
* Produces and transmits a describe message.
* @param desc_flags Flags describing the information to provide. A combination of {@code DESCRIBE_APPLICATION) and {@code DESCRIBE_SYSTEM) flags.
*/
ProtocolError Protocol::send_description(token_t token, message_id_t msg_id, int desc_flags)
{
Message message;
channel.create(message);
uint8_t* buf = message.buf();
message.set_id(msg_id);
size_t desc = Messages::description(buf, msg_id, token);

BufferAppender appender(buf + desc, message.capacity());

build_describe_message(appender, desc_flags);

int msglen = appender.next() - (uint8_t*) buf;
message.set_length(msglen);
LOG(INFO,"Sending '%s%s%s' describe message", desc_flags & DESCRIBE_SYSTEM ? "S" : "",
Expand Down Expand Up @@ -541,5 +546,14 @@ system_tick_t Protocol::ChunkedTransferCallbacks::millis()
return callbacks->millis();
}

int Protocol::get_describe_data(spark_protocol_describe_data* data, void* reserved)
{
data->maximum_size = 768; // a conservative guess based on dtls and lightssl encryption overhead and the CoAP data
BufferAppender2 appender(nullptr, 0); // don't need to store the data, just count the size
build_describe_message(appender, data->flags);
data->current_size = appender.dataSize();
return 0;
}


}}
4 changes: 4 additions & 0 deletions communication/src/protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class Protocol
* todo - move this into the message channel?
*/
system_tick_t last_message_millis;
system_tick_t cloud_connected_millis;

/**
* The product_id represented by this device. set_product_id()
Expand Down Expand Up @@ -383,6 +384,8 @@ class Protocol
return success;
}

void build_describe_message(Appender& appender, int desc_flags);

inline bool add_event_handler(const char *event_name, EventHandler handler)
{
return add_event_handler(event_name, handler, NULL,
Expand Down Expand Up @@ -462,6 +465,7 @@ class Protocol

virtual int command(ProtocolCommands::Enum command, uint32_t data)=0;

virtual int get_describe_data(spark_protocol_describe_data* data, void* reserved);
};

}
Expand Down
25 changes: 17 additions & 8 deletions communication/src/protocol_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,23 @@ system_error_t toSystemError(ProtocolError error);
typedef uint16_t chunk_index_t;

const chunk_index_t NO_CHUNKS_MISSING = 65535;
const chunk_index_t MAX_CHUNKS = 65535;
const size_t MISSED_CHUNKS_TO_SEND = 50;
const size_t MAX_FUNCTION_ARG_LENGTH = 64;
const size_t MAX_FUNCTION_KEY_LENGTH = 12;
const size_t MAX_VARIABLE_KEY_LENGTH = 12;
const size_t MAX_EVENT_NAME_LENGTH = 64;
const size_t MAX_EVENT_DATA_LENGTH = 64;
const size_t MAX_EVENT_TTL_SECONDS = 16777215;
const chunk_index_t MAX_CHUNKS = 65535;
const size_t MISSED_CHUNKS_TO_SEND = 50;
const size_t MAX_EVENT_TTL_SECONDS = 16777215;
const size_t MAX_OPTION_DELTA_LENGTH = 12;
#if PLATFORM_ID<2
const size_t MAX_FUNCTION_ARG_LENGTH = 64;
const size_t MAX_FUNCTION_KEY_LENGTH = 12;
const size_t MAX_VARIABLE_KEY_LENGTH = 12;
const size_t MAX_EVENT_NAME_LENGTH = 64;
const size_t MAX_EVENT_DATA_LENGTH = 255;
#else
const size_t MAX_FUNCTION_ARG_LENGTH = 622;
const size_t MAX_FUNCTION_KEY_LENGTH = 64;
const size_t MAX_VARIABLE_KEY_LENGTH = 64;
const size_t MAX_EVENT_NAME_LENGTH = 64;
const size_t MAX_EVENT_DATA_LENGTH = 622;
#endif

// Timeout in milliseconds given to receive an acknowledgement for a published event
const unsigned SEND_EVENT_ACK_TIMEOUT = 20000;
Expand Down
69 changes: 43 additions & 26 deletions communication/src/spark_protocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1330,36 +1330,47 @@ bool SparkProtocol::function_result(const void* result, SparkReturnType::Enum, u
bool SparkProtocol::handle_function_call(msg& message)
{
// copy the function key
char function_key[13];
memset(function_key, 0, 13);
int function_key_length = queue[7] & 0x0F;
memcpy(function_key, queue + 8, function_key_length);
char function_key[MAX_FUNCTION_KEY_LENGTH+1];
memset(function_key, 0, MAX_FUNCTION_KEY_LENGTH+1);

uint8_t queue_offset = 8;
size_t function_key_length = queue[7] & 0x0F;
if (function_key_length == MAX_OPTION_DELTA_LENGTH+1)
{
function_key_length = MAX_OPTION_DELTA_LENGTH+1 + queue[8];
queue_offset++;
}
// else if (function_key_length == MAX_OPTION_DELTA_LENGTH+2)
// {
// // MAX_OPTION_DELTA_LENGTH+2 not supported and not required for function_key_length
// }
memcpy(function_key, queue + queue_offset, function_key_length);

// How long is the argument?
size_t q_index = 8 + function_key_length;
size_t query_length = queue[q_index] & 0x0F;
if (13 == query_length)
size_t q_index = queue_offset + function_key_length;
size_t function_arg_length = queue[q_index] & 0x0F;
if (function_arg_length == MAX_OPTION_DELTA_LENGTH+1)
{
++q_index;
query_length = 13 + queue[q_index];
++q_index;
function_arg_length = MAX_OPTION_DELTA_LENGTH+1 + queue[q_index];
}
else if (14 == query_length)
else if (function_arg_length + MAX_OPTION_DELTA_LENGTH+2)
{
++q_index;
query_length = queue[q_index] << 8;
++q_index;
query_length |= queue[q_index];
query_length += 269;
++q_index;
function_arg_length = queue[q_index] << 8;
++q_index;
function_arg_length |= queue[q_index];
function_arg_length += 269;
}

bool has_function = false;

// allocated memory bounds check
if (MAX_FUNCTION_ARG_LENGTH > query_length)
if (function_arg_length <= MAX_FUNCTION_ARG_LENGTH)
{
// save a copy of the argument
memcpy(function_arg, queue + q_index + 1, query_length);
function_arg[query_length] = 0; // null terminate string
memcpy(function_arg, queue + q_index + 1, function_arg_length);
function_arg[function_arg_length] = 0; // null terminate string
has_function = true;
}

Expand All @@ -1370,8 +1381,8 @@ bool SparkProtocol::handle_function_call(msg& message)
coded_ack(msg_to_send + 2, has_function ? 0x00 : RESPONSE_CODE(4,00), queue[2], queue[3]);
if (0 > blocking_send(msg_to_send, 18))
{
// error
return false;
// error
return false;
}

// call the given user function
Expand Down Expand Up @@ -1511,13 +1522,19 @@ bool SparkProtocol::handle_message(msg& message, token_t token, CoAPMessageType:
case CoAPMessageType::VARIABLE_REQUEST:
{
// copy the variable key
int variable_key_length = queue[7] & 0x0F;
if (12 < variable_key_length)
variable_key_length = 12;
int queue_offset = 8;
size_t variable_key_length = queue[7] & 0x0F;
if (variable_key_length == MAX_OPTION_DELTA_LENGTH+1) {
variable_key_length = MAX_OPTION_DELTA_LENGTH+1 + queue[8];
queue_offset++;
}
if (variable_key_length > MAX_VARIABLE_KEY_LENGTH) {
variable_key_length = MAX_VARIABLE_KEY_LENGTH;
}

char variable_key[13];
memcpy(variable_key, queue + 8, variable_key_length);
memset(variable_key + variable_key_length, 0, 13 - variable_key_length);
char variable_key[MAX_VARIABLE_KEY_LENGTH+1];
memcpy(variable_key, queue + queue_offset, variable_key_length);
memset(variable_key + variable_key_length, 0, MAX_VARIABLE_KEY_LENGTH+1 - variable_key_length);

queue[0] = 0;
queue[1] = 16; // default buffer length
Expand Down
Loading

0 comments on commit 612ee42

Please sign in to comment.