tcti-socket: Add common Info and Init function.

These are implementations of the common discovery / initialization
functions. Using dlopen, dlsym and the types / structures / constants
from the tss2_tcti.h header this allows for the socket TCTI to be
initialized and configured dynamically.

Signed-off-by: Philip Tricca <philip.b.tricca@intel.com>
diff --git a/Makefile.am b/Makefile.am
index aa0a54c..433f865 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -140,8 +140,8 @@
 test_unit_tcti_device_SOURCES = tcti/tcti.c tcti/tcti.h tcti/tcti_device.c \
     test/unit/tcti-device.c log/log.h log/log.c
 
-test_unit_tcti_socket_CFLAGS  = $(CMOCKA_CFLAGS) $(AM_CFLAGS)
-test_unit_tcti_socket_LDADD   = $(CMOCKA_LIBS) $(libmarshal)
+test_unit_tcti_socket_CFLAGS  = $(CMOCKA_CFLAGS) $(AM_CFLAGS) $(URIPARSER_CFLAGS)
+test_unit_tcti_socket_LDADD   = $(CMOCKA_LIBS) $(libmarshal) $(URIPARSER_LIBS)
 test_unit_tcti_socket_LDFLAGS = -Wl,--wrap=connect,--wrap=recv,--wrap=select,--wrap=send
 test_unit_tcti_socket_SOURCES = tcti/platformcommand.c tcti/tcti_socket.c \
     tcti/tcti.c tcti/tcti.h tcti/sockets.c tcti/sockets.h \
@@ -219,11 +219,11 @@
 tcti_libtcti_device_la_SOURCES  = tcti/tcti_device.c tcti/tcti.c \
     tcti/tcti.h log/log.h log/log.c
 
-tcti_libtcti_socket_la_CFLAGS   = $(AM_CFLAGS)
+tcti_libtcti_socket_la_CFLAGS   = $(AM_CFLAGS) $(URIPARSER_CFLAGS)
 if HAVE_LD_VERSION_SCRIPT
 tcti_libtcti_socket_la_LDFLAGS  = -Wl,--version-script=$(srcdir)/tcti/tcti_socket.map
 endif # HAVE_LD_VERSION_SCRIPT
-tcti_libtcti_socket_la_LIBADD   = $(libmarshal)
+tcti_libtcti_socket_la_LIBADD   = $(libmarshal) $(URIPARSER_LIBS)
 tcti_libtcti_socket_la_SOURCES  = tcti/platformcommand.c tcti/tcti_socket.c \
     tcti/tcti.c tcti/tcti.h tcti/sockets.c tcti/sockets.h log/log.h log/log.c
 
diff --git a/configure.ac b/configure.ac
index 3d12e27..83f8cae 100644
--- a/configure.ac
+++ b/configure.ac
@@ -26,6 +26,10 @@
                          [AC_DEFINE([HAVE_CMOCKA],
                                     [1])])])
 AM_CONDITIONAL([UNIT], [test "x$enable_unit" != xno])
+
+# Uriparser library required by simulator TCTI library.
+PKG_CHECK_MODULES([URIPARSER],[liburiparser])
+
 #
 # simulator binary
 #
diff --git a/include/tcti/tcti_socket.h b/include/tcti/tcti_socket.h
index baab4e9..881c7d2 100644
--- a/include/tcti/tcti_socket.h
+++ b/include/tcti/tcti_socket.h
@@ -64,6 +64,12 @@
     UINT8 tpmCmdServer
     );
 
+TSS2_RC Tss2_Tcti_Socket_Init (
+    TSS2_TCTI_CONTEXT *tctiContext,
+    size_t *size,
+    const char *conf
+    );
+
 // Commands to send to OTHER port.
 #define MS_SIM_POWER_ON         1
 #define MS_SIM_POWER_OFF        2
diff --git a/tcti/tcti_socket.c b/tcti/tcti_socket.c
index 77d5f17..b3796fe 100644
--- a/tcti/tcti_socket.c
+++ b/tcti/tcti_socket.c
@@ -25,11 +25,15 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  **********************************************************************/
 
+#include <inttypes.h>
+#include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/time.h>
 #include <inttypes.h>
 
+#include <uriparser/Uri.h>
+
 #include "sapi/tpm20.h"
 #include "sapi/tss2_mu.h"
 #include "tcti/tcti_socket.h"
@@ -40,6 +44,8 @@
 #define LOGMODULE tcti
 #include "log/log.h"
 
+#define TCTI_SOCKET_DEFAULT "tcp://127.0.0.1:2321"
+
 static TSS2_RC tctiRecvBytes (
     TSS2_TCTI_CONTEXT *tctiContext,
     SOCKET sock,
@@ -528,3 +534,84 @@
 
     return rval;
 }
+/*
+ * This is a utility function to extract a TCP port number from a string.
+ * The string must be 6 characters long. If the supplied string contains an
+ * invalid port number then 0 is returned.
+ */
+static uint16_t
+string_to_port (char port_str[6])
+{
+    uint32_t port = 0;
+
+    if (sscanf (port_str, "%" SCNu32, &port) == EOF || port > UINT16_MAX) {
+        return 0;
+    }
+    return port;
+}
+
+TSS2_RC Tss2_Tcti_Socket_Init (
+    TSS2_TCTI_CONTEXT *tctiContext,
+    size_t *size,
+    const char *conf
+    )
+{
+    TCTI_SOCKET_CONF sock_conf = { 0 };
+    TSS2_RC rc;
+    UriParserStateA state;
+    UriUriA uri;
+    const char *uri_str = conf != NULL ? conf : TCTI_SOCKET_DEFAULT;
+    size_t range;
+    /* maximum 5 digits in uint16_t + 1 for \0 */
+    char port[6] = { 0 };
+    char hostname[HOST_NAME_MAX + 1] = { 0 };
+
+    state.uri = &uri;
+    if (uriParseUriA (&state, uri_str) != URI_SUCCESS) {
+        rc = TSS2_TCTI_RC_BAD_VALUE;
+        goto out;
+    }
+
+    /* extract host & domain name / fqdn */
+    range = uri.hostText.afterLast - uri.hostText.first;
+    if (range > HOST_NAME_MAX) {
+        rc = TSS2_TCTI_RC_BAD_VALUE;
+        goto out;
+    }
+    strncpy (hostname, uri.hostText.first, range);
+    sock_conf.hostname = hostname;
+
+    /* extract port number */
+    range = uri.portText.afterLast - uri.portText.first;
+    if (range <= 5 && range > 0) {
+        strncpy (port, uri.portText.first, range);
+        sock_conf.port = string_to_port (port);
+        if (sock_conf.port == 0) {
+            rc = TSS2_TCTI_RC_BAD_VALUE;
+            goto out;
+        }
+    } else if (range == 0) {
+        sock_conf.port = DEFAULT_SIMULATOR_TPM_PORT;
+    } else { /* range > 5 */
+        rc = TSS2_TCTI_RC_BAD_VALUE;
+        goto out;
+    }
+    rc = InitSocketTcti (tctiContext, size, &sock_conf, 0);
+out:
+    uriFreeUriMembersA (&uri);
+    return rc;
+}
+
+/* public info structure */
+const static TSS2_TCTI_INFO tss2_tcti_info = {
+    .name = "tcti-socket",
+    .description = "TCTI module for communication with the Microsoft TPM2 Simulator.",
+    .config_help = "Connection URI in the form tcp://ip_address[:port]. Default is tcp://127.0.0.1:2321.",
+    .init = Tss2_Tcti_Socket_Init,
+};
+
+const TSS2_TCTI_INFO*
+Tss2_Tcti_Info (void)
+{
+    return &tss2_tcti_info;
+}
diff --git a/tcti/tcti_socket.map b/tcti/tcti_socket.map
index 8c84850..94e2f17 100644
--- a/tcti/tcti_socket.map
+++ b/tcti/tcti_socket.map
@@ -2,6 +2,8 @@
     global:
         InitSocketTcti;
         PlatformCommand;
+        Tss2_Tcti_Info;
+        Tss2_Tcti_Socket_Init;
     local:
         *;
 };