You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by am...@apache.org on 2014/05/22 03:24:28 UTC

git commit: TS-2830 Make SPDY configurable.

Repository: trafficserver
Updated Branches:
  refs/heads/master 24d860c05 -> b7e69b0fa


TS-2830 Make SPDY configurable.


Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo
Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/b7e69b0f
Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/b7e69b0f
Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/b7e69b0f

Branch: refs/heads/master
Commit: b7e69b0fab91fc6a573b871bb11d82cb663e3a63
Parents: 24d860c
Author: Alan M. Carroll <am...@network-geographics.com>
Authored: Wed May 21 18:24:10 2014 -0700
Committer: Alan M. Carroll <am...@network-geographics.com>
Committed: Wed May 21 18:24:10 2014 -0700

----------------------------------------------------------------------
 CHANGES                                         |   2 +
 doc/admin/index.en.rst                          |   1 +
 .../configuration/records.config.en.rst         |  89 ++++--
 iocore/net/I_NetVConnection.h                   |   3 -
 iocore/net/P_SSLNextProtocolSet.h               |   3 +-
 iocore/net/SSLNetVConnection.cc                 |   4 +-
 iocore/net/SSLNextProtocolSet.cc                |  11 +-
 lib/records/I_RecCore.h                         |  10 +
 lib/records/I_RecDefs.h                         |   1 +
 lib/records/I_RecHttp.h                         | 187 +++++++++---
 lib/records/RecCore.cc                          |  18 ++
 lib/records/RecHttp.cc                          | 286 ++++++++++++++++---
 lib/records/RecLocal.cc                         |   1 +
 lib/records/RecMessage.cc                       |   1 +
 lib/ts/apidefs.h.in                             |  59 ++--
 lib/ts/ink_res_init.cc                          |   2 +-
 lib/ts/ink_resolver.h                           |   8 +-
 mgmt/Main.cc                                    |   1 +
 mgmt/RecordsConfig.cc                           |   6 +-
 proxy/FetchSM.cc                                |  14 +-
 proxy/FetchSM.h                                 |   4 -
 proxy/InkAPI.cc                                 |  28 +-
 proxy/InkAPITest.cc                             |   4 +-
 proxy/Main.cc                                   |   1 +
 proxy/ProtocolProbeSessionAccept.cc             |  21 +-
 proxy/ProtocolProbeSessionAccept.h              |  25 +-
 proxy/api/ts/experimental.h                     |  17 --
 proxy/api/ts/ts.h                               |   5 -
 proxy/http/HttpClientSession.cc                 |   1 -
 proxy/http/HttpProxyServerMain.cc               |  19 +-
 proxy/http/HttpSM.cc                            |   2 +-
 proxy/http/HttpSM.h                             |   1 -
 proxy/http/HttpSessionAccept.h                  |  11 +
 proxy/logging/Log.cc                            |   2 +
 proxy/logging/LogAccess.cc                      |   2 +
 proxy/logging/LogAccessHttp.cc                  |   4 +-
 proxy/logging/LogAccessHttp.h                   |   2 +-
 proxy/spdy/SpdyCallbacks.cc                     |   6 -
 proxy/spdy/SpdyCommon.cc                        |  19 +-
 proxy/spdy/SpdyCommon.h                         |  10 +-
 40 files changed, 613 insertions(+), 278 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b7e69b0f/CHANGES
----------------------------------------------------------------------
diff --git a/CHANGES b/CHANGES
index a260933..fe04ce5 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,8 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache Traffic Server 5.0.0
 
+  *) [TS-2830] Make SPDY configurable.
+
   *) [TS-2684] Add a text-log format to background_fetch plugin.
 
   *) [TS-2577] Tracing on e.g. -T http_hdrs does not show Proxy Request

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b7e69b0f/doc/admin/index.en.rst
----------------------------------------------------------------------
diff --git a/doc/admin/index.en.rst b/doc/admin/index.en.rst
index abc7be4..418d654 100644
--- a/doc/admin/index.en.rst
+++ b/doc/admin/index.en.rst
@@ -37,6 +37,7 @@ Contents:
    forward-proxy.en
    transparent-proxy.en
    explicit-proxy-caching.en
+   session-protocols.en
    hierachical-caching.en
    configuring-cache.en
    monitoring-traffic.en

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b7e69b0f/doc/reference/configuration/records.config.en.rst
----------------------------------------------------------------------
diff --git a/doc/reference/configuration/records.config.en.rst b/doc/reference/configuration/records.config.en.rst
index 58c9891..45734cd 100644
--- a/doc/reference/configuration/records.config.en.rst
+++ b/doc/reference/configuration/records.config.en.rst
@@ -451,29 +451,54 @@ Quick reference chart.
 Name        Note            Definition
 =========== =============== ========================================
 *number*    **Required**    The local port.
+blind                       Blind (``CONNECT``) port.
+compress    **N/I**         Compressed. Not implemented.
 ipv4        **Default**     Bind to IPv4 address family.
 ipv6                        Bind to IPv6 address family.
-tr-in                       Inbound transparent.
-tr-out                      Outbound transparent.
-tr-full                     Fully transparent (inbound and outbound)
-tr-pass                     Pass through enabled.
-ssl                         SSL terminated.
 ip-in       **Value**       Local inbound IP address.
 ip-out      **Value**       Local outbound IP address.
 ip-resolve  **Value**       IP address resolution style.
-blind                       Blind (``CONNECT``) port.
-compress    **N/I**         Compressed. Not implemented.
+proto       **Value**       List of supported session protocols.
+ssl                         SSL terminated.
+tr-full                     Fully transparent (inbound and outbound)
+tr-in                       Inbound transparent.
+tr-out                      Outbound transparent.
+tr-pass                     Pass through enabled.
 =========== =============== ========================================
 
 *number*
    Local IP port to bind. This is the port to which ATS clients will connect.
 
+blind
+   Accept only the ``CONNECT`` method on this port.
+
+   Not compatible with: ``tr-in``, ``ssl``.
+
+compress
+   Compress the connection. Retained only by inertia, should be considered "not implemented".
+
 ipv4
    Use IPv4. This is the default and is included primarily for completeness. This forced if the ``ip-in`` option is used with an IPv4 address.
 
 ipv6
    Use IPv6. This is forced if the ``ip-in`` option is used with an IPv6 address.
 
+ssl
+   Require SSL termination for inbound connections. SSL :ref:`must be configured <configuring-ssl-termination>` for this option to provide a functional server port.
+
+   Not compatible with: ``blind``.
+
+proto
+   Speficy the :ref:`session level protocols<session-protocol>` supported. These should be
+   separated by semi-colons. For TLS proxy ports the default value is
+   all available protocols. For non-TLS proxy ports the default is HTTP
+   only. SPDY can be enabled on non-TLS proxy ports but that must be done explicitly.
+
+tr-full
+   Fully transparent. This is a convenience option and is identical to specifying both ``tr-in`` and ``tr-out``.
+
+   Not compatible with: Any option not compatible with ``tr-in`` or ``tr-out``.
+
 tr-in
    Inbound transparent. The proxy port will accept connections to any IP address on the port. To have IPv6 inbound transparent you must use this and the ``ipv6`` option. This overrides :ts:cv:`proxy.local.incoming_ip_to_bind` for this port.
 
@@ -484,11 +509,6 @@ tr-out
 
    Not compatible with: ``ip-out``, ``ip-resolve``
 
-tr-full
-   Fully transparent. This is a convenience option and is identical to specifying both ``tr-in`` and ``tr-out``.
-
-   Not compatible with: Any option not compatible with ``tr-in`` or ``tr-out``.
-
 tr-pass
    Transparent pass through. This option is useful only for inbound transparent proxy ports. If the parsing of the expected HTTP header fails, then the transaction is switched to a blind tunnel instead of generating an error response to the client. It effectively enables :ts:cv:`proxy.config.http.use_client_target_addr` for the transaction as there is no other place to obtain the origin server address.
 
@@ -509,19 +529,6 @@ ip-resolve
 
    Not compatible with: ``tr-out`` - this option requires a value of ``client;none`` which is forced and should not be explicitly specified.
 
-ssl
-   Require SSL termination for inbound connections. SSL :ref:`must be configured <configuring-ssl-termination>` for this option to provide a functional server port.
-
-   Not compatible with: ``blind``.
-
-blind
-   Accept only ``CONNECT`` transactions on this port.
-
-   Not compatible with: ``tr-in``, ``ssl``.
-
-compress
-   Compress the connection. Retained only by inertia, should be considered "not implemented".
-
 .. topic:: Example
 
    Listen on port 80 on any address for IPv4 and IPv6.::
@@ -542,6 +549,12 @@ compress
 
       8080:ipv6:tr-full 443:ssl ip-in=192.168.17.1:80:ip-out=[fc01:10:10:1::1]:ip-out=10.10.10.1
 
+.. topic:: Example
+
+   Listen on port 9090 for TSL enabled SPDY or HTTP connections.::
+
+      9090:proto=spdy;http:ssl
+
 .. ts:cv:: CONFIG proxy.config.http.connect_ports STRING 443 563
 
    The range of origin server ports that can be used for tunneling via ``CONNECT``.
@@ -2235,10 +2248,32 @@ ICP Configuration
 SPDY Configuration
 ==================
 
-.. ts:cv:: CONFIG proxy.config.spdy.client.max_concurrent_streams INT 1000
+.. ts:cv:: CONFIG proxy.config.spdy.accept_no_activity_timeout INT 65536
+   :reloadable:
+
+   How long a SPDY connection will be kept open after an accept without any streams created.
+
+.. ts:cv:: CONFIG proxy.config.spdy.no_activity_timeout_in INT 65536
+   :reloadable:
+
+   How long a stream is kept open without activity.
+
+.. ts:cv:: CONFIG proxy.config.spdy.initial_window_size_in INT 65536
+   :reloadable:
+
+   The initial window size for inbound connections.
+
+.. ts:cv:: CONFIG proxy.config.spdy.max_concurrent_streams_in INT 1000
+   :reloadable:
+
+   The maximum number of concurrent streams per inbound connection.
+
+   .. note:: Reloading this value affects only new SPDY connections, not existing connects.
+
+.. ts:cv:: CONFIG proxy.config.spdy.verbose_in INT 65536
    :reloadable:
 
-   Set the maximum number of concurrent streams per client connection.
+   Set the verbose flag for SPDY streams on inbound connections.
 
 Scheduled Update Configuration
 ==============================

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b7e69b0f/iocore/net/I_NetVConnection.h
----------------------------------------------------------------------
diff --git a/iocore/net/I_NetVConnection.h b/iocore/net/I_NetVConnection.h
index 552e98b..5223267 100644
--- a/iocore/net/I_NetVConnection.h
+++ b/iocore/net/I_NetVConnection.h
@@ -409,9 +409,6 @@ public:
   /** Returns local port. */
   uint16_t get_local_port();
 
-  /** Client protocol stack of this VC */
-  TSClientProtoStack proto_stack;
-
   /** Returns remote sockaddr storage. */
   sockaddr const* get_remote_addr();
 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b7e69b0f/iocore/net/P_SSLNextProtocolSet.h
----------------------------------------------------------------------
diff --git a/iocore/net/P_SSLNextProtocolSet.h b/iocore/net/P_SSLNextProtocolSet.h
index d3c37b6..c4cae0e 100644
--- a/iocore/net/P_SSLNextProtocolSet.h
+++ b/iocore/net/P_SSLNextProtocolSet.h
@@ -40,7 +40,7 @@ public:
   bool advertiseProtocols(const unsigned char ** out, unsigned * len) const;
 
   Continuation * findEndpoint(const char *) const;
-  Continuation * findEndpoint(const unsigned char *, unsigned, TSClientProtoStack *, const char **) const;
+  Continuation * findEndpoint(const unsigned char *, unsigned, const char **) const;
 
   struct NextProtocolEndpoint
   {
@@ -50,7 +50,6 @@ public:
     ~NextProtocolEndpoint();
 
     const char * protocol;
-    TSClientProtoStack proto_stack;
     Continuation * endpoint;
     LINK(NextProtocolEndpoint, link);
 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b7e69b0f/iocore/net/SSLNetVConnection.cc
----------------------------------------------------------------------
diff --git a/iocore/net/SSLNetVConnection.cc b/iocore/net/SSLNetVConnection.cc
index da6830c..a25f873 100644
--- a/iocore/net/SSLNetVConnection.cc
+++ b/iocore/net/SSLNetVConnection.cc
@@ -595,14 +595,12 @@ SSLNetVConnection::sslServerHandShakeEvent(int &err)
         // If there's no NPN set, we should not have done this negotiation.
         ink_assert(this->npnSet != NULL);
 
-        this->npnEndpoint = this->npnSet->findEndpoint(proto, len, &this->proto_stack,
-                                                       &this->selected_next_protocol);
+        this->npnEndpoint = this->npnSet->findEndpoint(proto, len, &this->selected_next_protocol);
         this->npnSet = NULL;
 
         ink_assert(this->npnEndpoint != NULL);
         Debug("ssl", "client selected next protocol %.*s", len, proto);
       } else {
-        this->proto_stack = ((1u << TS_PROTO_TLS) | (1u << TS_PROTO_HTTP));
         Debug("ssl", "client did not select a next protocol");
       }
     }

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b7e69b0f/iocore/net/SSLNextProtocolSet.cc
----------------------------------------------------------------------
diff --git a/iocore/net/SSLNextProtocolSet.cc b/iocore/net/SSLNextProtocolSet.cc
index 7eb524a..ac5b22b 100644
--- a/iocore/net/SSLNextProtocolSet.cc
+++ b/iocore/net/SSLNextProtocolSet.cc
@@ -133,25 +133,18 @@ SSLNextProtocolSet::unregisterEndpoint(const char * proto, Continuation * ep)
 
 Continuation *
 SSLNextProtocolSet::findEndpoint(
-  const unsigned char * proto, unsigned len,
-  TSClientProtoStack *proto_stack, const char **selected_protocol) const
+  const unsigned char * proto, unsigned len, const char **selected_protocol) const
 {
   for (const NextProtocolEndpoint * ep = this->endpoints.head;
         ep != NULL; ep = this->endpoints.next(ep)) {
     size_t sz = strlen(ep->protocol);
     if (sz == len && memcmp(ep->protocol, proto, len) == 0) {
-      if (proto_stack) {
-        *proto_stack = ep->proto_stack;
-      }
-
       if (selected_protocol) {
         *selected_protocol = ep->protocol;
       }
-
       return ep->endpoint;
     }
   }
-
   return NULL;
 }
 
@@ -186,6 +179,7 @@ SSLNextProtocolSet::NextProtocolEndpoint::NextProtocolEndpoint(
         const char * proto, Continuation * ep)
   : protocol(proto), endpoint(ep)
 {
+# if 0
   if (proto == TS_NPN_PROTOCOL_HTTP_1_1 ||
       proto == TS_NPN_PROTOCOL_HTTP_1_0) {
     proto_stack = ((1u << TS_PROTO_TLS) | (1u << TS_PROTO_HTTP));
@@ -197,6 +191,7 @@ SSLNextProtocolSet::NextProtocolEndpoint::NextProtocolEndpoint(
   } else {
     proto_stack = (1u << TS_PROTO_TLS);
   }
+# endif
 }
 
 SSLNextProtocolSet::NextProtocolEndpoint::~NextProtocolEndpoint()

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b7e69b0f/lib/records/I_RecCore.h
----------------------------------------------------------------------
diff --git a/lib/records/I_RecCore.h b/lib/records/I_RecCore.h
index 9df6522..8b204c1 100644
--- a/lib/records/I_RecCore.h
+++ b/lib/records/I_RecCore.h
@@ -120,6 +120,7 @@ int RecLinkConfigFloat(const char *name, RecFloat * rec_float);
 int RecLinkConfigCounter(const char *name, RecCounter * rec_counter);
 int RecLinkConfigString(const char *name, RecString * rec_string);
 int RecLinkConfigByte(const char *name, RecByte * rec_byte);
+int RecLinkConfigBool(const char *name, RecBool * rec_byte);
 
 int RecRegisterConfigUpdateCb(const char *name, RecConfigUpdateCb update_cb, void *cookie);
 int RecRegisterRawStatUpdateFunc(const char *name, RecRawStatBlock * rsb, int id, RecStatUpdateFunc update_func, void *cookie);
@@ -149,6 +150,8 @@ int RecGetRecordString_Xmalloc(const char *name, RecString * rec_string, bool lo
 int RecGetRecordCounter(const char *name, RecCounter * rec_counter, bool lock = true);
 // Convenience to allow us to treat the RecInt as a single byte internally
 int RecGetRecordByte(const char *name, RecByte * rec_byte, bool lock = true);
+// Convenience to allow us to treat the RecInt as a bool internally
+int RecGetRecordBool(const char *name, RecBool * rec_byte, bool lock = true);
 
 //------------------------------------------------------------------------
 // Record Attributes Reading
@@ -247,6 +250,13 @@ void RecSignalManager(int, const char *);
     _var = (RecByte)REC_ConfigReadInteger(_config_var_name);    \
   } while (0)
 
+// Allow to treat our "INT" configs as a bool type internally. Note
+// that the bool type is just a wrapper around RECD_INT.
+#define REC_EstablishStaticConfigBool(_var, _config_var_name) do { \
+    RecLinkConfigBool(_config_var_name, &_var); \
+    _var = 0 != REC_ConfigReadInteger(_config_var_name);    \
+  } while (0)
+
 RecInt REC_ConfigReadInteger(const char *name);
 char *REC_ConfigReadString(const char *name);
 RecFloat REC_ConfigReadFloat(const char *name);

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b7e69b0f/lib/records/I_RecDefs.h
----------------------------------------------------------------------
diff --git a/lib/records/I_RecDefs.h b/lib/records/I_RecDefs.h
index 2edaf92..d423cec 100644
--- a/lib/records/I_RecDefs.h
+++ b/lib/records/I_RecDefs.h
@@ -53,6 +53,7 @@ typedef char *RecString;
 typedef const char *RecStringConst;
 typedef int64_t RecCounter;
 typedef int8_t RecByte;
+typedef bool RecBool;
 
 enum RecT
 {

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b7e69b0f/lib/records/I_RecHttp.h
----------------------------------------------------------------------
diff --git a/lib/records/I_RecHttp.h b/lib/records/I_RecHttp.h
index 760d476..83ffcbe 100644
--- a/lib/records/I_RecHttp.h
+++ b/lib/records/I_RecHttp.h
@@ -28,6 +28,7 @@
 #include <ts/ink_resolver.h>
 #include <ts/apidefs.h>
 #include <ts/Vec.h>
+#include <ts/apidefs.h>
 
 /// Load default inbound IP addresses from the configuration file.
 void RecHttpLoadIp(
@@ -36,6 +37,124 @@ void RecHttpLoadIp(
   IpAddr& ip6  ///< [out] Ipv6 address.
 );
 
+/** A set of session protocols.
+    This depends on using @c SessionProtocolNameRegistry to get the indices.
+*/
+class SessionProtocolSet {
+  typedef SessionProtocolSet self; ///< Self reference type.
+  /// Storage for the set - a bit vector.
+  uint32_t m_bits;
+public:
+  static int const MAX = sizeof(m_bits) * CHAR_BIT;
+  /// Default constructor.
+  /// Constructs and empty set.
+  SessionProtocolSet() : m_bits(0) { }
+
+  uint32_t indexToMask(int idx) const {
+    return 0 <= idx && idx < static_cast<int>(MAX)
+      ? static_cast<uint32_t>(1) << idx
+      : 0
+      ;
+  }
+
+  /// Mark the protocol at @a idx as present.
+  void markIn(int idx) { m_bits |= this->indexToMask(idx); }
+  /// Mark all the protocols in @a that as present in @a this.
+  void markIn(self const& that) { m_bits |= that.m_bits; }
+  /// Mark the protocol at a idx as not present.
+  void markOut(int idx) { m_bits &= ~this->indexToMask(idx); }
+  /// Mark the protocols in @a that as not in @a this.
+  void markOut(self const& that) { m_bits &= ~(that.m_bits); }
+  /// Test if a protocol is in the set.
+  bool contains(int idx) const { return 0 != (m_bits & this->indexToMask(idx)); }
+  /// Test if all the protocols in @a that are in @a this protocol set.
+  bool contains(self const& that) const { return that.m_bits == (that.m_bits & m_bits); }
+  /// Mark all possible protocols.
+  void markAllIn() { m_bits = ~static_cast<uint32_t>(0); }
+  /// Clear all protocols.
+  void markAllOut() { m_bits = 0; }
+
+  /// Check for intersection.
+  bool intersects(self const& that) { return 0 != (m_bits & that.m_bits); }
+
+  /// Check for empty set.
+  bool isEmpty() const { return m_bits == 0; }
+
+  /// Equality (identical sets).
+  bool operator == (self const& that) const { return m_bits == that.m_bits; }
+};
+
+// Predefined sets of protocols, useful for configuration.
+extern SessionProtocolSet HTTP_PROTOCOL_SET;
+extern SessionProtocolSet HTTP2_PROTOCOL_SET;
+extern SessionProtocolSet SPDY_PROTOCOL_SET;
+extern SessionProtocolSet DEFAULT_NON_TLS_SESSION_PROTOCOL_SET;
+extern SessionProtocolSet DEFAULT_TLS_SESSION_PROTOCOL_SET;
+
+/** Registered session protocol names.
+
+    We do this to avoid lots of string compares. By normalizing the
+    string names we can just compare their indices in this table.
+
+    @internal To simplify the implementation we limit the maximum
+    number of strings to 32. That will be sufficient for the forseeable
+    future. We can come back to this if it ever becomes a problem.
+
+    @internal Because we have so few strings we just use a linear search.
+    If the size gets much larger we should consider doing something more
+    clever.
+*/
+class SessionProtocolNameRegistry {
+ public:
+  static int const MAX  = SessionProtocolSet::MAX; ///< Maximum # of registered names.
+  static int const INVALID = -1; ///< Normalized invalid index value.
+
+  /// Default constructor.
+  /// Creates empty registry with no names.
+  SessionProtocolNameRegistry();
+
+  /// Destructor.
+  /// Cleans up strings.
+  ~SessionProtocolNameRegistry();
+
+  /** Get the index for @a name, registering it if needed.
+      The name is copied internally.
+      @return The index for the registered @a name.
+  */
+  int toIndex(char const* name);
+
+  /** Get the index for @a name, registering it if needed.
+      The caller @b guarantees @a name is persistent and immutable.
+      @return The index for the registered @a name.
+  */
+  int toIndexConst(char const* name);
+
+  /** Convert a @a name to an index.
+      @return The index for @a name or @c INVALID if it is not registered.
+  */
+  int indexFor(char const* name) const;
+
+  /** Convert an @a index to the corresponding name.
+      @return A pointer to the name or @c NULL if the index isn't registered.
+  */
+  char const* nameFor(int index) const;
+
+  /// Mark protocols as present in @a sp_set based on the names in @a value.
+  /// The names can be separated by ;/|,: and space.
+  /// @internal This is separated out to make it easy to access from the plugin API
+  /// implementation.
+  void markIn(char const* value, SessionProtocolSet& sp_set);
+
+ protected:
+  unsigned int m_n; ///< Index of first unused slot.
+  char const* m_names[MAX]; ///< Pointers to registered names.
+  uint8_t m_flags[MAX]; ///< Flags for each name.
+
+  static uint8_t const F_ALLOCATED = 0x1; ///< Flag for allocated by this instance.
+};
+
+extern SessionProtocolNameRegistry globalSessionProtocolNameRegistry;
+
 /** Description of an proxy port.
 
     This consolidates the options needed for proxy ports, both data
@@ -47,41 +166,8 @@ void RecHttpLoadIp(
     without spaces. The options are applied in left to right order. If
     options do not conflict the order is irrelevant.
 
-    Current supported options (case insensitive):
-
-    - ipv4 : Use IPv4.
-    - ipv6 : Use IPv6.
-    - ssl : SSL port.
-    - compressed : Compressed data.
-    - blind : Blind tunnel.
-    - tr-in : Inbound transparent (ignored if @c full is set).
-    - tr-out : Outbound transparent (ignored if @c full is set).
-    - tr-full : Fully transparent (inbound and outbound). Equivalent to "tr-in:tr-out".
-    - [number] : Port number.
-    - fd[number] : File descriptor.
-    - ip-in[IP addr] : Address to bind for inbound connections.
-    - ip-out[IP addr]: Address to bind for outbound connections.
-
-    For example, the string "ipv6:8080:full" means "Listen on port
-    8080 using IPv6 and full transparency". This is the same as
-    "8080:full:ipv6". The only option active by default is @c
-    ipv4. All others must be explicitly enabled. The port number
-    option is the only required option.
-
-    If @c ip-in or @c ip-out is used, the address family must agree
-    with the @c ipv4 or @c ipv6 option. If the address is IPv6, it
-    must be enclosed with brackets '[]' to distinguish its colons from
-    the value separating colons. An IPv4 may be enclosed in brackets
-    for constistency.
-
-    @note The previous notation is supported but deprecated.
-
-    @internal This is intended to replace the current bifurcated
-    processing that happens in Manager and Server. It also changes the
-    syntax so that a useful set of options can be supported and easily
-    extended as needed. Note that all options must start with a letter
-    - starting with a digit is reserved for the port value. Options
-    must not contain spaces or punctuation other than '-' and '_'.
+    IPv6 addresses must be enclosed by brackets. Unfortunate but colon is
+    so overloaded there's no other option.
  */
 struct HttpProxyPort {
 private:
@@ -101,8 +187,8 @@ public:
 
   int m_fd; ///< Pre-opened file descriptor if present.
   TransportType m_type; ///< Type of connection.
-  int m_port; ///< Port on which to listen.
-  unsigned int m_family; ///< IP address family.
+  in_port_t m_port; ///< Port on which to listen.
+  uint8_t m_family; ///< IP address family.
   /// True if inbound connects (from client) are transparent.
   bool m_inbound_transparent_p;
   /// True if outbound connections (to origin servers) are transparent.
@@ -121,6 +207,8 @@ public:
   HostResPreferenceOrder m_host_res_preference;
   /// Static preference list that is the default value.
   static HostResPreferenceOrder const DEFAULT_HOST_RES_PREFERENCE;
+  /// Enabled session transports for this port.
+  SessionProtocolSet m_session_protocol_preference;
 
   /// Default constructor.
   HttpProxyPort();
@@ -149,10 +237,8 @@ public:
 
   /** Global instance.
 
-      In general this data needs to be loaded only once. To support
-      that a global instance is provided. If accessed, it will
-      automatically load itself from the configuration data if not
-      already loaded.
+      This is provided because most of the work with this data is used as a singleton
+      and it's handy to encapsulate it here.
   */
   static Vec<self>& global();
 
@@ -267,12 +353,24 @@ public:
   static char const* const OPT_BLIND_TUNNEL; ///< Blind tunnel.
   static char const* const OPT_COMPRESSED; ///< Compressed.
   static char const* const OPT_HOST_RES_PREFIX; ///< Set DNS family preference.
+  static char const* const OPT_PROTO_PREFIX; ///< Transport layer protocols.
 
   static Vec<self>& m_global; ///< Global ("default") data.
 
 protected:
   /// Process @a value for DNS resolution family preferences.
-  void processFamilyPreferences(char const* value);
+  void processFamilyPreference(char const* value);
+  /// Process @a value for session protocol preferences.
+  void processSessionProtocolPreference(char const* value);
+
+  /** Check a prefix option and find the value.
+      @return The address of the start of the value, or @c NULL if the prefix doesn't match.
+  */
+
+  char const* checkPrefix( char const* src ///< Input text
+                         , char const* prefix ///< Keyword prefix
+                         , size_t prefix_len ///< Length of keyword prefix.
+                         );
 };
 
 inline bool HttpProxyPort::isSSL() const { return TRANSPORT_SSL == m_type; }
@@ -311,4 +409,9 @@ inline HttpProxyPort* HttpProxyPort::findHttp(uint16_t family) {
   return self::findHttp(m_global, family);
 }
 
+/** Session Protocol initialization.
+    This must be called before any proxy port parsing is done.
+*/
+extern void ts_session_protocol_well_known_name_indices_init();
+
 #endif // I_REC_HTTP_H

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b7e69b0f/lib/records/RecCore.cc
----------------------------------------------------------------------
diff --git a/lib/records/RecCore.cc b/lib/records/RecCore.cc
index 91466dc..d9c1049 100644
--- a/lib/records/RecCore.cc
+++ b/lib/records/RecCore.cc
@@ -267,6 +267,15 @@ RecLinkConfigByte(const char *name, RecByte * rec_byte)
   return RecRegisterConfigUpdateCb(name, link_byte, (void *) rec_byte);
 }
 
+int
+RecLinkConfigBool(const char *name, RecBool * rec_bool)
+{
+  if (RecGetRecordBool(name, rec_bool) == REC_ERR_FAIL) {
+    return REC_ERR_FAIL;
+  }
+  return RecRegisterConfigUpdateCb(name, link_byte, (void *) rec_bool);
+}
+
 
 //-------------------------------------------------------------------------
 // RecRegisterConfigUpdateCb
@@ -404,6 +413,15 @@ RecGetRecordByte(const char *name, RecByte *rec_byte, bool lock)
   return err;
 }
 
+int
+RecGetRecordBool(const char *name, RecBool *rec_bool, bool lock)
+{
+  int err;
+  RecData data;
+  if ((err = RecGetRecord_Xmalloc(name, RECD_INT, &data, lock)) == REC_ERR_OKAY)
+    *rec_bool = 0 != data.rec_int;
+  return err;
+}
 
 //-------------------------------------------------------------------------
 // RecGetRec Attributes

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b7e69b0f/lib/records/RecHttp.cc
----------------------------------------------------------------------
diff --git a/lib/records/RecHttp.cc b/lib/records/RecHttp.cc
index f79ff8a..753a3c1 100644
--- a/lib/records/RecHttp.cc
+++ b/lib/records/RecHttp.cc
@@ -27,6 +27,42 @@
 # include <ts/Tokenizer.h>
 # include <strings.h>
 
+SessionProtocolNameRegistry globalSessionProtocolNameRegistry;
+
+/* Protocol session well-known protocol names.
+   These are also used for NPN setup.
+*/
+
+const char * const TS_NPN_PROTOCOL_HTTP_0_9 = "http/0.9";
+const char * const TS_NPN_PROTOCOL_HTTP_1_0 = "http/1.0";
+const char * const TS_NPN_PROTOCOL_HTTP_1_1 = "http/1.1";
+const char * const TS_NPN_PROTOCOL_HTTP_2   = "http/2";
+const char * const TS_NPN_PROTOCOL_SPDY_1   = "spdy/1";   // obsolete
+const char * const TS_NPN_PROTOCOL_SPDY_2   = "spdy/2";
+const char * const TS_NPN_PROTOCOL_SPDY_3   = "spdy/3";
+const char * const TS_NPN_PROTOCOL_SPDY_3_1 = "spdy/3.1";
+
+const char * const TS_NPN_PROTOCOL_GROUP_HTTP = "http";
+const char * const TS_NPN_PROTOCOL_GROUP_HTTP2 = "http2";
+const char * const TS_NPN_PROTOCOL_GROUP_SPDY = "spdy";
+
+// Precomputed indices for ease of use.
+int TS_NPN_PROTOCOL_INDEX_HTTP_0_9 = SessionProtocolNameRegistry::INVALID;
+int TS_NPN_PROTOCOL_INDEX_HTTP_1_0 = SessionProtocolNameRegistry::INVALID;
+int TS_NPN_PROTOCOL_INDEX_HTTP_1_1 = SessionProtocolNameRegistry::INVALID;
+int TS_NPN_PROTOCOL_INDEX_HTTP_2 = SessionProtocolNameRegistry::INVALID;
+int TS_NPN_PROTOCOL_INDEX_SPDY_1 = SessionProtocolNameRegistry::INVALID;
+int TS_NPN_PROTOCOL_INDEX_SPDY_2 = SessionProtocolNameRegistry::INVALID;
+int TS_NPN_PROTOCOL_INDEX_SPDY_3 = SessionProtocolNameRegistry::INVALID;
+int TS_NPN_PROTOCOL_INDEX_SPDY_3_1 = SessionProtocolNameRegistry::INVALID;
+
+// Predefined protocol sets for ease of use.
+SessionProtocolSet HTTP_PROTOCOL_SET;
+SessionProtocolSet SPDY_PROTOCOL_SET;
+SessionProtocolSet HTTP2_PROTOCOL_SET;
+SessionProtocolSet DEFAULT_NON_TLS_SESSION_PROTOCOL_SET;
+SessionProtocolSet DEFAULT_TLS_SESSION_PROTOCOL_SET;
+
 void RecHttpLoadIp(char const* value_name, IpAddr& ip4, IpAddr& ip6)
 {
   char value[1024];
@@ -69,6 +105,7 @@ char const* const HttpProxyPort::OPT_FD_PREFIX = "fd";
 char const* const HttpProxyPort::OPT_OUTBOUND_IP_PREFIX = "ip-out";
 char const* const HttpProxyPort::OPT_INBOUND_IP_PREFIX = "ip-in";
 char const* const HttpProxyPort::OPT_HOST_RES_PREFIX = "ip-resolve";
+char const* const HttpProxyPort::OPT_PROTO_PREFIX = "proto";
 
 char const* const HttpProxyPort::OPT_IPV6 = "ipv6";
 char const* const HttpProxyPort::OPT_IPV4 = "ipv4";
@@ -88,6 +125,7 @@ namespace {
   size_t const OPT_OUTBOUND_IP_PREFIX_LEN = strlen(HttpProxyPort::OPT_OUTBOUND_IP_PREFIX);
   size_t const OPT_INBOUND_IP_PREFIX_LEN = strlen(HttpProxyPort::OPT_INBOUND_IP_PREFIX);
   size_t const OPT_HOST_RES_PREFIX_LEN = strlen(HttpProxyPort::OPT_HOST_RES_PREFIX);
+  size_t const OPT_PROTO_PREFIX_LEN = strlen(HttpProxyPort::OPT_PROTO_PREFIX);
 }
 
 namespace {
@@ -134,12 +172,22 @@ HttpProxyPort* HttpProxyPort::findHttp(Group const& ports, uint16_t family) {
   return zret;
 }
 
+char const*
+HttpProxyPort::checkPrefix(char const* src, char const* prefix, size_t prefix_len) {
+  char const* zret = 0;
+  if (0 == strncasecmp(prefix, src, prefix_len)) {
+    src += prefix_len;
+    if ('-' == *src || '=' == *src) ++src; // permit optional '-' or '='
+    zret = src;
+  }
+  return zret;
+}
+
 bool
 HttpProxyPort::loadConfig(Vec<self>& entries) {
   char* text;
   bool found_p;
 
-  // Do current style port configuration first.
   text = REC_readString(PORTS_CONFIG_NAME, &found_p);
   if (found_p) self::loadValue(entries, text);
   ats_free(text);
@@ -157,7 +205,7 @@ HttpProxyPort::loadDefaultIfEmpty(Group& ports) {
 
 bool
 HttpProxyPort::loadValue(Vec<self>& ports, char const* text) {
-  unsigned n_elts = ports.length(); // remember this.
+  unsigned old_port_length = ports.length(); // remember this.
   if (text && *text) {
     Tokenizer tokens(", ");
     int n_ports = tokens.Initialize(text);
@@ -166,19 +214,22 @@ HttpProxyPort::loadValue(Vec<self>& ports, char const* text) {
         char const* elt = tokens[p];
         HttpProxyPort entry;
         if (entry.processOptions(elt)) ports.push_back(entry);
-        else Warning("No port was found in port configuration element '%s'", elt);
+        else Warning("No valid definition was found in proxy port configuration element '%s'", elt);
       }
     }
   }
-  return ports.length() > n_elts; // we added at least one port.
+  return ports.length() > old_port_length; // we added at least one port.
 }
 
 bool
 HttpProxyPort::processOptions(char const* opts) {
-  bool zret = false; // no port found yet.
-  bool af_set_p = false; // AF explicitly specified.
-  bool host_res_set_p = false; // Host resolution order set explicitly.
-  bool bracket_p = false; // inside brackets during parse.
+  bool zret = false; // found a port?
+  bool af_set_p = false; // AF explicitly specified?
+  bool host_res_set_p = false; // Host resolution order set explicitly?
+  bool sp_set_p = false; // Session protocol set explicitly?
+  bool bracket_p = false; // found an open bracket in the input?
+  char const* value; // Temp holder for value of a prefix option.
+  IpAddr ip; // temp for loading IP addresses.
   Vec<char*> values; // Pointers to single option values.
 
   // Make a copy we can modify safely.
@@ -216,42 +267,32 @@ HttpProxyPort::processOptions(char const* opts) {
         // really, this shouldn't happen, since we checked for a leading digit.
         Warning("Mangled port value '%s' in port configuration '%s'", item, opts);
       } else if (port <= 0 || 65536 <= port) {
-        Warning("Port value '%s' out of range in port configuration '%s'", item, opts);
+        Warning("Port value '%s' out of range (1..65535) in port configuration '%s'", item, opts);
       } else {
         m_port = port;
         zret = true;
       }
-    } else if (0 == strncasecmp(OPT_FD_PREFIX, item, OPT_FD_PREFIX_LEN)) {
+    } else if (0 != (value = this->checkPrefix(item, OPT_FD_PREFIX, OPT_FD_PREFIX_LEN))) {
       char* ptr; // tmp for syntax check.
-      item += OPT_FD_PREFIX_LEN; // skip prefix
-      if ('-' == *item || '=' == *item) ++item; // permit optional '-' or '='
-      int fd = strtoul(item, &ptr, 10);
-      if (ptr == item) {
+      int fd = strtoul(value, &ptr, 10);
+      if (ptr == value) {
         Warning("Mangled file descriptor value '%s' in port descriptor '%s'", item, opts);
       } else {
         m_fd = fd;
         zret = true;
       }
-    } else if (0 == strncasecmp(OPT_INBOUND_IP_PREFIX, item, OPT_INBOUND_IP_PREFIX_LEN)) {
-      IpEndpoint ip;
-      item += OPT_INBOUND_IP_PREFIX_LEN; // skip prefix
-      if ('-' == *item || '=' == *item) ++item; // permit optional '-' or '='
-      if (0 == ats_ip_pton(item, &ip))
+    } else if (0 != (value = this->checkPrefix(item, OPT_INBOUND_IP_PREFIX, OPT_INBOUND_IP_PREFIX_LEN))) {
+      if (0 == ip.load(value))
         m_inbound_ip = ip;
       else
         Warning("Invalid IP address value '%s' in port descriptor '%s'",
           item, opts
         );
-    } else if (0 == strncasecmp(OPT_OUTBOUND_IP_PREFIX, item, OPT_OUTBOUND_IP_PREFIX_LEN)) {
-      IpAddr ip;
-      item += OPT_OUTBOUND_IP_PREFIX_LEN; // skip prefix
-      if ('-' == *item || '=' == *item) ++item; // permit optional '-' or '='
-      if (0 == ip.load(item))
+    } else if (0 != (value = this->checkPrefix(item, OPT_OUTBOUND_IP_PREFIX, OPT_OUTBOUND_IP_PREFIX_LEN))) {
+      if (0 == ip.load(value))
         this->outboundIp(ip.family()) = ip;
       else
-        Warning("Invalid IP address value '%s' in port descriptor '%s'",
-          item, opts
-        );
+        Warning("Invalid IP address value '%s' in port descriptor '%s'", item, opts);
     } else if (0 == strcasecmp(OPT_COMPRESSED, item)) {
       m_type = TRANSPORT_COMPRESSED;
     } else if (0 == strcasecmp(OPT_BLIND_TUNNEL, item)) {
@@ -291,14 +332,14 @@ HttpProxyPort::processOptions(char const* opts) {
 # else
       Warning("Transparent pass-through requested [%s] in port descriptor '%s' but TPROXY was not configured.", item, opts);
 # endif
-    } else if (0 == strncasecmp(OPT_HOST_RES_PREFIX, item, OPT_HOST_RES_PREFIX_LEN)) {
-      item += OPT_HOST_RES_PREFIX_LEN; // skip prefix
-      if ('-' == *item || '=' == *item) // permit optional '-' or '='
-        ++item;
-      this->processFamilyPreferences(item);
+    } else if (0 != (value = this->checkPrefix(item, OPT_HOST_RES_PREFIX, OPT_HOST_RES_PREFIX_LEN))) {
+      this->processFamilyPreference(value);
       host_res_set_p = true;
+    } else if (0 != (value = this->checkPrefix(item, OPT_PROTO_PREFIX, OPT_PROTO_PREFIX_LEN))) {
+      this->processSessionProtocolPreference(value);
+      sp_set_p = true;
     } else {
-      Warning("Invalid option '%s' in port configuration '%s'", item, opts);
+      Warning("Invalid option '%s' in proxy port configuration '%s'", item, opts);
     }
   }
 
@@ -337,12 +378,49 @@ HttpProxyPort::processOptions(char const* opts) {
     m_transparent_passthrough = false;
   }
 
+  // Set the default session protocols.
+  if (!sp_set_p)
+    m_session_protocol_preference = this->isSSL()
+      ? DEFAULT_TLS_SESSION_PROTOCOL_SET
+      : DEFAULT_NON_TLS_SESSION_PROTOCOL_SET
+      ;
+
   return zret;
 }
 
 void
-HttpProxyPort::processFamilyPreferences(char const* value) {
-  parse_host_res_preferences(value, m_host_res_preference);
+HttpProxyPort::processFamilyPreference(char const* value) {
+  parse_host_res_preference(value, m_host_res_preference);
+}
+
+void
+HttpProxyPort::processSessionProtocolPreference(char const* value) {
+  m_session_protocol_preference.markAllOut();
+  globalSessionProtocolNameRegistry.markIn(value, m_session_protocol_preference);
+}
+
+void
+SessionProtocolNameRegistry::markIn(char const* value, SessionProtocolSet& sp_set) {
+  int n; // # of tokens
+  Tokenizer tokens(" ;|,:");
+ 
+  n = tokens.Initialize(value);
+
+  for ( int i = 0 ; i < n ; ++i ) {
+    char const* elt = tokens[i];
+    
+    /// Check special cases
+    if (0 == strcasecmp(elt, TS_NPN_PROTOCOL_GROUP_HTTP)) {
+      sp_set.markIn(HTTP_PROTOCOL_SET);
+    } else if (0 == strcasecmp(elt, TS_NPN_PROTOCOL_GROUP_SPDY)) {
+      sp_set.markIn(SPDY_PROTOCOL_SET);
+    } else if (0 == strcasecmp(elt, TS_NPN_PROTOCOL_GROUP_HTTP2)) {
+      sp_set.markIn(HTTP2_PROTOCOL_SET);
+    } else { // user defined - register and mark.
+      int idx = globalSessionProtocolNameRegistry.toIndex(elt);
+      sp_set.markIn(idx);
+    }
+  }
 }
 
 int
@@ -394,6 +472,9 @@ HttpProxyPort::print(char* out, size_t n) {
   }
   if (zret >= n) return n;
 
+  // After this point, all of these options require other options which we've already
+  // generated so all of them need a leading colon and we can stop checking for that.
+
   if (AF_INET6 == m_family)
     zret += snprintf(out+zret, n-zret, ":%s", OPT_IPV6);
   if (zret >= n) return n;
@@ -428,6 +509,53 @@ HttpProxyPort::print(char* out, size_t n) {
     zret += ts_host_res_order_to_string(m_host_res_preference, out+zret, n-zret);
   }
 
+  // session protocol options - look for condensed options first
+  // first two cases are the defaults so if those match, print nothing.
+  SessionProtocolSet sp_set = m_session_protocol_preference; // need to modify so copy.
+  need_colon_p = true; // for listing case, turned off if we do a special case.
+  if (sp_set == DEFAULT_NON_TLS_SESSION_PROTOCOL_SET && !this->isSSL()) {
+    sp_set.markOut(DEFAULT_NON_TLS_SESSION_PROTOCOL_SET);
+  } else if (sp_set == DEFAULT_TLS_SESSION_PROTOCOL_SET && this->isSSL()) {
+    sp_set.markOut(DEFAULT_TLS_SESSION_PROTOCOL_SET);
+  }
+
+  // pull out groups.
+  if (sp_set.contains(HTTP_PROTOCOL_SET)) {
+    zret += snprintf(out+zret, n-zret, ":%s=%s", OPT_PROTO_PREFIX,TS_NPN_PROTOCOL_GROUP_HTTP);
+    sp_set.markOut(HTTP_PROTOCOL_SET);
+    need_colon_p = false;
+  }
+  if (sp_set.contains(SPDY_PROTOCOL_SET)) {
+    if (need_colon_p) 
+      zret += snprintf(out+zret, n-zret, ":%s=", OPT_PROTO_PREFIX);
+    else
+      out[zret++] = ';';
+    zret += snprintf(out+zret, n-zret, TS_NPN_PROTOCOL_GROUP_SPDY);
+    sp_set.markOut(SPDY_PROTOCOL_SET);
+    need_colon_p = false;
+  }
+  if (sp_set.contains(HTTP2_PROTOCOL_SET)) {
+    if (need_colon_p)
+      zret += snprintf(out+zret, n-zret, ":%s=", OPT_PROTO_PREFIX);
+    else
+      out[zret++] = ';';
+    zret += snprintf(out+zret, n-zret, "%s", TS_NPN_PROTOCOL_GROUP_HTTP2);
+    sp_set.markOut(HTTP2_PROTOCOL_SET);
+    need_colon_p = false;
+  }
+  // now enumerate what's left.
+  if (!sp_set.isEmpty()) {
+    if (need_colon_p)
+      zret += snprintf(out+zret, n-zret, ":%s=", OPT_PROTO_PREFIX);
+    bool sep_p = !need_colon_p;
+    for ( int k = 0 ; k < SessionProtocolSet::MAX ; ++k ) {
+      if (sp_set.contains(k)) {
+        zret += snprintf(out+zret, n-zret, "%s%s", sep_p ? ";" : "", globalSessionProtocolNameRegistry.nameFor(k));
+        sep_p = true;
+      }
+    }
+  }
+
   return min(zret,n);
 }
 
@@ -441,7 +569,93 @@ ts_host_res_global_init()
 
   char* ip_resolve = REC_ConfigReadString("proxy.config.hostdb.ip_resolve");
   if (ip_resolve) {
-    parse_host_res_preferences(ip_resolve, host_res_default_preference_order);
+    parse_host_res_preference(ip_resolve, host_res_default_preference_order);
   }
   ats_free(ip_resolve);
 }
+
+// Whatever executable uses librecords must call this.
+void
+ts_session_protocol_well_known_name_indices_init()
+{
+  // register all the well known protocols and get the indices set.
+  TS_NPN_PROTOCOL_INDEX_HTTP_0_9 = globalSessionProtocolNameRegistry.toIndexConst(TS_NPN_PROTOCOL_HTTP_0_9);
+  TS_NPN_PROTOCOL_INDEX_HTTP_1_0 = globalSessionProtocolNameRegistry.toIndexConst(TS_NPN_PROTOCOL_HTTP_1_0);
+  TS_NPN_PROTOCOL_INDEX_HTTP_1_1 = globalSessionProtocolNameRegistry.toIndexConst(TS_NPN_PROTOCOL_HTTP_1_1);
+  TS_NPN_PROTOCOL_INDEX_HTTP_2 = globalSessionProtocolNameRegistry.toIndexConst(TS_NPN_PROTOCOL_HTTP_2);
+  TS_NPN_PROTOCOL_INDEX_SPDY_1 = globalSessionProtocolNameRegistry.toIndexConst(TS_NPN_PROTOCOL_SPDY_1);
+  TS_NPN_PROTOCOL_INDEX_SPDY_2 = globalSessionProtocolNameRegistry.toIndexConst(TS_NPN_PROTOCOL_SPDY_2);
+  TS_NPN_PROTOCOL_INDEX_SPDY_3 = globalSessionProtocolNameRegistry.toIndexConst(TS_NPN_PROTOCOL_SPDY_3);
+  TS_NPN_PROTOCOL_INDEX_SPDY_3_1 = globalSessionProtocolNameRegistry.toIndexConst(TS_NPN_PROTOCOL_SPDY_3_1);
+
+  // Now do the predefined protocol sets.
+  HTTP_PROTOCOL_SET.markIn(TS_NPN_PROTOCOL_INDEX_HTTP_0_9);
+  HTTP_PROTOCOL_SET.markIn(TS_NPN_PROTOCOL_INDEX_HTTP_1_0);
+  HTTP_PROTOCOL_SET.markIn(TS_NPN_PROTOCOL_INDEX_HTTP_1_1);
+  HTTP2_PROTOCOL_SET.markIn(TS_NPN_PROTOCOL_INDEX_HTTP_2);
+  SPDY_PROTOCOL_SET.markIn(TS_NPN_PROTOCOL_INDEX_SPDY_3);
+  SPDY_PROTOCOL_SET.markIn(TS_NPN_PROTOCOL_INDEX_SPDY_3_1);
+
+  DEFAULT_TLS_SESSION_PROTOCOL_SET.markAllIn();
+  DEFAULT_NON_TLS_SESSION_PROTOCOL_SET = HTTP_PROTOCOL_SET;
+}
+
+SessionProtocolNameRegistry::SessionProtocolNameRegistry()
+  : m_n(0)
+{
+  memset(m_names, 0, sizeof(m_names));
+  memset(&m_flags, 0, sizeof(m_flags));
+}
+
+SessionProtocolNameRegistry::~SessionProtocolNameRegistry() {
+  for ( size_t i = 0 ; i < m_n ; ++i ) {
+    if (m_flags[i] & F_ALLOCATED)
+      ats_free(const_cast<char*>(m_names[i])); // blech - ats_free won't take a char const*
+  }
+}
+
+int
+SessionProtocolNameRegistry::toIndex(char const* name) {
+  int zret = this->indexFor(name);
+  if (INVALID == zret) {
+    if (m_n < static_cast<size_t>(MAX)) {
+      m_names[m_n] = ats_strdup(name);
+      m_flags[m_n] = F_ALLOCATED;
+      zret = m_n++;
+    } else {
+      ink_release_assert(!"Session protocol name registry overflow");
+    }
+  }
+  return zret;
+}
+
+int
+SessionProtocolNameRegistry::toIndexConst(char const* name) {
+  int zret = this->indexFor(name);
+  if (INVALID == zret) {
+    if ( m_n < static_cast<size_t>(MAX)) {
+      m_names[m_n] = name;
+      zret = m_n++;
+    } else {
+      ink_release_assert(!"Session protocol name registry overflow");
+    }
+  }
+  return zret;
+}
+
+int
+SessionProtocolNameRegistry::indexFor(char const* name) const {
+  for ( size_t i = 0 ; i < m_n ; ++i ) {
+    if (0 == strcasecmp(name, m_names[i]))
+      return i;
+  }
+  return INVALID;
+}
+
+char const*
+SessionProtocolNameRegistry::nameFor(int idx) const {
+  return 0 <= idx && idx < static_cast<int>(m_n)
+    ? m_names[idx]
+    : 0
+    ;
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b7e69b0f/lib/records/RecLocal.cc
----------------------------------------------------------------------
diff --git a/lib/records/RecLocal.cc b/lib/records/RecLocal.cc
index 87622f4..3a2371a 100644
--- a/lib/records/RecLocal.cc
+++ b/lib/records/RecLocal.cc
@@ -22,6 +22,7 @@
  */
 
 #include "libts.h"
+#include "Rollback.h"
 #include "ParseRules.h"
 #include "P_RecCore.h"
 #include "P_RecLocal.h"

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b7e69b0f/lib/records/RecMessage.cc
----------------------------------------------------------------------
diff --git a/lib/records/RecMessage.cc b/lib/records/RecMessage.cc
index d4e1b8c..bf07841 100644
--- a/lib/records/RecMessage.cc
+++ b/lib/records/RecMessage.cc
@@ -27,6 +27,7 @@
 #include "P_RecFile.h"
 #include "P_RecMessage.h"
 #include "P_RecUtils.h"
+#include "P_RecCore.h"
 #include "I_Layout.h"
 
 static bool g_message_initialized = false;

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b7e69b0f/lib/ts/apidefs.h.in
----------------------------------------------------------------------
diff --git a/lib/ts/apidefs.h.in b/lib/ts/apidefs.h.in
index 7958c59..130b91b 100644
--- a/lib/ts/apidefs.h.in
+++ b/lib/ts/apidefs.h.in
@@ -94,37 +94,6 @@ extern "C"
 #endif
 
   /**
-      TSClientProtoStack represents what protocols are used by
-      the client. It may be composed by several TSProtoType.
-
-      The value of TSProtoType indicates bit-offset that can
-      be mapped to TSClientProtoStack by bit shifting.
-
-      For example, TLS+SPDY can be mapped to protocol stack:
-        proto_stack = (1u << TS_PROTO_TLS) | (1u << TS_PROTO_SPDY)
-
-      For the sake of brevity, TS_PROTO_TCP is usually omitted in
-      protocol stack.
-   */
-  typedef enum {
-    /* Transport protocols (0~11) */
-    TS_PROTO_UDP = 0,
-    TS_PROTO_TCP = 1,
-    TS_PROTO_TLS = 2,   /* TLS/SSL */
-
-    /* Application protocols (12~31) */
-    TS_PROTO_HTTP = 12,
-    TS_PROTO_SPDY = 13,
-    TS_PROTO_RTMP = 14,
-    TS_PROTO_WS   = 15, /* WebSocket */
-
-    /* MAX value of TSProtoType  */
-    TS_PROTO_NULL = 32
-  } TSProtoType;
-
-  typedef uint32_t TSClientProtoStack;
-
-  /**
       The following struct is used by TSPluginRegister(). It stores
       registration information about the plugin.
 
@@ -1151,12 +1120,28 @@ extern "C"
 
   /* --------------------------------------------------------------------------
      TLS Next Protocol well-known protocol names. */
-  extern tsapi const char * TS_NPN_PROTOCOL_HTTP_1_0;
-  extern tsapi const char * TS_NPN_PROTOCOL_HTTP_1_1;
-  extern tsapi const char * TS_NPN_PROTOCOL_SPDY_1;
-  extern tsapi const char * TS_NPN_PROTOCOL_SPDY_2;
-  extern tsapi const char * TS_NPN_PROTOCOL_SPDY_3;
-  extern tsapi const char * TS_NPN_PROTOCOL_SPDY_3_1;
+
+  extern tsapi const char * const TS_NPN_PROTOCOL_HTTP_0_9;
+  extern tsapi const char * const TS_NPN_PROTOCOL_HTTP_1_0;
+  extern tsapi const char * const TS_NPN_PROTOCOL_HTTP_1_1;
+  extern tsapi const char * const TS_NPN_PROTOCOL_HTTP_2_0;
+  extern tsapi const char * const TS_NPN_PROTOCOL_SPDY_1;
+  extern tsapi const char * const TS_NPN_PROTOCOL_SPDY_2;
+  extern tsapi const char * const TS_NPN_PROTOCOL_SPDY_3;
+  extern tsapi const char * const TS_NPN_PROTOCOL_SPDY_3_1;
+
+  extern tsapi int TS_NPN_PROTOCOL_INDEX_HTTP_0_9;
+  extern tsapi int TS_NPN_PROTOCOL_INDEX_HTTP_1_0;
+  extern tsapi int TS_NPN_PROTOCOL_INDEX_HTTP_1_1;
+  extern tsapi int TS_NPN_PROTOCOL_INDEX_SPDY_1;
+  extern tsapi int TS_NPN_PROTOCOL_INDEX_SPDY_2;
+  extern tsapi int TS_NPN_PROTOCOL_INDEX_SPDY_3;
+  extern tsapi int TS_NPN_PROTOCOL_INDEX_SPDY_3_1;
+  extern tsapi int TS_NPN_PROTOCOL_INDEX_HTTP_2_0;
+
+  extern tsapi const char * const TS_NPN_PROTOCOL_GROUP_HTTP;
+  extern tsapi const char * const TS_NPN_PROTOCOL_GROUP_HTTP2;
+  extern tsapi const char * const TS_NPN_PROTOCOL_GROUP_SPDY;
 
   /* --------------------------------------------------------------------------
      MLoc Constants */

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b7e69b0f/lib/ts/ink_res_init.cc
----------------------------------------------------------------------
diff --git a/lib/ts/ink_res_init.cc b/lib/ts/ink_res_init.cc
index 81a25b1..dee9acc 100644
--- a/lib/ts/ink_res_init.cc
+++ b/lib/ts/ink_res_init.cc
@@ -579,7 +579,7 @@ ink_res_init(
 }
 
 void
-parse_host_res_preferences(char const* value, HostResPreferenceOrder order) {
+parse_host_res_preference(char const* value, HostResPreferenceOrder order) {
   Tokenizer tokens(";/|");
   // preference from the config string.
   int np = 0; // index in to @a m_host_res_preference

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b7e69b0f/lib/ts/ink_resolver.h
----------------------------------------------------------------------
diff --git a/lib/ts/ink_resolver.h b/lib/ts/ink_resolver.h
index 80e0dfc..ce94e2f 100644
--- a/lib/ts/ink_resolver.h
+++ b/lib/ts/ink_resolver.h
@@ -195,10 +195,10 @@ ats_host_res_match(sockaddr const* addr);
 /** Parse a host resolution configuration string.
  */
 extern void
-parse_host_res_preferences(
-			   char const* value, ///< [in] Configuration string.
-			   HostResPreferenceOrder order /// [out] Order to update.
-			   );
+parse_host_res_preference(
+			 char const* value, ///< [in] Configuration string.
+			  HostResPreferenceOrder order /// [out] Order to update.
+			  );
 
 #ifndef NS_GET16
 #define NS_GET16(s, cp) do { \

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b7e69b0f/mgmt/Main.cc
----------------------------------------------------------------------
diff --git a/mgmt/Main.cc b/mgmt/Main.cc
index a02d4bf..ba5f9ba 100644
--- a/mgmt/Main.cc
+++ b/mgmt/Main.cc
@@ -582,6 +582,7 @@ main(int argc, char **argv)
   Init_Errata_Logging();
 #endif
   ts_host_res_global_init();
+  ts_session_protocol_well_known_name_indices_init();
   lmgmt = new LocalManager(proxy_on);
   RecLocalInitMessage();
   lmgmt->initAlarm();

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b7e69b0f/mgmt/RecordsConfig.cc
----------------------------------------------------------------------
diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc
index cb46861..91ac5d7 100644
--- a/mgmt/RecordsConfig.cc
+++ b/mgmt/RecordsConfig.cc
@@ -1940,7 +1940,11 @@ RecordElement RecordsConfig[] = {
   //# SPDY global configuration.
   //#
   //############
-  {RECT_CONFIG, "proxy.config.spdy.client.max_concurrent_streams", RECD_INT, "100", RECU_DYNAMIC, RR_NULL, RECC_INT, NULL, RECA_NULL},
+  {RECT_CONFIG, "proxy.config.spdy.max_concurrent_streams_in", RECD_INT, "100", RECU_DYNAMIC, RR_NULL, RECC_INT, NULL, RECA_NULL},
+  {RECT_CONFIG, "proxy.config.spdy.no_activity_timeout_in", RECD_INT, "30", RECU_DYNAMIC, RR_NULL, RECC_INT, NULL, RECA_NULL},
+  {RECT_CONFIG, "proxy.config.spdy.initial_window_size_in", RECD_INT, "65536", RECU_DYNAMIC, RR_NULL, RECC_INT, NULL, RECA_NULL},
+  {RECT_CONFIG, "proxy.config.spdy.verbose_in", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_INT, NULL, RECA_NULL},
+  {RECT_CONFIG, "proxy.config.spdy.accept_no_activity_timeout", RECD_INT, "30", RECU_DYNAMIC, RR_NULL, RECC_INT, NULL, RECA_NULL},
 
   //# Add LOCAL Records Here
   {RECT_LOCAL, "proxy.local.incoming_ip_to_bind", RECD_STRING, NULL, RECU_NULL, RR_NULL, RECC_NULL, NULL, RECA_NULL}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b7e69b0f/proxy/FetchSM.cc
----------------------------------------------------------------------
diff --git a/proxy/FetchSM.cc b/proxy/FetchSM.cc
index e9af1f9..c119aca 100644
--- a/proxy/FetchSM.cc
+++ b/proxy/FetchSM.cc
@@ -72,7 +72,7 @@ void
 FetchSM::httpConnect()
 {
   Debug(DEBUG_TAG, "[%s] calling httpconnect write", __FUNCTION__);
-  http_vc = TSHttpConnectWithProtoStack(&_addr.sa, proto_stack);
+  http_vc = TSHttpConnect(&_addr.sa);
 
   PluginVC *vc = (PluginVC *) http_vc;
 
@@ -630,18 +630,6 @@ FetchSM::ext_get_user_data()
   return user_data;
 }
 
-void
-FetchSM::ext_set_proto_stack(TSClientProtoStack proto_stack)
-{
-  this->proto_stack = proto_stack;
-}
-
-TSClientProtoStack
-FetchSM::ext_get_proto_stack()
-{
-  return proto_stack;
-}
-
 TSMBuffer
 FetchSM::resp_hdr_bufp()
 {

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b7e69b0f/proxy/FetchSM.h
----------------------------------------------------------------------
diff --git a/proxy/FetchSM.h b/proxy/FetchSM.h
index d315cdb..0de5d96 100644
--- a/proxy/FetchSM.h
+++ b/proxy/FetchSM.h
@@ -49,7 +49,6 @@ public:
     header_done = 0;
     user_data = NULL;
     has_sent_header = false;
-    proto_stack = (1u << TS_PROTO_HTTP);
     req_method = TS_FETCH_METHOD_NONE;
     req_content_length = 0;
     resp_is_chunked = -1;
@@ -119,8 +118,6 @@ public:
   void ext_write_data(const void *data, size_t len);
   void ext_set_user_data(void *data);
   void* ext_get_user_data();
-  void ext_set_proto_stack(TSClientProtoStack proto_stack);
-  TSClientProtoStack ext_get_proto_stack();
 
 private:
   int InvokePlugin(int event, void*data);
@@ -166,7 +163,6 @@ private:
   int fetch_flags;
   void *user_data;
   bool has_sent_header;
-  TSClientProtoStack proto_stack;
   TSFetchMethod req_method;
   int64_t req_content_length;
   int64_t resp_content_length;

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b7e69b0f/proxy/InkAPI.cc
----------------------------------------------------------------------
diff --git a/proxy/InkAPI.cc b/proxy/InkAPI.cc
index 34845ca..d8bf08d 100644
--- a/proxy/InkAPI.cc
+++ b/proxy/InkAPI.cc
@@ -85,6 +85,9 @@
 volatile int top_stat = 0;
 RecRawStatBlock *api_rsb;
 
+// Library init functions needed for API.
+extern void ts_session_protocol_well_known_name_indices_init();
+
 // Globals for the Sessions/Transaction index registry
 volatile int next_argv_index = 0;
 
@@ -356,15 +359,6 @@ tsapi int TS_HTTP_LEN_PUT;
 tsapi int TS_HTTP_LEN_TRACE;
 tsapi int TS_HTTP_LEN_PUSH;
 
-/* TLS Next Protocol well-known protocol names. */
-
-tsapi const char * TS_NPN_PROTOCOL_HTTP_1_0 = "http/1.0";
-tsapi const char * TS_NPN_PROTOCOL_HTTP_1_1 = "http/1.1";
-tsapi const char * TS_NPN_PROTOCOL_SPDY_1   = "spdy/1";   // obsolete
-tsapi const char * TS_NPN_PROTOCOL_SPDY_2   = "spdy/2";
-tsapi const char * TS_NPN_PROTOCOL_SPDY_3   = "spdy/3";
-tsapi const char * TS_NPN_PROTOCOL_SPDY_3_1 = "spdy/3.1";
-
 /* MLoc Constants */
 tsapi const TSMLoc TS_NULL_MLOC = (TSMLoc)NULL;
 
@@ -1618,7 +1612,6 @@ api_init()
     if (sscanf(traffic_server_version, "%d.%d.%d", &ts_major_version, &ts_minor_version, &ts_patch_version) != 3) {
       Warning("Unable to parse traffic server version string '%s'\n", traffic_server_version);
     }
-
   }
 }
 
@@ -6048,6 +6041,7 @@ TSHttpAltInfoQualitySet(TSHttpAltInfo infop, float quality)
   info->m_qvalue = quality;
 }
 
+# if 0
 TSClientProtoStack
 TSClientProtoStackCreate(TSProtoType ptype, ...)
 {
@@ -6083,6 +6077,7 @@ TSClientProtoStackCreate(TSProtoType ptype, ...)
   // We can't get here.
   ink_release_assert(0);
 }
+# endif
 
 extern HttpSessionAccept *plugin_http_accept;
 extern HttpSessionAccept *plugin_http_transparent_accept;
@@ -6090,13 +6085,6 @@ extern HttpSessionAccept *plugin_http_transparent_accept;
 TSVConn
 TSHttpConnect(sockaddr const* addr)
 {
-  return TSHttpConnectWithProtoStack(addr, (1u << TS_PROTO_HTTP));
-}
-
-TSVConn
-TSHttpConnectWithProtoStack(sockaddr const* addr,
-                            TSClientProtoStack proto_stack)
-{
   sdk_assert(addr);
 
   sdk_assert(ats_is_ip(addr));
@@ -6108,9 +6096,6 @@ TSHttpConnectWithProtoStack(sockaddr const* addr,
     new_pvc->set_active_addr(addr);
     new_pvc->set_accept_cont(plugin_http_accept);
 
-    new_pvc->active_vc.proto_stack = proto_stack;
-    new_pvc->passive_vc.proto_stack = proto_stack;
-
     PluginVC *return_vc = new_pvc->connect();
 
     if (return_vc != NULL) {
@@ -6127,6 +6112,7 @@ TSHttpConnectWithProtoStack(sockaddr const* addr,
   return NULL;
 }
 
+
 TSVConn
 TSHttpConnectTransparent(sockaddr const* client_addr, sockaddr const* server_addr)
 {
@@ -7407,6 +7393,7 @@ TSFetchUserDataSet(TSFetchSM fetch_sm, void *data)
   ((FetchSM*)fetch_sm)->ext_set_user_data(data);
 }
 
+# if 0
 void
 TSFetchClientProtoStackSet(TSFetchSM fetch_sm, TSClientProtoStack proto_stack)
 {
@@ -7422,6 +7409,7 @@ TSFetchClientProtoStackGet(TSFetchSM fetch_sm)
 
   return ((FetchSM*)fetch_sm)->ext_get_proto_stack();
 }
+# endif
 
 void*
 TSFetchUserDataGet(TSFetchSM fetch_sm)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b7e69b0f/proxy/InkAPITest.cc
----------------------------------------------------------------------
diff --git a/proxy/InkAPITest.cc b/proxy/InkAPITest.cc
index 1ff7cd5..b233d35 100644
--- a/proxy/InkAPITest.cc
+++ b/proxy/InkAPITest.cc
@@ -7667,6 +7667,7 @@ REGRESSION_TEST(SDK_API_DEBUG_NAME_LOOKUPS) (RegressionTest * test, int /* atype
 }
 
 
+# if 0
 ////////////////////////////////////////////////
 // SDK_API_PROTO_STACK_CREATE
 //
@@ -7691,5 +7692,4 @@ REGRESSION_TEST(SDK_API_TSClientProtoStackCreate)(RegressionTest * t, int /* aty
  CHECK(TSClientProtoStackCreate(TS_PROTO_UDP, TS_PROTO_TCP, TS_PROTO_NULL), 3);
 
 }
-
-
+# endif

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b7e69b0f/proxy/Main.cc
----------------------------------------------------------------------
diff --git a/proxy/Main.cc b/proxy/Main.cc
index d46ebfd..e6fd0cb 100644
--- a/proxy/Main.cc
+++ b/proxy/Main.cc
@@ -1428,6 +1428,7 @@ main(int /* argc ATS_UNUSED */, char **argv)
   REC_ReadConfigInteger(res_track_memory, "proxy.config.res_track_memory");
 
   init_http_header();
+  ts_session_protocol_well_known_name_indices_init();
 
   // Sanity checks
   check_fd_limit();

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b7e69b0f/proxy/ProtocolProbeSessionAccept.cc
----------------------------------------------------------------------
diff --git a/proxy/ProtocolProbeSessionAccept.cc b/proxy/ProtocolProbeSessionAccept.cc
index 7296aa7..2c82c7c 100644
--- a/proxy/ProtocolProbeSessionAccept.cc
+++ b/proxy/ProtocolProbeSessionAccept.cc
@@ -26,7 +26,7 @@
 #include "ProtocolProbeSessionAccept.h"
 #include "Error.h"
 
-struct ProtocolProbeTrampoline : public Continuation
+struct ProtocolProbeTrampoline : public Continuation, public ProtocolProbeSessionAcceptEnums
 {
   static const size_t minimum_read_size = 1;
   static const unsigned buffer_size_index = CLIENT_CONNECTION_FIRST_READ_BUFFER_SIZE_INDEX;
@@ -44,7 +44,7 @@ struct ProtocolProbeTrampoline : public Continuation
     VIO *             vio;
     IOBufferReader *  reader;
     NetVConnection *  netvc;
-    TSProtoType       proto_type = TS_PROTO_NULL;
+    ProtoGroupKey  key = N_PROTO_GROUPS; // use this as an invalid value.
 
     vio = static_cast<VIO *>(edata);
     netvc = static_cast<NetVConnection *>(vio->vc_server);
@@ -76,22 +76,21 @@ struct ProtocolProbeTrampoline : public Continuation
     // SPDY clients have to start by sending a control frame (the high bit is set). Let's assume
     // that no other protocol could possibly ever set this bit!
     if ((uint8_t)(*reader->start()) == 0x80u) {
-      proto_type = TS_PROTO_SPDY;
+      key = PROTO_SPDY;
     } else {
-      proto_type = TS_PROTO_HTTP;
+      key = PROTO_HTTP;
     }
 
     netvc->do_io_read(this, 0, NULL); // Disable the read IO that we started.
-    netvc->proto_stack |= (1u << proto_type);
 
-    if (probeParent->endpoint[proto_type] == NULL) {
-      Warning("Unregistered protocol type %d", proto_type);
+    if (probeParent->endpoint[key] == NULL) {
+      Warning("Unregistered protocol type %d", key);
       netvc->do_io_close();
       goto done;
     }
 
     // Directly invoke the session acceptor, letting it take ownership of the input buffer.
-    probeParent->endpoint[proto_type]->accept(netvc, this->iobuf, reader);
+    probeParent->endpoint[key]->accept(netvc, this->iobuf, reader);
     delete this;
     return EVENT_CONT;
 
@@ -134,8 +133,8 @@ ProtocolProbeSessionAccept::accept(NetVConnection *, MIOBuffer *, IOBufferReader
 }
 
 void
-ProtocolProbeSessionAccept::registerEndpoint(TSProtoType proto_type, SessionAccept * ap)
+ProtocolProbeSessionAccept::registerEndpoint(ProtoGroupKey key, SessionAccept * ap)
 {
-  ink_release_assert(endpoint[proto_type] == NULL);
-  this->endpoint[proto_type] = ap;
+  ink_release_assert(endpoint[key] == NULL);
+  this->endpoint[key] = ap;
 }

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b7e69b0f/proxy/ProtocolProbeSessionAccept.h
----------------------------------------------------------------------
diff --git a/proxy/ProtocolProbeSessionAccept.h b/proxy/ProtocolProbeSessionAccept.h
index 9ad8c3d..7694653 100644
--- a/proxy/ProtocolProbeSessionAccept.h
+++ b/proxy/ProtocolProbeSessionAccept.h
@@ -26,7 +26,20 @@
 
 #include "I_SessionAccept.h"
 
-class ProtocolProbeSessionAccept: public SessionAccept
+struct ProtocolProbeSessionAcceptEnums
+{
+  /// Enumeration for related groups of protocols.
+  /// There is a child acceptor for each group which
+  /// handles finer grained stuff.
+  enum ProtoGroupKey {
+    PROTO_HTTP, ///< HTTP group (0.9-1.1)
+    PROTO_HTTP2, ///< HTTP 2 group
+    PROTO_SPDY, ///< All SPDY versions
+    N_PROTO_GROUPS ///< Size value.
+  };
+};
+
+class ProtocolProbeSessionAccept: public SessionAccept, public ProtocolProbeSessionAcceptEnums
 {
 public:
   ProtocolProbeSessionAccept(): SessionAccept(NULL)
@@ -36,7 +49,7 @@ public:
   }
   ~ProtocolProbeSessionAccept() {}
 
-  void registerEndpoint(TSProtoType proto_type, SessionAccept * ap);
+  void registerEndpoint(ProtoGroupKey key, SessionAccept * ap);
 
   void accept(NetVConnection *, MIOBuffer *, IOBufferReader*);
 
@@ -45,7 +58,13 @@ private:
   ProtocolProbeSessionAccept(const ProtocolProbeSessionAccept &); // disabled
   ProtocolProbeSessionAccept& operator =(const ProtocolProbeSessionAccept&); // disabled
 
-  SessionAccept * endpoint[sizeof(TSClientProtoStack) * CHAR_BIT];
+  /** Child acceptors, index by @c ProtoGroupKey
+
+      We pass on the actual accept to one of these after doing protocol sniffing.
+      We make it one larger and leave the last entry NULL so we don't have to
+      do range checks on the enum value.
+   */
+  SessionAccept * endpoint[N_PROTO_GROUPS+1];
 
 friend struct ProtocolProbeTrampoline;
 };

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b7e69b0f/proxy/api/ts/experimental.h
----------------------------------------------------------------------
diff --git a/proxy/api/ts/experimental.h b/proxy/api/ts/experimental.h
index 8118df5..b5742d7 100644
--- a/proxy/api/ts/experimental.h
+++ b/proxy/api/ts/experimental.h
@@ -702,23 +702,6 @@ extern "C"
   tsapi void TSFetchDestroy(TSFetchSM fetch_sm);
 
   /*
-   * Set client protocol stack in FetchSM
-   *
-   * @param fetch_sm: returned value of TSFetchCreate().
-   * @param proto_stack: client protocol stack.
-   */
-  tsapi void TSFetchClientProtoStackSet(TSFetchSM fetch_sm, TSClientProtoStack proto_stack);
-
-  /*
-   * Get client protocol stack in FetchSM
-   *
-   * @param fetch_sm: returned value of TSFetchCreate().
-   *
-   * return the client protocol stack of fetch_sm.
-   */
-  tsapi TSClientProtoStack TSFetchClientProtoStackGet(TSFetchSM fetch_sm);
-
-  /*
    * Set user-defined data in FetchSM
    */
   tsapi void TSFetchUserDataSet(TSFetchSM fetch_sm, void *data);

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b7e69b0f/proxy/api/ts/ts.h
----------------------------------------------------------------------
diff --git a/proxy/api/ts/ts.h b/proxy/api/ts/ts.h
index b327780..27d0546 100644
--- a/proxy/api/ts/ts.h
+++ b/proxy/api/ts/ts.h
@@ -1578,8 +1578,6 @@ extern "C"
   /* --------------------------------------------------------------------------
      Initiate Http Connection */
 
-  tsapi TSClientProtoStack TSClientProtoStackCreate(TSProtoType, ...);
-
   /**
       Allows the plugin to initiate an http connection. The TSVConn the
       plugin receives as the result of successful operates identically to
@@ -1599,9 +1597,6 @@ extern "C"
    */
   tsapi TSVConn TSHttpConnect(struct sockaddr const* addr);
 
-  tsapi TSVConn TSHttpConnectWithProtoStack(struct sockaddr const* addr,
-                                            TSClientProtoStack proto_stack);
-
     /* --------------------------------------------------------------------------
      Initiate Transparent Http Connection */
   /**

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b7e69b0f/proxy/http/HttpClientSession.cc
----------------------------------------------------------------------
diff --git a/proxy/http/HttpClientSession.cc b/proxy/http/HttpClientSession.cc
index 48ca3b6..d2246c8 100644
--- a/proxy/http/HttpClientSession.cc
+++ b/proxy/http/HttpClientSession.cc
@@ -144,7 +144,6 @@ HttpClientSession::new_transaction()
   transact_count++;
   DebugSsn("http_cs", "[%" PRId64 "] Starting transaction %d using sm [%" PRId64 "]", con_id, transact_count, current_reader->sm_id);
 
-  current_reader->proto_stack = client_vc->proto_stack;
   current_reader->attach_client_session(this, sm_reader);
 }
 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b7e69b0f/proxy/http/HttpProxyServerMain.cc
----------------------------------------------------------------------
diff --git a/proxy/http/HttpProxyServerMain.cc b/proxy/http/HttpProxyServerMain.cc
index c9fdbde..28386cf 100644
--- a/proxy/http/HttpProxyServerMain.cc
+++ b/proxy/http/HttpProxyServerMain.cc
@@ -149,6 +149,7 @@ MakeHttpProxyAcceptor(HttpProxyAcceptor& acceptor, HttpProxyPort& port, unsigned
   accept_opt.transport_type = port.m_type;
   accept_opt.setHostResPreference(port.m_host_res_preference);
   accept_opt.setTransparentPassthrough(port.m_transparent_passthrough);
+  accept_opt.setSessionProtocolPreference(port.m_session_protocol_preference);
 
   if (port.m_outbound_ip4.isValid()) {
     accept_opt.outbound_ip4 = port.m_outbound_ip4;
@@ -171,13 +172,15 @@ MakeHttpProxyAcceptor(HttpProxyAcceptor& acceptor, HttpProxyPort& port, unsigned
 
   ProtocolProbeSessionAccept *probe = NEW(new ProtocolProbeSessionAccept());
   HttpSessionAccept *http = NEW(new HttpSessionAccept(accept_opt));
+  if (port.m_session_protocol_preference.intersects(HTTP_PROTOCOL_SET))
+    probe->registerEndpoint(ProtocolProbeSessionAccept::PROTO_HTTP, http);
 
 #if TS_HAS_SPDY
   SpdySessionAccept *spdy = NEW(new SpdySessionAccept(http));
-  probe->registerEndpoint(TS_PROTO_SPDY, spdy);
+  if (port.m_session_protocol_preference.intersects(SPDY_PROTOCOL_SET))
+    probe->registerEndpoint(ProtocolProbeSessionAccept::PROTO_SPDY, spdy);
 #endif
 
-  probe->registerEndpoint(TS_PROTO_HTTP, http);
 
   if (port.isSSL()) {
     SSLNextProtocolAccept *ssl = NEW(new SSLNextProtocolAccept(probe));
@@ -190,13 +193,17 @@ MakeHttpProxyAcceptor(HttpProxyAcceptor& acceptor, HttpProxyPort& port, unsigned
     // http/1.0, http/1.1, spdy/3, spdy/3.1
 
     // HTTP
-    ssl->registerEndpoint(TS_NPN_PROTOCOL_HTTP_1_0, http);
-    ssl->registerEndpoint(TS_NPN_PROTOCOL_HTTP_1_1, http);
+    if (port.m_session_protocol_preference.contains(TS_NPN_PROTOCOL_INDEX_HTTP_1_0))
+      ssl->registerEndpoint(TS_NPN_PROTOCOL_HTTP_1_0, http);
+    if (port.m_session_protocol_preference.contains(TS_NPN_PROTOCOL_INDEX_HTTP_1_1))
+      ssl->registerEndpoint(TS_NPN_PROTOCOL_HTTP_1_1, http);
 
     // SPDY
 #if TS_HAS_SPDY
-    ssl->registerEndpoint(TS_NPN_PROTOCOL_SPDY_3, spdy);
-    ssl->registerEndpoint(TS_NPN_PROTOCOL_SPDY_3_1, spdy);
+    if (port.m_session_protocol_preference.contains(TS_NPN_PROTOCOL_INDEX_SPDY_3))
+      ssl->registerEndpoint(TS_NPN_PROTOCOL_SPDY_3, spdy);
+    if (port.m_session_protocol_preference.contains(TS_NPN_PROTOCOL_INDEX_SPDY_3_1))
+      ssl->registerEndpoint(TS_NPN_PROTOCOL_SPDY_3_1, spdy);
 #endif
 
     ink_scoped_mutex lock(ssl_plugin_mutex);

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b7e69b0f/proxy/http/HttpSM.cc
----------------------------------------------------------------------
diff --git a/proxy/http/HttpSM.cc b/proxy/http/HttpSM.cc
index 7edca5d..9066968 100644
--- a/proxy/http/HttpSM.cc
+++ b/proxy/http/HttpSM.cc
@@ -303,7 +303,7 @@ static int next_sm_id = 0;
 
 
 HttpSM::HttpSM()
-  : Continuation(NULL), proto_stack(1u << TS_PROTO_HTTP), sm_id(-1), magic(HTTP_SM_MAGIC_DEAD),
+  : Continuation(NULL), sm_id(-1), magic(HTTP_SM_MAGIC_DEAD),
     //YTS Team, yamsat Plugin
     enable_redirection(false), redirect_url(NULL), redirect_url_len(0), redirection_tries(0),
     transfered_bytes(0), post_failed(false), debug_on(false),

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b7e69b0f/proxy/http/HttpSM.h
----------------------------------------------------------------------
diff --git a/proxy/http/HttpSM.h b/proxy/http/HttpSM.h
index d5675d3..56b5077 100644
--- a/proxy/http/HttpSM.h
+++ b/proxy/http/HttpSM.h
@@ -264,7 +264,6 @@ public:
   bool is_private();
   bool is_redirect_required();
 
-  TSClientProtoStack proto_stack;
   int64_t sm_id;
   unsigned int magic;
 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b7e69b0f/proxy/http/HttpSessionAccept.h
----------------------------------------------------------------------
diff --git a/proxy/http/HttpSessionAccept.h b/proxy/http/HttpSessionAccept.h
index 67b7c62..05033d3 100644
--- a/proxy/http/HttpSessionAccept.h
+++ b/proxy/http/HttpSessionAccept.h
@@ -29,6 +29,7 @@
 #include "HttpConfig.h"
 #include "HTTP.h"
 #include "I_Net.h"
+#include <records/I_RecHttp.h>
 
 namespace detail {
   /** Options for @c HttpSessionAccept.
@@ -86,6 +87,10 @@ namespace detail {
     HostResPreferenceOrder host_res_preference;
     /// Set the host query preference.
     self& setHostResPreference(HostResPreferenceOrder const);
+    /// Acceptable session protocols.
+    SessionProtocolSet session_protocol_preference;
+    /// Set the session protocol preference.
+    self& setSessionProtocolPreference(SessionProtocolSet const&);
   };
 
   inline HttpSessionAcceptOptions::HttpSessionAcceptOptions()
@@ -147,6 +152,12 @@ namespace detail {
     memcpy(host_res_preference, order, sizeof(host_res_preference));
     return *this;
   }
+
+  inline HttpSessionAcceptOptions&
+  HttpSessionAcceptOptions::setSessionProtocolPreference(SessionProtocolSet const& sp_set) {
+    session_protocol_preference = sp_set;
+    return *this;
+  }
 }
 
 /**

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b7e69b0f/proxy/logging/Log.cc
----------------------------------------------------------------------
diff --git a/proxy/logging/Log.cc b/proxy/logging/Log.cc
index 11f8311..a862e0e 100644
--- a/proxy/logging/Log.cc
+++ b/proxy/logging/Log.cc
@@ -365,6 +365,7 @@ Log::init_fields()
   global_field_list.add (field, false);
   ink_hash_table_insert (field_symbol_hash, "caun", field);
 
+# if 0
   Ptr<LogFieldAliasTable> proto_type_map = make_ptr(NEW(new LogFieldAliasTable));
   proto_type_map->init(7,
                        // Transport protocols
@@ -384,6 +385,7 @@ Log::init_fields()
                            (Ptr<LogFieldAliasMap>) proto_type_map));
   global_field_list.add(field, false);
   ink_hash_table_insert(field_symbol_hash, "cps", field);
+# endif
 
   field = NEW(new LogField("client_req_timestamp_sec", "cqts",
                            LogField::sINT,

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b7e69b0f/proxy/logging/LogAccess.cc
----------------------------------------------------------------------
diff --git a/proxy/logging/LogAccess.cc b/proxy/logging/LogAccess.cc
index 20121f7..968762e 100644
--- a/proxy/logging/LogAccess.cc
+++ b/proxy/logging/LogAccess.cc
@@ -1311,6 +1311,7 @@ LogAccess::unmarshal_cache_write_code(char **buf, char *dest, int len, Ptr<LogFi
   return (LogAccess::unmarshal_with_map(unmarshal_int(buf), dest, len, map, "UNKNOWN_CACHE_WRITE_CODE"));
 }
 
+# if 0
 int
 LogAccess::unmarshal_client_protocol_stack(char **buf, char *dest, int len, Ptr<LogFieldAliasMap> map)
 {
@@ -1345,6 +1346,7 @@ LogAccess::unmarshal_client_protocol_stack(char **buf, char *dest, int len, Ptr<
 
   return (len - left_len);
 }
+# endif
 
 int
 LogAccess::unmarshal_record(char **buf, char *dest, int len)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b7e69b0f/proxy/logging/LogAccessHttp.cc
----------------------------------------------------------------------
diff --git a/proxy/logging/LogAccessHttp.cc b/proxy/logging/LogAccessHttp.cc
index 4b8d39c..a8dad70 100644
--- a/proxy/logging/LogAccessHttp.cc
+++ b/proxy/logging/LogAccessHttp.cc
@@ -206,7 +206,7 @@ LogAccessHttp::set_client_req_url_path(char *buf, int len)
 
 /*-------------------------------------------------------------------------
   -------------------------------------------------------------------------*/
-
+# if 0
 int
 LogAccessHttp::marshal_client_protocol_stack(char *buf)
 {
@@ -215,7 +215,7 @@ LogAccessHttp::marshal_client_protocol_stack(char *buf)
   }
   return INK_MIN_ALIGN;
 }
-
+# endif
 int
 LogAccessHttp::marshal_client_host_ip(char *buf)
 {

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b7e69b0f/proxy/logging/LogAccessHttp.h
----------------------------------------------------------------------
diff --git a/proxy/logging/LogAccessHttp.h b/proxy/logging/LogAccessHttp.h
index e487326..53a0ff5 100644
--- a/proxy/logging/LogAccessHttp.h
+++ b/proxy/logging/LogAccessHttp.h
@@ -58,7 +58,7 @@ public:
   virtual int marshal_client_host_ip(char *);   // STR
   virtual int marshal_client_host_port(char *); // INT
   virtual int marshal_client_auth_user_name(char *);    // STR
-  virtual int marshal_client_protocol_stack(char *);    // INT
+  //  virtual int marshal_client_protocol_stack(char *);    // INT
   virtual int marshal_client_req_text(char *);  // STR
   virtual int marshal_client_req_http_method(char *);   // INT
   virtual int marshal_client_req_url(char *);   // STR

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b7e69b0f/proxy/spdy/SpdyCallbacks.cc
----------------------------------------------------------------------
diff --git a/proxy/spdy/SpdyCallbacks.cc b/proxy/spdy/SpdyCallbacks.cc
index c5712f4..59dd443 100644
--- a/proxy/spdy/SpdyCallbacks.cc
+++ b/proxy/spdy/SpdyCallbacks.cc
@@ -188,12 +188,6 @@ spdy_fetcher_launch(SpdyRequest *req, TSFetchMethod method)
   TSFetchUserDataSet(req->fetch_sm, req);
 
   //
-  // Set client protocol stack in FetchSM that needed by logging module
-  //
-  NetVConnection *netvc = (NetVConnection *)sm->vc;
-  TSFetchClientProtoStackSet(req->fetch_sm, netvc->proto_stack);
-
-  //
   // Set header list
   //
   for (size_t i = 0; i < req->headers.size(); i++) {

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b7e69b0f/proxy/spdy/SpdyCommon.cc
----------------------------------------------------------------------
diff --git a/proxy/spdy/SpdyCommon.cc b/proxy/spdy/SpdyCommon.cc
index 58ba1d9..775923d 100644
--- a/proxy/spdy/SpdyCommon.cc
+++ b/proxy/spdy/SpdyCommon.cc
@@ -38,20 +38,11 @@ http_date(time_t t)
 int
 spdy_config_load()
 {
-  SPDY_CFG.nr_accept_threads = 1;
-  SPDY_CFG.accept_no_activity_timeout = 30;
-  SPDY_CFG.no_activity_timeout_in = 30;
-  SPDY_CFG.spdy.verbose = false;
-  SPDY_CFG.spdy.enable_tls = false;
-  SPDY_CFG.spdy.keep_host_port = false;
-  //
-  // SPDY plugin will share the same port number with
-  // http server, unless '--port' is given.
-  //
-  SPDY_CFG.spdy.serv_port = -1;
-//  SPDY_CFG.spdy.max_concurrent_streams = 1000;
-  REC_EstablishStaticConfigInt32(SPDY_CFG.spdy.max_concurrent_streams, "proxy.config.spdy.client.max_concurrent_streams");
-  SPDY_CFG.spdy.initial_window_size = (64 << 10);
+  REC_EstablishStaticConfigInt32(SPDY_CFG.spdy.max_concurrent_streams, "proxy.config.spdy.max_concurrent_streams_in");
+  REC_EstablishStaticConfigBool(SPDY_CFG.spdy.verbose, "proxy.config.spdy.verbose_in");
+  REC_EstablishStaticConfigInt32(SPDY_CFG.no_activity_timeout_in, "proxy.config.spdy.no_activity_timeout_in");
+  REC_EstablishStaticConfigInt32(SPDY_CFG.accept_no_activity_timeout, "proxy.config.spdy.accept_no_activity_timeout");
+  REC_EstablishStaticConfigInt32(SPDY_CFG.spdy.initial_window_size, "proxy.config.spdy.initial_window_size_in");
 
   spdy_callbacks_init(&SPDY_CFG.spdy.callbacks);
 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/b7e69b0f/proxy/spdy/SpdyCommon.h
----------------------------------------------------------------------
diff --git a/proxy/spdy/SpdyCommon.h b/proxy/spdy/SpdyCommon.h
index 33bab9a..cb32672 100644
--- a/proxy/spdy/SpdyCommon.h
+++ b/proxy/spdy/SpdyCommon.h
@@ -57,19 +57,15 @@ using namespace std;
 
 struct SpdyConfig {
   bool verbose;
-  bool enable_tls;
-  bool keep_host_port;
-  int serv_port;
   int32_t max_concurrent_streams;
-  int initial_window_size;
+  int32_t initial_window_size;
   spdylay_session_callbacks callbacks;
 };
 
 struct Config {
   SpdyConfig spdy;
-  int nr_accept_threads;
-  int accept_no_activity_timeout;
-  int no_activity_timeout_in;
+  int32_t accept_no_activity_timeout;
+  int32_t no_activity_timeout_in;
 };
 
 // Spdy Name/Value pairs


Re: git commit: TS-2830 Make SPDY configurable.

Posted by James Peach <jp...@apache.org>.
On May 21, 2014, at 6:24 PM, amc@apache.org wrote:

> Repository: trafficserver
> Updated Branches:
>  refs/heads/master 24d860c05 -> b7e69b0fa
> 
> 
> TS-2830 Make SPDY configurable.
[snip]
> cts only new SPDY connections, not existing connects.
> +
> +.. ts:cv:: CONFIG proxy.config.spdy.verbose_in INT 65536
>    :reloadable:
> 
> -   Set the maximum number of concurrent streams per client connection.
> +   Set the verbose flag for SPDY streams on inbound connections.

Huh? Do we have to keep this?

Re: git commit: TS-2830 Make SPDY configurable.

Posted by James Peach <jp...@apache.org>.
On May 21, 2014, at 6:24 PM, amc@apache.org wrote:

> Repository: trafficserver
> Updated Branches:
>  refs/heads/master 24d860c05 -> b7e69b0fa
> 
> 
> TS-2830 Make SPDY configurable.
[snip]
> cts only new SPDY connections, not existing connects.
> +
> +.. ts:cv:: CONFIG proxy.config.spdy.verbose_in INT 65536
>    :reloadable:
> 
> -   Set the maximum number of concurrent streams per client connection.
> +   Set the verbose flag for SPDY streams on inbound connections.

Huh? Do we have to keep this?