[asterisk-commits] mmichelson: branch mmichelson/uuid r376687 - in /team/mmichelson/uuid: ./ inc...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Nov 27 17:37:45 CST 2012


Author: mmichelson
Date: Tue Nov 27 17:37:40 2012
New Revision: 376687

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=376687
Log:
Add some UUID support.

Well, I hadn't intended to do this all in just
one commit, but that's how it's ended up happening.


Added:
    team/mmichelson/uuid/include/asterisk/uuid.h   (with props)
    team/mmichelson/uuid/main/uuid.c   (with props)
    team/mmichelson/uuid/tests/test_uuid.c   (with props)
Modified:
    team/mmichelson/uuid/configure
    team/mmichelson/uuid/configure.ac
    team/mmichelson/uuid/include/asterisk/autoconfig.h.in
    team/mmichelson/uuid/main/Makefile
    team/mmichelson/uuid/main/asterisk.c

Modified: team/mmichelson/uuid/configure.ac
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/uuid/configure.ac?view=diff&rev=376687&r1=376686&r2=376687
==============================================================================
--- team/mmichelson/uuid/configure.ac (original)
+++ team/mmichelson/uuid/configure.ac Tue Nov 27 17:37:40 2012
@@ -489,11 +489,12 @@
 AC_HEADER_SYS_WAIT
 AC_CHECK_HEADERS([arpa/inet.h fcntl.h inttypes.h libintl.h limits.h locale.h malloc.h netdb.h netinet/in.h stddef.h stdint.h stdlib.h string.h strings.h sys/event.h sys/file.h sys/ioctl.h sys/param.h sys/socket.h sys/time.h syslog.h termios.h unistd.h utime.h arpa/nameser.h sys/io.h])
 
-# Any one of these 4 packages support a mandatory requirement, so we want to check on them as early as possible.
+# Any one of these 5 packages support a mandatory requirement, so we want to check on them as early as possible.
 AST_EXT_LIB_CHECK([TERMCAP], [termcap], [tgetent], [])
 AST_EXT_LIB_CHECK([TINFO], [tinfo], [tgetent], [])
 AST_EXT_LIB_CHECK([CURSES], [curses], [initscr], [curses.h])
 AST_EXT_LIB_CHECK([NCURSES], [ncurses], [initscr], [curses.h])
+AST_EXT_LIB_CHECK([UUID], [uuid], [uuid_generate_random], [uuid.h], [-luuid])
 
 EDITLINE_LIB=""
 if test "x$TERMCAP_LIB" != "x" ; then

Modified: team/mmichelson/uuid/include/asterisk/autoconfig.h.in
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/uuid/include/asterisk/autoconfig.h.in?view=diff&rev=376687&r1=376686&r2=376687
==============================================================================
--- team/mmichelson/uuid/include/asterisk/autoconfig.h.in (original)
+++ team/mmichelson/uuid/include/asterisk/autoconfig.h.in Tue Nov 27 17:37:40 2012
@@ -848,19 +848,19 @@
 /* Define to 1 if you have the `strtoq' function. */
 #undef HAVE_STRTOQ
 
-/* Define to 1 if `ifr_ifru.ifru_hwaddr' is member of `struct ifreq'. */
+/* Define to 1 if `ifr_ifru.ifru_hwaddr' is a member of `struct ifreq'. */
 #undef HAVE_STRUCT_IFREQ_IFR_IFRU_IFRU_HWADDR
 
-/* Define to 1 if `uid' is member of `struct sockpeercred'. */
+/* Define to 1 if `uid' is a member of `struct sockpeercred'. */
 #undef HAVE_STRUCT_SOCKPEERCRED_UID
 
-/* Define to 1 if `st_blksize' is member of `struct stat'. */
+/* Define to 1 if `st_blksize' is a member of `struct stat'. */
 #undef HAVE_STRUCT_STAT_ST_BLKSIZE
 
-/* Define to 1 if `cr_uid' is member of `struct ucred'. */
+/* Define to 1 if `cr_uid' is a member of `struct ucred'. */
 #undef HAVE_STRUCT_UCRED_CR_UID
 
-/* Define to 1 if `uid' is member of `struct ucred'. */
+/* Define to 1 if `uid' is a member of `struct ucred'. */
 #undef HAVE_STRUCT_UCRED_UID
 
 /* Define to 1 if you have the mISDN Supplemental Services library. */
@@ -1137,6 +1137,9 @@
 
 /* Define to the one symbol short name of this package. */
 #undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
 
 /* Define to the version of this package. */
 #undef PACKAGE_VERSION

Added: team/mmichelson/uuid/include/asterisk/uuid.h
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/uuid/include/asterisk/uuid.h?view=auto&rev=376687
==============================================================================
--- team/mmichelson/uuid/include/asterisk/uuid.h (added)
+++ team/mmichelson/uuid/include/asterisk/uuid.h Tue Nov 27 17:37:40 2012
@@ -1,0 +1,102 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2012, Digium, Inc.
+ *
+ * Mark Michelson <mmmichelson at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ * \brief Universally unique identifier support
+ */
+
+#ifndef _ASTERISK_UUID_H
+#define _ASTERISK_UUID_H
+
+struct ast_uuid;
+
+/*!
+ * \brief Initialize the UUID system
+ */
+void ast_uuid_init(void);
+
+/*!
+ * \brief Generate a UUID
+ *
+ * This function allocates memory on the heap. The returned
+ * pointer must be freed using ast_free()
+ *
+ * \retval NULL Generation failed
+ * \retval non-NULL heap-allocated UUID
+ */
+struct ast_uuid *ast_uuid_generate(void);
+
+/*!
+ * \brief Convert a UUID to a string
+ *
+ * \param uuid The UUID to convert to a string
+ * \param str The string where the UUID will be stored
+ */
+void ast_uuid_to_str(const struct ast_uuid *uuid, struct ast_str **str);
+
+/*!
+ * \brief Convert a string to a UUID
+ *
+ * This function allocates memory on the heap. The returned
+ * pointer must be freed using ast_free()
+ *
+ * \param str The string to convert to a UUID
+ * \retval NULL Failed to convert
+ * \retval non-NULL The heap-allocated converted UUID
+ */
+struct ast_uuid *ast_str_to_uuid(const struct ast_str *str);
+
+/*!
+ * \brief Make a copy of a UUID
+ *
+ * This function allocates memory on the heap. The returned
+ * pointer must be freed using ast_free()
+ *
+ * \param src The source UUID to copy
+ * \retval NULL Failed to copy
+ * \retval non-NULL The heap-allocated duplicate UUID
+ */
+struct ast_uuid *ast_uuid_copy(const struct ast_uuid *src);
+
+/*!
+ * \brief Compare two UUIDs
+ *
+ * \param left First UUID to compare
+ * \param right Second UUID to compare
+ * \retval <0 left is lexicographically less than right
+ * \retval 0 left and right are the same
+ * \retval >0 left is lexicographically greater than right
+ */
+int ast_uuid_compare(const struct ast_uuid *left, const struct ast_uuid *right);
+
+/*!
+ * \brief Clear a UUID by setting it to be a nil UUID (all 0s)
+ *
+ * \param uuid UUID to clear
+ */
+void ast_uuid_clear(struct ast_uuid *uuid);
+
+/*!
+ * \brief Check if a UUID is a nil UUID (all 0s)
+ *
+ * \param uuid UUID to check
+ * \retval 0 The UUID is not nil
+ * \retval non-zero The UUID is nil
+ */
+int ast_uuid_is_nil(const struct ast_uuid *uuid);
+#endif

Propchange: team/mmichelson/uuid/include/asterisk/uuid.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/mmichelson/uuid/include/asterisk/uuid.h
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/mmichelson/uuid/include/asterisk/uuid.h
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: team/mmichelson/uuid/main/Makefile
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/uuid/main/Makefile?view=diff&rev=376687&r1=376686&r2=376687
==============================================================================
--- team/mmichelson/uuid/main/Makefile (original)
+++ team/mmichelson/uuid/main/Makefile Tue Nov 27 17:37:40 2012
@@ -43,7 +43,7 @@
   ifneq (x$(CAP_LIB),x)
     AST_LIBS+=$(CAP_LIB)
   endif
-  AST_LIBS+=-lpthread $(EDITLINE_LIB) -lm -lresolv
+  AST_LIBS+=-lpthread $(EDITLINE_LIB) -lm -lresolv -luuid
 else
   AST_LIBS+=$(EDITLINE_LIB) -lm
 endif

Modified: team/mmichelson/uuid/main/asterisk.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/uuid/main/asterisk.c?view=diff&rev=376687&r1=376686&r2=376687
==============================================================================
--- team/mmichelson/uuid/main/asterisk.c (original)
+++ team/mmichelson/uuid/main/asterisk.c Tue Nov 27 17:37:40 2012
@@ -238,6 +238,7 @@
 #include "asterisk/rtp_engine.h"
 #include "asterisk/format.h"
 #include "asterisk/aoc.h"
+#include "asterisk/uuid.h"
 
 #include "../defaults.h"
 
@@ -4082,6 +4083,7 @@
 	}
 
 	ast_aoc_cli_init();
+	ast_uuid_init();
 
 	ast_makesocket();
 	sigemptyset(&sigs);

Added: team/mmichelson/uuid/main/uuid.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/uuid/main/uuid.c?view=auto&rev=376687
==============================================================================
--- team/mmichelson/uuid/main/uuid.c (added)
+++ team/mmichelson/uuid/main/uuid.c Tue Nov 27 17:37:40 2012
@@ -1,0 +1,172 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2012, Digium, Inc.
+ *
+ * Mark Michelson <mmmichelson at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ * \brief Universally unique identifier support
+ */
+
+#include "asterisk.h"
+#include <uuid/uuid.h>
+
+#include "asterisk/uuid.h"
+#include "asterisk/utils.h"
+#include "asterisk/strings.h"
+#include "asterisk/logger.h"
+
+#define UUID_STR_LEN 37
+
+struct ast_uuid {
+	uuid_t uu;
+};
+
+struct ast_uuid *ast_uuid_generate(void)
+{
+	struct ast_uuid *uuid = ast_calloc(1, sizeof(*uuid));
+
+	if (!uuid) {
+		return NULL;
+	}
+	/* libuuid provides three methods of generating uuids,
+	 * uuid_generate(), uuid_generate_random(), and uuid_generate_time().
+	 *
+	 * uuid_generate_random() creates a UUID based on random numbers. The method
+	 * attempts to use either /dev/urandom or /dev/random to generate random values.
+	 * If these resources are unavailable, then random numbers will be generated
+	 * using C library calls to generate pseudorandom numbers.
+	 * This method of generating UUIDs corresponds to section 4.2 of RFC 4122.
+	 *
+	 * uuid_generate_time() creates a UUID based on the current time plus
+	 * a system identifier (MAC address of the ethernet interface). This
+	 * method of generating UUIDs corresponds to section 4.2 of RFC 4122.
+	 *
+	 * uuid_generate() will check if /dev/urandom or /dev/random is available to
+	 * use. If so, it will use uuid_generate_random(). Otherwise, it will use
+	 * uuid_generate_time(). The idea is that it avoids using pseudorandom
+	 * numbers if necessary.
+	 *
+	 * For our purposes, we do not use the time-based UUID at all. There are
+	 * several reasons for this:
+	 *
+	 * 1) The time-based algorithm makes use of a daemon process (uuidd) in order
+	 * to ensure that any concurrent requests for UUIDs result in unique results.
+	 * Use of this daemon is a bit dodgy for a few reasons
+	 *
+	 *     a) libuuid assumes a hardcoded location for the .pid file of the daemon.
+	 *     However, the daemon could already be running on the system in a different
+	 *     location than expected. If this is the case, then attempting to connect
+	 *     to the daemon will fail, and attempting to launch another instance in
+	 *     the expected location will also fail.
+	 *
+	 *     b) If the daemon is not running, then the first attempt to create a
+	 *     time-based UUID will result in launching the daemon. Because of the hard-
+	 *     coded locations that libuuid assumes for the daemon, Asterisk must be
+	 *     run with permissions that will allow for the daemon to be launched in
+	 *     the expected directories.
+	 *
+	 *     c) Once the daemon is running, concurrent requests for UUIDs is thread-safe.
+	 *     However, the actual launching of the daemon is not thread-safe since libuuid
+	 *     uses no synchronization primitives to ensure that only one thread (or process)
+	 *     launches the daemon.
+	 *
+	 *     d) When libuuid launches the daemon, it sets an inactivity timer.
+	 *     If no UUID generation requests are issued in that time period,
+	 *     then the daemon will stop. If a new request should occur after the daemon
+	 *     exits, then the daemon will be relaunched. Given point c), we could not
+	 *     necessarily guarantee the thread-safety of time-based UUID generation since
+	 *     we could not necessarily guarantee the daemon was running as we expected.
+	 *     We could set up a watchdog thread to generate UUIDs at regular intervals to
+	 *     prevent the daemon from exiting, but frankly, that sucks.
+	 *
+	 * 2) Since the MAC address of the Ethernet interface is part of the UUID when
+	 * using the time-based method, there is information leaked.
+	 *
+	 * Given these drawbacks, we stick to only using random UUIDs. The chance of /dev/random
+	 * or /dev/urandom not existing on systems in this age is next to none.
+	 */
+	uuid_generate_random(uuid->uu);
+	return uuid;
+}
+
+void ast_uuid_to_str(const struct ast_uuid *uuid, struct ast_str **str)
+{
+	char uu_str[UUID_STR_LEN];
+	uuid_unparse_lower(uuid->uu, uu_str);
+
+	ast_str_set(str, 0, "%s", uu_str);
+}
+
+struct ast_uuid *ast_str_to_uuid(const struct ast_str *str)
+{
+	struct ast_uuid *uuid = ast_calloc(1, sizeof(*uuid));
+	if (!uuid) {
+		return NULL;
+	}
+	uuid_parse(ast_str_buffer(str), uuid->uu);
+	return uuid;
+}
+
+struct ast_uuid *ast_uuid_copy(const struct ast_uuid *src)
+{
+	struct ast_uuid *dst = ast_calloc(1, sizeof(*dst));
+	if (!dst) {
+		return NULL;
+	}
+	uuid_copy(dst->uu, src->uu);
+	return dst;
+}
+
+int ast_uuid_compare(const struct ast_uuid *left, const struct ast_uuid *right)
+{
+	return uuid_compare(left->uu, right->uu);
+}
+
+void ast_uuid_clear(struct ast_uuid *uuid)
+{
+	uuid_clear(uuid->uu);
+}
+
+int ast_uuid_is_nil(const struct ast_uuid *uuid)
+{
+	return uuid_is_null(uuid->uu);
+}
+
+void ast_uuid_init(void)
+{
+	/* This requires some explanation.
+	 *
+	 * libuuid generates UUIDs based on random number generation. This involves
+	 * opening a handle to /dev/urandom or /dev/random in order to get random
+	 * data for the UUIDs.
+	 *
+	 * This is thread-safe, to a point. The problem is that the first attempt
+	 * to generate a UUID will result in opening the random number handle. Once
+	 * the handle is opened, all further generation is thread safe. This
+	 * first generation can be potentially risky if multiple threads attempt
+	 * to generate a UUID at the same time, though, since there is no thread
+	 * synchronization used within libuuid. To get around this potential
+	 * issue, we go ahead and generate a UUID up front so that the underlying
+	 * work is done before we start requesting UUIDs for real.
+	 *
+	 * Think of this along the same lines as initializing a singleton.
+	 */
+	uuid_t uu;
+	uuid_generate_random(uu);
+
+	ast_debug(1, "UUID system initiated\n");
+	return;
+}

Propchange: team/mmichelson/uuid/main/uuid.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/mmichelson/uuid/main/uuid.c
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/mmichelson/uuid/main/uuid.c
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: team/mmichelson/uuid/tests/test_uuid.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/uuid/tests/test_uuid.c?view=auto&rev=376687
==============================================================================
--- team/mmichelson/uuid/tests/test_uuid.c (added)
+++ team/mmichelson/uuid/tests/test_uuid.c Tue Nov 27 17:37:40 2012
@@ -1,0 +1,141 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2012, Digium, Inc.
+ *
+ * Mark Michelson <mmmichelson at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ * \brief Universally unique identifier tests
+ */
+
+/*** MODULEINFO
+	<depend>TEST_FRAMEWORK</depend>
+	<support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+#include "asterisk/test.h"
+#include "asterisk/uuid.h"
+#include "asterisk/module.h"
+
+AST_TEST_DEFINE(uuid)
+{
+	struct ast_uuid *uuid1 = NULL;
+	struct ast_uuid *uuid2 = NULL;
+	struct ast_uuid *uuid3 = NULL;
+	struct ast_str *uuid_str;
+	enum ast_test_result_state res = AST_TEST_FAIL;
+
+	switch (cmd) {
+	case TEST_INIT:
+		info->name = "uuid";
+		info->category = "/main/uuid/";
+		info->summary = "UUID unit test";
+		info->description =
+			"This tests basic UUID operations to ensure they work properly";
+		return AST_TEST_NOT_RUN;
+	case TEST_EXECUTE:
+		break;
+	}
+
+	uuid_str = ast_str_alloca(64);
+	/* First, make sure that we can generate a UUID */
+	uuid1 = ast_uuid_generate();
+	if (!uuid1) {
+		ast_test_status_update(test, "Unable to generate a UUID\n");
+		goto end;
+	}
+
+	/* Make sure we're not generating nil UUIDs */
+	if (ast_uuid_is_nil(uuid1)) {
+		ast_test_status_update(test, "We generated a nil UUID. Something is wrong\n");
+		goto end;
+	}
+
+	/* Convert it to a string */
+	ast_uuid_to_str(uuid1, &uuid_str);
+
+	/* While it would be great to ensure the string is a specific length, we'll just
+	 * have to settle for making sure it's not zero-length in case we switch out UUID
+	 * libraries
+	 */
+	if (ast_str_strlen(uuid_str) == 0) {
+		ast_test_status_update(test, "Failed to convert the UUID to a string\n");
+		goto end;
+	}
+
+	ast_test_status_update(test, "Converted uuid to string, got %s\n", ast_str_buffer(uuid_str));
+
+	/* Now convert the string back to a UUID */
+	uuid2 = ast_str_to_uuid(uuid_str);
+	if (!uuid2) {
+		ast_test_status_update(test, "Unable to convert string to UUID\n");
+		goto end;
+	}
+
+	/* Make sure the UUIDs are identical */
+	if (ast_uuid_compare(uuid1, uuid2) != 0) {
+		ast_test_status_update(test, "UUIDs that should be identical are different\n");
+		goto end;
+	}
+
+	/* Try copying a UUID */
+	uuid3 = ast_uuid_copy(uuid1);
+	if (!uuid3) {
+		ast_test_status_update(test, "Unable to copy UUID\n");
+		goto end;
+	}
+
+	/* Make sure copied UUIDs are identical */
+	if (ast_uuid_compare(uuid1, uuid3) != 0) {
+		ast_test_status_update(test, "UUIDs that should be identical are different\n");
+		goto end;
+	}
+
+	if (ast_uuid_compare(uuid2, uuid3) != 0) {
+		ast_test_status_update(test, "UUIDs that should be identical are different\n");
+		goto end;
+	}
+
+	/* Clear a UUID and ensure that it registers as nil */
+	ast_uuid_clear(uuid1);
+
+	if (!ast_uuid_is_nil(uuid1)) {
+		ast_test_status_update(test, "UUID that was cleared does not appear to be nil\n");
+		goto end;
+	}
+
+	res = AST_TEST_PASS;
+
+end:
+	ast_free(uuid1);
+	ast_free(uuid2);
+	ast_free(uuid3);
+	return res;
+}
+
+static int unload_module(void)
+{
+	AST_TEST_UNREGISTER(uuid);
+	return 0;
+}
+
+static int load_module(void)
+{
+	AST_TEST_REGISTER(uuid);
+	return AST_MODULE_LOAD_SUCCESS;
+}
+
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "UUID test module");

Propchange: team/mmichelson/uuid/tests/test_uuid.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/mmichelson/uuid/tests/test_uuid.c
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/mmichelson/uuid/tests/test_uuid.c
------------------------------------------------------------------------------
    svn:mime-type = text/plain




More information about the asterisk-commits mailing list