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