00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 # include <records/I_RecCore.h>
00025 # include <records/I_RecHttp.h>
00026 # include <ts/ink_defs.h>
00027 # include <ts/Tokenizer.h>
00028 # include <strings.h>
00029 
00030 SessionProtocolNameRegistry globalSessionProtocolNameRegistry;
00031 
00032 
00033 
00034 
00035 
00036 const char * const TS_NPN_PROTOCOL_HTTP_0_9 = "http/0.9";
00037 const char * const TS_NPN_PROTOCOL_HTTP_1_0 = "http/1.0";
00038 const char * const TS_NPN_PROTOCOL_HTTP_1_1 = "http/1.1";
00039 const char * const TS_NPN_PROTOCOL_HTTP_2_0 = "h2-12";    
00040 const char * const TS_NPN_PROTOCOL_SPDY_1   = "spdy/1";   
00041 const char * const TS_NPN_PROTOCOL_SPDY_2   = "spdy/2";
00042 const char * const TS_NPN_PROTOCOL_SPDY_3   = "spdy/3";
00043 const char * const TS_NPN_PROTOCOL_SPDY_3_1 = "spdy/3.1";
00044 
00045 const char * const TS_NPN_PROTOCOL_GROUP_HTTP = "http";
00046 const char * const TS_NPN_PROTOCOL_GROUP_HTTP2 = "http2";
00047 const char * const TS_NPN_PROTOCOL_GROUP_SPDY = "spdy";
00048 
00049 
00050 int TS_NPN_PROTOCOL_INDEX_HTTP_0_9 = SessionProtocolNameRegistry::INVALID;
00051 int TS_NPN_PROTOCOL_INDEX_HTTP_1_0 = SessionProtocolNameRegistry::INVALID;
00052 int TS_NPN_PROTOCOL_INDEX_HTTP_1_1 = SessionProtocolNameRegistry::INVALID;
00053 int TS_NPN_PROTOCOL_INDEX_HTTP_2_0 = SessionProtocolNameRegistry::INVALID;
00054 int TS_NPN_PROTOCOL_INDEX_SPDY_1 = SessionProtocolNameRegistry::INVALID;
00055 int TS_NPN_PROTOCOL_INDEX_SPDY_2 = SessionProtocolNameRegistry::INVALID;
00056 int TS_NPN_PROTOCOL_INDEX_SPDY_3 = SessionProtocolNameRegistry::INVALID;
00057 int TS_NPN_PROTOCOL_INDEX_SPDY_3_1 = SessionProtocolNameRegistry::INVALID;
00058 
00059 
00060 SessionProtocolSet HTTP_PROTOCOL_SET;
00061 SessionProtocolSet SPDY_PROTOCOL_SET;
00062 SessionProtocolSet HTTP2_PROTOCOL_SET;
00063 SessionProtocolSet DEFAULT_NON_TLS_SESSION_PROTOCOL_SET;
00064 SessionProtocolSet DEFAULT_TLS_SESSION_PROTOCOL_SET;
00065 
00066 void RecHttpLoadIp(char const* value_name, IpAddr& ip4, IpAddr& ip6)
00067 {
00068   char value[1024];
00069   ip4.invalidate();
00070   ip6.invalidate();
00071   if (REC_ERR_OKAY == RecGetRecordString(value_name, value, sizeof(value))) {
00072     Tokenizer tokens(", ");
00073     int n_addrs = tokens.Initialize(value);
00074     for (int i = 0 ; i < n_addrs ; ++i ) {
00075       char const* host = tokens[i];
00076       IpEndpoint tmp4, tmp6;
00077       
00078       
00079       if (0 == ats_ip_getbestaddrinfo(host, &tmp4, &tmp6)) {
00080         if (ats_is_ip4(&tmp4)) {
00081           if (!ip4.isValid()) ip4 = tmp4;
00082           else Warning("'%s' specifies more than one IPv4 address, ignoring %s.", value_name, host);
00083         }
00084         if (ats_is_ip6(&tmp6)) {
00085           if (!ip6.isValid()) ip6 = tmp6;
00086           else Warning("'%s' specifies more than one IPv6 address, ignoring %s.", value_name, host);
00087         }
00088       } else {
00089         Warning("'%s' has an value '%s' that is not recognized as an IP address, ignored.", value_name, host);
00090       }
00091     }
00092   }
00093 }
00094 
00095 
00096 char const* const HttpProxyPort::DEFAULT_VALUE = "8080";
00097 
00098 char const* const HttpProxyPort::PORTS_CONFIG_NAME = "proxy.config.http.server_ports";
00099 
00100 
00101 
00102 
00103 
00104 char const* const HttpProxyPort::OPT_FD_PREFIX = "fd";
00105 char const* const HttpProxyPort::OPT_OUTBOUND_IP_PREFIX = "ip-out";
00106 char const* const HttpProxyPort::OPT_INBOUND_IP_PREFIX = "ip-in";
00107 char const* const HttpProxyPort::OPT_HOST_RES_PREFIX = "ip-resolve";
00108 char const* const HttpProxyPort::OPT_PROTO_PREFIX = "proto";
00109 
00110 char const* const HttpProxyPort::OPT_IPV6 = "ipv6";
00111 char const* const HttpProxyPort::OPT_IPV4 = "ipv4";
00112 char const* const HttpProxyPort::OPT_TRANSPARENT_INBOUND = "tr-in";
00113 char const* const HttpProxyPort::OPT_TRANSPARENT_OUTBOUND = "tr-out";
00114 char const* const HttpProxyPort::OPT_TRANSPARENT_FULL = "tr-full";
00115 char const* const HttpProxyPort::OPT_TRANSPARENT_PASSTHROUGH = "tr-pass";
00116 char const* const HttpProxyPort::OPT_SSL = "ssl";
00117 char const* const HttpProxyPort::OPT_PLUGIN = "plugin";
00118 char const* const HttpProxyPort::OPT_BLIND_TUNNEL = "blind";
00119 char const* const HttpProxyPort::OPT_COMPRESSED = "compressed";
00120 
00121 
00122 namespace {
00123   
00124   size_t const OPT_FD_PREFIX_LEN = strlen(HttpProxyPort::OPT_FD_PREFIX);
00125   size_t const OPT_OUTBOUND_IP_PREFIX_LEN = strlen(HttpProxyPort::OPT_OUTBOUND_IP_PREFIX);
00126   size_t const OPT_INBOUND_IP_PREFIX_LEN = strlen(HttpProxyPort::OPT_INBOUND_IP_PREFIX);
00127   size_t const OPT_HOST_RES_PREFIX_LEN = strlen(HttpProxyPort::OPT_HOST_RES_PREFIX);
00128   size_t const OPT_PROTO_PREFIX_LEN = strlen(HttpProxyPort::OPT_PROTO_PREFIX);
00129 }
00130 
00131 namespace {
00132 
00133 
00134 
00135 
00136 
00137   HttpProxyPort::Group GLOBAL_DATA;
00138 }
00139 HttpProxyPort::Group& HttpProxyPort::m_global = GLOBAL_DATA;
00140 
00141 HttpProxyPort::HttpProxyPort()
00142   : m_fd(ts::NO_FD)
00143   , m_type(TRANSPORT_DEFAULT)
00144   , m_port(0)
00145   , m_family(AF_INET)
00146   , m_inbound_transparent_p(false)
00147   , m_outbound_transparent_p(false)
00148   , m_transparent_passthrough(false)
00149 {
00150   memcpy(m_host_res_preference, host_res_default_preference_order, sizeof(m_host_res_preference));
00151 }
00152 
00153 bool HttpProxyPort::hasSSL(Group const& ports) {
00154   bool zret = false;
00155   for ( int i = 0 , n = ports.length() ; i < n && !zret ; ++i ) {
00156     if (ports[i].isSSL()) zret = true;
00157   }
00158   return zret;
00159 }
00160 
00161 HttpProxyPort* HttpProxyPort::findHttp(Group const& ports, uint16_t family) {
00162   bool check_family_p = ats_is_ip(family);
00163   self* zret = 0;
00164   for ( int i = 0 , n = ports.length() ; i < n && !zret ; ++i ) {
00165     HttpProxyPort& p = ports[i];
00166     if (p.m_port && 
00167         TRANSPORT_DEFAULT == p.m_type && 
00168         ( !check_family_p || p.m_family == family) 
00169         )
00170       zret = &p;;
00171   }
00172   return zret;
00173 }
00174 
00175 char const*
00176 HttpProxyPort::checkPrefix(char const* src, char const* prefix, size_t prefix_len) {
00177   char const* zret = 0;
00178   if (0 == strncasecmp(prefix, src, prefix_len)) {
00179     src += prefix_len;
00180     if ('-' == *src || '=' == *src) ++src; 
00181     zret = src;
00182   }
00183   return zret;
00184 }
00185 
00186 bool
00187 HttpProxyPort::loadConfig(Vec<self>& entries) {
00188   char* text;
00189   bool found_p;
00190 
00191   text = REC_readString(PORTS_CONFIG_NAME, &found_p);
00192   if (found_p) self::loadValue(entries, text);
00193   ats_free(text);
00194 
00195   return 0 < entries.length();
00196 }
00197 
00198 bool
00199 HttpProxyPort::loadDefaultIfEmpty(Group& ports) {
00200   if (0 == ports.length())
00201     self::loadValue(ports, DEFAULT_VALUE);
00202 
00203   return 0 < ports.length();
00204 }
00205 
00206 bool
00207 HttpProxyPort::loadValue(Vec<self>& ports, char const* text) {
00208   unsigned old_port_length = ports.length(); 
00209   if (text && *text) {
00210     Tokenizer tokens(", ");
00211     int n_ports = tokens.Initialize(text);
00212     if (n_ports > 0) {
00213       for ( int p = 0 ; p < n_ports ; ++p ) {
00214         char const* elt = tokens[p];
00215         HttpProxyPort entry;
00216         if (entry.processOptions(elt)) ports.push_back(entry);
00217         else Warning("No valid definition was found in proxy port configuration element '%s'", elt);
00218       }
00219     }
00220   }
00221   return ports.length() > old_port_length; 
00222 }
00223 
00224 bool
00225 HttpProxyPort::processOptions(char const* opts) {
00226   bool zret = false; 
00227   bool af_set_p = false; 
00228   bool host_res_set_p = false; 
00229   bool sp_set_p = false; 
00230   bool bracket_p = false; 
00231   char const* value; 
00232   IpAddr ip; 
00233   Vec<char*> values; 
00234 
00235   
00236   size_t opts_len = strlen(opts) + 1;
00237   char* text = static_cast<char*>(alloca(opts_len));
00238   memcpy(text, opts, opts_len);
00239 
00240   
00241   char* token = 0;
00242   for (char* spot = text ; *spot ; ++spot ) {
00243     if (bracket_p) {
00244       if (']' == *spot) bracket_p = false;
00245     } else if (':' == *spot) {
00246       *spot = 0;
00247       token = 0;
00248     } else {
00249       if (! token) {
00250         token = spot;
00251         values.push_back(token);
00252       }
00253       if ('[' == *spot) bracket_p = true;
00254     }
00255   }
00256   if (bracket_p) {
00257     Warning("Invalid port descriptor '%s' - left bracket without closing right bracket", opts);
00258     return zret;
00259   }
00260 
00261   for ( int i = 0, n_items = values.length() ; i < n_items ; ++i) {
00262     char const* item = values[i];
00263     if (isdigit(item[0])) { 
00264       char* ptr;
00265       int port = strtoul(item, &ptr, 10);
00266       if (ptr == item) {
00267         
00268         Warning("Mangled port value '%s' in port configuration '%s'", item, opts);
00269       } else if (port <= 0 || 65536 <= port) {
00270         Warning("Port value '%s' out of range (1..65535) in port configuration '%s'", item, opts);
00271       } else {
00272         m_port = port;
00273         zret = true;
00274       }
00275     } else if (0 != (value = this->checkPrefix(item, OPT_FD_PREFIX, OPT_FD_PREFIX_LEN))) {
00276       char* ptr; 
00277       int fd = strtoul(value, &ptr, 10);
00278       if (ptr == value) {
00279         Warning("Mangled file descriptor value '%s' in port descriptor '%s'", item, opts);
00280       } else {
00281         m_fd = fd;
00282         zret = true;
00283       }
00284     } else if (0 != (value = this->checkPrefix(item, OPT_INBOUND_IP_PREFIX, OPT_INBOUND_IP_PREFIX_LEN))) {
00285       if (0 == ip.load(value))
00286         m_inbound_ip = ip;
00287       else
00288         Warning("Invalid IP address value '%s' in port descriptor '%s'",
00289           item, opts
00290         );
00291     } else if (0 != (value = this->checkPrefix(item, OPT_OUTBOUND_IP_PREFIX, OPT_OUTBOUND_IP_PREFIX_LEN))) {
00292       if (0 == ip.load(value))
00293         this->outboundIp(ip.family()) = ip;
00294       else
00295         Warning("Invalid IP address value '%s' in port descriptor '%s'", item, opts);
00296     } else if (0 == strcasecmp(OPT_COMPRESSED, item)) {
00297       m_type = TRANSPORT_COMPRESSED;
00298     } else if (0 == strcasecmp(OPT_BLIND_TUNNEL, item)) {
00299       m_type = TRANSPORT_BLIND_TUNNEL;
00300     } else if (0 == strcasecmp(OPT_IPV6, item)) {
00301       m_family = AF_INET6;
00302       af_set_p = true;
00303     } else if (0 == strcasecmp(OPT_IPV4, item)) {
00304       m_family = AF_INET;
00305       af_set_p = true;
00306     } else if (0 == strcasecmp(OPT_SSL, item)) {
00307       m_type = TRANSPORT_SSL;
00308     } else if (0 == strcasecmp(OPT_PLUGIN, item)) {
00309       m_type = TRANSPORT_PLUGIN;
00310     } else if (0 == strcasecmp(OPT_TRANSPARENT_INBOUND, item)) {
00311 # if TS_USE_TPROXY
00312       m_inbound_transparent_p = true;
00313 # else
00314       Warning("Transparency requested [%s] in port descriptor '%s' but TPROXY was not configured.", item, opts);
00315 # endif
00316     } else if (0 == strcasecmp(OPT_TRANSPARENT_OUTBOUND, item)) {
00317 # if TS_USE_TPROXY
00318       m_outbound_transparent_p = true;
00319 # else
00320       Warning("Transparency requested [%s] in port descriptor '%s' but TPROXY was not configured.", item, opts);
00321 # endif
00322     } else if (0 == strcasecmp(OPT_TRANSPARENT_FULL, item)) {
00323 # if TS_USE_TPROXY
00324       m_inbound_transparent_p = true;
00325       m_outbound_transparent_p = true;
00326 # else
00327       Warning("Transparency requested [%s] in port descriptor '%s' but TPROXY was not configured.", item, opts);
00328 # endif
00329     } else if (0 == strcasecmp(OPT_TRANSPARENT_PASSTHROUGH, item)) {
00330 # if TS_USE_TPROXY
00331       m_transparent_passthrough = true;
00332 # else
00333       Warning("Transparent pass-through requested [%s] in port descriptor '%s' but TPROXY was not configured.", item, opts);
00334 # endif
00335     } else if (0 != (value = this->checkPrefix(item, OPT_HOST_RES_PREFIX, OPT_HOST_RES_PREFIX_LEN))) {
00336       this->processFamilyPreference(value);
00337       host_res_set_p = true;
00338     } else if (0 != (value = this->checkPrefix(item, OPT_PROTO_PREFIX, OPT_PROTO_PREFIX_LEN))) {
00339       this->processSessionProtocolPreference(value);
00340       sp_set_p = true;
00341     } else {
00342       Warning("Invalid option '%s' in proxy port configuration '%s'", item, opts);
00343     }
00344   }
00345 
00346   bool in_ip_set_p = m_inbound_ip.isValid();
00347 
00348   if (af_set_p) {
00349     if (in_ip_set_p && m_family != m_inbound_ip.family()) {
00350       Warning("Invalid port descriptor '%s' - the inbound adddress family [%s] is not the same type as the explicit family value [%s]",
00351         opts, ats_ip_family_name(m_inbound_ip.family()), ats_ip_family_name(m_family));
00352       zret = false;
00353     }
00354   } else if (in_ip_set_p) {
00355     m_family = m_inbound_ip.family(); 
00356   }
00357 
00358   
00359   if (m_outbound_transparent_p) {
00360     if (host_res_set_p &&
00361         (m_host_res_preference[0] != HOST_RES_PREFER_CLIENT ||
00362          m_host_res_preference[1] != HOST_RES_PREFER_NONE
00363     )) {
00364       Warning("Outbound transparent port '%s' requires the IP address resolution ordering '%s,%s'. "
00365               "This is set automatically and does not need to be set explicitly."
00366               , opts
00367               , HOST_RES_PREFERENCE_STRING[HOST_RES_PREFER_CLIENT]
00368               , HOST_RES_PREFERENCE_STRING[HOST_RES_PREFER_NONE]
00369         );
00370     }
00371     m_host_res_preference[0] = HOST_RES_PREFER_CLIENT;
00372     m_host_res_preference[1] = HOST_RES_PREFER_NONE;
00373   }
00374 
00375   
00376   if (m_transparent_passthrough && !m_inbound_transparent_p) {
00377     Warning("Port descriptor '%s' has transparent pass-through enabled without inbound transparency, this will be ignored.", opts);
00378     m_transparent_passthrough = false;
00379   }
00380 
00381   
00382   if (!sp_set_p)
00383     m_session_protocol_preference = this->isSSL()
00384       ? DEFAULT_TLS_SESSION_PROTOCOL_SET
00385       : DEFAULT_NON_TLS_SESSION_PROTOCOL_SET
00386       ;
00387 
00388   return zret;
00389 }
00390 
00391 void
00392 HttpProxyPort::processFamilyPreference(char const* value) {
00393   parse_host_res_preference(value, m_host_res_preference);
00394 }
00395 
00396 void
00397 HttpProxyPort::processSessionProtocolPreference(char const* value) {
00398   m_session_protocol_preference.markAllOut();
00399   globalSessionProtocolNameRegistry.markIn(value, m_session_protocol_preference);
00400 }
00401 
00402 void
00403 SessionProtocolNameRegistry::markIn(char const* value, SessionProtocolSet& sp_set) {
00404   int n; 
00405   Tokenizer tokens(" ;|,:");
00406  
00407   n = tokens.Initialize(value);
00408 
00409   for ( int i = 0 ; i < n ; ++i ) {
00410     char const* elt = tokens[i];
00411     
00412 
00413     if (0 == strcasecmp(elt, TS_NPN_PROTOCOL_GROUP_HTTP)) {
00414       sp_set.markIn(HTTP_PROTOCOL_SET);
00415     } else if (0 == strcasecmp(elt, TS_NPN_PROTOCOL_GROUP_SPDY)) {
00416       sp_set.markIn(SPDY_PROTOCOL_SET);
00417     } else if (0 == strcasecmp(elt, TS_NPN_PROTOCOL_GROUP_HTTP2)) {
00418       sp_set.markIn(HTTP2_PROTOCOL_SET);
00419     } else { 
00420       int idx = globalSessionProtocolNameRegistry.toIndex(elt);
00421       sp_set.markIn(idx);
00422     }
00423   }
00424 }
00425 
00426 int
00427 HttpProxyPort::print(char* out, size_t n) {
00428   size_t zret = 0; 
00429   ip_text_buffer ipb;
00430   bool need_colon_p = false;
00431 
00432   if (m_inbound_ip.isValid()) {
00433     zret += snprintf(out+zret, n-zret, "%s=[%s]",
00434       OPT_INBOUND_IP_PREFIX,
00435       m_inbound_ip.toString(ipb, sizeof(ipb))
00436     );
00437     need_colon_p = true;
00438   }
00439   if (zret >= n) return n;
00440 
00441   if (m_outbound_ip4.isValid()) {
00442     if (need_colon_p) out[zret++] = ':';
00443     zret += snprintf(out+zret, n-zret, "%s=[%s]",
00444       OPT_OUTBOUND_IP_PREFIX,
00445       m_outbound_ip4.toString(ipb, sizeof(ipb))
00446     );
00447     need_colon_p = true;
00448   }
00449   if (zret >= n) return n;
00450 
00451   if (m_outbound_ip6.isValid()) {
00452     if (need_colon_p) out[zret++] = ':';
00453     zret += snprintf(out+zret, n-zret, "%s=[%s]",
00454       OPT_OUTBOUND_IP_PREFIX,
00455       m_outbound_ip6.toString(ipb, sizeof(ipb))
00456     );
00457     need_colon_p = true;
00458   }
00459   if (zret >= n) return n;
00460 
00461   if (0 != m_port) {
00462     if (need_colon_p) out[zret++] = ':';
00463     zret += snprintf(out+zret, n-zret, "%d", m_port);
00464     need_colon_p = true;
00465   }
00466   if (zret >= n) return n;
00467 
00468   if (ts::NO_FD != m_fd) {
00469     if (need_colon_p) out[zret++] = ':';
00470     zret += snprintf(out+zret, n-zret, "fd=%d", m_fd);
00471   }
00472   if (zret >= n) return n;
00473 
00474   
00475   
00476 
00477   if (AF_INET6 == m_family)
00478     zret += snprintf(out+zret, n-zret, ":%s", OPT_IPV6);
00479   if (zret >= n) return n;
00480 
00481   if (TRANSPORT_BLIND_TUNNEL == m_type)
00482     zret += snprintf(out+zret, n-zret, ":%s", OPT_BLIND_TUNNEL);
00483   else if (TRANSPORT_SSL == m_type)
00484     zret += snprintf(out+zret, n-zret, ":%s", OPT_SSL);
00485   else if (TRANSPORT_PLUGIN == m_type)
00486     zret += snprintf(out+zret, n-zret, ":%s", OPT_PLUGIN);
00487   else if (TRANSPORT_COMPRESSED == m_type)
00488     zret += snprintf(out+zret, n-zret, ":%s", OPT_COMPRESSED);
00489   if (zret >= n) return n;
00490 
00491   if (m_outbound_transparent_p && m_inbound_transparent_p)
00492     zret += snprintf(out+zret, n-zret, ":%s", OPT_TRANSPARENT_FULL);
00493   else if (m_inbound_transparent_p)
00494     zret += snprintf(out+zret, n-zret, ":%s", OPT_TRANSPARENT_INBOUND);
00495   else if (m_outbound_transparent_p)
00496     zret += snprintf(out+zret, n-zret, ":%s", OPT_TRANSPARENT_OUTBOUND);
00497 
00498   if (m_transparent_passthrough)
00499     zret += snprintf(out+zret, n-zret, ":%s", OPT_TRANSPARENT_PASSTHROUGH);
00500 
00501   
00502 
00503 
00504 
00505   if (!m_outbound_transparent_p &&
00506       0 != memcmp(m_host_res_preference, host_res_default_preference_order, sizeof(m_host_res_preference))) {
00507     zret += snprintf(out+zret, n-zret, ":%s=", OPT_HOST_RES_PREFIX);
00508     zret += ts_host_res_order_to_string(m_host_res_preference, out+zret, n-zret);
00509   }
00510 
00511   
00512   
00513   SessionProtocolSet sp_set = m_session_protocol_preference; 
00514   need_colon_p = true; 
00515   if (sp_set == DEFAULT_NON_TLS_SESSION_PROTOCOL_SET && !this->isSSL()) {
00516     sp_set.markOut(DEFAULT_NON_TLS_SESSION_PROTOCOL_SET);
00517   } else if (sp_set == DEFAULT_TLS_SESSION_PROTOCOL_SET && this->isSSL()) {
00518     sp_set.markOut(DEFAULT_TLS_SESSION_PROTOCOL_SET);
00519   }
00520 
00521   
00522   if (sp_set.contains(HTTP_PROTOCOL_SET)) {
00523     zret += snprintf(out+zret, n-zret, ":%s=%s", OPT_PROTO_PREFIX,TS_NPN_PROTOCOL_GROUP_HTTP);
00524     sp_set.markOut(HTTP_PROTOCOL_SET);
00525     need_colon_p = false;
00526   }
00527   if (sp_set.contains(SPDY_PROTOCOL_SET)) {
00528     if (need_colon_p) 
00529       zret += snprintf(out+zret, n-zret, ":%s=", OPT_PROTO_PREFIX);
00530     else
00531       out[zret++] = ';';
00532     zret += snprintf(out+zret, n-zret, TS_NPN_PROTOCOL_GROUP_SPDY);
00533     sp_set.markOut(SPDY_PROTOCOL_SET);
00534     need_colon_p = false;
00535   }
00536   if (sp_set.contains(HTTP2_PROTOCOL_SET)) {
00537     if (need_colon_p)
00538       zret += snprintf(out+zret, n-zret, ":%s=", OPT_PROTO_PREFIX);
00539     else
00540       out[zret++] = ';';
00541     zret += snprintf(out+zret, n-zret, "%s", TS_NPN_PROTOCOL_GROUP_HTTP2);
00542     sp_set.markOut(HTTP2_PROTOCOL_SET);
00543     need_colon_p = false;
00544   }
00545   
00546   if (!sp_set.isEmpty()) {
00547     if (need_colon_p)
00548       zret += snprintf(out+zret, n-zret, ":%s=", OPT_PROTO_PREFIX);
00549     bool sep_p = !need_colon_p;
00550     for ( int k = 0 ; k < SessionProtocolSet::MAX ; ++k ) {
00551       if (sp_set.contains(k)) {
00552         zret += snprintf(out+zret, n-zret, "%s%s", sep_p ? ";" : "", globalSessionProtocolNameRegistry.nameFor(k));
00553         sep_p = true;
00554       }
00555     }
00556   }
00557 
00558   return min(zret,n);
00559 }
00560 
00561 void
00562 ts_host_res_global_init()
00563 {
00564   
00565   memcpy(host_res_default_preference_order,
00566          HOST_RES_DEFAULT_PREFERENCE_ORDER,
00567          sizeof(host_res_default_preference_order));
00568 
00569   char* ip_resolve = REC_ConfigReadString("proxy.config.hostdb.ip_resolve");
00570   if (ip_resolve) {
00571     parse_host_res_preference(ip_resolve, host_res_default_preference_order);
00572   }
00573   ats_free(ip_resolve);
00574 }
00575 
00576 
00577 void
00578 ts_session_protocol_well_known_name_indices_init()
00579 {
00580   
00581   TS_NPN_PROTOCOL_INDEX_HTTP_0_9 = globalSessionProtocolNameRegistry.toIndexConst(TS_NPN_PROTOCOL_HTTP_0_9);
00582   TS_NPN_PROTOCOL_INDEX_HTTP_1_0 = globalSessionProtocolNameRegistry.toIndexConst(TS_NPN_PROTOCOL_HTTP_1_0);
00583   TS_NPN_PROTOCOL_INDEX_HTTP_1_1 = globalSessionProtocolNameRegistry.toIndexConst(TS_NPN_PROTOCOL_HTTP_1_1);
00584   TS_NPN_PROTOCOL_INDEX_HTTP_2_0 = globalSessionProtocolNameRegistry.toIndexConst(TS_NPN_PROTOCOL_HTTP_2_0);
00585   TS_NPN_PROTOCOL_INDEX_SPDY_1 = globalSessionProtocolNameRegistry.toIndexConst(TS_NPN_PROTOCOL_SPDY_1);
00586   TS_NPN_PROTOCOL_INDEX_SPDY_2 = globalSessionProtocolNameRegistry.toIndexConst(TS_NPN_PROTOCOL_SPDY_2);
00587   TS_NPN_PROTOCOL_INDEX_SPDY_3 = globalSessionProtocolNameRegistry.toIndexConst(TS_NPN_PROTOCOL_SPDY_3);
00588   TS_NPN_PROTOCOL_INDEX_SPDY_3_1 = globalSessionProtocolNameRegistry.toIndexConst(TS_NPN_PROTOCOL_SPDY_3_1);
00589 
00590   
00591   HTTP_PROTOCOL_SET.markIn(TS_NPN_PROTOCOL_INDEX_HTTP_0_9);
00592   HTTP_PROTOCOL_SET.markIn(TS_NPN_PROTOCOL_INDEX_HTTP_1_0);
00593   HTTP_PROTOCOL_SET.markIn(TS_NPN_PROTOCOL_INDEX_HTTP_1_1);
00594   HTTP2_PROTOCOL_SET.markIn(TS_NPN_PROTOCOL_INDEX_HTTP_2_0);
00595   SPDY_PROTOCOL_SET.markIn(TS_NPN_PROTOCOL_INDEX_SPDY_3);
00596   SPDY_PROTOCOL_SET.markIn(TS_NPN_PROTOCOL_INDEX_SPDY_3_1);
00597 
00598   DEFAULT_TLS_SESSION_PROTOCOL_SET.markAllIn();
00599   DEFAULT_NON_TLS_SESSION_PROTOCOL_SET = HTTP_PROTOCOL_SET;
00600 }
00601 
00602 SessionProtocolNameRegistry::SessionProtocolNameRegistry()
00603   : m_n(0)
00604 {
00605   memset(m_names, 0, sizeof(m_names));
00606   memset(&m_flags, 0, sizeof(m_flags));
00607 }
00608 
00609 SessionProtocolNameRegistry::~SessionProtocolNameRegistry() {
00610   for ( size_t i = 0 ; i < m_n ; ++i ) {
00611     if (m_flags[i] & F_ALLOCATED)
00612       ats_free(const_cast<char*>(m_names[i])); 
00613   }
00614 }
00615 
00616 int
00617 SessionProtocolNameRegistry::toIndex(char const* name) {
00618   int zret = this->indexFor(name);
00619   if (INVALID == zret) {
00620     if (m_n < static_cast<size_t>(MAX)) {
00621       m_names[m_n] = ats_strdup(name);
00622       m_flags[m_n] = F_ALLOCATED;
00623       zret = m_n++;
00624     } else {
00625       ink_release_assert(!"Session protocol name registry overflow");
00626     }
00627   }
00628   return zret;
00629 }
00630 
00631 int
00632 SessionProtocolNameRegistry::toIndexConst(char const* name) {
00633   int zret = this->indexFor(name);
00634   if (INVALID == zret) {
00635     if ( m_n < static_cast<size_t>(MAX)) {
00636       m_names[m_n] = name;
00637       zret = m_n++;
00638     } else {
00639       ink_release_assert(!"Session protocol name registry overflow");
00640     }
00641   }
00642   return zret;
00643 }
00644 
00645 int
00646 SessionProtocolNameRegistry::indexFor(char const* name) const {
00647   for ( size_t i = 0 ; i < m_n ; ++i ) {
00648     if (0 == strcasecmp(name, m_names[i]))
00649       return i;
00650   }
00651   return INVALID;
00652 }
00653 
00654 char const*
00655 SessionProtocolNameRegistry::nameFor(int idx) const {
00656   return 0 <= idx && idx < static_cast<int>(m_n)
00657     ? m_names[idx]
00658     : 0
00659     ;
00660 }