1 /** @file
2 
3   A brief file description
4 
5   @section license License
6 
7   Licensed to the Apache Software Foundation (ASF) under one
8   or more contributor license agreements.  See the NOTICE file
9   distributed with this work for additional information
10   regarding copyright ownership.  The ASF licenses this file
11   to you under the Apache License, Version 2.0 (the
12   "License"); you may not use this file except in compliance
13   with the License.  You may obtain a copy of the License at
14 
15       http://www.apache.org/licenses/LICENSE-2.0
16 
17   Unless required by applicable law or agreed to in writing, software
18   distributed under the License is distributed on an "AS IS" BASIS,
19   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20   See the License for the specific language governing permissions and
21   limitations under the License.
22  */
23 
24 /****************************************************************************
25 
26    Http1ServerSession.cc
27 
28    Description:
29 
30  ****************************************************************************/
31 #include "tscore/ink_config.h"
32 #include "tscore/BufferWriter.h"
33 #include "tscore/bwf_std_format.h"
34 #include "tscore/Allocator.h"
35 #include "Http1ServerSession.h"
36 #include "HttpSessionManager.h"
37 #include "HttpSM.h"
38 
39 ClassAllocator<Http1ServerSession, true> httpServerSessionAllocator("httpServerSessionAllocator");
40 
41 void
destroy()42 Http1ServerSession::destroy()
43 {
44   ink_release_assert(_vc == nullptr);
45   ink_assert(read_buffer);
46   magic = HTTP_SS_MAGIC_DEAD;
47   if (read_buffer) {
48     free_MIOBuffer(read_buffer);
49     read_buffer = nullptr;
50   }
51 
52   mutex.clear();
53   if (httpSessionManager.get_pool_type() == TS_SERVER_SESSION_SHARING_POOL_THREAD) {
54     THREAD_FREE(this, httpServerSessionAllocator, this_thread());
55   } else {
56     httpServerSessionAllocator.free(this);
57   }
58 }
59 
60 void
free()61 Http1ServerSession::free()
62 {
63   // Unlike Http1ClientSession, Http1ServerSession is freed in destroy()
64 }
65 
66 void
new_connection(NetVConnection * new_vc,MIOBuffer * iobuf,IOBufferReader * reader)67 Http1ServerSession::new_connection(NetVConnection *new_vc, MIOBuffer *iobuf, IOBufferReader *reader)
68 {
69   ink_assert(new_vc != nullptr);
70   _vc = new_vc;
71 
72   // Used to do e.g. mutex = new_vc->thread->mutex; when per-thread pools enabled
73   mutex = new_vc->mutex;
74 
75   // Unique session identifier.
76   con_id = ProxySession::next_connection_id();
77 
78   magic = HTTP_SS_MAGIC_ALIVE;
79   HTTP_SUM_GLOBAL_DYN_STAT(http_current_server_connections_stat, 1); // Update the true global stat
80   HTTP_INCREMENT_DYN_STAT(http_total_server_connections_stat);
81 
82   if (iobuf == nullptr) {
83     read_buffer = new_MIOBuffer(HTTP_SERVER_RESP_HDR_BUFFER_INDEX);
84     buf_reader  = read_buffer->alloc_reader();
85   } else {
86     read_buffer = iobuf;
87     buf_reader  = reader;
88   }
89   Debug("http_ss", "[%" PRId64 "] session born, netvc %p", con_id, new_vc);
90   state = INIT;
91 
92   new_vc->set_tcp_congestion_control(SERVER_SIDE);
93 }
94 
95 void
enable_outbound_connection_tracking(OutboundConnTrack::Group * group)96 Http1ServerSession::enable_outbound_connection_tracking(OutboundConnTrack::Group *group)
97 {
98   ink_assert(nullptr == conn_track_group);
99   conn_track_group = group;
100   if (is_debug_tag_set("http_ss")) {
101     ts::LocalBufferWriter<256> w;
102     w.print("[{}] new connection, ip: {}, group ({}), count: {}\0", con_id, get_server_ip(), *group, group->_count);
103     Debug("http_ss", "%s", w.data());
104   }
105 }
106 
107 void
do_io_close(int alerrno)108 Http1ServerSession::do_io_close(int alerrno)
109 {
110   ts::LocalBufferWriter<256> w;
111   bool debug_p = is_debug_tag_set("http_ss");
112 
113   if (state == SSN_IN_USE) {
114     HTTP_DECREMENT_DYN_STAT(http_current_server_transactions_stat);
115   }
116 
117   if (debug_p) {
118     w.print("[{}] session close: nevtc {:x}", con_id, _vc);
119   }
120 
121   HTTP_SUM_GLOBAL_DYN_STAT(http_current_server_connections_stat, -1); // Make sure to work on the global stat
122   HTTP_SUM_DYN_STAT(http_transactions_per_server_con, transact_count);
123 
124   // Update upstream connection tracking data if present.
125   if (conn_track_group) {
126     if (conn_track_group->_count >= 0) {
127       auto n = (conn_track_group->_count)--;
128       if (debug_p) {
129         w.print(" conn track group ({}) count {}", conn_track_group->_key, n);
130       }
131     } else {
132       // A bit dubious, as there's no guarantee it's still negative, but even that would be interesting to know.
133       Error("[http_ss] [%" PRId64 "] number of connections should be greater than or equal to zero: %u", con_id,
134             conn_track_group->_count.load());
135     }
136   }
137   if (debug_p) {
138     Debug("http_ss", "%.*s", static_cast<int>(w.size()), w.data());
139   }
140 
141   if (_vc) {
142     _vc->do_io_close(alerrno);
143   }
144   _vc = nullptr;
145 
146   if (to_parent_proxy) {
147     HTTP_DECREMENT_DYN_STAT(http_current_parent_proxy_connections_stat);
148   }
149   destroy();
150 }
151 
152 // void Http1ServerSession::release()
153 //
154 //   Releases the session for K-A reuse
155 //
156 void
release(ProxyTransaction * trans)157 Http1ServerSession::release(ProxyTransaction *trans)
158 {
159   Debug("http_ss", "Releasing session, private_session=%d, sharing_match=%d", this->is_private(), sharing_match);
160   // Set our state to KA for stat issues
161   state = KA_POOLED;
162 
163   _vc->control_flags.set_flags(0);
164 
165   // Private sessions are never released back to the shared pool
166   if (this->is_private() || sharing_match == 0) {
167     this->do_io_close();
168     return;
169   }
170 
171   // do not change the read/write cont and mutex yet
172   // release_session() will either swap them with the
173   // pool continuation with a valid read buffer or if
174   // it fails, do_io_close() will clear the cont anyway
175 
176   HSMresult_t r = httpSessionManager.release_session(this);
177 
178   if (r == HSM_RETRY) {
179     // Session could not be put in the session manager
180     //  due to lock contention
181     // FIX:  should retry instead of closing
182     this->do_io_close();
183     HTTP_INCREMENT_DYN_STAT(http_origin_shutdown_pool_lock_contention);
184   } else {
185     // The session was successfully put into the session
186     //    manager and it will manage it
187     // (Note: should never get HSM_NOT_FOUND here)
188     ink_assert(r == HSM_DONE);
189   }
190 }
191 
192 // Keys for matching hostnames
193 IpEndpoint const &
get_server_ip() const194 Http1ServerSession::get_server_ip() const
195 {
196   ink_release_assert(_vc != nullptr);
197   return _vc->get_remote_endpoint();
198 }
199 
200 int
get_transact_count() const201 Http1ServerSession::get_transact_count() const
202 {
203   return transact_count;
204 }
205 
206 const char *
get_protocol_string() const207 Http1ServerSession::get_protocol_string() const
208 {
209   return "http";
210 }
211 void
increment_current_active_connections_stat()212 Http1ServerSession::increment_current_active_connections_stat()
213 {
214   // TODO: Implement stats
215 }
216 void
decrement_current_active_connections_stat()217 Http1ServerSession::decrement_current_active_connections_stat()
218 {
219   // TODO: Implement stats
220 }
221 
222 void
start()223 Http1ServerSession::start()
224 {
225 }
226