00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 #include "ink_config.h"
00034 #include "Allocator.h"
00035 #include "HttpClientSession.h"
00036 #include "HttpSM.h"
00037 #include "HttpDebugNames.h"
00038 #include "HttpServerSession.h"
00039 #include "Plugin.h"
00040 
00041 #define DebugHttpSsn(fmt, ...) DebugSsn(this, "http_cs", fmt, __VA_ARGS__)
00042 
00043 #define STATE_ENTER(state_name, event, vio) do { \
00044      \
00045   DebugHttpSsn("[%" PRId64 "] [%s, %s]", con_id, #state_name, HttpDebugNames::get_event_name(event)); \
00046 } while(0)
00047 
00048 enum
00049 {
00050   HTTP_CS_MAGIC_ALIVE = 0x0123F00D,
00051   HTTP_CS_MAGIC_DEAD = 0xDEADF00D
00052 };
00053 
00054 
00055 
00056 DLL<HttpClientSession> debug_cs_list;
00057 ink_mutex debug_cs_list_mutex;
00058 
00059 ClassAllocator<HttpClientSession> httpClientSessionAllocator("httpClientSessionAllocator");
00060 
00061 HttpClientSession::HttpClientSession()
00062   : con_id(0), client_vc(NULL), magic(HTTP_CS_MAGIC_DEAD),
00063     transact_count(0), tcp_init_cwnd_set(false),
00064     half_close(false), conn_decrease(false), bound_ss(NULL),
00065     read_buffer(NULL), current_reader(NULL), read_state(HCS_INIT),
00066     ka_vio(NULL), slave_ka_vio(NULL),
00067     outbound_port(0), f_outbound_transparent(false),
00068     host_res_style(HOST_RES_IPV4), acl_record(NULL),
00069     m_active(false)
00070 {
00071 }
00072 
00073 void
00074 HttpClientSession::destroy()
00075 {
00076   DebugHttpSsn("[%" PRId64 "] session destroy", con_id);
00077 
00078   ink_release_assert(client_vc == NULL);
00079   ink_release_assert(bound_ss == NULL);
00080   ink_assert(read_buffer);
00081 
00082   magic = HTTP_CS_MAGIC_DEAD;
00083   if (read_buffer) {
00084     free_MIOBuffer(read_buffer);
00085     read_buffer = NULL;
00086   }
00087 
00088 #ifdef USE_HTTP_DEBUG_LISTS
00089   ink_mutex_acquire(&debug_cs_list_mutex);
00090   debug_cs_list.remove(this, this->debug_link);
00091   ink_mutex_release(&debug_cs_list_mutex);
00092 #endif
00093 
00094   if (conn_decrease) {
00095     HTTP_DECREMENT_DYN_STAT(http_current_client_connections_stat);
00096     conn_decrease = false;
00097   }
00098 
00099   ProxyClientSession::cleanup();
00100   THREAD_FREE(this, httpClientSessionAllocator, this_thread());
00101 }
00102 
00103 void
00104 HttpClientSession::ssn_hook_append(TSHttpHookID id, INKContInternal * cont)
00105 {
00106   ProxyClientSession::ssn_hook_append(id, cont);
00107   if (current_reader) {
00108     current_reader->hooks_set = 1;
00109   }
00110 }
00111 
00112 void
00113 HttpClientSession::ssn_hook_prepend(TSHttpHookID id, INKContInternal * cont)
00114 {
00115   ProxyClientSession::ssn_hook_prepend(id, cont);
00116   if (current_reader) {
00117     current_reader->hooks_set = 1;
00118   }
00119 }
00120 
00121 void
00122 HttpClientSession::new_transaction()
00123 {
00124   ink_assert(current_reader == NULL);
00125   PluginIdentity* pi = dynamic_cast<PluginIdentity*>(client_vc);
00126 
00127   read_state = HCS_ACTIVE_READER;
00128   current_reader = HttpSM::allocate();
00129   current_reader->init();
00130   transact_count++;
00131   DebugHttpSsn("[%" PRId64 "] Starting transaction %d using sm [%" PRId64 "]", con_id, transact_count, current_reader->sm_id);
00132 
00133   current_reader->attach_client_session(this, sm_reader);
00134   if (pi) {
00135     
00136     
00137     current_reader->plugin_tag = pi->getPluginTag();
00138     current_reader->plugin_id = pi->getPluginId();
00139   }
00140 }
00141 
00142 void
00143 HttpClientSession::new_connection(NetVConnection * new_vc, MIOBuffer * iobuf, IOBufferReader * reader, bool backdoor)
00144 {
00145   ink_assert(new_vc != NULL);
00146   ink_assert(client_vc == NULL);
00147   client_vc = new_vc;
00148   magic = HTTP_CS_MAGIC_ALIVE;
00149   mutex = new_vc->mutex;
00150   MUTEX_TRY_LOCK(lock, mutex, this_ethread());
00151   ink_assert(!!lock);
00152 
00153   
00154   this->hooks_on = !backdoor;
00155 
00156   
00157   con_id = ProxyClientSession::next_connection_id();
00158 
00159   HTTP_INCREMENT_DYN_STAT(http_current_client_connections_stat);
00160   conn_decrease = true;
00161   HTTP_INCREMENT_DYN_STAT(http_total_client_connections_stat);
00162   if (static_cast<HttpProxyPort::TransportType>(new_vc->attributes) == HttpProxyPort::TRANSPORT_SSL) {
00163     HTTP_INCREMENT_DYN_STAT(https_total_client_connections_stat);
00164   }
00165 
00166   
00167 
00168   HTTP_INCREMENT_DYN_STAT(http_total_incoming_connections_stat);
00169 
00170   
00171   
00172   
00173   switch(new_vc->get_remote_addr()->sa_family) {
00174     case AF_INET:
00175       HTTP_INCREMENT_DYN_STAT(http_total_client_connections_ipv4_stat);
00176     break;
00177     case AF_INET6:
00178       HTTP_INCREMENT_DYN_STAT(http_total_client_connections_ipv6_stat);
00179     break;
00180     default:
00181       
00182       
00183       
00184     break;
00185   }
00186 
00187 #ifdef USE_HTTP_DEBUG_LISTS
00188   ink_mutex_acquire(&debug_cs_list_mutex);
00189   debug_cs_list.push(this, this->debug_link);
00190   ink_mutex_release(&debug_cs_list_mutex);
00191 #endif
00192 
00193   DebugHttpSsn("[%" PRId64 "] session born, netvc %p", con_id, new_vc);
00194 
00195   read_buffer = iobuf ? iobuf : new_MIOBuffer(HTTP_HEADER_BUFFER_SIZE_INDEX);
00196   sm_reader = reader ? reader : read_buffer->alloc_reader();
00197 
00198   
00199   
00200   
00201   EThread *ethis = this_ethread();
00202   Ptr<ProxyMutex> lmutex = this->mutex;
00203   MUTEX_TAKE_LOCK(lmutex, ethis);
00204   do_api_callout(TS_HTTP_SSN_START_HOOK);
00205   MUTEX_UNTAKE_LOCK(lmutex, ethis);
00206   lmutex.clear();
00207 }
00208 
00209 VIO *
00210 HttpClientSession::do_io_read(Continuation * c, int64_t nbytes, MIOBuffer * buf)
00211 {
00212   return client_vc->do_io_read(c, nbytes, buf);
00213 }
00214 
00215 VIO *
00216 HttpClientSession::do_io_write(Continuation * c, int64_t nbytes, IOBufferReader * buf, bool owner)
00217 {
00218   
00219 
00220   DebugHttpSsn("tcp_init_cwnd_set %d\n", (int)tcp_init_cwnd_set);
00221   if(!tcp_init_cwnd_set) {
00222     tcp_init_cwnd_set = true;
00223     set_tcp_init_cwnd();
00224   }
00225   return client_vc->do_io_write(c, nbytes, buf, owner);
00226 }
00227 
00228 void
00229 HttpClientSession::set_tcp_init_cwnd()
00230 {
00231   int desired_tcp_init_cwnd = current_reader->t_state.txn_conf->server_tcp_init_cwnd;
00232   DebugHttpSsn("desired TCP congestion window is %d\n", desired_tcp_init_cwnd);
00233   if(desired_tcp_init_cwnd == 0) return;
00234   if(get_netvc()->set_tcp_init_cwnd(desired_tcp_init_cwnd) != 0)
00235     DebugHttpSsn("set_tcp_init_cwnd(%d) failed", desired_tcp_init_cwnd);
00236 }
00237 
00238 void
00239 HttpClientSession::do_io_shutdown(ShutdownHowTo_t howto)
00240 {
00241   client_vc->do_io_shutdown(howto);
00242 }
00243 
00244 void
00245 HttpClientSession::do_io_close(int alerrno)
00246 {
00247 
00248   if (read_state == HCS_ACTIVE_READER) {
00249     HTTP_DECREMENT_DYN_STAT(http_current_client_transactions_stat);
00250     if (m_active) {
00251       m_active = false;
00252       HTTP_DECREMENT_DYN_STAT(http_current_active_client_connections_stat);
00253     }
00254   }
00255 
00256   
00257   ink_release_assert(read_state != HCS_CLOSED);
00258 
00259   
00260   
00261   if (bound_ss) {
00262     bound_ss->release();
00263     bound_ss = NULL;
00264     slave_ka_vio = NULL;
00265   }
00266 
00267   if (half_close) {
00268     read_state = HCS_HALF_CLOSED;
00269     SET_HANDLER(&HttpClientSession::state_wait_for_close);
00270     DebugHttpSsn("[%" PRId64 "] session half close", con_id);
00271 
00272     
00273     
00274     
00275     
00276     
00277     
00278     client_vc->do_io_shutdown(IO_SHUTDOWN_WRITE);
00279 
00280     ka_vio = client_vc->do_io_read(this, INT64_MAX, read_buffer);
00281     ink_assert(slave_ka_vio != ka_vio);
00282 
00283     
00284     
00285     
00286     sm_reader->consume(sm_reader->read_avail());
00287 
00288     
00289     
00290     
00291     client_vc->set_active_timeout(HRTIME_SECONDS(current_reader->t_state.txn_conf->keep_alive_no_activity_timeout_out));
00292   } else {
00293     read_state = HCS_CLOSED;
00294     client_vc->do_io_close(alerrno);
00295     DebugHttpSsn("[%" PRId64 "] session closed", con_id);
00296     client_vc = NULL;
00297     HTTP_SUM_DYN_STAT(http_transactions_per_client_con, transact_count);
00298     HTTP_DECREMENT_DYN_STAT(http_current_client_connections_stat);
00299     conn_decrease = false;
00300     do_api_callout(TS_HTTP_SSN_CLOSE_HOOK);
00301   }
00302 }
00303 
00304 int
00305 HttpClientSession::state_wait_for_close(int event, void *data)
00306 {
00307 
00308   STATE_ENTER(&HttpClientSession::state_wait_for_close, event, data);
00309 
00310   ink_assert(data == ka_vio);
00311   ink_assert(read_state == HCS_HALF_CLOSED);
00312 
00313   switch (event) {
00314   case VC_EVENT_EOS:
00315   case VC_EVENT_ERROR:
00316   case VC_EVENT_ACTIVE_TIMEOUT:
00317   case VC_EVENT_INACTIVITY_TIMEOUT:
00318     half_close = false;
00319     this->do_io_close();
00320     break;
00321   case VC_EVENT_READ_READY:
00322     
00323     sm_reader->consume(sm_reader->read_avail());
00324     break;
00325   default:
00326     ink_release_assert(0);
00327     break;
00328   }
00329 
00330   return 0;
00331 }
00332 
00333 int
00334 HttpClientSession::state_slave_keep_alive(int event, void *data)
00335 {
00336 
00337   STATE_ENTER(&HttpClientSession::state_slave_keep_alive, event, data);
00338 
00339   ink_assert(data == slave_ka_vio);
00340   ink_assert(bound_ss != NULL);
00341 
00342   switch (event) {
00343   default:
00344   case VC_EVENT_READ_COMPLETE:
00345     
00346     ink_assert(0);
00347     
00348   case VC_EVENT_ERROR:
00349   case VC_EVENT_READ_READY:
00350   case VC_EVENT_EOS:
00351     
00352     bound_ss->do_io_close();
00353     bound_ss = NULL;
00354     slave_ka_vio = NULL;
00355     break;
00356 
00357   case VC_EVENT_ACTIVE_TIMEOUT:
00358   case VC_EVENT_INACTIVITY_TIMEOUT:
00359     
00360     bound_ss->release();
00361     bound_ss = NULL;
00362     slave_ka_vio = NULL;
00363     break;
00364   }
00365 
00366   return 0;
00367 }
00368 
00369 int
00370 HttpClientSession::state_keep_alive(int event, void *data)
00371 {
00372 
00373   
00374   
00375   if (data && data == slave_ka_vio) {
00376     return state_slave_keep_alive(event, data);
00377   } else {
00378     ink_assert(data && data == ka_vio);
00379     ink_assert(read_state == HCS_KEEP_ALIVE);
00380   }
00381 
00382   STATE_ENTER(&HttpClientSession::state_keep_alive, event, data);
00383 
00384   switch (event) {
00385   case VC_EVENT_READ_READY:
00386     
00387     
00388     new_transaction();
00389     break;
00390 
00391   case VC_EVENT_EOS:
00392     
00393     
00394     if (sm_reader->read_avail() > 0) {
00395       new_transaction();
00396     } else {
00397       this->do_io_close();
00398     }
00399     break;
00400 
00401   case VC_EVENT_READ_COMPLETE:
00402   default:
00403     
00404     ink_assert(0);
00405     
00406   case VC_EVENT_ERROR:
00407   case VC_EVENT_ACTIVE_TIMEOUT:
00408   case VC_EVENT_INACTIVITY_TIMEOUT:
00409     
00410     this->do_io_close();
00411     break;
00412   }
00413 
00414   return 0;
00415 }
00416 void
00417 HttpClientSession::reenable(VIO * vio)
00418 {
00419   client_vc->reenable(vio);
00420 }
00421 
00422 void
00423 HttpClientSession::attach_server_session(HttpServerSession * ssession, bool transaction_done)
00424 {
00425   if (ssession) {
00426     ink_assert(bound_ss == NULL);
00427     ssession->state = HSS_KA_CLIENT_SLAVE;
00428     bound_ss = ssession;
00429     DebugHttpSsn("[%" PRId64 "] attaching server session [%" PRId64 "] as slave", con_id, ssession->con_id);
00430     ink_assert(ssession->get_reader()->read_avail() == 0);
00431     ink_assert(ssession->get_netvc() != client_vc);
00432 
00433     
00434     if (m_active) {
00435       m_active = false;
00436       HTTP_DECREMENT_DYN_STAT(http_current_active_client_connections_stat);
00437     }
00438     
00439     
00440     
00441     SET_HANDLER(&HttpClientSession::state_keep_alive);
00442     slave_ka_vio = ssession->do_io_read(this, INT64_MAX, ssession->read_buffer);
00443     ink_assert(slave_ka_vio != ka_vio);
00444 
00445     
00446     ssession->do_io_write(this, 0, NULL);
00447 
00448     if (transaction_done) {
00449       ssession->get_netvc()->
00450         set_inactivity_timeout(HRTIME_SECONDS(current_reader->t_state.txn_conf->keep_alive_no_activity_timeout_out));
00451       ssession->get_netvc()->cancel_active_timeout();
00452     } else {
00453       
00454       ssession->get_netvc()->cancel_inactivity_timeout();
00455       ssession->get_netvc()->cancel_active_timeout();
00456     }
00457   } else {
00458     ink_assert(bound_ss != NULL);
00459     bound_ss = NULL;
00460     slave_ka_vio = NULL;
00461   }
00462 }
00463 
00464 void
00465 HttpClientSession::release(IOBufferReader * r)
00466 {
00467   ink_assert(read_state == HCS_ACTIVE_READER);
00468   ink_assert(current_reader != NULL);
00469   MgmtInt ka_in = current_reader->t_state.txn_conf->keep_alive_no_activity_timeout_in;
00470 
00471   DebugHttpSsn("[%" PRId64 "] session released by sm [%" PRId64 "]", con_id, current_reader->sm_id);
00472   current_reader = NULL;
00473 
00474   
00475   if (m_active) {
00476     m_active = false;
00477     HTTP_DECREMENT_DYN_STAT(http_current_active_client_connections_stat);
00478   }
00479   
00480   
00481   ink_assert(r == sm_reader);
00482   if (r != sm_reader) {
00483     this->do_io_close();
00484     return;
00485   }
00486 
00487   HTTP_DECREMENT_DYN_STAT(http_current_client_transactions_stat);
00488 
00489   
00490   
00491   
00492   
00493   if (sm_reader->read_avail() > 0) {
00494     DebugHttpSsn("[%" PRId64 "] data already in buffer, starting new transaction", con_id);
00495     new_transaction();
00496   } else {
00497     DebugHttpSsn("[%" PRId64 "] initiating io for next header", con_id);
00498     read_state = HCS_KEEP_ALIVE;
00499     SET_HANDLER(&HttpClientSession::state_keep_alive);
00500     ka_vio = this->do_io_read(this, INT64_MAX, read_buffer);
00501     ink_assert(slave_ka_vio != ka_vio);
00502     client_vc->set_inactivity_timeout(HRTIME_SECONDS(ka_in));
00503     client_vc->cancel_active_timeout();
00504   }
00505 }
00506 
00507 HttpServerSession *
00508 HttpClientSession::get_bound_ss()
00509 {
00510   return bound_ss;
00511 }