You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by zw...@apache.org on 2016/06/27 17:47:18 UTC

[trafficserver] branch master updated: TS-4518 Add the basic APIs and code for UUIDs

This is an automated email from the ASF dual-hosted git repository.

zwoop pushed a commit to branch master
in repository https://git-dual.apache.org/repos/asf/trafficserver.git

The following commit(s) were added to refs/heads/master by this push:
       new  9f774fb   TS-4518 Add the basic APIs and code for UUIDs
9f774fb is described below

commit 9f774fb656b44930375746e63df1b2cdb583bd18
Author: Leif Hedstrom <zw...@apache.org>
AuthorDate: Fri Jun 10 22:03:35 2016 -0600

    TS-4518 Add the basic APIs and code for UUIDs
---
 .../api/functions/TSUuidCreate.en.rst              | 136 +++++++++++++++++++
 doc/developer-guide/api/types/TSUuid.en.rst        |  48 +++++++
 iocore/utils/I_Machine.h                           |   3 +
 iocore/utils/Machine.cc                            |  36 ++---
 lib/ts/Makefile.am                                 |   2 +
 lib/ts/apidefs.h.in                                |  86 ++++++++++--
 lib/ts/ink_uuid.cc                                 |  97 ++++++++++++++
 lib/ts/ink_uuid.h                                  | 135 +++++++++++++++++++
 proxy/InkAPI.cc                                    |  95 ++++++++++++++
 proxy/InkAPITest.cc                                | 146 +++++++++++++++++++++
 proxy/Main.cc                                      |   3 +
 proxy/api/ts/ts.h                                  |  17 +++
 12 files changed, 776 insertions(+), 28 deletions(-)

diff --git a/doc/developer-guide/api/functions/TSUuidCreate.en.rst b/doc/developer-guide/api/functions/TSUuidCreate.en.rst
new file mode 100644
index 0000000..d0f9429
--- /dev/null
+++ b/doc/developer-guide/api/functions/TSUuidCreate.en.rst
@@ -0,0 +1,136 @@
+.. Licensed to the Apache Software Foundation (ASF) under one
+   or more contributor license agreements.  See the NOTICE file
+   distributed with this work for additional information
+   regarding copyright ownership.  The ASF licenses this file
+   to you 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:: ../../../common.defs
+
+.. default-domain:: c
+
+TSUuidCreate
+************
+
+Traffic Server UUID construction APIs.
+
+Synopsis
+========
+
+`#include <ts/ts.h>`
+
+.. function:: TSUuid TSUuidCreate(void);
+.. function:: TSReturnCode TSUuidInitialize(TSUuid uuid, TSUuidVersion v);
+.. function:: void TSUuidDestroy(TSUuid uuid);
+.. function:: TSReturnCode TSUuidCopy(TSUuid dest, const TSUuid src);
+.. function:: const char *TSUuidStringGet(const TSUuid uuid);
+.. function:: TSUuidVersion TSUuidVersionGet(const TSUuid uuid);
+.. function:: TSReturnCode TSUuidStringParse(TSUuid uuid, const char *uuid_str);
+.. function:: const TSUuid TSProcessUuidGet(void);
+
+Description
+===========
+
+These APIs are used to create, manage, and use UUIDs in a plugin, implementing
+part of RFC 4122. Currently, only the V4 variant of the specifications is
+implemented. In addition, an internal, process unique UUID is provided, which
+can be used to uniquely identifying the running Traffic Server process.
+
+:func:`TSUuidCreate` creates a new :type:`TSUuid` object, which is returned
+and can be used by the other APIs. Similarly, a read-only global process UUID
+is returned from the function :func:`TSProcessUuidGet`. You must not attempt
+to modify any data as returned by either of these functions.
+
+:func:`TSUuidInitialize` initializes a :type:`TSUuid` object, using the
+algorithm defined for the specified version. Note that only the V4 variants is
+currently supported. You can call :func:`TSUuidInitialize` repeatedly, which
+each generates a new UUID, but this will overwrite any existing UUID data in
+the object. This also implies that any strings retrieved using
+:func:`TSUuidStringGet` are also modified accordingly.
+
+:func:`TSUuidDestroy` destroys (releases) an :type:`TSUuid` object, and frees
+all memory associated with this object. This includes any strings as returned
+by e.g. :func:`TSUuidStringGet`.
+
+:func:`TSUuidCopy` copies one :type:`TSUuid` to another, making an exact
+duplicate. Note that both the source and the destination UUIDs must be created
+appropriately, and should not have been previously destroyed.
+
+:func:`TSUuidVersionGet` returns the version number for the
+:type:`TSUuid`. This will work properly for any RFC 4122 initialized UUID
+object, e.g. if you parse a string with :func:`TSUuidStringParse` this will
+return the correct variant ID.
+
+:func:`TSUuidStringGet` returns a pointer to the internal string
+representation of the :type:`TSUuid` object. It's important to know that there
+is no transfer of ownership of this string. If you need a copy of it, you are
+responsible of doing so yourself. In particular, using a string as returned by
+:func:`TSUuidStringGet` **after** you have called :func:`TSUuidDestroy` on the
+corresponding :type:`TSUuid` object is a serious error. The UUID object does
+not do any sort of reference counting on the string, and you must absolutely
+not free the memory as returned by this API.
+
+Finally, :func:`TSUuidStringParse` can be used to convert an existing
+:type:`TSUuid` string to a Traffic Server UUID object. This will only succeed
+if the :type:`TSUuid` string is a proper *RFC 4122* UUID. The :type:`TSUuid`
+argument passed to this function must be a properly :func:`TSUuidCreate`
+object, but it does not need to be previously initialized.
+
+Return Values
+=============
+
+The :type:`TSUuid` type is an opaque pointer to an internal representation of
+the UUID object. Several of the functions returns a normal Traffic Server
+return status code, :type:`TSReturnCode`. You should verify the success of
+those APIs, of course.
+
+The :func:`TSUuidStringGet` function will return ``NULL`` if the :type:`TSUuid`
+object is not properly inititialized. Likewise, :func:`TSUuidVersionGet` would
+then return ``TS_UUID_UNDEFINED``.
+
+The :func:`TSUuidDestroy` function can not fail, and does not have a return
+value,  but you are of course responsible for providing a valid :type:`TSUuid`
+object.
+
+Examples
+========
+
+.. code-block:: c
+
+    #include <ts/ts.h>
+
+    TSUuid machine, uuid;
+
+    machine = TSProcessUuidGet();
+    printf("Machine UUID is %s\n", TSUuidStringGet(machine);
+
+    if (uuid = TSUuidCreate()) {
+      if (TS_SUCCESS == TSUuidInitialize(uuid, TS_UUID_V4) {
+        printf("My UUID is %s\n", TSUuidStringGet(uuid));
+      }
+      TSUuidDestroy(uuid);
+    }
+
+    const char* str = "c71e2bab-90dc-4770-9535-c9304c3de38e";
+
+    if (TS_SUCCESS == TSUuidStringParse(uuid, str)) {
+      if (TS_UUID_V4 == TSUuidVersionGet(uuid)) {
+        // Yes!
+      }
+    }
+
+See Also
+========
+
+:manpage:`TSAPI(3ts)`,
+:manpage:`TSUuid(3ts)`,
+:manpage:`TSReturnCode(3ts)`,
diff --git a/doc/developer-guide/api/types/TSUuid.en.rst b/doc/developer-guide/api/types/TSUuid.en.rst
new file mode 100644
index 0000000..abf5044
--- /dev/null
+++ b/doc/developer-guide/api/types/TSUuid.en.rst
@@ -0,0 +1,48 @@
+.. Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed
+   with this work for additional information regarding copyright
+   ownership.  The ASF licenses this file to you 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:: ../../../common.defs
+
+TSUuid
+******
+
+Synopsis
+========
+
+`#include <ts/apidefs.h>`
+
+.. c:type:: TSUuid
+
+An opaque pointer to an internal representation of a UUID object.
+
+
+Description
+===========
+
+The UUID object is managed and created via the various UUID APIs. You can not
+access nor modify this object using anything but the provided APIs.
+
+See Also
+========
+
+:manpage:`TSUuidCreate(3ts)`,
+:manpage:`TSUuidInitialize(3ts)`,
+:manpage:`TSUuidDestroy(3ts)`,
+:manpage:`TSUuidCopy(3ts)`,
+:manpage:`TSUuidStringGet(3ts)`,
+:manpage:`TSUuidVersionGet(3ts)`,
+:manpage:`TSUuidStringParse(3ts)`,
+:manpage:`TSProcessUuidGet(3ts)`
diff --git a/iocore/utils/I_Machine.h b/iocore/utils/I_Machine.h
index 6a15b89..ef9d7e0 100644
--- a/iocore/utils/I_Machine.h
+++ b/iocore/utils/I_Machine.h
@@ -32,6 +32,7 @@
 #define _I_Machine_h
 
 #include "ts/ink_inet.h"
+#include "ts/ink_uuid.h"
 
 /**
   The Machine is a simple place holder for the hostname and the ip
@@ -63,6 +64,8 @@ struct Machine {
   char ip_hex_string[TS_IP6_SIZE * 2 + 1]; ///< IP address as hex string
   int ip_hex_string_len;
 
+  ATSUuid uuid;
+
   ~Machine();
 
   /** Initialize the singleton.
diff --git a/iocore/utils/Machine.cc b/iocore/utils/Machine.cc
index 9b2695b..8deb003 100644
--- a/iocore/utils/Machine.cc
+++ b/iocore/utils/Machine.cc
@@ -60,6 +60,7 @@ Machine::Machine(char const *the_hostname, sockaddr const *addr)
   ink_zero(ip);
   ink_zero(ip4);
   ink_zero(ip6);
+  uuid.initialize(TS_UUID_V4);
 
   localhost[sizeof(localhost) - 1] = 0; // ensure termination.
 
@@ -122,25 +123,28 @@ Machine::Machine(char const *the_hostname, sockaddr const *addr)
         // get the interface's flags
         struct ifreq ifr;
         ink_strlcpy(ifr.ifr_name, spot->ifr_name, IFNAMSIZ);
-        if (ioctl(s, SIOCGIFFLAGS, &ifr) == 0)
+        if (ioctl(s, SIOCGIFFLAGS, &ifr) == 0) {
           ifflags = ifr.ifr_flags;
-        else
+        } else {
           ifflags = 0; // flags not available, default to just looking at IP
+        }
 #endif
-        if (!ats_is_ip(ifip))
+        if (!ats_is_ip(ifip)) {
           spot_type = NA;
-        else if (ats_is_ip_loopback(ifip) || (IFF_LOOPBACK & ifflags))
+        } else if (ats_is_ip_loopback(ifip) || (IFF_LOOPBACK & ifflags)) {
           spot_type = LO;
-        else if (ats_is_ip_linklocal(ifip))
+        } else if (ats_is_ip_linklocal(ifip)) {
           spot_type = LL;
-        else if (ats_is_ip_private(ifip))
+        } else if (ats_is_ip_private(ifip)) {
           spot_type = PR;
-        else if (ats_is_ip_multicast(ifip))
+        } else if (ats_is_ip_multicast(ifip)) {
           spot_type = MC;
-        else
+        } else {
           spot_type = GL;
-        if (spot_type == NA)
+        }
+        if (spot_type == NA) {
           continue; // Next!
+        }
 
         if (ats_is_ip4(ifip)) {
           if (spot_type > ip4_type) {
@@ -160,24 +164,24 @@ Machine::Machine(char const *the_hostname, sockaddr const *addr)
 #endif
 
       // What about the general address? Prefer IPv4?
-      if (ip4_type >= ip6_type)
+      if (ip4_type >= ip6_type) {
         ats_ip_copy(&ip.sa, &ip4.sa);
-      else
+      } else {
         ats_ip_copy(&ip.sa, &ip6.sa);
+      }
     }
 #if !HAVE_IFADDRS_H
     close(s);
 #endif
   } else { // address provided.
     ats_ip_copy(&ip, addr);
-    if (ats_is_ip4(addr))
+    if (ats_is_ip4(addr)) {
       ats_ip_copy(&ip4, addr);
-    else if (ats_is_ip6(addr))
+    } else if (ats_is_ip6(addr)) {
       ats_ip_copy(&ip6, addr);
+    }
 
-    status = getnameinfo(addr, ats_ip_size(addr), localhost, sizeof(localhost) - 1, 0, 0, // do not request service info
-                         0                                                                // no flags.
-                         );
+    status = getnameinfo(addr, ats_ip_size(addr), localhost, sizeof(localhost) - 1, 0, 0, 0); // no flags
 
     if (0 != status) {
       ip_text_buffer ipbuff;
diff --git a/lib/ts/Makefile.am b/lib/ts/Makefile.am
index a3ddf43..9a13750 100644
--- a/lib/ts/Makefile.am
+++ b/lib/ts/Makefile.am
@@ -178,6 +178,8 @@ libtsutil_la_SOURCES = \
   ink_thread.h \
   ink_time.cc \
   ink_time.h \
+  ink_uuid.cc \
+  ink_uuid.h \
   llqueue.cc \
   lockfile.cc \
   signals.cc \
diff --git a/lib/ts/apidefs.h.in b/lib/ts/apidefs.h.in
index 28d0a7a..a9030cc 100644
--- a/lib/ts/apidefs.h.in
+++ b/lib/ts/apidefs.h.in
@@ -121,7 +121,12 @@ typedef struct {
     TSHttpHdrParseReq() and TSHttpHdrParseResp().
 
  */
-typedef enum { TS_PARSE_ERROR = -1, TS_PARSE_DONE = 0, TS_PARSE_OK = 1, TS_PARSE_CONT = 2 } TSParseResult;
+typedef enum {
+  TS_PARSE_ERROR = -1,
+  TS_PARSE_DONE = 0,
+  TS_PARSE_OK = 1,
+  TS_PARSE_CONT = 2,
+} TSParseResult;
 
 /**
     This set of enums represents the possible HTTP types that
@@ -133,7 +138,11 @@ typedef enum { TS_PARSE_ERROR = -1, TS_PARSE_DONE = 0, TS_PARSE_OK = 1, TS_PARSE
     to obtain the TSHttpType of an HTTP header.
 
  */
-typedef enum { TS_HTTP_TYPE_UNKNOWN, TS_HTTP_TYPE_REQUEST, TS_HTTP_TYPE_RESPONSE } TSHttpType;
+typedef enum {
+  TS_HTTP_TYPE_UNKNOWN,
+  TS_HTTP_TYPE_REQUEST,
+  TS_HTTP_TYPE_RESPONSE,
+} TSHttpType;
 
 /**
     This set of enums represents possible return values from
@@ -475,9 +484,17 @@ typedef enum {
   TS_CACHE_LOOKUP_SKIPPED
 } TSCacheLookupResult;
 
-typedef enum { TS_CACHE_DATA_TYPE_NONE, TS_CACHE_DATA_TYPE_HTTP, TS_CACHE_DATA_TYPE_OTHER } TSCacheDataType;
+typedef enum {
+  TS_CACHE_DATA_TYPE_NONE,
+  TS_CACHE_DATA_TYPE_HTTP,
+  TS_CACHE_DATA_TYPE_OTHER,
+} TSCacheDataType;
 
-typedef enum { TS_CACHE_ERROR_NO_DOC = -20400, TS_CACHE_ERROR_DOC_BUSY = -20401, TS_CACHE_ERROR_NOT_READY = -20407 } TSCacheError;
+typedef enum {
+  TS_CACHE_ERROR_NO_DOC = -20400,
+  TS_CACHE_ERROR_DOC_BUSY = -20401,
+  TS_CACHE_ERROR_NOT_READY = -20407,
+} TSCacheError;
 
 typedef enum {
   TS_CACHE_SCAN_RESULT_DONE     = 0,
@@ -499,7 +516,10 @@ typedef enum {
   TS_TXN_INFO_LAST_ENTRY
 } TSHttpTxnInfoKey;
 
-typedef enum { TS_VC_CLOSE_ABORT = -1, TS_VC_CLOSE_NORMAL = 1 } TSVConnCloseFlags;
+typedef enum {
+  TS_VC_CLOSE_ABORT = -1,
+  TS_VC_CLOSE_NORMAL = 1,
+} TSVConnCloseFlags;
 
 typedef enum {
   TS_IOBUFFER_SIZE_INDEX_128  = 0,
@@ -519,9 +539,16 @@ typedef enum {
   TS_IOBUFFER_SIZE_INDEX_2M   = 14
 } TSIOBufferSizeIndex;
 
-typedef enum { TS_ERROR = -1, TS_SUCCESS = 0 } TSReturnCode;
+typedef enum {
+  TS_ERROR = -1,
+  TS_SUCCESS = 0,
+} TSReturnCode;
 
-typedef enum { NO_CALLBACK = 0, AFTER_HEADER, AFTER_BODY } TSFetchWakeUpOptions;
+typedef enum {
+  NO_CALLBACK = 0,
+  AFTER_HEADER,
+  AFTER_BODY,
+} TSFetchWakeUpOptions;
 
 #ifndef _HTTP_PROXY_API_ENUMS_H_
 #define _HTTP_PROXY_API_ENUMS_H_
@@ -536,7 +563,10 @@ typedef enum {
 
 /// Server session sharing values - pool
 /// Must be identical to definition in HttpProxyAPIEnums.h
-typedef enum { TS_SERVER_SESSION_SHARING_POOL_GLOBAL, TS_SERVER_SESSION_SHARING_POOL_THREAD } TSServerSessionSharingPoolType;
+typedef enum {
+  TS_SERVER_SESSION_SHARING_POOL_GLOBAL,
+  TS_SERVER_SESSION_SHARING_POOL_THREAD,
+} TSServerSessionSharingPoolType;
 #endif
 
 /* librecords types */
@@ -573,7 +603,11 @@ typedef union {
 } TSRecordData;
 
 /* The values of this enum must match enum RecPersistT in I_RecDefs.h */
-typedef enum { TS_RECORDP_NULL, TS_RECORDP_PERSISTENT, TS_RECORDP_NON_PERSISTENT } TSRecordPersistType;
+typedef enum {
+  TS_RECORDP_NULL,
+  TS_RECORDP_PERSISTENT,
+  TS_RECORDP_NON_PERSISTENT,
+} TSRecordPersistType;
 
 /* The values of this enum must match enum RecUpdateT in I_RecDefs.h */
 typedef enum {
@@ -585,13 +619,27 @@ typedef enum {
 } TSRecordUpdateType;
 
 /* The values of this enum must match enum RecCheckT in I_RecDefs.h */
-typedef enum { TS_RECORDCHECK_NULL, TS_RECORDCHECK_STR, TS_RECORDCHECK_INT, TS_RECORDCHECK_IP } TSRecordCheckType;
+typedef enum {
+  TS_RECORDCHECK_NULL,
+  TS_RECORDCHECK_STR,
+  TS_RECORDCHECK_INT,
+  TS_RECORDCHECK_IP,
+} TSRecordCheckType;
 
 /* The values of this enum must match enum RecModeT in I_RecDefs.h */
-typedef enum { TS_RECORDMODE_NULL, TS_RECORDMODE_CLIENT, TS_RECORDMODE_SERVER, TS_RECORDMODE_STAND_ALONE } TSRecordModeType;
+typedef enum {
+  TS_RECORDMODE_NULL,
+  TS_RECORDMODE_CLIENT,
+  TS_RECORDMODE_SERVER,
+  TS_RECORDMODE_STAND_ALONE,
+} TSRecordModeType;
 
 /* The values of this enum must match enum RecAccessT in I_RecDefs.h */
-typedef enum { TS_RECORDACCESS_NULL, TS_RECORDACCESS_NO_ACCESS, TS_RECORDACCESS_READ_ONLY } TSRecordAccessType;
+typedef enum {
+  TS_RECORDACCESS_NULL,
+  TS_RECORDACCESS_NO_ACCESS,
+  TS_RECORDACCESS_READ_ONLY,
+} TSRecordAccessType;
 
 typedef enum {
   TS_CONFIG_NULL = -1,
@@ -1125,6 +1173,20 @@ extern tsapi const char *const TS_NPN_PROTOCOL_GROUP_SPDY;
  */
 extern tsapi const TSMLoc TS_NULL_MLOC;
 
+/* --------------------------------------------------------------------------
+   Interface for the UUID APIs. https://www.ietf.org/rfc/rfc4122.txt. */
+typedef enum {
+  TS_UUID_UNDEFINED = 0,
+  TS_UUID_V1 = 1,
+  TS_UUID_V2,
+  TS_UUID_V3,
+  TS_UUID_V4, /* At this point, this is the only implemented version (or variant) */
+  TS_UUID_V5,
+} TSUuidVersion;
+
+#define TS_UUID_STRING_LEN 36
+typedef struct tsapi_uuid *TSUuid;
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
diff --git a/lib/ts/ink_uuid.cc b/lib/ts/ink_uuid.cc
new file mode 100644
index 0000000..88bc75c
--- /dev/null
+++ b/lib/ts/ink_uuid.cc
@@ -0,0 +1,97 @@
+/** @file
+ *
+ *  Basic implementation of RFC 4122, see
+ *      https://www.ietf.org/rfc/rfc4122.txt
+ *
+ *  @section license License
+ *
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you 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 <openssl/rand.h>
+
+#include "ts/ink_error.h"
+#include "ts/ink_uuid.h"
+
+void
+ATSUuid::initialize(TSUuidVersion v)
+{
+  switch (v) {
+  case TS_UUID_UNDEFINED:
+    ink_abort("Don't initialize to undefined UUID variant!");
+    break;
+  case TS_UUID_V1:
+  case TS_UUID_V2:
+  case TS_UUID_V3:
+  case TS_UUID_V5:
+    ink_zero(_uuid.data); // Not properly implemented yet, so set it to the Nil UUID
+    break;
+  case TS_UUID_V4:
+    RAND_bytes(_uuid.data, sizeof(_uuid.data));
+    _uuid.clockSeqAndReserved = (uint8_t)((_uuid.clockSeqAndReserved & 0x3F) | 0x80);
+    _uuid.timeHighAndVersion  = (uint16_t)((_uuid.timeHighAndVersion & 0x0FFF) | 0x4000);
+
+    break;
+  }
+
+  _version = _toString(_string) ? v : TS_UUID_UNDEFINED;
+}
+
+// Copy assignment
+ATSUuid &
+ATSUuid::operator=(const ATSUuid other)
+{
+  memcpy(_uuid.data, other._uuid.data, sizeof(_uuid.data));
+  memcpy(_string, other._string, sizeof(_string));
+  _version = other._version;
+
+  return *this;
+}
+
+bool
+ATSUuid::parseString(const char *str)
+{
+  int cnt = sscanf(str, "%08x-%04hx-%04hx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", &_uuid.timeLow, &_uuid.timeMid,
+                   &_uuid.timeHighAndVersion, &_uuid.clockSeqAndReserved, &_uuid.clockSeqLow, &_uuid.node[0], &_uuid.node[1],
+                   &_uuid.node[2], &_uuid.node[3], &_uuid.node[4], &_uuid.node[5]);
+
+  if ((11 == cnt) && _toString(_string)) {
+    switch (_uuid.timeHighAndVersion >> 12) {
+    case 1:
+      _version = TS_UUID_V1;
+      break;
+    case 2:
+      _version = TS_UUID_V2;
+      break;
+    case 3:
+      _version = TS_UUID_V3;
+      break;
+    case 4:
+      _version = TS_UUID_V4;
+      break;
+    case 5:
+      _version = TS_UUID_V5;
+      break;
+    default:
+      _version = TS_UUID_UNDEFINED;
+      break;
+    }
+  } else {
+    _version = TS_UUID_UNDEFINED;
+  }
+
+  return (TS_UUID_UNDEFINED != _version);
+}
diff --git a/lib/ts/ink_uuid.h b/lib/ts/ink_uuid.h
new file mode 100644
index 0000000..7df48d8
--- /dev/null
+++ b/lib/ts/ink_uuid.h
@@ -0,0 +1,135 @@
+/** @file
+ *
+ *  Basic implementation of RFC 4122, see
+ *      https://www.ietf.org/rfc/rfc4122.txt
+ *
+ *  @section license License
+ *
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you 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 <stdio.h>
+
+#include "ts/apidefs.h"
+#include "ts/ink_memory.h"
+
+// This is the C++ portions of things, which will need to get wrapped in C-helper APIs.
+class ATSUuid
+{
+public:
+  // Constructors
+  ATSUuid() : _version(TS_UUID_UNDEFINED) {}
+  ATSUuid &operator=(const ATSUuid other);
+
+  // Initialize the UUID from a string
+  bool parseString(const char *str);
+
+  // Initialize a UUID using appropriate logic for the version specified. This can be done multiple times.
+  void initialize(TSUuidVersion v);
+
+  // These return the internal string representation of the UUID, do not mess with this string. There is
+  // no transfer of ownership here. You will have to make a copy to take ownership!
+  const char *
+  getString() const
+  {
+    return valid() ? _string : NULL;
+  }
+
+  const char *
+  c_str() const
+  {
+    return getString();
+  }
+
+  TSUuidVersion
+  version() const
+  {
+    return _version;
+  }
+
+  bool
+  valid() const
+  {
+    return (TS_UUID_UNDEFINED != _version);
+  }
+
+  // Getter's for the various UUID components.
+  uint32_t
+  getTimeLow() const
+  {
+    return _uuid.timeLow;
+  }
+
+  uint16_t
+  getTimeMid() const
+  {
+    return _uuid.timeMid;
+  }
+
+  uint16_t
+  getTimeHighAndVersion() const
+  {
+    return _uuid.timeHighAndVersion;
+  }
+
+  uint8_t
+  getClockSeqAndReserved() const
+  {
+    return _uuid.clockSeqAndReserved;
+  }
+
+  uint8_t
+  getClockSeqLow() const
+  {
+    return _uuid.clockSeqLow;
+  }
+
+  const uint8_t *
+  getNode() const
+  {
+    return _uuid.node;
+  }
+
+private:
+  // This is the union of the raw data (128 bits) and the fields as specified in
+  // RFC 4122. Technically we only need the raw data, but might as well unionize here.
+  union {
+    uint8_t data[16];
+
+    struct {
+      uint32_t timeLow;
+      uint16_t timeMid;
+      uint16_t timeHighAndVersion;
+      uint8_t clockSeqAndReserved;
+      uint8_t clockSeqLow;
+      uint8_t node[6];
+    };
+  } _uuid;
+
+  // This is the typically used visible portion of the UUID
+  TSUuidVersion _version;
+  char _string[TS_UUID_STRING_LEN + 1];
+
+  bool
+  _toString(char *buf)
+  {
+    int len = snprintf(buf, TS_UUID_STRING_LEN + 1, "%08x-%04hx-%04hx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
+                       _uuid.timeLow, _uuid.timeMid, _uuid.timeHighAndVersion, _uuid.clockSeqAndReserved, _uuid.clockSeqLow,
+                       _uuid.node[0], _uuid.node[1], _uuid.node[2], _uuid.node[3], _uuid.node[4], _uuid.node[5]);
+
+    return (len == TS_UUID_STRING_LEN);
+  }
+};
diff --git a/proxy/InkAPI.cc b/proxy/InkAPI.cc
index 5772c12..ea1e073 100644
--- a/proxy/InkAPI.cc
+++ b/proxy/InkAPI.cc
@@ -59,6 +59,7 @@
 
 #include "I_RecDefs.h"
 #include "I_RecCore.h"
+#include "I_Machine.h"
 #include "HttpProxyServerMain.h"
 
 /****************************************************************
@@ -8941,3 +8942,97 @@ TSVConnReenable(TSVConn vconn)
     }
   }
 }
+
+// APIs for managing and using UUIDs.
+TSUuid
+TSUuidCreate(void)
+{
+  ATSUuid *uuid = new ATSUuid();
+  return (TSUuid)uuid;
+}
+
+void
+TSUuidDestroy(TSUuid uuid)
+{
+  sdk_assert(sdk_sanity_check_null_ptr((void *)uuid) == TS_SUCCESS);
+  delete (ATSUuid *)uuid;
+}
+
+TSReturnCode
+TSUuidCopy(TSUuid dest, const TSUuid src)
+{
+  sdk_assert(sdk_sanity_check_null_ptr((void *)dest) == TS_SUCCESS);
+  sdk_assert(sdk_sanity_check_null_ptr((void *)src) == TS_SUCCESS);
+  ATSUuid *d = (ATSUuid *)dest;
+  ATSUuid *s = (ATSUuid *)src;
+
+  if (s->valid()) {
+    *d = *s;
+    return TS_SUCCESS;
+  }
+
+  return TS_ERROR;
+}
+
+TSReturnCode
+TSUuidInitialize(TSUuid uuid, TSUuidVersion v)
+{
+  sdk_assert(sdk_sanity_check_null_ptr((void *)uuid) == TS_SUCCESS);
+  ATSUuid *u = (ATSUuid *)uuid;
+
+  u->initialize(v);
+  return u->valid() ? TS_SUCCESS : TS_ERROR;
+}
+
+const TSUuid
+TSProcessUuidGet(void)
+{
+  Machine *machine = Machine::instance();
+  return (TSUuid)(&machine->uuid);
+}
+
+const char *
+TSUuidStringGet(const TSUuid uuid)
+{
+  sdk_assert(sdk_sanity_check_null_ptr((void *)uuid) == TS_SUCCESS);
+  ATSUuid *u = (ATSUuid *)(uuid);
+
+  if (u->valid()) {
+    return u->getString();
+  }
+
+  return NULL;
+}
+
+TSReturnCode
+TSUuidStringParse(TSUuid uuid, const char *str)
+{
+  sdk_assert(sdk_sanity_check_null_ptr((void *)uuid) == TS_SUCCESS);
+  sdk_assert(sdk_sanity_check_null_ptr((void *)str) == TS_SUCCESS);
+  ATSUuid *u = (ATSUuid *)uuid;
+
+  if (u->parseString(str)) {
+    return TS_SUCCESS;
+  }
+
+  return TS_ERROR;
+}
+
+TSUuidVersion
+TSUuidVersionGet(TSUuid uuid)
+{
+  sdk_assert(sdk_sanity_check_null_ptr((void *)uuid) == TS_SUCCESS);
+  ATSUuid *u = (ATSUuid *)uuid;
+
+  return u->version();
+}
+
+// Expose the HttpSM's sequence number (ID)
+uint64_t
+TSHttpTxnIdGet(TSHttpTxn txnp)
+{
+  sdk_assert(sdk_sanity_check_txn(txnp) == TS_SUCCESS);
+  HttpSM *sm = (HttpSM *)txnp;
+
+  return (uint64_t)sm->sm_id;
+}
diff --git a/proxy/InkAPITest.cc b/proxy/InkAPITest.cc
index d156403..8cfe6b1 100644
--- a/proxy/InkAPITest.cc
+++ b/proxy/InkAPITest.cc
@@ -7775,3 +7775,149 @@ REGRESSION_TEST(SDK_API_DEBUG_NAME_LOOKUPS)(RegressionTest *test, int /* atype A
 
   return;
 }
+
+////////////////////////////////////////////////
+// SDK_API_UUID
+//
+// Unit Test for API: TSUuidCreate
+//                    TSUuidDestroy
+//                    TSUuidCopy
+//                    TSUuidInitialize
+//                    TSProcessUuidGet
+//                    TSUuidStringGet
+//                    TSUuidVersionGet
+//                    TSUuidStringParse
+////////////////////////////////////////////////
+#include "ts/ink_uuid.h"
+
+REGRESSION_TEST(SDK_API_UUID)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus)
+{
+  TSUuid machine, uuid;
+  const char *str1;
+  const char *str2;
+  static const char uuid_v1[] = "5de5f9ec-30f4-11e6-a073-002590a33e4e";
+  static const char uuid_v4[] = "0e95fe5f-295a-401d-9ae4-eb32756d73cb";
+
+  *pstatus = REGRESSION_TEST_INPROGRESS;
+
+  // Test TSProcessUuidGet(), should just return a non-NULL pointer now.
+  machine = TSProcessUuidGet();
+  if (!machine) {
+    SDK_RPRINT(test, "TSProcessUuidGet", "TestCase1", TC_FAIL, "Returned a NULL pointer");
+    *pstatus = REGRESSION_TEST_FAILED;
+    return;
+  } else if (!((ATSUuid *)machine)->valid()) {
+    SDK_RPRINT(test, "TSProcessUuidGet", "TestCase2", TC_FAIL, "Returned an invalid UUID object");
+    *pstatus = REGRESSION_TEST_FAILED;
+    return;
+  } else {
+    SDK_RPRINT(test, "TSProcessUuidGet", "TestCase1", TC_PASS, "ok");
+    SDK_RPRINT(test, "TSProcessUuidGet", "TestCase2", TC_PASS, "ok");
+  }
+
+  // Test TSUuidStringGet, should return a random string (so can't check the string value itself)
+  str1 = TSUuidStringGet(machine);
+  if (!str1 || (TS_UUID_STRING_LEN != strlen(str1))) {
+    SDK_RPRINT(test, "TSUuidStringGet", "TestCase1", TC_FAIL, "Did not return a valid UUID string representation");
+    *pstatus = REGRESSION_TEST_FAILED;
+    return;
+  } else {
+    SDK_RPRINT(test, "TSUuidStringGet", "TestCase1", TC_PASS, "ok");
+  }
+
+  // Test TSUuidCreate
+  if (!(uuid = TSUuidCreate())) {
+    SDK_RPRINT(test, "TSUuidCreate", "TestCase1", TC_FAIL, "Failed to crete a UUID object");
+    *pstatus = REGRESSION_TEST_FAILED;
+    return;
+  } else {
+    SDK_RPRINT(test, "TSUuidCreate", "TestCase1", TC_PASS, "ok");
+    if (TS_SUCCESS != TSUuidInitialize(uuid, TS_UUID_V4)) {
+      SDK_RPRINT(test, "TSUuidInitialize", "TestCase1", TC_FAIL, "Failed to Initialize a V4 UUID");
+      *pstatus = REGRESSION_TEST_FAILED;
+      return;
+    } else {
+      SDK_RPRINT(test, "TSUuidInitialize", "TestCase1", TC_PASS, "ok");
+    }
+  }
+
+  // Test TSUuidVersion
+  if (TS_UUID_V4 != TSUuidVersionGet(uuid)) {
+    SDK_RPRINT(test, "TSUuidVersionGet", "TestCase1", TC_FAIL, "Failed to get the UUID version");
+    *pstatus = REGRESSION_TEST_FAILED;
+    return;
+  } else {
+    SDK_RPRINT(test, "TSUuidVersionGet", "TestCase1", TC_PASS, "ok");
+  }
+
+  // Test TSUuidCopy
+  if (TS_SUCCESS != TSUuidCopy(uuid, machine)) {
+    SDK_RPRINT(test, "TSUuidCopy", "TestCase1", TC_FAIL, "Failed to copy the Machine UUID object");
+    *pstatus = REGRESSION_TEST_FAILED;
+    return;
+  } else {
+    SDK_RPRINT(test, "TSUuidCopy", "TestCase1", TC_PASS, "ok");
+    str2 = TSUuidStringGet(uuid);
+    if (!str2 || (TS_UUID_STRING_LEN != strlen(str2)) || strcmp(str1, str2)) {
+      SDK_RPRINT(test, "TSUuidCopy", "TestCase2", TC_FAIL, "The copied UUID strings are not identical");
+      *pstatus = REGRESSION_TEST_FAILED;
+      return;
+    } else {
+      SDK_RPRINT(test, "TSUuidCopy", "TestCase2", TC_PASS, "ok");
+    }
+  }
+
+  // Test TSUuidInitialize again, make sure they take effect when called multiple times
+  if (TS_SUCCESS != TSUuidInitialize(uuid, TS_UUID_V4)) {
+    SDK_RPRINT(test, "TSUuidInitialize", "TestCase2", TC_FAIL, "Failed to re-initialize the UUID object");
+    *pstatus = REGRESSION_TEST_FAILED;
+    return;
+  } else {
+    SDK_RPRINT(test, "TSUuidInitialize", "TestCase2", TC_PASS, "ok");
+    str2 = TSUuidStringGet(uuid);
+    if (!str2 || (TS_UUID_STRING_LEN != strlen(str2)) || !strcmp(str1, str2)) {
+      SDK_RPRINT(test, "TSUuidInitialize", "TestCase3", TC_FAIL, "The re-initialized string is the same as before");
+      *pstatus = REGRESSION_TEST_FAILED;
+      return;
+    } else {
+      SDK_RPRINT(test, "TSUuidInitialize", "TestCase3", TC_PASS, "ok");
+    }
+  }
+
+  // Test TSUuidStringParse
+  if ((TS_SUCCESS != TSUuidStringParse(uuid, uuid_v1)) || (TS_UUID_V1 != TSUuidVersionGet(uuid))) {
+    SDK_RPRINT(test, "TSUuidStringParse", "TestCase1", TC_FAIL, "Failed to parse the UUID v1 string");
+    *pstatus = REGRESSION_TEST_FAILED;
+    return;
+  } else {
+    SDK_RPRINT(test, "TSUuidStringParse", "TestCase1", TC_PASS, "ok");
+    str1 = TSUuidStringGet(uuid);
+    if (!str1 || (TS_UUID_STRING_LEN != strlen(str1)) || strcmp(str1, uuid_v1)) {
+      SDK_RPRINT(test, "TSUuidStringString", "TestCase2", TC_FAIL, "The parse UUID v1 string does not match the original");
+      *pstatus = REGRESSION_TEST_FAILED;
+      return;
+    } else {
+      SDK_RPRINT(test, "TSUuidStringParse", "TestCase2", TC_PASS, "ok");
+    }
+  }
+  if ((TS_SUCCESS != TSUuidStringParse(uuid, uuid_v4)) || (TS_UUID_V4 != TSUuidVersionGet(uuid))) {
+    SDK_RPRINT(test, "TSUuidStringParse", "TestCase3", TC_FAIL, "Failed to parse the UUID v4 string");
+    *pstatus = REGRESSION_TEST_FAILED;
+    return;
+  } else {
+    SDK_RPRINT(test, "TSUuidStringParse", "TestCase3", TC_PASS, "ok");
+    str1 = TSUuidStringGet(uuid);
+    if (!str1 || (TS_UUID_STRING_LEN != strlen(str1)) || strcmp(str1, uuid_v4)) {
+      SDK_RPRINT(test, "TSUuidStringParse", "TestCase4", TC_FAIL, "The parse UUID v4 string does not match the original");
+      *pstatus = REGRESSION_TEST_FAILED;
+      return;
+    } else {
+      SDK_RPRINT(test, "TSUuidStringParse", "TestCase4", TC_PASS, "ok");
+    }
+  }
+
+  TSUuidDestroy(uuid);
+
+  *pstatus = REGRESSION_TEST_PASSED;
+  return;
+}
diff --git a/proxy/Main.cc b/proxy/Main.cc
index 27fcc16..5ce9da2 100644
--- a/proxy/Main.cc
+++ b/proxy/Main.cc
@@ -1674,6 +1674,9 @@ main(int /* argc ATS_UNUSED */, const char **argv)
     machine_addr.assign(HttpConfig::m_master.inbound_ip6);
   Machine::init(0, &machine_addr.sa);
 
+  RecRegisterStatString(RECT_PROCESS, "proxy.process.version.server.uuid", (char *)Machine::instance()->uuid.getString(),
+                        RECP_NON_PERSISTENT);
+
   // pmgmt->start() must occur after initialization of Diags but
   // before calling RecProcessInit()
 
diff --git a/proxy/api/ts/ts.h b/proxy/api/ts/ts.h
index 919a5ae..2a03952 100644
--- a/proxy/api/ts/ts.h
+++ b/proxy/api/ts/ts.h
@@ -2329,6 +2329,9 @@ tsapi TSReturnCode TSHttpTxnCacheLookupUrlSet(TSHttpTxn txnp, TSMBuffer bufp, TS
 tsapi TSReturnCode TSHttpTxnPrivateSessionSet(TSHttpTxn txnp, int private_session);
 tsapi int TSHttpTxnBackgroundFillStarted(TSHttpTxn txnp);
 
+/* Get the Txn's (HttpSM's) unique identifier, which is a sequence number since server start) */
+tsapi uint64_t TSHttpTxnIdGet(TSHttpTxn txnp);
+
 /* Expose internal Base64 Encoding / Decoding */
 tsapi TSReturnCode TSBase64Decode(const char *str, size_t str_len, unsigned char *dst, size_t dst_size, size_t *length);
 tsapi TSReturnCode TSBase64Encode(const char *str, size_t str_len, char *dst, size_t dst_size, size_t *length);
@@ -2389,6 +2392,20 @@ tsapi const char *TSHttpHookNameLookup(TSHttpHookID hook);
 */
 tsapi const char *TSHttpEventNameLookup(TSEvent event);
 
+/* APIs for dealing with UUIDs, either self made, or the system wide process UUID. See
+   https://docs.trafficserver.apache.org/en/latest/developer-guide/api/functions/TSUuidCreate.en.html
+*/
+tsapi TSUuid TSUuidCreate(void);
+tsapi TSReturnCode TSUuidInitialize(TSUuid uuid, TSUuidVersion v);
+tsapi void TSUuidDestroy(TSUuid uuid);
+tsapi TSReturnCode TSUuidCopy(TSUuid dest, const TSUuid src);
+tsapi const char *TSUuidStringGet(const TSUuid uuid);
+tsapi TSUuidVersion TSUuidVersionGet(const TSUuid uuid);
+tsapi TSReturnCode TSUuidStringParse(TSUuid uuid, const char *uuid_str);
+
+/* Get the process global UUID, resets on every startup */
+tsapi const TSUuid TSProcessUuidGet(void);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */

-- 
To stop receiving notification emails like this one, please contact
['"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>'].