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 1016 : TcpServer::TcpServer(EventManager *evm)
33 1016 : : evm_(evm), socket_open_failure_(false), intf_id_(-1) {
34 1016 : refcount_ = 0;
35 1016 : TcpServerManager::AddServer(this);
36 1016 : }
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 1015 : TcpServer::~TcpServer() {
44 1015 : assert(acceptor_ == NULL);
45 1015 : assert(session_ref_.empty());
46 1015 : assert(session_map_.empty());
47 1015 : }
48 :
49 832 : void TcpServer::SetName(Endpoint local_endpoint) {
50 832 : ostringstream out;
51 832 : out << local_endpoint;
52 832 : name_ = out.str();
53 832 : }
54 :
55 832 : void TcpServer::ResetAcceptor() {
56 832 : acceptor_.reset();
57 832 : name_ = "";
58 832 : }
59 :
60 475 : bool TcpServer::Initialize(unsigned short port) {
61 475 : intf_id_ = -1; //this initializer is only for IPv4
62 475 : tcp::endpoint localaddr(tcp::v4(), port);
63 475 : return InitializeInternal(localaddr);
64 : }
65 :
66 357 : bool TcpServer::Initialize(unsigned short port,
67 : const IpAddress &host_ip,
68 : int intf_id) {
69 357 : tcp::endpoint localaddr(host_ip, port);
70 357 : tcp::endpoint serv_ep(host_ip, port);
71 357 : intf_id_ = intf_id;
72 357 : 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 357 : return InitializeInternal(serv_ep);
80 : }
81 :
82 832 : bool TcpServer::InitializeInternal(tcp::endpoint localaddr) {
83 832 : acceptor_.reset(new tcp::acceptor(*evm_->io_service()));
84 832 : if (!acceptor_) {
85 0 : TCP_SERVER_LOG_ERROR(this, TCP_DIR_NA, "Cannot create acceptor");
86 0 : return false;
87 : }
88 :
89 832 : error_code ec;
90 832 : if (localaddr.address().is_v4())
91 828 : acceptor_->open(tcp::v4(), ec);
92 : else
93 4 : acceptor_->open(tcp::v6(), ec);
94 :
95 832 : 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 832 : acceptor_->set_option(socket_base::reuse_address(true), ec);
102 832 : 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 832 : acceptor_->bind(localaddr, ec);
110 832 : if (ec) {
111 0 : TCP_SERVER_LOG_ERROR(this, TCP_DIR_NA, "TCP bind(" << localaddr.address() <<
112 : ":" << localaddr.port() << "): " << ec.message());
113 0 : ResetAcceptor();
114 0 : return false;
115 : }
116 :
117 832 : tcp::endpoint local_endpoint = acceptor_->local_endpoint(ec);
118 832 : 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 832 : SetName(local_endpoint);
129 :
130 832 : acceptor_->listen(socket_base::max_connections, ec);
131 832 : 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 832 : TCP_SERVER_LOG_DEBUG(this, TCP_DIR_NA, "Initialization complete");
139 832 : AsyncAccept();
140 :
141 832 : return true;
142 : }
143 :
144 971 : void TcpServer::Shutdown() {
145 971 : std::scoped_lock lock(mutex_);
146 971 : error_code ec;
147 :
148 971 : if (acceptor_) {
149 832 : acceptor_->close(ec);
150 832 : if (ec) {
151 0 : TCP_SERVER_LOG_ERROR(this, TCP_DIR_NA, "Error during shutdown: "
152 : << ec.message());
153 : }
154 832 : ResetAcceptor();
155 : }
156 971 : }
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 1021 : void TcpServer::ClearSessions() {
161 1021 : SessionSet refs;
162 : {
163 1021 : std::scoped_lock lock(mutex_);
164 1021 : refs.swap(session_ref_);
165 1021 : }
166 :
167 1021 : for (SessionSet::iterator iter = refs.begin(), next = iter;
168 1254 : iter != refs.end(); iter = next) {
169 233 : ++next;
170 233 : TcpSession *session = iter->get();
171 233 : session->Close();
172 : }
173 1021 : refs.clear();
174 1021 : if (session_ref_.empty() && session_map_.empty()) {
175 1017 : cond_var_.notify_all();
176 : }
177 1021 : }
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 1277 : TcpSession *TcpServer::CreateSession() {
191 1277 : TcpSession *session = AllocSession(false);
192 : {
193 1262 : std::scoped_lock lock(mutex_);
194 1282 : session_ref_.insert(TcpSessionPtr(session));
195 1282 : }
196 1282 : return session;
197 : }
198 :
199 2081 : void TcpServer::DeleteSession(TcpSession *session) {
200 : // The caller will typically close the socket before deleting the
201 : // session.
202 2081 : session->Close();
203 : {
204 2083 : std::scoped_lock lock(mutex_);
205 2084 : assert(session->refcount_);
206 2084 : session_ref_.erase(TcpSessionPtr(session));
207 2084 : if (session_ref_.empty() && session_map_.empty()) {
208 731 : cond_var_.notify_all();
209 : }
210 2084 : }
211 2084 : }
212 :
213 : //
214 : // Insert into SessionMap.
215 : // Assumes that caller has the mutex.
216 : //
217 2157 : void TcpServer::InsertSessionToMap(Endpoint remote, TcpSession *session) {
218 2157 : session_map_.insert(make_pair(remote, session));
219 2157 : }
220 :
221 : //
222 : // Remove from SessionMap.
223 : // Assumes that caller has the mutex.
224 : // Return true if the session is found.
225 : //
226 2157 : bool TcpServer::RemoveSessionFromMap(Endpoint remote, TcpSession *session) {
227 2157 : for (SessionMap::iterator iter = session_map_.find(remote);
228 2497 : iter != session_map_.end() && iter->first == remote; ++iter) {
229 2496 : if (iter->second == session) {
230 2155 : session_map_.erase(iter);
231 2157 : return true;
232 : }
233 : }
234 0 : return false;
235 : }
236 :
237 2156 : void TcpServer::OnSessionClose(TcpSession *session) {
238 2156 : std::scoped_lock lock(mutex_);
239 :
240 : // CloseSessions closes and removes all the sessions from the map.
241 2157 : if (session_map_.empty()) {
242 0 : return;
243 : }
244 :
245 2157 : bool found = RemoveSessionFromMap(session->remote_endpoint(), session);
246 2157 : if (session_map_.empty() && session_ref_.empty()) {
247 147 : cond_var_.notify_all();
248 : }
249 2157 : assert(found);
250 2157 : }
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 1061 : void TcpServer::WaitForEmpty() {
257 1061 : std::unique_lock<std::mutex> lock(mutex_);
258 1065 : while (!session_ref_.empty() || !session_map_.empty()) {
259 4 : cond_var_.wait(lock);
260 : }
261 1061 : }
262 :
263 2617 : void TcpServer::AsyncAccept() {
264 2617 : std::scoped_lock lock(mutex_);
265 2617 : if (acceptor_ == NULL) {
266 708 : return;
267 : }
268 1909 : set_accept_socket();
269 3818 : acceptor_->async_accept(*accept_socket(),
270 3818 : bind(&TcpServer::AcceptHandlerInternal, this,
271 3818 : TcpServerPtr(this), error));
272 2617 : }
273 :
274 1957 : int TcpServer::GetPort() const {
275 1957 : std::scoped_lock lock(mutex_);
276 1970 : if (acceptor_.get() == NULL) {
277 133 : return -1;
278 : }
279 1837 : error_code ec;
280 1837 : tcp::endpoint ep = acceptor_->local_endpoint(ec);
281 1837 : if (ec) {
282 0 : return -1;
283 : }
284 1837 : return ep.port();
285 1970 : }
286 :
287 3 : bool TcpServer::HasSessions() const {
288 3 : std::scoped_lock lock(mutex_);
289 6 : return !session_map_.empty();
290 3 : }
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 634 : TcpServer::Endpoint TcpServer::LocalEndpoint() const {
309 634 : std::scoped_lock lock(mutex_);
310 634 : if (acceptor_.get() == NULL) {
311 310 : return Endpoint();
312 : }
313 324 : error_code ec;
314 324 : Endpoint local = acceptor_->local_endpoint(ec);
315 324 : if (ec) {
316 0 : return Endpoint();
317 : }
318 324 : return local;
319 634 : }
320 :
321 2171 : TcpSession *TcpServer::AllocSession(bool server_session) {
322 : TcpSession *session;
323 2171 : if (server_session) {
324 1049 : session = AllocSession(so_accept_.get());
325 :
326 : // if session allocate succeeds release ownership to so_accept.
327 1049 : if (session != NULL) {
328 1049 : so_accept_.release();
329 : }
330 : } else {
331 1122 : Socket *socket = new Socket(*evm_->io_service());
332 1119 : session = AllocSession(socket);
333 : }
334 :
335 2154 : return session;
336 : }
337 :
338 2802 : TcpServer::Socket *TcpServer::accept_socket() const {
339 2802 : return so_accept_.get();
340 : }
341 :
342 1753 : void TcpServer::set_accept_socket() {
343 1753 : so_accept_.reset(new Socket(*evm_->io_service()));
344 1753 : }
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 1785 : void TcpServer::AcceptHandlerInternal(TcpServerPtr server,
357 : const error_code& error) {
358 1785 : tcp::endpoint remote;
359 1785 : error_code ec;
360 1785 : TcpSessionPtr session;
361 1785 : bool need_close = false;
362 :
363 1785 : if (error) {
364 708 : goto done;
365 : }
366 :
367 1077 : remote = accept_socket()->remote_endpoint(ec);
368 1077 : 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 1077 : 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 1077 : session.reset(AllocSession(true));
384 1077 : if (session == NULL) {
385 0 : TCP_SERVER_LOG_DEBUG(this, TCP_DIR_IN, "Session not created");
386 0 : goto done;
387 : }
388 :
389 1077 : ec = session->SetSocketOptions();
390 1077 : 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 1077 : session->SessionEstablished(remote, TcpSession::PASSIVE);
398 1077 : AcceptHandlerComplete(session);
399 :
400 1785 : done:
401 1785 : if (need_close) {
402 0 : session->CloseInternal(ec, false, false);
403 : }
404 1785 : AsyncAccept();
405 1785 : }
406 :
407 1075 : void TcpServer::AcceptHandlerComplete(TcpSessionPtr session) {
408 1075 : tcp::endpoint remote = session->remote_endpoint();
409 : {
410 1075 : std::scoped_lock lock(mutex_);
411 1075 : if (AcceptSession(session.get())) {
412 1035 : TCP_SESSION_LOG_UT_DEBUG(session, TCP_DIR_IN,
413 : "Accepted session from "
414 : << remote.address().to_string()
415 : << ":" << remote.port());
416 1035 : session_ref_.insert(session);
417 1035 : InsertSessionToMap(remote, session.get());
418 : } else {
419 40 : TCP_SESSION_LOG_UT_DEBUG(session, TCP_DIR_IN,
420 : "Rejected session from "
421 : << remote.address().to_string()
422 : << ":" << remote.port());
423 40 : error_code ec;
424 40 : session->CloseInternal(ec, false, false);
425 40 : return;
426 : }
427 1075 : }
428 :
429 1035 : session->Accepted();
430 : }
431 :
432 160674 : TcpSession *TcpServer::GetSession(Endpoint remote) {
433 160674 : std::scoped_lock lock(mutex_);
434 160674 : SessionMap::const_iterator iter = session_map_.find(remote);
435 160674 : if (iter != session_map_.end()) {
436 160666 : return iter->second;
437 : }
438 8 : return NULL;
439 160674 : }
440 :
441 1171 : void TcpServer::ConnectHandler(TcpServerPtr server, TcpSessionPtr session,
442 : const error_code &error) {
443 1171 : if (error) {
444 47 : TCP_SERVER_LOG_UT_DEBUG(server, TCP_DIR_OUT,
445 : "Connect failure: " << error.message());
446 47 : session->ConnectFailed();
447 47 : return;
448 : }
449 :
450 1124 : ConnectHandlerComplete(session);
451 : }
452 :
453 1122 : void TcpServer::ConnectHandlerComplete(TcpSessionPtr session) {
454 1122 : error_code ec;
455 1122 : Endpoint remote = session->socket()->remote_endpoint(ec);
456 1122 : 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 1122 : std::scoped_lock lock(mutex_);
465 1122 : InsertSessionToMap(remote, session.get());
466 1122 : }
467 :
468 : // Connected verifies whether the session has been closed or is still
469 : // active.
470 1122 : if (!session->Connected(remote)) {
471 0 : std::scoped_lock lock(mutex_);
472 0 : RemoveSessionFromMap(remote, session.get());
473 0 : }
474 : }
475 :
476 1171 : void TcpServer::Connect(TcpSession *session, Endpoint remote) {
477 1171 : assert(session->refcount_);
478 1171 : Socket *socket = session->socket();
479 1171 : socket->async_connect(remote,
480 2341 : bind(&TcpServer::ConnectHandler, this, TcpServerPtr(this),
481 2341 : TcpSessionPtr(session), error));
482 1170 : }
483 :
484 0 : int TcpServer::SetMd5SocketOption(NativeSocketType fd, uint32_t peer_ip,
485 : const string &md5_password) {
486 0 : assert(md5_password.size() <= TCP_MD5SIG_MAXKEYLEN);
487 0 : 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 0 : memset(&local_addr, 0, sizeof(local_addr));
494 :
495 0 : local_addr.sin_family = AF_INET;
496 0 : local_addr.sin_addr.s_addr = htonl(peer_ip);
497 :
498 : struct tcp_md5sig md5sig;
499 0 : memset(&md5sig, 0, sizeof (md5sig));
500 :
501 0 : memcpy(md5sig.tcpm_key, md5_password.c_str(), md5_password.size());
502 0 : md5sig.tcpm_keylen = md5_password.size();
503 0 : memcpy(&md5sig.tcpm_addr, &local_addr, sizeof(local_addr));
504 0 : int retval = setsockopt(fd, IPPROTO_TCP, TCP_MD5SIG, (const char *)&md5sig,
505 : sizeof(md5sig));
506 0 : if (retval < 0) {
507 0 : 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 0 : 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 0 : return retval;
517 : }
518 :
519 0 : int TcpServer::SetListenSocketMd5Option(uint32_t peer_ip,
520 : const string &md5_password) {
521 0 : int retval = 0;
522 0 : if (acceptor_) {
523 0 : retval = SetMd5SocketOption(acceptor_->native_handle(), peer_ip,
524 : md5_password);
525 : }
526 0 : 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 700 : 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 700 : value = value << 2;
543 700 : int retval = setsockopt(fd, IPPROTO_IP, IP_TOS,
544 : reinterpret_cast<const char *>(&value), sizeof(value));
545 700 : 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 700 : return retval;
552 : }
553 :
554 0 : uint8_t TcpServer::GetDscpValue(NativeSocketType fd) const {
555 0 : uint8_t dscp = 0;
556 0 : unsigned int optlen = sizeof(dscp);
557 0 : int retval = getsockopt(fd, IPPROTO_IP, IP_TOS,
558 : reinterpret_cast<char *>(&dscp),
559 : reinterpret_cast<socklen_t *>(&optlen));
560 0 : 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 0 : return dscp;
566 : }
567 :
568 46 : int TcpServer::SetSocketOptions(const SandeshConfig &sandesh_config) {
569 46 : int retval = 0;
570 46 : if (acceptor_ && sandesh_config.tcp_keepalive_enable) {
571 46 : retval = SetKeepAliveSocketOption(acceptor_->native_handle(), sandesh_config);
572 : }
573 46 : return retval;
574 : }
575 :
576 46 : int TcpServer::SetKeepAliveSocketOption(int fd, const SandeshConfig &sandesh_config) {
577 46 : int tcp_keepalive_enable = 1, retval = 0;
578 46 : int tcp_keepalive_idle_time = sandesh_config.tcp_keepalive_idle_time;
579 46 : int tcp_keepalive_probes = sandesh_config.tcp_keepalive_probes;
580 46 : int tcp_keepalive_interval = sandesh_config.tcp_keepalive_interval;
581 46 : retval = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
582 : reinterpret_cast<const char *>(&tcp_keepalive_enable), sizeof(tcp_keepalive_enable));
583 46 : 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 46 : retval = setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE,
593 : reinterpret_cast<const char *>(&tcp_keepalive_idle_time), sizeof(tcp_keepalive_idle_time));
594 46 : 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 46 : retval = setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT,
617 : reinterpret_cast<const char *>(&tcp_keepalive_probes), sizeof(tcp_keepalive_probes));
618 46 : 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 46 : retval = setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL,
629 : reinterpret_cast<const char *>(&tcp_keepalive_interval), sizeof(tcp_keepalive_interval));
630 46 : 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 46 : return retval;
639 : }
640 :
641 399 : void TcpServer::GetRxSocketStats(SocketIOStats *socket_stats) const {
642 399 : stats_.GetRxStats(socket_stats);
643 399 : }
644 :
645 399 : void TcpServer::GetTxSocketStats(SocketIOStats *socket_stats) const {
646 399 : stats_.GetTxStats(socket_stats);
647 399 : }
648 :
649 : //
650 : // TcpServerManager class routines
651 : //
652 : ServerManager<TcpServer, TcpServerPtr> TcpServerManager::impl_;
653 :
654 1016 : void TcpServerManager::AddServer(TcpServer *server) {
655 1016 : impl_.AddServer(server);
656 1016 : }
657 :
658 1015 : void TcpServerManager::DeleteServer(TcpServer *server) {
659 : // Wait for pending writes to be complete
660 1015 : server->WaitForEmpty();
661 1015 : impl_.DeleteServer(server);
662 1015 : }
663 :
664 126 : size_t TcpServerManager::GetServerCount() {
665 126 : return impl_.GetServerCount();
666 : }
|