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 }