Commit 7333523f authored by Erich Keane's avatar Erich Keane

Changed ServerInstanceID to UUID

The specification and design document both specify that server instance
ID should be a UUID, yet this was initially implemented as a Uint32.

This patch implements UUID generation, UUID-as-string generation,
and UUID-to-string conversion in the ocrandom module.  Additionally,
the server instance ID calls now correctly work with UUID rather than
the int32.  OCResourceIdentifer also now work directly with strings
rather than converting the value to an int32.

Change-Id: Ic37559973f82515f795d75f798dab6b6ff99d31f
Signed-off-by: default avatarErich Keane <erich.keane@intel.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/983Tested-by: default avatarjenkins-iotivity <jenkins-iotivity@opendaylight.org>
Reviewed-by: default avatarSachin Agrawal <sachin.agrawal@intel.com>
Reviewed-by: default avatarDoug Hudson <douglas.hudson@intel.com>
Reviewed-by: default avatarJoseph Morrow <joseph.l.morrow@intel.com>
parent d147b915
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
command in this directory) command in this directory)
Install external libraries: Install external libraries:
$ sudo apt-get install libboost-dev libboost-program-options-dev libexpat1-dev libboost-thread-dev $ sudo apt-get install libboost-dev libboost-program-options-dev libexpat1-dev libboost-thread-dev uuid-dev
Build release binaries: Build release binaries:
$ scons $ scons
......
...@@ -19,6 +19,7 @@ if env.get('LOGGING'): ...@@ -19,6 +19,7 @@ if env.get('LOGGING'):
env.AppendUnique(CPPDEFINES = ['WITH_POSIX', '__linux__']) env.AppendUnique(CPPDEFINES = ['WITH_POSIX', '__linux__'])
env.AppendUnique(CFLAGS = ['-std=gnu99']) env.AppendUnique(CFLAGS = ['-std=gnu99'])
env.AppendUnique(CCFLAGS = ['-Wall', '-fPIC']) env.AppendUnique(CCFLAGS = ['-Wall', '-fPIC'])
env.AppendUnique(LIBS = ['uuid'])
env.AppendUnique(LINKFLAGS = ['-ldl', '-lpthread']) env.AppendUnique(LINKFLAGS = ['-ldl', '-lpthread'])
if env.get('TARGET_OS') == 'tizen': if env.get('TARGET_OS') == 'tizen':
......
...@@ -36,6 +36,17 @@ extern "C" { ...@@ -36,6 +36,17 @@ extern "C" {
#define ANALOG_IN (10) #define ANALOG_IN (10)
#endif #endif
#define UUID_SIZE (16)
// The characters are 36 long, 37 for the null-term
#define UUID_STRING_SIZE (37)
typedef enum
{
RAND_UUID_OK = 0,
RAND_UUID_INVALID_PARAM = -1,
RAND_UUID_READ_ERROR = -2,
RAND_UUID_CONVERT_ERROR = -3
} OCRandomUuidResult;
/** /**
* Seed the random number generator. Seeding depends on platform. * Seed the random number generator. Seeding depends on platform.
* Android and Linux uses current time. Arduino uses Analog reading on pin ANALOG_IN * Android and Linux uses current time. Arduino uses Analog reading on pin ANALOG_IN
...@@ -73,6 +84,46 @@ void OCFillRandomMem(uint8_t * location, uint16_t len); ...@@ -73,6 +84,46 @@ void OCFillRandomMem(uint8_t * location, uint16_t len);
*/ */
uint32_t OCGetRandomRange(uint32_t firstBound, uint32_t secondBound); uint32_t OCGetRandomRange(uint32_t firstBound, uint32_t secondBound);
/**
* Generate a Uniformly Unique Identifier based on RFC4122 and
* provide it as a 16 byte byte-array
*
* @param[out] uuid
* the 16 byte array to fill with the UUID data
* of a new UUID
*
* @retval RAND_UUID_OK for success, otherwise an error value
*/
OCRandomUuidResult OCGenerateUuid(uint8_t uuid[UUID_SIZE]);
/**
* Generate a Uniformly Unique Identifier based on RFC4122 and
* provide it as a C style string.
*
* @param[out] uuidString
* a 37-byte length string to fill with the string
* representation of a new UUID. Size is 32 chars
* for the hex data, 4 for '-' characters, and 1
* for the NULL terminator
*
* @retval RAND_UUID_OK for success, otherwise an error value
*/
OCRandomUuidResult OCGenerateUuidString(char uuidString[UUID_STRING_SIZE]);
/**
* Convert a UUID generated by OCGenerateUuid to a C style string
* based on RFC 4122
*
* @param[in] uuid
* The 16 byte array filled with UUID data by OCGenerateUuid
* @param[out] uuidString
* a 37 byte length string to fill with the string
* representation of the passed UUID.
* @retval RAND_UUID_OK for success, otherwise an error value
*/
OCRandomUuidResult OCConvertUuidToString(const uint8_t uuid[UUID_SIZE],
char uuidString[UUID_STRING_SIZE]);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
......
...@@ -24,6 +24,11 @@ ...@@ -24,6 +24,11 @@
#include "unistd.h" #include "unistd.h"
#endif #endif
#include "ocrandom.h" #include "ocrandom.h"
#include <stdio.h>
#if defined(__linux__) || defined(__APPLE__)
#include <uuid/uuid.h>
#endif
#ifdef ARDUINO #ifdef ARDUINO
#include "Arduino.h" #include "Arduino.h"
...@@ -132,3 +137,148 @@ uint32_t OCGetRandomRange(uint32_t firstBound, uint32_t secondBound){ ...@@ -132,3 +137,148 @@ uint32_t OCGetRandomRange(uint32_t firstBound, uint32_t secondBound){
result = ((float)OCGetRandom()/((float)(0xFFFFFFFF))*(float)diff) + (float) base; result = ((float)OCGetRandom()/((float)(0xFFFFFFFF))*(float)diff) + (float) base;
return result; return result;
} }
#if defined(__ANDROID__)
uint8_t parseUuidChar(char c)
{
if(isdigit(c))
{
return c - '0';
}
else
{
return c - 'a' + 10;
}
}
uint8_t parseUuidPart(const char *c)
{
return (parseUuidChar(c[0])<<4) + parseUuidChar(c[1]);
}
#endif
OCRandomUuidResult OCGenerateUuid(uint8_t uuid[UUID_SIZE])
{
if(!uuid)
{
return RAND_UUID_INVALID_PARAM;
}
#if defined(__linux__) || defined(__APPLE__)
// note: uuid_t is typedefed as unsigned char[16] on linux/apple
uuid_generate(uuid);
return RAND_UUID_OK;
#elif defined(__ANDROID__)
char uuidString[UUID_STRING_SIZE];
int8_t ret = OCGenerateUuidString(uuidString);
if(ret < 0)
{
return ret;
}
uuid[ 0] = parseUuidPart(&uuidString[0]);
uuid[ 1] = parseUuidPart(&uuidString[2]);
uuid[ 2] = parseUuidPart(&uuidString[4]);
uuid[ 3] = parseUuidPart(&uuidString[6]);
uuid[ 4] = parseUuidPart(&uuidString[9]);
uuid[ 5] = parseUuidPart(&uuidString[11]);
uuid[ 6] = parseUuidPart(&uuidString[14]);
uuid[ 7] = parseUuidPart(&uuidString[16]);
uuid[ 8] = parseUuidPart(&uuidString[19]);
uuid[ 9] = parseUuidPart(&uuidString[21]);
uuid[10] = parseUuidPart(&uuidString[24]);
uuid[11] = parseUuidPart(&uuidString[26]);
uuid[12] = parseUuidPart(&uuidString[28]);
uuid[13] = parseUuidPart(&uuidString[30]);
uuid[14] = parseUuidPart(&uuidString[32]);
uuid[15] = parseUuidPart(&uuidString[34]);
return RAND_UUID_OK;
#else
// Fallback for all platforms is filling the array with random data
OCFillRandomMem(uuid, UUID_SIZE);
return RAND_UUID_OK;
#endif
}
OCRandomUuidResult OCGenerateUuidString(char uuidString[UUID_STRING_SIZE])
{
if(!uuidString)
{
return RAND_UUID_INVALID_PARAM;
}
#if defined(__linux__) || defined(__APPLE__)
uint8_t uuid[UUID_SIZE];
int8_t ret = OCGenerateUuid(uuid);
if(ret != 0)
{
return ret;
}
uuid_unparse_lower(uuid, uuidString);
return RAND_UUID_OK;
#elif defined(__ANDROID__)
int32_t fd = open("/proc/sys/kernel/random/uuid", O_RDONLY);
if(fd > 0)
{
ssize_t readResult = read(fd, uuidString, UUID_STRING_SIZE - 1);
close(fd);
if(readResult < 0)
{
return RAND_UUID_READ_ERROR;
}
else if(readResult < UUID_STRING_SIZE - 1)
{
uuidString[0] = '\0';
return RAND_UUID_READ_ERROR;
}
uuidString[UUID_STRING_SIZE - 1] = '\0';
for(char* p = uuidString; *p; ++p)
{
*p = tolower(*p);
}
return RAND_UUID_OK;
}
else
{
close(fd);
return RAND_UUID_READ_ERROR;
}
#else
uint8_t uuid[UUID_SIZE];
OCGenerateUuid(uuid);
return OCConvertUuidToString(uuid, uuidString);
#endif
}
OCRandomUuidResult OCConvertUuidToString(const uint8_t uuid[UUID_SIZE],
char uuidString[UUID_STRING_SIZE])
{
if (uuid == NULL || uuidString == NULL)
{
return RAND_UUID_INVALID_PARAM;
}
int ret = snprintf(uuidString, UUID_STRING_SIZE,
"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
uuid[0], uuid[1], uuid[2], uuid[3],
uuid[4], uuid[5], uuid[6], uuid[7],
uuid[8], uuid[9], uuid[10], uuid[11],
uuid[12], uuid[13], uuid[14], uuid[15]
);
if (ret != UUID_STRING_SIZE - 1)
{
return RAND_UUID_CONVERT_ERROR;
}
return RAND_UUID_OK;
}
...@@ -63,3 +63,43 @@ TEST(RandomGeneration,OCFillRandomMem) { ...@@ -63,3 +63,43 @@ TEST(RandomGeneration,OCFillRandomMem) {
EXPECT_EQ((uint8_t )0, array[ARR_SIZE - 1]); EXPECT_EQ((uint8_t )0, array[ARR_SIZE - 1]);
} }
TEST(RandomGeneration, OCGenerateUuid)
{
EXPECT_EQ(RAND_UUID_INVALID_PARAM, OCGenerateUuid(NULL));
uint8_t uuid[16] = {};
EXPECT_EQ(RAND_UUID_OK, OCGenerateUuid(uuid));
EXPECT_FALSE(uuid[0] == '0' && uuid[1] == '0' &&
uuid[2] == '0' && uuid[3] == '0' &&
uuid[4] == '0' && uuid[5] == '0' &&
uuid[6] == '0' && uuid[7] == '0' &&
uuid[8] == '0' && uuid[9] == '0' &&
uuid[10] == '0' && uuid[11] == '0' &&
uuid[12] == '0' && uuid[13] == '0' &&
uuid[14] == '0' && uuid[15] == '0');
}
TEST(RandomGeneration, OCGenerateUuidString)
{
EXPECT_EQ(RAND_UUID_INVALID_PARAM, OCGenerateUuidString(NULL));
char uuidString[37] ={};
EXPECT_EQ(RAND_UUID_OK, OCGenerateUuidString(uuidString));
EXPECT_EQ(0, uuidString[36]);
EXPECT_EQ('-', uuidString[8]);
EXPECT_EQ('-', uuidString[13]);
EXPECT_EQ('-', uuidString[18]);
EXPECT_EQ('-', uuidString[23]);
for(int i = 0; i < 36; ++i)
{
EXPECT_TRUE(
i == 8 || i == 13 || i == 18 || i == 23 ||
(uuidString[i] >= 'a' && uuidString[i] <= 'f') ||
(uuidString[i] >= '0' && uuidString[i] <= '9'))
<< "UUID Character out of range: "<< uuidString[i];
}
}
...@@ -64,3 +64,43 @@ TEST(RandomGeneration,OCFillRandomMem) { ...@@ -64,3 +64,43 @@ TEST(RandomGeneration,OCFillRandomMem) {
EXPECT_EQ((uint8_t )0, array[ARR_SIZE - 1]); EXPECT_EQ((uint8_t )0, array[ARR_SIZE - 1]);
} }
TEST(RandomGeneration, OCGenerateUuid)
{
EXPECT_EQ(RAND_UUID_INVALID_PARAM, OCGenerateUuid(NULL));
uint8_t uuid[16] = {};
EXPECT_EQ(RAND_UUID_OK, OCGenerateUuid(uuid));
EXPECT_FALSE(uuid[0] == '0' && uuid[1] == '0' &&
uuid[2] == '0' && uuid[3] == '0' &&
uuid[4] == '0' && uuid[5] == '0' &&
uuid[6] == '0' && uuid[7] == '0' &&
uuid[8] == '0' && uuid[9] == '0' &&
uuid[10] == '0' && uuid[11] == '0' &&
uuid[12] == '0' && uuid[13] == '0' &&
uuid[14] == '0' && uuid[15] == '0');
}
TEST(RandomGeneration, OCGenerateUuidString)
{
EXPECT_EQ(RAND_UUID_INVALID_PARAM, OCGenerateUuidString(NULL));
char uuidString[37] = {};
EXPECT_EQ(RAND_UUID_OK, OCGenerateUuidString(uuidString));
EXPECT_EQ('\0', uuidString[36]);
EXPECT_EQ('-', uuidString[8]);
EXPECT_EQ('-', uuidString[13]);
EXPECT_EQ('-', uuidString[18]);
EXPECT_EQ('-', uuidString[23]);
for(int i = 0; i < 36; ++i)
{
EXPECT_TRUE(
i == 8 || i == 13 || i == 18 || i == 23 ||
(uuidString[i] >= 'a' && uuidString[i] <= 'f') ||
(uuidString[i] >= '0' && uuidString[i] <= '9'))
<< "UUID Character out of range: "<< uuidString[i];
}
}
...@@ -124,7 +124,7 @@ typedef struct ...@@ -124,7 +124,7 @@ typedef struct
/** /**
* This typedef is to represent our Server Instance identification. * This typedef is to represent our Server Instance identification.
*/ */
typedef uint32_t ServerID; typedef uint8_t ServerID[16];
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Internal function prototypes // Internal function prototypes
...@@ -188,12 +188,25 @@ OCStackResult BindResourceTypeToResource(OCResource* resource, ...@@ -188,12 +188,25 @@ OCStackResult BindResourceTypeToResource(OCResource* resource,
*/ */
OCStackResult CAResultToOCResult(CAResult_t caResult); OCStackResult CAResultToOCResult(CAResult_t caResult);
/**
* Get a byte representation of the server instance ID.
* The memory is managed internal to this function, so freeing it externally will
* result in a runtime error
*
* Note: This will NOT seed the RNG, so it must be called after the RNG is seeded.
* This is done automatically during the OCInit process,
* so ensure that this call is done after that.
*
* @return A uint8_t representation the server instance ID.
*/
const uint8_t* OCGetServerInstanceID(void);
/** /**
* Get a string representation the server instance ID. * Get a string representation the server instance ID.
* The memory is managed internal to this function, so freeing externally will result * The memory is managed internal to this function, so freeing externally will result
* in a compiler error * in a runtime error
* Note: This will NOT seed the RNG, so it must be called after the RNG is seeded. * Note: This will NOT seed the RNG, so it must be called after the RNG is seeded.
* This is done automatically during the OCInit process (via the call to OCInitCoAP), * This is done automatically during the OCInit process,
* so ensure that this call is done after that. * so ensure that this call is done after that.
* *
* @return A string representation the server instance ID. * @return A string representation the server instance ID.
......
...@@ -435,13 +435,6 @@ static OCResourceType *findResourceType(OCResourceType * resourceTypeList, ...@@ -435,13 +435,6 @@ static OCResourceType *findResourceType(OCResourceType * resourceTypeList,
*/ */
static OCStackResult ResetPresenceTTL(ClientCB *cbNode, uint32_t maxAgeSeconds); static OCStackResult ResetPresenceTTL(ClientCB *cbNode, uint32_t maxAgeSeconds);
/**
* Return a server instance ID.
*
* @return Instance ID of the server.
*/
static const ServerID OCGetServerInstanceID(void);
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Internal functions // Internal functions
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
...@@ -3802,7 +3795,7 @@ OCStackResult getQueryFromUri(const char * uri, char** query, char ** uriWithout ...@@ -3802,7 +3795,7 @@ OCStackResult getQueryFromUri(const char * uri, char** query, char ** uriWithout
return OC_STACK_NO_MEMORY; return OC_STACK_NO_MEMORY;
} }
const ServerID OCGetServerInstanceID(void) const uint8_t* OCGetServerInstanceID(void)
{ {
static bool generated = false; static bool generated = false;
static ServerID sid; static ServerID sid;
...@@ -3811,25 +3804,35 @@ const ServerID OCGetServerInstanceID(void) ...@@ -3811,25 +3804,35 @@ const ServerID OCGetServerInstanceID(void)
return sid; return sid;
} }
sid = OCGetRandom(); if (OCGenerateUuid(sid) != RAND_UUID_OK)
{
OC_LOG(FATAL, TAG, PCF("Generate UUID for Server Instance failed!"));
return NULL;
}
generated = true; generated = true;
return sid; return sid;
} }
const char* OCGetServerInstanceIDString(void) const char* OCGetServerInstanceIDString(void)
{ {
// max printed length of a base 10 static bool generated = false;
// uint32 is 10 characters, so 11 includes null. static char sidStr[UUID_STRING_SIZE];
// This will change as the representation gets switched
// to another value
static char buffer[11];
if (snprintf(buffer, sizeof(buffer),"%u", OCGetServerInstanceID()) < 0) if(generated)
{ {
buffer[0]='\0'; return sidStr;
} }
return buffer; const uint8_t* sid = OCGetServerInstanceID();
if(OCConvertUuidToString(sid, sidStr) != RAND_UUID_OK)
{
OC_LOG(FATAL, TAG, PCF("Generate UUID String for Server Instance failed!"));
return NULL;
}
generated = true;
return sidStr;
} }
int32_t OCDevAddrToIPv4Addr(OCDevAddr *ipAddr, uint8_t *a, uint8_t *b, int32_t OCDevAddrToIPv4Addr(OCDevAddr *ipAddr, uint8_t *a, uint8_t *b,
......
...@@ -84,7 +84,7 @@ namespace OC ...@@ -84,7 +84,7 @@ namespace OC
const std::string& resourceUri ); const std::string& resourceUri );
private: private:
uint32_t m_representation; std::string m_representation;
const std::string& m_resourceUri; const std::string& m_resourceUri;
}; };
......
...@@ -294,9 +294,7 @@ OCResourceIdentifier OCResource::uniqueIdentifier() const ...@@ -294,9 +294,7 @@ OCResourceIdentifier OCResource::uniqueIdentifier() const
std::string OCResource::sid() const std::string OCResource::sid() const
{ {
std::ostringstream os; return this->uniqueIdentifier().m_representation;
os << this->uniqueIdentifier().m_representation;
return os.str();
} }
bool OCResource::operator==(const OCResource &other) const bool OCResource::operator==(const OCResource &other) const
...@@ -331,13 +329,8 @@ bool OCResource::operator>=(const OCResource &other) const ...@@ -331,13 +329,8 @@ bool OCResource::operator>=(const OCResource &other) const
OCResourceIdentifier::OCResourceIdentifier(const std::string& wireServerIdentifier, OCResourceIdentifier::OCResourceIdentifier(const std::string& wireServerIdentifier,
const std::string& resourceUri) const std::string& resourceUri)
:m_representation(0), m_resourceUri(resourceUri) :m_representation(wireServerIdentifier), m_resourceUri(resourceUri)
{ {
// test required so we can create Resources without a server. Will leave as default.
if(!wireServerIdentifier.empty())
{
m_representation = boost::lexical_cast<unsigned int>(wireServerIdentifier);
}
} }
std::ostream& operator <<(std::ostream& os, const OCResourceIdentifier& ri) std::ostream& operator <<(std::ostream& os, const OCResourceIdentifier& ri)
......
...@@ -40,6 +40,7 @@ if target_os == 'linux': ...@@ -40,6 +40,7 @@ if target_os == 'linux':
# Build C unit tests # Build C unit tests
SConscript('csdk/stack/test/SConscript') SConscript('csdk/stack/test/SConscript')
SConscript('csdk/ocrandom/test/SConscript')
SConscript('csdk/connectivity/test/SConscript') SConscript('csdk/connectivity/test/SConscript')
......
...@@ -466,7 +466,7 @@ namespace OCResourceTest ...@@ -466,7 +466,7 @@ namespace OCResourceTest
{ {
OCResource::Ptr resource = ConstructResourceObject("coap://192.168.1.2:5000", "/resource"); OCResource::Ptr resource = ConstructResourceObject("coap://192.168.1.2:5000", "/resource");
EXPECT_TRUE(resource != NULL); EXPECT_TRUE(resource != NULL);
EXPECT_TRUE(resource->sid() == "0"); EXPECT_TRUE(resource->sid() == "");
} }
//UniqueIdentifier Test //UniqueIdentifier Test
...@@ -476,7 +476,7 @@ namespace OCResourceTest ...@@ -476,7 +476,7 @@ namespace OCResourceTest
EXPECT_TRUE(resource != NULL); EXPECT_TRUE(resource != NULL);
std::ostringstream ss; std::ostringstream ss;
ss << resource->uniqueIdentifier(); ss << resource->uniqueIdentifier();
EXPECT_TRUE(ss.str() == "0/resource"); EXPECT_TRUE(ss.str() == "/resource");
} }
// HeaderOptions Test // HeaderOptions Test
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment