Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #include "io/tcp_server.h"
6 :
7 : #include <errno.h>
8 :
9 : #include <boost/asio/connect.hpp>
10 : #include <boost/asio/placeholders.hpp>
11 : #include <boost/bind/bind.hpp>
12 : #include <netinet/tcp.h>
13 :
14 : #include "base/logging.h"
15 : #include "io/event_manager.h"
16 : #include "io/tcp_session.h"
17 : #include "io/io_log.h"
18 : #include "io/io_utils.h"
19 :
20 : using boost::asio::ip::address;
21 : using boost::asio::ip::tcp;
22 : using boost::asio::placeholders::error;
23 : using boost::asio::socket_base;
24 : using boost::bind;
25 : using boost::system::error_code;
26 : using namespace boost::placeholders;
27 :
28 : using boost::asio::socket_base;
29 : using std::ostringstream;
30 : using std::string;
31 :
32 17561 : TcpServer::TcpServer(EventManager *evm)
33 17561 : : evm_(evm), socket_open_failure_(false), intf_id_(-1) {
34 17561 : refcount_ = 0;
35 17561 : TcpServerManager::AddServer(this);
36 17561 : }
37 :
38 : // TcpServer delete procedure:
39 : // 1. Shutdown() to stop accepting incoming sessions.
40 : // 2. Close and terminate current sessions. ASIO callbacks maybe in-flight.
41 : // 3. Optionally: WaitForEmpty().
42 : // 4. Destroy TcpServer.
43 17561 : TcpServer::~TcpServer() {
44 17561 : assert(acceptor_ == NULL);
45 17561 : assert(session_ref_.empty());
46 17561 : assert(session_map_.empty());
47 17561 : }
48 :
49 8060 : void TcpServer::SetName(Endpoint local_endpoint) {
50 8060 : ostringstream out;
51 8060 : out << local_endpoint;
52 8060 : name_ = out.str();
53 8060 : }
54 :
55 8193 : void TcpServer::ResetAcceptor() {
56 8193 : acceptor_.reset();
57 8193 : name_ = "";
58 8193 : }
59 :
60 2474 : bool TcpServer::Initialize(unsigned short port) {
61 2474 : intf_id_ = -1; //this initializer is only for IPv4
62 2474 : tcp::endpoint localaddr(tcp::v4(), port);
63 2474 : return InitializeInternal(localaddr);
64 : }
65 :
66 5719 : bool TcpServer::Initialize(unsigned short port,
67 : const IpAddress &host_ip,
68 : int intf_id) {
69 5719 : tcp::endpoint localaddr(host_ip, port);
70 5719 : tcp::endpoint serv_ep(host_ip, port);
71 5719 : intf_id_ = intf_id;
72 5719 : if (host_ip.is_v6()) {
73 4 : Ip6Address ipaddr = host_ip.to_v6();
74 4 : if (intf_id_ > 0) {
75 1 : ipaddr.scope_id(this->intf_id_);
76 1 : serv_ep.address(ipaddr);
77 : }
78 : }
79 5719 : return InitializeInternal(serv_ep);
80 : }
81 :
82 8193 : bool TcpServer::InitializeInternal(tcp::endpoint localaddr) {
83 8193 : acceptor_.reset(new tcp::acceptor(*evm_->io_service()));
84 8193 : if (!acceptor_) {
85 0 : TCP_SERVER_LOG_ERROR(this, TCP_DIR_NA, "Cannot create acceptor");
86 0 : return false;
87 : }
88 :
89 8193 : error_code ec;
90 8193 : if (localaddr.address().is_v4())
91 8189 : acceptor_->open(tcp::v4(), ec);
92 : else
93 4 : acceptor_->open(tcp::v6(), ec);
94 :
95 8193 : if (ec) {
96 0 : TCP_SERVER_LOG_ERROR(this, TCP_DIR_NA, "TCP open: " << ec.message());
97 0 : ResetAcceptor();
98 0 : return false;
99 : }
100 :
101 8193 : acceptor_->set_option(socket_base::reuse_address(true), ec);
102 8193 : if (ec) {
103 0 : TCP_SERVER_LOG_ERROR(this, TCP_DIR_NA, "TCP reuse_address: "
104 : << ec.message());
105 0 : ResetAcceptor();
106 0 : return false;
107 : }
108 :
109 8193 : acceptor_->bind(localaddr, ec);
110 8193 : if (ec) {
111 133 : TCP_SERVER_LOG_ERROR(this, TCP_DIR_NA, "TCP bind(" << localaddr.address() <<
112 : ":" << localaddr.port() << "): " << ec.message());
113 133 : ResetAcceptor();
114 133 : return false;
115 : }
116 :
117 8060 : tcp::endpoint local_endpoint = acceptor_->local_endpoint(ec);
118 8060 : if (ec) {
119 0 : TCP_SERVER_LOG_ERROR(this, TCP_DIR_NA,
120 : "Cannot retrieve acceptor local-endpont");
121 0 : ResetAcceptor();
122 0 : return false;
123 : }
124 :
125 : //
126 : // Server name can be set after local-endpoint information is available.
127 : //
128 8060 : SetName(local_endpoint);
129 :
130 8060 : acceptor_->listen(socket_base::max_connections, ec);
131 8060 : if (ec) {
132 0 : TCP_SERVER_LOG_ERROR(this, TCP_DIR_NA, "TCP listen(" << localaddr.port() <<
133 : "): " << ec.message());
134 0 : ResetAcceptor();
135 0 : return false;
136 : }
137 :
138 8096 : TCP_SERVER_LOG_DEBUG(this, TCP_DIR_NA, "Initialization complete");
139 8060 : AsyncAccept();
140 :
141 8060 : return true;
142 : }
143 :
144 17373 : void TcpServer::Shutdown() {
145 17373 : std::scoped_lock lock(mutex_);
146 17373 : error_code ec;
147 :
148 17373 : if (acceptor_) {
149 8060 : acceptor_->close(ec);
150 8060 : if (ec) {
151 0 : TCP_SERVER_LOG_ERROR(this, TCP_DIR_NA, "Error during shutdown: "
152 : << ec.message());
153 : }
154 8060 : ResetAcceptor();
155 : }
156 17373 : }
157 :
158 : // Close and remove references from all sessions. The application code must
159 : // make sure it no longer holds any references to these sessions.
160 14554 : void TcpServer::ClearSessions() {
161 14554 : SessionSet refs;
162 : {
163 14554 : std::scoped_lock lock(mutex_);
164 14554 : refs.swap(session_ref_);
165 14554 : }
166 :
167 14554 : for (SessionSet::iterator iter = refs.begin(), next = iter;
168 14786 : iter != refs.end(); iter = next) {
169 232 : ++next;
170 232 : TcpSession *session = iter->get();
171 232 : session->Close();
172 : }
173 14554 : refs.clear();
174 14554 : if (session_ref_.empty() && session_map_.empty()) {
175 14550 : cond_var_.notify_all();
176 : }
177 14554 : }
178 :
179 0 : void TcpServer::UpdateSessionsDscp(uint8_t dscp) {
180 0 : std::scoped_lock lock(mutex_);
181 :
182 0 : for (SessionSet::iterator iter = session_ref_.begin(), next = iter;
183 0 : iter != session_ref_.end(); iter = next) {
184 0 : ++next;
185 0 : TcpSession *session = iter->get();
186 0 : session->SetDscpSocketOption(dscp);
187 : }
188 0 : }
189 :
190 16373 : TcpSession *TcpServer::CreateSession() {
191 16373 : TcpSession *session = AllocSession(false);
192 : {
193 16360 : std::scoped_lock lock(mutex_);
194 16374 : session_ref_.insert(TcpSessionPtr(session));
195 16374 : }
196 16374 : return session;
197 : }
198 :
199 30714 : void TcpServer::DeleteSession(TcpSession *session) {
200 : // The caller will typically close the socket before deleting the
201 : // session.
202 30714 : session->Close();
203 : {
204 30713 : std::scoped_lock lock(mutex_);
205 30716 : assert(session->refcount_);
206 30716 : session_ref_.erase(TcpSessionPtr(session));
207 30717 : if (session_ref_.empty() && session_map_.empty()) {
208 15818 : cond_var_.notify_all();
209 : }
210 30719 : }
211 30718 : }
212 :
213 : //
214 : // Insert into SessionMap.
215 : // Assumes that caller has the mutex.
216 : //
217 29242 : void TcpServer::InsertSessionToMap(Endpoint remote, TcpSession *session) {
218 29242 : session_map_.insert(make_pair(remote, session));
219 29242 : }
220 :
221 : //
222 : // Remove from SessionMap.
223 : // Assumes that caller has the mutex.
224 : // Return true if the session is found.
225 : //
226 29239 : bool TcpServer::RemoveSessionFromMap(Endpoint remote, TcpSession *session) {
227 29239 : for (SessionMap::iterator iter = session_map_.find(remote);
228 29588 : iter != session_map_.end() && iter->first == remote; ++iter) {
229 29588 : if (iter->second == session) {
230 29234 : session_map_.erase(iter);
231 29237 : return true;
232 : }
233 : }
234 0 : return false;
235 : }
236 :
237 29240 : void TcpServer::OnSessionClose(TcpSession *session) {
238 29240 : std::scoped_lock lock(mutex_);
239 :
240 : // CloseSessions closes and removes all the sessions from the map.
241 29239 : if (session_map_.empty()) {
242 0 : return;
243 : }
244 :
245 29239 : bool found = RemoveSessionFromMap(session->remote_endpoint(), session);
246 29237 : if (session_map_.empty() && session_ref_.empty()) {
247 2904 : cond_var_.notify_all();
248 : }
249 29235 : assert(found);
250 29235 : }
251 :
252 : // This method ensures that the application code requested the session to be
253 : // deleted (which may be a delayed action). It does not guarantee that the
254 : // session object has actually been freed yet as ASIO callbacks can be in
255 : // progress.
256 22518 : void TcpServer::WaitForEmpty() {
257 22518 : std::unique_lock<std::mutex> lock(mutex_);
258 22522 : while (!session_ref_.empty() || !session_map_.empty()) {
259 4 : cond_var_.wait(lock);
260 : }
261 22518 : }
262 :
263 29679 : void TcpServer::AsyncAccept() {
264 29679 : std::scoped_lock lock(mutex_);
265 29679 : if (acceptor_ == NULL) {
266 6996 : return;
267 : }
268 22683 : set_accept_socket();
269 45366 : acceptor_->async_accept(*accept_socket(),
270 45366 : bind(&TcpServer::AcceptHandlerInternal, this,
271 45366 : TcpServerPtr(this), error));
272 29679 : }
273 :
274 5734704 : int TcpServer::GetPort() const {
275 5734704 : std::scoped_lock lock(mutex_);
276 5735228 : if (acceptor_.get() == NULL) {
277 1402285 : return -1;
278 : }
279 4332908 : error_code ec;
280 4332908 : tcp::endpoint ep = acceptor_->local_endpoint(ec);
281 4332850 : if (ec) {
282 0 : return -1;
283 : }
284 4332835 : return ep.port();
285 5735047 : }
286 :
287 4 : bool TcpServer::HasSessions() const {
288 4 : std::scoped_lock lock(mutex_);
289 8 : return !session_map_.empty();
290 4 : }
291 :
292 0 : bool TcpServer::HasSessionReadAvailable() const {
293 0 : std::scoped_lock lock(mutex_);
294 0 : error_code error;
295 0 : if (accept_socket()->available(error) > 0) {
296 0 : return true;
297 : }
298 0 : for (SessionMap::const_iterator iter = session_map_.begin();
299 0 : iter != session_map_.end();
300 0 : ++iter) {
301 0 : if (iter->second->socket()->available(error) > 0) {
302 0 : return true;
303 : }
304 : }
305 0 : return false;
306 0 : }
307 :
308 11452 : TcpServer::Endpoint TcpServer::LocalEndpoint() const {
309 11452 : std::scoped_lock lock(mutex_);
310 11452 : if (acceptor_.get() == NULL) {
311 5514 : return Endpoint();
312 : }
313 5938 : error_code ec;
314 5938 : Endpoint local = acceptor_->local_endpoint(ec);
315 5938 : if (ec) {
316 0 : return Endpoint();
317 : }
318 5938 : return local;
319 11452 : }
320 :
321 16255 : TcpSession *TcpServer::AllocSession(bool server_session) {
322 : TcpSession *session;
323 16255 : if (server_session) {
324 8008 : session = AllocSession(so_accept_.get());
325 :
326 : // if session allocate succeeds release ownership to so_accept.
327 8008 : if (session != NULL) {
328 8008 : so_accept_.release();
329 : }
330 : } else {
331 8247 : Socket *socket = new Socket(*evm_->io_service());
332 8249 : session = AllocSession(socket);
333 : }
334 :
335 16239 : return session;
336 : }
337 :
338 21792 : TcpServer::Socket *TcpServer::accept_socket() const {
339 21792 : return so_accept_.get();
340 : }
341 :
342 13784 : void TcpServer::set_accept_socket() {
343 13784 : so_accept_.reset(new Socket(*evm_->io_service()));
344 13784 : }
345 :
346 12 : bool TcpServer::AcceptSession(TcpSession *session) {
347 12 : return true;
348 : }
349 :
350 : //
351 : // concurrency: called from the event_manager thread.
352 : //
353 : // accept() tcp connections. Once done, must register with boost again
354 : // via AsyncAccept() in order to process future accept calls
355 : //
356 21619 : void TcpServer::AcceptHandlerInternal(TcpServerPtr server,
357 : const error_code& error) {
358 21619 : tcp::endpoint remote;
359 21619 : error_code ec;
360 21619 : TcpSessionPtr session;
361 21619 : bool need_close = false;
362 :
363 21619 : if (error) {
364 6996 : goto done;
365 : }
366 :
367 14623 : remote = accept_socket()->remote_endpoint(ec);
368 14623 : if (ec) {
369 0 : TCP_SERVER_LOG_ERROR(this, TCP_DIR_IN,
370 : "Accept: No remote endpoint: " << ec.message());
371 0 : goto done;
372 : }
373 :
374 14623 : if (acceptor_ == NULL) {
375 0 : TCP_SESSION_LOG_DEBUG(session, TCP_DIR_IN,
376 : "Session accepted after server shutdown: "
377 : << remote.address().to_string()
378 : << ":" << remote.port());
379 0 : accept_socket()->close(ec);
380 0 : goto done;
381 : }
382 :
383 14623 : session.reset(AllocSession(true));
384 14623 : if (session == NULL) {
385 0 : TCP_SERVER_LOG_DEBUG(this, TCP_DIR_IN, "Session not created");
386 0 : goto done;
387 : }
388 :
389 14623 : ec = session->SetSocketOptions();
390 14623 : if (ec) {
391 0 : TCP_SESSION_LOG_ERROR(session, TCP_DIR_IN,
392 : "Accept: Non-blocking error: " << ec.message());
393 0 : need_close = true;
394 0 : goto done;
395 : }
396 :
397 14623 : session->SessionEstablished(remote, TcpSession::PASSIVE);
398 14623 : AcceptHandlerComplete(session);
399 :
400 21619 : done:
401 21619 : if (need_close) {
402 0 : session->CloseInternal(ec, false, false);
403 : }
404 21619 : AsyncAccept();
405 21619 : }
406 :
407 14621 : void TcpServer::AcceptHandlerComplete(TcpSessionPtr session) {
408 14621 : tcp::endpoint remote = session->remote_endpoint();
409 : {
410 14621 : std::scoped_lock lock(mutex_);
411 14621 : if (AcceptSession(session.get())) {
412 14613 : TCP_SESSION_LOG_UT_DEBUG(session, TCP_DIR_IN,
413 : "Accepted session from "
414 : << remote.address().to_string()
415 : << ":" << remote.port());
416 14577 : session_ref_.insert(session);
417 14577 : InsertSessionToMap(remote, session.get());
418 : } else {
419 44 : TCP_SESSION_LOG_UT_DEBUG(session, TCP_DIR_IN,
420 : "Rejected session from "
421 : << remote.address().to_string()
422 : << ":" << remote.port());
423 44 : error_code ec;
424 44 : session->CloseInternal(ec, false, false);
425 44 : return;
426 : }
427 14621 : }
428 :
429 14577 : session->Accepted();
430 : }
431 :
432 242845 : TcpSession *TcpServer::GetSession(Endpoint remote) {
433 242845 : std::scoped_lock lock(mutex_);
434 242845 : SessionMap::const_iterator iter = session_map_.find(remote);
435 242845 : if (iter != session_map_.end()) {
436 242830 : return iter->second;
437 : }
438 15 : return NULL;
439 242845 : }
440 :
441 16263 : void TcpServer::ConnectHandler(TcpServerPtr server, TcpSessionPtr session,
442 : const error_code &error) {
443 16263 : if (error) {
444 1596 : TCP_SERVER_LOG_UT_DEBUG(server, TCP_DIR_OUT,
445 : "Connect failure: " << error.message());
446 1596 : session->ConnectFailed();
447 1596 : return;
448 : }
449 :
450 14667 : ConnectHandlerComplete(session);
451 : }
452 :
453 14665 : void TcpServer::ConnectHandlerComplete(TcpSessionPtr session) {
454 14665 : error_code ec;
455 14665 : Endpoint remote = session->socket()->remote_endpoint(ec);
456 14665 : if (ec) {
457 0 : TCP_SERVER_LOG_INFO(this, TCP_DIR_OUT,
458 : "Connect getsockaddr: " << ec.message());
459 0 : session->ConnectFailed();
460 0 : return;
461 : }
462 :
463 : {
464 14665 : std::scoped_lock lock(mutex_);
465 14665 : InsertSessionToMap(remote, session.get());
466 14665 : }
467 :
468 : // Connected verifies whether the session has been closed or is still
469 : // active.
470 14665 : if (!session->Connected(remote)) {
471 0 : std::scoped_lock lock(mutex_);
472 0 : RemoveSessionFromMap(remote, session.get());
473 0 : }
474 : }
475 :
476 16260 : void TcpServer::Connect(TcpSession *session, Endpoint remote) {
477 16260 : assert(session->refcount_);
478 16263 : Socket *socket = session->socket();
479 16263 : socket->async_connect(remote,
480 32525 : bind(&TcpServer::ConnectHandler, this, TcpServerPtr(this),
481 32526 : TcpSessionPtr(session), error));
482 16263 : }
483 :
484 2010 : int TcpServer::SetMd5SocketOption(NativeSocketType fd, uint32_t peer_ip,
485 : const string &md5_password) {
486 2010 : assert(md5_password.size() <= TCP_MD5SIG_MAXKEYLEN);
487 2010 : if (!peer_ip) {
488 0 : TCP_SERVER_LOG_ERROR(this, TCP_DIR_NA, "Invalid peer IP");
489 0 : return 0;
490 : }
491 :
492 : struct sockaddr_in local_addr;
493 2010 : memset(&local_addr, 0, sizeof(local_addr));
494 :
495 2010 : local_addr.sin_family = AF_INET;
496 2010 : local_addr.sin_addr.s_addr = htonl(peer_ip);
497 :
498 : struct tcp_md5sig md5sig;
499 2010 : memset(&md5sig, 0, sizeof (md5sig));
500 :
501 2010 : memcpy(md5sig.tcpm_key, md5_password.c_str(), md5_password.size());
502 2010 : md5sig.tcpm_keylen = md5_password.size();
503 2010 : memcpy(&md5sig.tcpm_addr, &local_addr, sizeof(local_addr));
504 2010 : int retval = setsockopt(fd, IPPROTO_TCP, TCP_MD5SIG, (const char *)&md5sig,
505 : sizeof(md5sig));
506 2010 : if (retval < 0) {
507 12 : TCP_SERVER_LOG_ERROR(this, TCP_DIR_NA,
508 : "Failure in setting md5 key on the socket " +
509 : integerToString(fd) + " for peer " + integerToString(peer_ip) +
510 : " with errno " + strerror(errno));
511 : } else {
512 1998 : TCP_SERVER_LOG_DEBUG(this, TCP_DIR_NA,
513 : "Success in setting md5 key on the socket " +
514 : integerToString(fd) + " for peer " + integerToString(peer_ip));
515 : }
516 2010 : return retval;
517 : }
518 :
519 364 : int TcpServer::SetListenSocketMd5Option(uint32_t peer_ip,
520 : const string &md5_password) {
521 364 : int retval = 0;
522 364 : if (acceptor_) {
523 256 : retval = SetMd5SocketOption(acceptor_->native_handle(), peer_ip,
524 : md5_password);
525 : }
526 364 : return retval;
527 : }
528 :
529 0 : int TcpServer::SetListenSocketDscp(uint8_t value) {
530 0 : int retval = 0;
531 0 : if (acceptor_) {
532 0 : retval = SetDscpSocketOption(acceptor_->native_handle(), value);
533 : }
534 0 : return retval;
535 : }
536 :
537 4586 : int TcpServer::SetDscpSocketOption(NativeSocketType fd, uint8_t value) {
538 : /* The 'value' argument is expected to have DSCP value between 0 and 63 ie
539 : * in the lower order 6 bits of a byte. However, setsockopt expects DSCP
540 : * value in upper 6 bits of a byte. Hence left shift the value by 2 digits
541 : * before passing it to setsockopt */
542 4586 : value = value << 2;
543 4586 : int retval = setsockopt(fd, IPPROTO_IP, IP_TOS,
544 : reinterpret_cast<const char *>(&value), sizeof(value));
545 4586 : if (retval < 0) {
546 0 : TCP_SERVER_LOG_ERROR(this, TCP_DIR_NA,
547 : "Failure in setting DSCP value on the socket " +
548 : integerToString(fd) + " for value " + integerToString(value) +
549 : " with errno " + strerror(errno));
550 : }
551 4586 : return retval;
552 : }
553 :
554 968 : uint8_t TcpServer::GetDscpValue(NativeSocketType fd) const {
555 968 : uint8_t dscp = 0;
556 968 : unsigned int optlen = sizeof(dscp);
557 968 : int retval = getsockopt(fd, IPPROTO_IP, IP_TOS,
558 : reinterpret_cast<char *>(&dscp),
559 : reinterpret_cast<socklen_t *>(&optlen));
560 968 : if (retval < 0) {
561 0 : TCP_SERVER_LOG_ERROR(this, TCP_DIR_NA,
562 : "Failure in getting DSCP value on the socket " +
563 : integerToString(fd) + " with errno " + strerror(errno));
564 : }
565 968 : return dscp;
566 : }
567 :
568 87 : int TcpServer::SetSocketOptions(const SandeshConfig &sandesh_config) {
569 87 : int retval = 0;
570 87 : if (acceptor_ && sandesh_config.tcp_keepalive_enable) {
571 87 : retval = SetKeepAliveSocketOption(acceptor_->native_handle(), sandesh_config);
572 : }
573 87 : return retval;
574 : }
575 :
576 87 : int TcpServer::SetKeepAliveSocketOption(int fd, const SandeshConfig &sandesh_config) {
577 87 : int tcp_keepalive_enable = 1, retval = 0;
578 87 : int tcp_keepalive_idle_time = sandesh_config.tcp_keepalive_idle_time;
579 87 : int tcp_keepalive_probes = sandesh_config.tcp_keepalive_probes;
580 87 : int tcp_keepalive_interval = sandesh_config.tcp_keepalive_interval;
581 87 : retval = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
582 : reinterpret_cast<const char *>(&tcp_keepalive_enable), sizeof(tcp_keepalive_enable));
583 87 : if (retval < 0) {
584 0 : TCP_SERVER_LOG_ERROR(this, TCP_DIR_NA,
585 : "Failure in setting Keepalive enable on the socket " +
586 : integerToString(fd) +
587 : " with errno " + strerror(errno));
588 0 : return retval;
589 : }
590 :
591 : #ifdef TCP_KEEPIDLE
592 87 : retval = setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE,
593 : reinterpret_cast<const char *>(&tcp_keepalive_idle_time), sizeof(tcp_keepalive_idle_time));
594 87 : if (retval < 0) {
595 0 : TCP_SERVER_LOG_ERROR(this, TCP_DIR_NA,
596 : "Failure in setting keepalive idle time on the socket " +
597 : integerToString(fd) +
598 : " with errno " + strerror(errno));
599 0 : return retval;
600 : }
601 : #elif TCP_KEEPALIVE
602 : retval = setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE,
603 : reinterpret_cast<const char *>(&tcp_keepalive_idle_time), sizeof(tcp_keepalive_idle_time));
604 : if (retval < 0) {
605 : TCP_SERVER_LOG_ERROR(this, TCP_DIR_NA,
606 : "Failure in setting keepalive time on the socket " +
607 : integerToString(fd) +
608 : " with errno " + strerror(errno));
609 : return retval;
610 : }
611 : #else
612 : #error No TCP keepalive option defined.
613 : #endif
614 :
615 : #ifdef TCP_KEEPCNT
616 87 : retval = setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT,
617 : reinterpret_cast<const char *>(&tcp_keepalive_probes), sizeof(tcp_keepalive_probes));
618 87 : if (retval < 0) {
619 0 : TCP_SERVER_LOG_ERROR(this, TCP_DIR_NA,
620 : "Failure in setting keepalive probes on the socket " +
621 : integerToString(fd) +
622 : " with errno " + strerror(errno));
623 0 : return retval;
624 : }
625 : #endif
626 :
627 : #ifdef TCP_KEEPINTVL
628 87 : retval = setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL,
629 : reinterpret_cast<const char *>(&tcp_keepalive_interval), sizeof(tcp_keepalive_interval));
630 87 : if (retval < 0) {
631 0 : TCP_SERVER_LOG_ERROR(this, TCP_DIR_NA,
632 : "Failure in setting keepalive interval on the socket " +
633 : integerToString(fd) +
634 : " with errno " + strerror(errno));
635 0 : return retval;
636 : }
637 : #endif
638 87 : return retval;
639 : }
640 :
641 669 : void TcpServer::GetRxSocketStats(SocketIOStats *socket_stats) const {
642 669 : stats_.GetRxStats(socket_stats);
643 669 : }
644 :
645 669 : void TcpServer::GetTxSocketStats(SocketIOStats *socket_stats) const {
646 669 : stats_.GetTxStats(socket_stats);
647 669 : }
648 :
649 : //
650 : // TcpServerManager class routines
651 : //
652 : ServerManager<TcpServer, TcpServerPtr> TcpServerManager::impl_;
653 :
654 17561 : void TcpServerManager::AddServer(TcpServer *server) {
655 17561 : impl_.AddServer(server);
656 17561 : }
657 :
658 17453 : void TcpServerManager::DeleteServer(TcpServer *server) {
659 : // Wait for pending writes to be complete
660 17453 : server->WaitForEmpty();
661 17453 : impl_.DeleteServer(server);
662 17453 : }
663 :
664 1243 : size_t TcpServerManager::GetServerCount() {
665 1243 : return impl_.GetServerCount();
666 : }
|