• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

HttpProxyServerMain.cc

Go to the documentation of this file.
00001 /** @file
00002 
00003   A brief file description
00004 
00005   @section license License
00006 
00007   Licensed to the Apache Software Foundation (ASF) under one
00008   or more contributor license agreements.  See the NOTICE file
00009   distributed with this work for additional information
00010   regarding copyright ownership.  The ASF licenses this file
00011   to you under the Apache License, Version 2.0 (the
00012   "License"); you may not use this file except in compliance
00013   with the License.  You may obtain a copy of the License at
00014 
00015       http://www.apache.org/licenses/LICENSE-2.0
00016 
00017   Unless required by applicable law or agreed to in writing, software
00018   distributed under the License is distributed on an "AS IS" BASIS,
00019   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00020   See the License for the specific language governing permissions and
00021   limitations under the License.
00022  */
00023 
00024 #include "ink_config.h"
00025 #include "P_Net.h"
00026 #include "Main.h"
00027 #include "Error.h"
00028 #include "HttpConfig.h"
00029 #include "HttpSessionAccept.h"
00030 #include "ReverseProxy.h"
00031 #include "HttpSessionManager.h"
00032 #include "HttpUpdateSM.h"
00033 #include "HttpClientSession.h"
00034 #include "HttpPages.h"
00035 #include "HttpTunnel.h"
00036 #include "Tokenizer.h"
00037 #include "P_SSLNextProtocolAccept.h"
00038 #include "ProtocolProbeSessionAccept.h"
00039 #include "SpdySessionAccept.h"
00040 #include "http2/Http2SessionAccept.h"
00041 
00042 HttpSessionAccept *plugin_http_accept = NULL;
00043 HttpSessionAccept *plugin_http_transparent_accept = 0;
00044 
00045 static SLL<SSLNextProtocolAccept> ssl_plugin_acceptors;
00046 static ink_mutex ssl_plugin_mutex = PTHREAD_MUTEX_INITIALIZER;
00047 
00048 bool
00049 ssl_register_protocol(const char * protocol, Continuation * contp)
00050 {
00051   ink_scoped_mutex lock(ssl_plugin_mutex);
00052 
00053   for (SSLNextProtocolAccept * ssl = ssl_plugin_acceptors.head;
00054         ssl; ssl = ssl_plugin_acceptors.next(ssl)) {
00055     if (!ssl->registerEndpoint(protocol, contp)) {
00056       return false;
00057     }
00058   }
00059 
00060   return true;
00061 }
00062 
00063 bool
00064 ssl_unregister_protocol(const char * protocol, Continuation * contp)
00065 {
00066   ink_scoped_mutex lock(ssl_plugin_mutex);
00067 
00068   for (SSLNextProtocolAccept * ssl = ssl_plugin_acceptors.head;
00069         ssl; ssl = ssl_plugin_acceptors.next(ssl)) {
00070     // Ignore possible failure because we want to try to unregister
00071     // from all SSL ports.
00072     ssl->unregisterEndpoint(protocol, contp);
00073   }
00074 
00075   return true;
00076 }
00077 
00078 /////////////////////////////////////////////////////////////////
00079 //
00080 //  main()
00081 //
00082 /////////////////////////////////////////////////////////////////
00083 
00084 /** Data about an acceptor.
00085 
00086     This is used to separate setting up the proxy ports and
00087     starting to accept on them.
00088 
00089 */
00090 struct HttpProxyAcceptor {
00091   /// Accept continuation.
00092   Continuation* _accept;
00093   /// Options for @c NetProcessor.
00094   NetProcessor::AcceptOptions _net_opt;
00095 
00096   /// Default constructor.
00097   HttpProxyAcceptor()
00098     : _accept(0)
00099     {
00100     }
00101 };
00102 
00103 /** Global acceptors.
00104     
00105     This is parallel to @c HttpProxyPort::global(), each generated
00106     from the corresponding port descriptor.
00107 
00108     @internal We use @c Continuation instead of @c HttpAccept because
00109     @c SSLNextProtocolAccept is a subclass of @c Cont instead of @c
00110     HttpAccept.
00111 */
00112 Vec<HttpProxyAcceptor> HttpProxyAcceptors;
00113 
00114 // Called from InkAPI.cc
00115 NetProcessor::AcceptOptions
00116 make_net_accept_options(const HttpProxyPort& port, unsigned nthreads)
00117 {
00118   NetProcessor::AcceptOptions net;
00119 
00120   net.accept_threads = nthreads;
00121 
00122   net.f_inbound_transparent = port.m_inbound_transparent_p;
00123   net.ip_family = port.m_family;
00124   net.local_port = port.m_port;
00125 
00126   if (port.m_inbound_ip.isValid()) {
00127     net.local_ip = port.m_inbound_ip;
00128   } else if (AF_INET6 == port.m_family && HttpConfig::m_master.inbound_ip6.isIp6()) {
00129     net.local_ip = HttpConfig::m_master.inbound_ip6;
00130   } else if (AF_INET == port.m_family && HttpConfig::m_master.inbound_ip4.isIp4()) {
00131     net.local_ip = HttpConfig::m_master.inbound_ip4;
00132   }
00133 
00134   return net;
00135 }
00136 
00137 static void
00138 MakeHttpProxyAcceptor(HttpProxyAcceptor& acceptor, HttpProxyPort& port, unsigned nthreads)
00139 {
00140   NetProcessor::AcceptOptions& net_opt = acceptor._net_opt;
00141   HttpSessionAccept::Options         accept_opt;
00142 
00143   net_opt = make_net_accept_options(port, nthreads);
00144   REC_ReadConfigInteger(net_opt.recv_bufsize, "proxy.config.net.sock_recv_buffer_size_in");
00145   REC_ReadConfigInteger(net_opt.send_bufsize, "proxy.config.net.sock_send_buffer_size_in");
00146   REC_ReadConfigInteger(net_opt.packet_mark, "proxy.config.net.sock_packet_mark_in");
00147   REC_ReadConfigInteger(net_opt.packet_tos, "proxy.config.net.sock_packet_tos_in");
00148 
00149   accept_opt.f_outbound_transparent = port.m_outbound_transparent_p;
00150   accept_opt.transport_type = port.m_type;
00151   accept_opt.setHostResPreference(port.m_host_res_preference);
00152   accept_opt.setTransparentPassthrough(port.m_transparent_passthrough);
00153   accept_opt.setSessionProtocolPreference(port.m_session_protocol_preference);
00154 
00155   if (port.m_outbound_ip4.isValid()) {
00156     accept_opt.outbound_ip4 = port.m_outbound_ip4;
00157   } else if (HttpConfig::m_master.outbound_ip4.isValid()) {
00158     accept_opt.outbound_ip4 = HttpConfig::m_master.outbound_ip4;
00159   }
00160 
00161   if (port.m_outbound_ip6.isValid()) {
00162     accept_opt.outbound_ip6 = port.m_outbound_ip6;
00163   } else if (HttpConfig::m_master.outbound_ip6.isValid()) {
00164     accept_opt.outbound_ip6 = HttpConfig::m_master.outbound_ip6;
00165   }
00166 
00167   // OK the way this works is that the fallback for each port is a protocol
00168   // probe acceptor. For SSL ports, we can stack a NPN+ALPN acceptor in front
00169   // of that, and these ports will fall back to the probe if no NPN+ALPN endpoint
00170   // was negotiated.
00171 
00172   // XXX the protocol probe should be a configuration option.
00173 
00174   ProtocolProbeSessionAccept *probe = new ProtocolProbeSessionAccept();
00175   HttpSessionAccept *http = 0; // don't allocate this unless it will be used.
00176 
00177   if (port.m_session_protocol_preference.intersects(HTTP_PROTOCOL_SET)) {
00178     http = new HttpSessionAccept(accept_opt);
00179     probe->registerEndpoint(ProtocolProbeSessionAccept::PROTO_HTTP, http);
00180   }
00181 
00182 #if TS_HAS_SPDY
00183   if (port.m_session_protocol_preference.intersects(SPDY_PROTOCOL_SET)) {
00184     probe->registerEndpoint(ProtocolProbeSessionAccept::PROTO_SPDY, new SpdySessionAccept(spdy::SESSION_VERSION_3_1));
00185   }
00186 #endif
00187 
00188   if (port.m_session_protocol_preference.intersects(HTTP2_PROTOCOL_SET)) {
00189     probe->registerEndpoint(ProtocolProbeSessionAccept::PROTO_HTTP2, new Http2SessionAccept(accept_opt));
00190   }
00191 
00192   if (port.isSSL()) {
00193     SSLNextProtocolAccept *ssl = new SSLNextProtocolAccept(probe);
00194 
00195     // ALPN selects the first server-offered protocol,
00196     // so make sure that we offer the newest protocol first.
00197     // But since registerEndpoint prepends you want to
00198     // register them backwards, so you'd want to register
00199     // the least important protocol first:
00200     // http/1.0, http/1.1, spdy/3, spdy/3.1
00201 
00202     // HTTP
00203     if (port.m_session_protocol_preference.contains(TS_NPN_PROTOCOL_INDEX_HTTP_1_0)) {
00204       ssl->registerEndpoint(TS_NPN_PROTOCOL_HTTP_1_0, http);
00205     }
00206 
00207     if (port.m_session_protocol_preference.contains(TS_NPN_PROTOCOL_INDEX_HTTP_1_1)) {
00208       ssl->registerEndpoint(TS_NPN_PROTOCOL_HTTP_1_1, http);
00209     }
00210 
00211     // HTTP2
00212     if (port.m_session_protocol_preference.contains(TS_NPN_PROTOCOL_INDEX_HTTP_2_0)) {
00213       ssl->registerEndpoint(TS_NPN_PROTOCOL_HTTP_2_0, new Http2SessionAccept(accept_opt));
00214     }
00215 
00216     // SPDY
00217 #if TS_HAS_SPDY
00218     if (port.m_session_protocol_preference.contains(TS_NPN_PROTOCOL_INDEX_SPDY_3)) {
00219       ssl->registerEndpoint(TS_NPN_PROTOCOL_SPDY_3, new SpdySessionAccept(spdy::SESSION_VERSION_3));
00220     }
00221 
00222     if (port.m_session_protocol_preference.contains(TS_NPN_PROTOCOL_INDEX_SPDY_3_1)) {
00223       ssl->registerEndpoint(TS_NPN_PROTOCOL_SPDY_3_1, new SpdySessionAccept(spdy::SESSION_VERSION_3_1));
00224     }
00225 #endif
00226 
00227     ink_scoped_mutex lock(ssl_plugin_mutex);
00228     ssl_plugin_acceptors.push(ssl);
00229 
00230     acceptor._accept = ssl;
00231   } else {
00232     acceptor._accept = probe;
00233   }
00234 }
00235 
00236 /** Set up all the accepts and sockets.
00237  */
00238 void
00239 init_HttpProxyServer(int n_accept_threads)
00240 {
00241   HttpProxyPort::Group& proxy_ports = HttpProxyPort::global();
00242 
00243   init_reverse_proxy();
00244   httpSessionManager.init();
00245   http_pages_init();
00246   ink_mutex_init(&debug_sm_list_mutex, "HttpSM Debug List");
00247   ink_mutex_init(&debug_cs_list_mutex, "HttpCS Debug List");
00248   // DI's request to disable/reenable ICP on the fly
00249   icp_dynamic_enabled = 1;
00250 
00251   // Used to give plugins the ability to create http requests
00252   //   The equivalent of the connecting to localhost on the  proxy
00253   //   port but without going through the operating system
00254   //
00255   if (plugin_http_accept == NULL) {
00256     plugin_http_accept = new HttpSessionAccept;
00257     plugin_http_accept->mutex = new_ProxyMutex();
00258   }
00259   // Same as plugin_http_accept except outbound transparent.
00260   if (! plugin_http_transparent_accept) {
00261     HttpSessionAccept::Options ha_opt;
00262     ha_opt.setOutboundTransparent(true);
00263     plugin_http_transparent_accept = new HttpSessionAccept(ha_opt);
00264     plugin_http_transparent_accept->mutex = new_ProxyMutex();
00265   }
00266   ink_mutex_init(&ssl_plugin_mutex, "SSL Acceptor List");
00267 
00268   // Do the configuration defined ports.
00269   for ( int i = 0 , n = proxy_ports.length() ; i < n ; ++i ) {
00270     MakeHttpProxyAcceptor(HttpProxyAcceptors.add(), proxy_ports[i], n_accept_threads);
00271   }
00272   
00273 }
00274 
00275 void
00276 start_HttpProxyServer()
00277 {
00278   static bool called_once = false;
00279   HttpProxyPort::Group& proxy_ports = HttpProxyPort::global();
00280 
00281   ///////////////////////////////////
00282   // start accepting connections   //
00283   ///////////////////////////////////
00284 
00285   ink_assert(!called_once);
00286   ink_assert(proxy_ports.length() == HttpProxyAcceptors.length());
00287 
00288   for ( int i = 0 , n = proxy_ports.length() ; i < n ; ++i ) {
00289     HttpProxyAcceptor& acceptor = HttpProxyAcceptors[i];
00290     HttpProxyPort& port = proxy_ports[i];
00291     if (port.isSSL()) {
00292       if (NULL == sslNetProcessor.main_accept(acceptor._accept, port.m_fd, acceptor._net_opt))
00293         return;
00294     } else if (! port.isPlugin()) {
00295       if (NULL == netProcessor.main_accept(acceptor._accept, port.m_fd, acceptor._net_opt))
00296         return;
00297     }
00298     // XXX although we make a good pretence here, I don't believe that NetProcessor::main_accept() ever actually returns
00299     // NULL. It would be useful to be able to detect errors and spew them here though.
00300   }
00301 
00302 #if TS_HAS_TESTS
00303   if (is_action_tag_set("http_update_test")) {
00304     init_http_update_test();
00305   }
00306 #endif
00307 
00308   // Alert plugins that connections will be accepted.
00309   APIHook* hook = lifecycle_hooks->get(TS_LIFECYCLE_PORTS_READY_HOOK);
00310   while (hook) {
00311     hook->invoke(TS_EVENT_LIFECYCLE_PORTS_READY, NULL);
00312     hook = hook->next();
00313   }
00314 
00315 }
00316 
00317 void
00318 start_HttpProxyServerBackDoor(int port, int accept_threads)
00319 {
00320   NetProcessor::AcceptOptions opt;
00321   HttpSessionAccept::Options ha_opt;
00322 
00323   opt.local_port = port;
00324   opt.accept_threads = accept_threads;
00325   opt.localhost_only = true;
00326   ha_opt.backdoor = true;
00327   opt.backdoor = true;
00328 
00329   // The backdoor only binds the loopback interface
00330   netProcessor.main_accept(new HttpSessionAccept(ha_opt), NO_FD, opt);
00331 }

Generated by  doxygen 1.7.1