Compare commits

...

4 Commits

Author SHA1 Message Date
David Rebbe 1ca9f0fdb4 added icsneo_message_get_netid and icsneo_get_netid_name 2024-12-09 09:38:01 -05:00
David Rebbe bfd8a023c6 add bus name string to example 2024-12-09 07:52:39 -05:00
David Rebbe 76fd1177de fixed calls around safe_str_copy 2024-12-09 07:52:26 -05:00
David Rebbe 7e616536ef fixed unsafe warnings and added icsneo_get_bus_type_name 2024-12-09 07:33:49 -05:00
3 changed files with 129 additions and 35 deletions

View File

@ -55,6 +55,41 @@ typedef struct icsneo_event_t {
static std::vector<std::shared_ptr<icsneo_device_t>> g_devices;
static std::vector<icsneo_event_t> g_events;
/**
* Safely copies a std::string to a char array.
*
* @param dest The buffer to copy the string into
* @param dest_size* The size of the buffer. Will be modified to the length of the string
* @param src The string to copy
*
* @return true if the string was successfully copied, false otherwise
*
* @note This function always null terminates the buffer, even if the string is too long.
* This is done for security reasons, not performance.
*/
bool safe_str_copy(const char* dest, uint32_t* const dest_size, std::string src) {
if (!dest || !dest_size) {
return false;
}
// zero terminate the entire string, this is done for security not for performance
memset(const_cast<char*>(dest), 0, *dest_size);
// Need to save room for the null terminator
*dest_size -= 1;
try {
auto copied = src.copy(const_cast<char*>(dest), static_cast<size_t>(*dest_size), 0);
*dest_size = static_cast<uint32_t>(copied);
// Somehow we didn't copy the number of bytes we needed to? This check probably isn't needed.
if (copied != src.length()) {
return false;
}
return true;
} catch (std::out_of_range& ex) {
// if pos > size()
(void)ex;
return false;
}
}
ICSNEO_API icsneo_error_t icsneo_get_error_code(icsneo_error_t error_code, const char* value, uint32_t* value_length) {
if (!value || !value_length) {
return icsneo_error_invalid_parameters;
@ -89,15 +124,13 @@ ICSNEO_API icsneo_error_t icsneo_get_error_code(icsneo_error_t error_code, const
case icsneo_error_transmit_messages_failed:
error = "Transmitting messages failed";
break;
case icsneo_error_string_copy_failed:
error = "String copy failed";
break;
// Don't default, let the compiler warn us if we forget to handle an error code
}
// Find the minimum length of the error string and set value_length
auto min_length = std::minmax(static_cast<uint32_t>(error.length()), *value_length).first;
*value_length = min_length;
// Copy the string into value
strncpy(const_cast<char *>(value), error.c_str(), min_length);
return icsneo_error_success;
return safe_str_copy(value, value_length, error) ? icsneo_error_success : icsneo_error_string_copy_failed;
}
ICSNEO_API icsneo_error_t icsneo_device_type_from_type(icsneo_devicetype_t device_type, const char* value, uint32_t* value_length) {
@ -106,16 +139,12 @@ ICSNEO_API icsneo_error_t icsneo_device_type_from_type(icsneo_devicetype_t devic
}
auto device_type_str = DeviceType::getGenericProductName(device_type);
// Find the minimum length of the device type string and set value_length
auto min_length = std::minmax(static_cast<uint32_t>(device_type_str.length()), *value_length).first;
*value_length = min_length;
// Copy the string into value
strncpy(const_cast<char *>(value), device_type_str.c_str(), min_length);
return icsneo_error_success;
return safe_str_copy(value, value_length, device_type_str) ? icsneo_error_success : icsneo_error_string_copy_failed;
}
ICSNEO_API icsneo_error_t icsneo_device_find_all(icsneo_device_t** devices, uint32_t* devices_count, void* reserved) {
(void)reserved;
if (!devices || !devices_count) {
return icsneo_error_invalid_parameters;
}
@ -231,13 +260,8 @@ ICSNEO_API icsneo_error_t icsneo_device_get_description(icsneo_device_t* device,
return icsneo_error_invalid_parameters;
}
auto dev = device->device;
// Get and set the length
auto min_length = std::minmax(static_cast<uint32_t>(dev->describe().length()), *value_length).first;
*value_length = min_length;
// Copy the string into value
strncpy(const_cast<char *>(value), dev->describe().c_str(), min_length);
return icsneo_error_success;
return safe_str_copy(value, value_length, dev->describe()) ? icsneo_error_success : icsneo_error_string_copy_failed;
}
ICSNEO_API icsneo_error_t icsneo_device_get_type(icsneo_device_t* device, icsneo_devicetype_t* value) {
@ -255,13 +279,8 @@ ICSNEO_API icsneo_error_t icsneo_device_get_serial(icsneo_device_t* device, cons
return icsneo_error_invalid_parameters;
}
auto dev = device->device;
// Get and set the length
auto min_length = std::minmax(static_cast<uint32_t>(dev->getSerial().length()), *value_length).first;
*value_length = min_length;
// Copy the string into value
strncpy(const_cast<char *>(value), dev->getSerial().c_str(), min_length);
return icsneo_error_success;
return safe_str_copy(value, value_length, dev->getSerial()) ? icsneo_error_success : icsneo_error_string_copy_failed;
}
@ -472,6 +491,40 @@ ICSNEO_API icsneo_error_t icsneo_message_get_bus_type(icsneo_device_t* device, i
return icsneo_error_success;
}
ICSNEO_API icsneo_error_t icsneo_get_bus_type_name(icsneo_msg_bus_type_t* bus_type, const char* value, uint32_t* value_length) {
if (!bus_type || !value || !value_length) {
return icsneo_error_invalid_parameters;
}
auto bus_type_str = std::string(Network::GetTypeString(*bus_type));
// Copy the string into value
return safe_str_copy(value, value_length, bus_type_str) ? icsneo_error_success : icsneo_error_string_copy_failed;
}
ICSNEO_API icsneo_error_t icsneo_message_get_netid(icsneo_device_t* device, icsneo_message_t* message, icsneo_netid_t* netid) {
if (!device || !message || !netid) {
return icsneo_error_invalid_parameters;
}
// TODO: Check if message is valid
// Make sure the message is a bus message
if (message->message->getMsgType() != icsneo_msg_type_bus) {
return icsneo_error_invalid_type;
}
// We can static cast here because we are relying on the type being correct at this point
auto bus_message = static_cast<BusMessage*>(message->message.get());
*netid = static_cast<icsneo_netid_t>(bus_message->network.getNetID());
return icsneo_error_success;
}
ICSNEO_API icsneo_error_t icsneo_get_netid_name(icsneo_netid_t netid, const char* value, uint32_t* value_length) {
if (!netid || !value || !value_length) {
return icsneo_error_invalid_parameters;
}
auto netid_str = std::string(Network::GetNetIDString(static_cast<_icsneo_netid_t>(netid), true));
// Copy the string into value
return safe_str_copy(value, value_length, netid_str) ? icsneo_error_success : icsneo_error_string_copy_failed;
}
ICSNEO_API icsneo_error_t icsneo_message_get_data(icsneo_device_t* device, icsneo_message_t* message, uint8_t* data, uint32_t* data_length) {
if (!device || !message || !data || !data_length) {
return icsneo_error_invalid_parameters;
@ -689,14 +742,8 @@ ICSNEO_API icsneo_error_t icsneo_event_get_description(icsneo_event_t* event, co
}
// TODO: Check if event is valid
auto ev = event->event;
// Get and set the length
auto min_length = std::minmax(static_cast<uint32_t>(ev.describe().length()), *value_length).first;
*value_length = min_length;
// Copy the string into value
strncpy(const_cast<char *>(value), ev.describe().c_str(), min_length);
return icsneo_error_success;
return safe_str_copy(value, value_length, ev.describe()) ? icsneo_error_success : icsneo_error_string_copy_failed;
}
ICSNEO_API icsneo_error_t icsneo_device_get_rtc(icsneo_device_t* device, int64_t* unix_epoch) {

View File

@ -206,16 +206,28 @@ int process_messages(icsneo_device_t* device, icsneo_message_t** messages, uint3
if (res != icsneo_error_success) {
return print_error_code("Failed to get message bus type", res);
}
printf("\t%d) Message type: %u bus type: %u\n", i, msg_type, bus_type);
const char bus_name[128] = {0};
uint32_t bus_name_length = 128;
res = icsneo_get_bus_type_name(&bus_type, bus_name, &bus_name_length);
if (res != icsneo_error_success) {
return print_error_code("Failed to get message bus type name", res);
}
printf("\t%d) Message type: %u bus type: %s (%u)\n", i, msg_type, bus_name, bus_type);
if (bus_type == icsneo_msg_bus_type_can) {
uint32_t arbid = 0;
uint32_t dlc = 0;
icsneo_netid_t netid = 0;
bool is_remote = false;
bool is_canfd = false;
bool is_extended = false;
uint8_t data[64] = {0};
uint32_t data_length = 64;
uint32_t result = icsneo_can_message_get_arbid(device, message, &arbid);
const char netid_name[128] = {0};
uint32_t netid_name_length = 128;
uint32_t result = icsneo_message_get_netid(device, message, &netid);
result += icsneo_get_netid_name(netid, netid_name, &netid_name_length);
result += icsneo_can_message_get_arbid(device, message, &arbid);
result += icsneo_can_message_get_dlc_on_wire(device, message, &dlc);
result += icsneo_can_message_is_remote(device, message, &is_remote);
result += icsneo_can_message_is_canfd(device, message, &is_canfd);
@ -225,7 +237,7 @@ int process_messages(icsneo_device_t* device, icsneo_message_t** messages, uint3
printf("\tFailed get get CAN parameters (error: %u) for index %u\n", result, i);
continue;
}
printf("\t ArbID: 0x%x\t DLC: %u\t Remote: %d\t CANFD: %d\t Extended: %d\t Data length: %u\n", arbid, dlc, is_remote, is_canfd, is_extended, data_length);
printf("\t NetID: %s (0x%x)\tArbID: 0x%x\t DLC: %u\t Remote: %d\t CANFD: %d\t Extended: %d\t Data length: %u\n", netid_name, netid, arbid, dlc, is_remote, is_canfd, is_extended, data_length);
printf("\t Data: [");
for (uint32_t x = 0; x < data_length; x++) {
printf(" 0x%x", data[x]);

View File

@ -88,6 +88,8 @@ typedef enum _icsneo_error_t {
icsneo_error_set_settings_failure,
// Failed to transmit messages
icsneo_error_transmit_messages_failed,
// Failed to copy string to buffer
icsneo_error_string_copy_failed
} _icsneo_error_t;
/** @brief Integer representation of _icsneo_error_t enum.
@ -349,10 +351,43 @@ ICSNEO_API icsneo_error_t icsneo_message_get_type(icsneo_device_t* device, icsne
*
* @return icsneo_error_t icsneo_error_success if successful, icsneo_error_invalid_parameters or icsneo_error_invalid_type otherwise.
*
* @see icsneo_msg_bus_type_t
* @see icsneo_msg_bus_type_t, icsneo_get_bus_type_name
*/
ICSNEO_API icsneo_error_t icsneo_message_get_bus_type(icsneo_device_t* device, icsneo_message_t* message, icsneo_msg_bus_type_t* bus_type);
/** @brief Get the bus type string for a icsneo_msg_bus_type_t.
*
* @param[in] icsneo_msg_bus_type_t* bus_type The bus type to get the description of.
* @param[out] const char* value Pointer to a buffer to copy the description into. Null terminated.
* @param[in,out] uint32_t* value_length Size of the value buffer. Modified with the length of the description.
*
* @return icsneo_error_t icsneo_error_success if successful, icsneo_error_invalid_parameters otherwise.
*/
ICSNEO_API icsneo_error_t icsneo_get_bus_type_name(icsneo_msg_bus_type_t* bus_type, const char* value, uint32_t* value_length);
/** @brief Get the Network ID (netid) of a bus message
*
* @param[in] icsneo_device_t* device The device to check against.
* @param[in] icsneo_message_t* message The message to check.
* @param[out] icsneo_netid_t* netid Pointer to a icsneo_netid_t to copy the type of the value into.
*
* @return icsneo_error_t icsneo_error_success if successful, icsneo_error_invalid_parameters or icsneo_error_invalid_type otherwise.
*
* @see icsneo_netid_t, icsneo_get_netid_name
*/
ICSNEO_API icsneo_error_t icsneo_message_get_netid(icsneo_device_t* device, icsneo_message_t* message, icsneo_netid_t* netid);
/** @brief Get the netid string for a icsneo_netid_t.
*
* @param[in] icsneo_netid_t netid The network id to get the description of.
* @param[out] const char* value Pointer to a buffer to copy the description into. Null terminated.
* @param[in,out] uint32_t* value_length Size of the value buffer. Modified with the length of the description.
*
* @return icsneo_error_t icsneo_error_success if successful, icsneo_error_invalid_parameters otherwise.
*/
ICSNEO_API icsneo_error_t icsneo_get_netid_name(icsneo_netid_t netid, const char* value, uint32_t* value_length);
/** @brief Get the data bytes of a message
*
* @param[in] icsneo_device_t* device The device to check against.