Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support node namespaces #95

Merged
merged 10 commits into from
Apr 8, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions rmw/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ include_directories(include)
add_library(${PROJECT_NAME} SHARED
"src/allocators.c"
"src/error_handling.c"
"src/validate_namespace.c"
"src/validate_node_name.c"
"src/validate_topic_name.c"
"src/sanity_checks.c")
Expand Down
2 changes: 1 addition & 1 deletion rmw/include/rmw/rmw.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ rmw_init(void);
RMW_PUBLIC
RMW_WARN_UNUSED
rmw_node_t *
rmw_create_node(const char * name, size_t domain_id);
rmw_create_node(const char * name, const char * namespace_, size_t domain_id);

RMW_PUBLIC
RMW_WARN_UNUSED
Expand Down
1 change: 1 addition & 0 deletions rmw/include/rmw/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ typedef struct RMW_PUBLIC_TYPE rmw_node_t
const char * implementation_identifier;
void * data;
const char * name;
const char * namespace_;
const size_t domain_id;
} rmw_node_t;

Expand Down
108 changes: 108 additions & 0 deletions rmw/include/rmw/validate_namespace.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// Copyright 2017 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef RMW__VALIDATE_NAMESPACE_H_
#define RMW__VALIDATE_NAMESPACE_H_

#if __cplusplus
extern "C"
{
#endif

#include "rmw/macros.h"
#include "rmw/types.h"
#include "rmw/validate_topic_name.h"

#define RMW_NAMESPACE_VALID 0
#define RMW_NAMESPACE_INVALID_IS_EMPTY_STRING 1
#define RMW_NAMESPACE_INVALID_NOT_ABSOLUTE 2
#define RMW_NAMESPACE_INVALID_ENDS_WITH_FORWARD_SLASH 3
#define RMW_NAMESPACE_INVALID_CONTAINS_UNALLOWED_CHARACTERS 4
#define RMW_NAMESPACE_INVALID_CONTAINS_REPEATED_FORWARD_SLASH 5
#define RMW_NAMESPACE_INVALID_NAME_TOKEN_STARTS_WITH_NUMBER 6
#define RMW_NAMESPACE_INVALID_TOO_LONG 7

// An additional 2 characters are reserved for the shortest possible topic, e.g. '/X'.
#define RMW_NAMESPACE_MAX_LENGTH (RMW_TOPIC_MAX_NAME_LENGTH - 2)

/// Determine if a given namespace is valid.
/** Validity of a namespace is based on rules for a topic defined here:
*
* http://design.ros2.org/articles/topic_and_service_names.html
*
* Note that this function expects that there are no URL suffixes as described
* in the above document which can be used for topics and services.
*
* If either the C string or validation_result pointer are null, then
* `RMW_RET_INVALID_ARGUMENT` will be returned.
* The namespace_ should be a valid, null-terminated C string.
* The validation_result int pointer should point to valid memory so a result
* can be stored in it as an output variable.
* The invalid_index size_t pointer should either point NULL or to valid memory
* so in the event of a validation error, the location in the input string can
* be stored therein.
* If NULL is passed in for invalid_index, it will be not be set.
*
* The invalid_index will not be assigned a value if the namespace is valid.
*
* The int which validation_result points to will have a one of a few possible
* results values (defined with macros) stored into it:
*
* - RMW_NAMESPACE_VALID
* - RMW_NAMESPACE_INVALID_IS_EMPTY_STRING
* - RMW_NAMESPACE_INVALID_NOT_ABSOLUTE
* - RMW_NAMESPACE_INVALID_ENDS_WITH_FORWARD_SLASH
* - RMW_NAMESPACE_INVALID_CONTAINS_UNALLOWED_CHARACTERS
* - RMW_NAMESPACE_INVALID_CONTAINS_REPEATED_FORWARD_SLASH
* - RMW_NAMESPACE_INVALID_NAME_TOKEN_STARTS_WITH_NUMBER
* - RMW_NAMESPACE_INVALID_TOO_LONG
*
* The result value can be converted to a description with the
* rmw_namespace_validation_result_string() function.
*
* The ``RMW_NAMESPACE_INVALID_ENDS_WITH_FORWARD_SLASH`` validation result does
* not apply to ``"/"``, which is a valid namespace.
*
* The ``RMW_NAMESPACE_INVALID_TOO_LONG`` is guaranteed to be checked last,
* such that if you get that result, then you can assume all other checks
* succeeded.
* This is done so that the length limit can be treated as a warning rather
* than an error if desired.
*
* \param[in] namespace_ namespace to be validated
* \param[out] validation_result int in which the result of the check is stored
* \param[out] invalid_index index of the input string where an error occurred
* \returns `RMW_RET_OK` on successfully running the check, or
* \returns `RMW_RET_INVALID_ARGUMENT` on invalid parameters, or
* \returns `RMW_RET_ERROR` when an unspecified error occurs.
*/
RMW_PUBLIC
RMW_WARN_UNUSED
rmw_ret_t
rmw_validate_namespace(
const char * namespace_,
int * validation_result,
size_t * invalid_index);

/// Return a validation result description, or NULL if unknown or RMW_NAMESPACE_VALID.
RMW_PUBLIC
RMW_WARN_UNUSED
const char *
rmw_namespace_validation_result_string(int validation_result);

#if __cplusplus
}
#endif

#endif // RMW__VALIDATE_NAMESPACE_H_
9 changes: 5 additions & 4 deletions rmw/include/rmw/validate_node_name.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,17 @@ extern "C"
*
* - must not be an empty string
* - must only contain alphanumeric characters and underscores (a-z|A-Z|0-9|_)
* - must not start with an number
* - must not start with a number
*
* If either the node name C string or validation_result pointer are null, then
* `RMW_RET_INVALID_ARGUMENT` will be returned.
* The node_name should be a valid, null-terminated C string.
* The validation_result int pointer should point to valid memory so a result
* can be stored in it as an output variable.
* The invalid_index size_t pointer should point to valid memory so in the
* event of a validation error, the location in the input string can be stored
* therein.
* The invalid_index size_t pointer should either point NULL or to valid memory
* so in the event of a validation error, the location in the input string can
* be stored therein.
* If NULL is passed in for invalid_index, it will be not be set.
*
* The invalid_index will not be assigned a value if the node name is valid.
*
Expand Down
9 changes: 5 additions & 4 deletions rmw/include/rmw/validate_topic_name.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,17 @@ extern "C"
* The topic_name should be a valid, null-terminated C string.
* The validation_result int pointer should point to valid memory so a result
* can be stored in it as an output variable.
* The invalid_index size_t pointer should point to valid memory so in the
* event of a validation error, the location in the input string can be stored
* therein.
* The invalid_index size_t pointer should either point NULL or to valid memory
* so in the event of a validation error, the location in the input string can
* be stored therein.
* If NULL is passed in for invalid_index, it will be not be set.
*
* The invalid_index will not be assigned a value if the topic is valid.
*
* The int which validation_result points to will have a one of a few possible
* results values (defined with macros) stored into it:
*
* - RMW_VALID_TOPIC
* - RMW_TOPIC_VALID
* - RMW_TOPIC_INVALID_IS_EMPTY_STRING
* - RMW_TOPIC_INVALID_NOT_ABSOLUTE
* - RMW_TOPIC_INVALID_ENDS_WITH_FORWARD_SLASH
Expand Down
139 changes: 139 additions & 0 deletions rmw/src/validate_namespace.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// Copyright 2017 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "rmw/validate_namespace.h"

#include <ctype.h>
#include <stdio.h>
#include <string.h>

#include "rmw/error_handling.h"
#include "rmw/validate_topic_name.h"

#include "./isalnum_no_locale.h"

#ifndef _WIN32
#define LOCAL_SNPRINTF snprintf
#else
#define LOCAL_SNPRINTF(buffer, buffer_size, format, ...) \
_snprintf_s(buffer, buffer_size, _TRUNCATE, format, __VA_ARGS__)
#endif

rmw_ret_t
rmw_validate_namespace(
const char * namespace_,
int * validation_result,
size_t * invalid_index)
{
if (!namespace_) {
return RMW_RET_INVALID_ARGUMENT;
}
if (!validation_result) {
return RMW_RET_INVALID_ARGUMENT;
}

size_t namespace_length = strlen(namespace_);
// Special case for root namepsace
if (namespace_length == 1 && namespace_[0] == '/') {
// Ok to return here, it is valid and will not exceed RMW_NAMESPACE_MAX_LENGTH.
*validation_result = RMW_NAMESPACE_VALID;
return RMW_RET_OK;
}

// All other cases should pass the validate topic name test.
int t_validation_result;
size_t t_invalid_index;
rmw_ret_t ret = rmw_validate_topic_name(namespace_, &t_validation_result, &t_invalid_index);
if (ret != RMW_RET_OK) {
// error already set
return ret;
}

if (t_validation_result != RMW_TOPIC_VALID && t_validation_result != RMW_TOPIC_INVALID_TOO_LONG) {
switch (t_validation_result) {
case RMW_TOPIC_INVALID_IS_EMPTY_STRING:
*validation_result = RMW_NAMESPACE_INVALID_IS_EMPTY_STRING;
break;
case RMW_TOPIC_INVALID_NOT_ABSOLUTE:
*validation_result = RMW_NAMESPACE_INVALID_NOT_ABSOLUTE;
break;
case RMW_TOPIC_INVALID_ENDS_WITH_FORWARD_SLASH:
*validation_result = RMW_NAMESPACE_INVALID_ENDS_WITH_FORWARD_SLASH;
break;
case RMW_TOPIC_INVALID_CONTAINS_UNALLOWED_CHARACTERS:
*validation_result = RMW_NAMESPACE_INVALID_CONTAINS_UNALLOWED_CHARACTERS;
break;
case RMW_TOPIC_INVALID_CONTAINS_REPEATED_FORWARD_SLASH:
*validation_result = RMW_NAMESPACE_INVALID_CONTAINS_REPEATED_FORWARD_SLASH;
break;
case RMW_TOPIC_INVALID_NAME_TOKEN_STARTS_WITH_NUMBER:
*validation_result = RMW_NAMESPACE_INVALID_NAME_TOKEN_STARTS_WITH_NUMBER;
break;
default:
{
char default_err_msg[256];
// explicitly not taking return value which is number of bytes written
LOCAL_SNPRINTF(
default_err_msg, sizeof(default_err_msg),
"rmw_validate_namespace(): unknown rmw_validate_topic_name() validation result '%d'",
*validation_result
);
RMW_SET_ERROR_MSG(default_err_msg);
}
return RMW_RET_ERROR;
}
if (invalid_index) {
*invalid_index = t_invalid_index;
}
return RMW_RET_OK;
}

// check if the namespace is too long last, since it might be a soft invalidation
if (namespace_length > RMW_NAMESPACE_MAX_LENGTH) {
*validation_result = RMW_NAMESPACE_INVALID_TOO_LONG;
if (invalid_index) {
*invalid_index = RMW_NAMESPACE_MAX_LENGTH - 1;
}
return RMW_RET_OK;
}

// everything was ok, set result to valid namespace, avoid setting invalid_index, and return
*validation_result = RMW_NAMESPACE_VALID;
return RMW_RET_OK;
}

const char *
rmw_namespace_validation_result_string(int validation_result)
{
switch (validation_result) {
case RMW_NAMESPACE_VALID:
return NULL;
case RMW_NAMESPACE_INVALID_IS_EMPTY_STRING:
return "namespace must not be empty";
case RMW_NAMESPACE_INVALID_NOT_ABSOLUTE:
return "namespace must be absolute, it must lead with a '/'";
case RMW_NAMESPACE_INVALID_ENDS_WITH_FORWARD_SLASH:
return "namespace must not end with a '/', unless only a '/'";
case RMW_NAMESPACE_INVALID_CONTAINS_UNALLOWED_CHARACTERS:
return "namespace must not contain characters other than alphanumerics, '_', or '/'";
case RMW_NAMESPACE_INVALID_CONTAINS_REPEATED_FORWARD_SLASH:
return "namespace must not contain repeated '/'";
case RMW_NAMESPACE_INVALID_NAME_TOKEN_STARTS_WITH_NUMBER:
return "namespace must not have a token that starts with a number";
case RMW_NAMESPACE_INVALID_TOO_LONG:
return "namespace should not exceed '" RMW_STRINGIFY(RMW_NAMESPACE_MAX_NAME_LENGTH) "'";
default:
return NULL;
}
}
19 changes: 12 additions & 7 deletions rmw/src/validate_node_name.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,12 @@ rmw_validate_node_name(
if (!validation_result) {
return RMW_RET_INVALID_ARGUMENT;
}
if (!invalid_index) {
return RMW_RET_INVALID_ARGUMENT;
}
size_t node_name_length = strlen(node_name);
if (node_name_length == 0) {
*validation_result = RMW_NODE_NAME_INVALID_IS_EMPTY_STRING;
*invalid_index = 0;
if (invalid_index) {
*invalid_index = 0;
}
return RMW_RET_OK;
}
// check for unallowed characters
Expand All @@ -51,20 +50,26 @@ rmw_validate_node_name(
} else {
// if it is none of these, then it is an unallowed character in a node name
*validation_result = RMW_NODE_NAME_INVALID_CONTAINS_UNALLOWED_CHARACTERS;
*invalid_index = i;
if (invalid_index) {
*invalid_index = i;
}
return RMW_RET_OK;
}
}
if (isdigit(node_name[0]) != 0) {
// this is the case where the name starts with a number, i.e. [0-9]
*validation_result = RMW_NODE_NAME_INVALID_STARTS_WITH_NUMBER;
*invalid_index = 0;
if (invalid_index) {
*invalid_index = 0;
}
return RMW_RET_OK;
}
// check if the node name is too long last, since it might be a soft invalidation
if (node_name_length > RMW_NODE_NAME_MAX_NAME_LENGTH) {
*validation_result = RMW_NODE_NAME_INVALID_TOO_LONG;
*invalid_index = RMW_NODE_NAME_MAX_NAME_LENGTH - 1;
if (invalid_index) {
*invalid_index = RMW_NODE_NAME_MAX_NAME_LENGTH - 1;
}
return RMW_RET_OK;
}
// everything was ok, set result to valid node name, avoid setting invalid_index, and return
Expand Down
Loading