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 17555 : TcpServer::TcpServer(EventManager *evm)
33 17555 : : evm_(evm), socket_open_failure_(false), intf_id_(-1) {
34 17555 : refcount_ = 0;
35 17555 : TcpServerManager::AddServer(this);
36 17555 : }
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 17554 : TcpServer::~TcpServer() {
44 17554 : assert(acceptor_ == NULL);
45 17554 : assert(session_ref_.empty());
46 17554 : assert(session_map_.empty());
47 17554 : }
48 :
49 8075 : void TcpServer::SetName(Endpoint local_endpoint) {
50 8075 : ostringstream out;
51 8075 : out << local_endpoint;
52 8075 : name_ = out.str();
53 8075 : }
54 :
55 8187 : void TcpServer::ResetAcceptor() {
56 8187 : acceptor_.reset();
57 8187 : name_ = "";
58 8187 : }
59 :
60 2472 : bool TcpServer::Initialize(unsigned short port) {
61 2472 : intf_id_ = -1; //this initializer is only for IPv4
62 2472 : tcp::endpoint localaddr(tcp::v4(), port);
63 2472 : return InitializeInternal(localaddr);
64 : }
65 :
66 5715 : bool TcpServer::Initialize(unsigned short port,
67 : const IpAddress &host_ip,
68 : int intf_id) {
69 5715 : tcp::endpoint localaddr(host_ip, port);
70 5715 : tcp::endpoint serv_ep(host_ip, port);
71 5715 : intf_id_ = intf_id;
72 5715 : 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 5715 : return InitializeInternal(serv_ep);
80 : }
81 :
82 8187 : bool TcpServer::InitializeInternal(tcp::endpoint localaddr) {
83 8187 : acceptor_.reset(new tcp::acceptor(*evm_->io_service()));
84 8187 : if (!acceptor_) {
85 0 : TCP_SERVER_LOG_ERROR(this, TCP_DIR_NA, "Cannot create acceptor");
86 0 : return false;
87 : }
88 :
89 8187 : error_code ec;
90 8187 : if (localaddr.address().is_v4())
91 8183 : acceptor_->open(tcp::v4(), ec);
92 : else
93 4 : acceptor_->open(tcp::v6(), ec);
94 :
95 8187 : 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 8187 : acceptor_->set_option(socket_base::reuse_address(true), ec);
102 8187 : 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 8187 : acceptor_->bind(localaddr, ec);
110 8187 : if (ec) {
111 112 : TCP_SERVER_LOG_ERROR(this, TCP_DIR_NA, "TCP bind(" << localaddr.address() <<
112 : ":" << localaddr.port() << "): " << ec.message());
113 112 : ResetAcceptor();
114 112 : return false;
115 : }
116 :
117 8075 : tcp::endpoint local_endpoint = acceptor_->local_endpoint(ec);
118 8075 : 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 8075 : SetName(local_endpoint);
129 :
130 8075 : acceptor_->listen(socket_base::max_connections, ec);
131 8075 : 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 8111 : TCP_SERVER_LOG_DEBUG(this, TCP_DIR_NA, "Initialization complete");
139 8075 : AsyncAccept();
140 :
141 8075 : return true;
142 : }
143 :
144 17369 : void TcpServer::Shutdown() {
145 17369 : std::scoped_lock lock(mutex_);
146 17369 : error_code ec;
147 :
148 17369 : if (acceptor_) {
149 8075 : acceptor_->close(ec);
150 8075 : if (ec) {
151 0 : TCP_SERVER_LOG_ERROR(this, TCP_DIR_NA, "Error during shutdown: "
152 : << ec.message());
153 : }
154 8075 : ResetAcceptor();
155 : }
156 17369 : }
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 14550 : void TcpServer::ClearSessions() {
161 14550 : SessionSet refs;
162 : {
163 14550 : std::scoped_lock lock(mutex_);
164 14550 : refs.swap(session_ref_);
165 14550 : }
166 :
167 14550 : for (SessionSet::iterator iter = refs.begin(), next = iter;
168 14783 : iter != refs.end(); iter = next) {
169 233 : ++next;
170 233 : TcpSession *session = iter->get();
171 233 : session->Close();
172 : }
173 14550 : refs.clear();
174 14550 : if (session_ref_.empty() && session_map_.empty()) {
175 14548 : cond_var_.notify_all();
176 : }
177 14550 : }
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 15228 : TcpSession *TcpServer::CreateSession() {
191 15228 : TcpSession *session = AllocSession(false);
192 : {
193 15215 : std::scoped_lock lock(mutex_);
194 15230 : session_ref_.insert(TcpSessionPtr(session));
195 15230 : }
196 15230 : return session;
197 : }
198 :
199 28587 : void TcpServer::DeleteSession(TcpSession *session) {
200 : // The caller will typically close the socket before deleting the
201 : // session.
202 28587 : session->Close();
203 : {
204 28588 : std::scoped_lock lock(mutex_);
205 28592 : assert(session->refcount_);
206 28590 : session_ref_.erase(TcpSessionPtr(session));
207 28591 : if (session_ref_.empty() && session_map_.empty()) {
208 14890 : cond_var_.notify_all();
209 : }
210 28592 : }
211 28592 : }
212 :
213 : //
214 : // Insert into SessionMap.
215 : // Assumes that caller has the mutex.
216 : //
217 27277 : void TcpServer::InsertSessionToMap(Endpoint remote, TcpSession *session) {
218 27277 : session_map_.insert(make_pair(remote, session));
219 27277 : }
220 :
221 : //
222 : // Remove from SessionMap.
223 : // Assumes that caller has the mutex.
224 : // Return true if the session is found.
225 : //
226 27275 : bool TcpServer::RemoveSessionFromMap(Endpoint remote, TcpSession *session) {
227 27275 : for (SessionMap::iterator iter = session_map_.find(remote);
228 27603 : iter != session_map_.end() && iter->first == remote; ++iter) {
229 27601 : if (iter->second == session) {
230 27266 : session_map_.erase(iter);
231 27273 : return true;
232 : }
233 : }
234 0 : return false;
235 : }
236 :
237 27273 : void TcpServer::OnSessionClose(TcpSession *session) {
238 27273 : std::scoped_lock lock(mutex_);
239 :
240 : // CloseSessions closes and removes all the sessions from the map.
241 27277 : if (session_map_.empty()) {
242 0 : return;
243 : }
244 :
245 27277 : bool found = RemoveSessionFromMap(session->remote_endpoint(), session);
246 27273 : if (session_map_.empty() && session_ref_.empty()) {
247 2660 : cond_var_.notify_all();
248 : }
249 27268 : assert(found);
250 27268 : }
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 22512 : void TcpServer::WaitForEmpty() {
257 22512 : std::unique_lock<std::mutex> lock(mutex_);
258 22514 : while (!session_ref_.empty() || !session_map_.empty()) {
259 2 : cond_var_.wait(lock);
260 : }
261 22512 : }
262 :
263 28803 : void TcpServer::AsyncAccept() {
264 28803 : std::scoped_lock lock(mutex_);
265 28803 : if (acceptor_ == NULL) {
266 7087 : return;
267 : }
268 21716 : set_accept_socket();
269 43432 : acceptor_->async_accept(*accept_socket(),
270 43432 : bind(&TcpServer::AcceptHandlerInternal, this,
271 43432 : TcpServerPtr(this), error));
272 28803 : }
273 :
274 5708329 : int TcpServer::GetPort() const {
275 5708329 : std::scoped_lock lock(mutex_);
276 5709092 : if (acceptor_.get() == NULL) {
277 1269706 : return -1;
278 : }
279 4439337 : error_code ec;
280 4439337 : tcp::endpoint ep = acceptor_->local_endpoint(ec);
281 4439298 : if (ec) {
282 0 : return -1;
283 : }
284 4439285 : return ep.port();
285 5708919 : }
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 5510 : return Endpoint();
312 : }
313 5942 : error_code ec;
314 5942 : Endpoint local = acceptor_->local_endpoint(ec);
315 5942 : if (ec) {
316 0 : return Endpoint();
317 : }
318 5942 : return local;
319 11452 : }
320 :
321 14299 : TcpSession *TcpServer::AllocSession(bool server_session) {
322 : TcpSession *session;
323 14299 : if (server_session) {
324 7029 : session = AllocSession(so_accept_.get());
325 :
326 : // if session allocate succeeds release ownership to so_accept.
327 7029 : if (session != NULL) {
328 7029 : so_accept_.release();
329 : }
330 : } else {
331 7270 : Socket *socket = new Socket(*evm_->io_service());
332 7267 : session = AllocSession(socket);
333 : }
334 :
335 14284 : return session;
336 : }
337 :
338 19851 : TcpServer::Socket *TcpServer::accept_socket() const {
339 19851 : return so_accept_.get();
340 : }
341 :
342 12822 : void TcpServer::set_accept_socket() {
343 12822 : so_accept_.reset(new Socket(*evm_->io_service()));
344 12822 : }
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 20728 : void TcpServer::AcceptHandlerInternal(TcpServerPtr server,
357 : const error_code& error) {
358 20728 : tcp::endpoint remote;
359 20728 : error_code ec;
360 20728 : TcpSessionPtr session;
361 20728 : bool need_close = false;
362 :
363 20728 : if (error) {
364 7087 : goto done;
365 : }
366 :
367 13641 : remote = accept_socket()->remote_endpoint(ec);
368 13641 : 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 13641 : 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 13641 : session.reset(AllocSession(true));
384 13641 : if (session == NULL) {
385 0 : TCP_SERVER_LOG_DEBUG(this, TCP_DIR_IN, "Session not created");
386 0 : goto done;
387 : }
388 :
389 13641 : ec = session->SetSocketOptions();
390 13641 : 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 13641 : session->SessionEstablished(remote, TcpSession::PASSIVE);
398 13641 : AcceptHandlerComplete(session);
399 :
400 20728 : done:
401 20728 : if (need_close) {
402 0 : session->CloseInternal(ec, false, false);
403 : }
404 20728 : AsyncAccept();
405 20728 : }
406 :
407 13639 : void TcpServer::AcceptHandlerComplete(TcpSessionPtr session) {
408 13639 : tcp::endpoint remote = session->remote_endpoint();
409 : {
410 13639 : std::scoped_lock lock(mutex_);
411 13639 : if (AcceptSession(session.get())) {
412 13631 : TCP_SESSION_LOG_UT_DEBUG(session, TCP_DIR_IN,
413 : "Accepted session from "
414 : << remote.address().to_string()
415 : << ":" << remote.port());
416 13595 : session_ref_.insert(session);
417 13595 : 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 13639 : }
428 :
429 13595 : session->Accepted();
430 : }
431 :
432 161610 : TcpSession *TcpServer::GetSession(Endpoint remote) {
433 161610 : std::scoped_lock lock(mutex_);
434 161610 : SessionMap::const_iterator iter = session_map_.find(remote);
435 161610 : if (iter != session_map_.end()) {
436 161600 : return iter->second;
437 : }
438 10 : return NULL;
439 161610 : }
440 :
441 15119 : void TcpServer::ConnectHandler(TcpServerPtr server, TcpSessionPtr session,
442 : const error_code &error) {
443 15119 : if (error) {
444 1435 : TCP_SERVER_LOG_UT_DEBUG(server, TCP_DIR_OUT,
445 : "Connect failure: " << error.message());
446 1435 : session->ConnectFailed();
447 1435 : return;
448 : }
449 :
450 13684 : ConnectHandlerComplete(session);
451 : }
452 :
453 13682 : void TcpServer::ConnectHandlerComplete(TcpSessionPtr session) {
454 13682 : error_code ec;
455 13682 : Endpoint remote = session->socket()->remote_endpoint(ec);
456 13682 : 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 13682 : std::scoped_lock lock(mutex_);
465 13682 : InsertSessionToMap(remote, session.get());
466 13682 : }
467 :
468 : // Connected verifies whether the session has been closed or is still
469 : // active.
470 13682 : if (!session->Connected(remote)) {
471 0 : std::scoped_lock lock(mutex_);
472 0 : RemoveSessionFromMap(remote, session.get());
473 0 : }
474 : }
475 :
476 15115 : void TcpServer::Connect(TcpSession *session, Endpoint remote) {
477 15115 : assert(session->refcount_);
478 15118 : Socket *socket = session->socket();
479 15119 : socket->async_connect(remote,
480 30238 : bind(&TcpServer::ConnectHandler, this, TcpServerPtr(this),
481 30236 : TcpSessionPtr(session), error));
482 15119 : }
483 :
484 1546 : int TcpServer::SetMd5SocketOption(NativeSocketType fd, uint32_t peer_ip,
485 : const string &md5_password) {
486 1546 : assert(md5_password.size() <= TCP_MD5SIG_MAXKEYLEN);
487 1546 : 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 1546 : memset(&local_addr, 0, sizeof(local_addr));
494 :
495 1546 : local_addr.sin_family = AF_INET;
496 1546 : local_addr.sin_addr.s_addr = htonl(peer_ip);
497 :
498 : struct tcp_md5sig md5sig;
499 1546 : memset(&md5sig, 0, sizeof (md5sig));
500 :
501 1546 : memcpy(md5sig.tcpm_key, md5_password.c_str(), md5_password.size());
502 1546 : md5sig.tcpm_keylen = md5_password.size();
503 1546 : memcpy(&md5sig.tcpm_addr, &local_addr, sizeof(local_addr));
504 1546 : int retval = setsockopt(fd, IPPROTO_TCP, TCP_MD5SIG, (const char *)&md5sig,
505 : sizeof(md5sig));
506 1546 : 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 1534 : 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 1546 : 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 4187 : 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 4187 : value = value << 2;
543 4187 : int retval = setsockopt(fd, IPPROTO_IP, IP_TOS,
544 : reinterpret_cast<const char *>(&value), sizeof(value));
545 4187 : 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 4187 : 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 85 : int TcpServer::SetSocketOptions(const SandeshConfig &sandesh_config) {
569 85 : int retval = 0;
570 85 : if (acceptor_ && sandesh_config.tcp_keepalive_enable) {
571 85 : retval = SetKeepAliveSocketOption(acceptor_->native_handle(), sandesh_config);
572 : }
573 85 : return retval;
574 : }
575 :
576 85 : int TcpServer::SetKeepAliveSocketOption(int fd, const SandeshConfig &sandesh_config) {
577 85 : int tcp_keepalive_enable = 1, retval = 0;
578 85 : int tcp_keepalive_idle_time = sandesh_config.tcp_keepalive_idle_time;
579 85 : int tcp_keepalive_probes = sandesh_config.tcp_keepalive_probes;
580 85 : int tcp_keepalive_interval = sandesh_config.tcp_keepalive_interval;
581 85 : retval = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
582 : reinterpret_cast<const char *>(&tcp_keepalive_enable), sizeof(tcp_keepalive_enable));
583 85 : 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 85 : retval = setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE,
593 : reinterpret_cast<const char *>(&tcp_keepalive_idle_time), sizeof(tcp_keepalive_idle_time));
594 85 : 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 85 : retval = setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT,
617 : reinterpret_cast<const char *>(&tcp_keepalive_probes), sizeof(tcp_keepalive_probes));
618 85 : 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 85 : retval = setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL,
629 : reinterpret_cast<const char *>(&tcp_keepalive_interval), sizeof(tcp_keepalive_interval));
630 85 : 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 85 : return retval;
639 : }
640 :
641 659 : void TcpServer::GetRxSocketStats(SocketIOStats *socket_stats) const {
642 659 : stats_.GetRxStats(socket_stats);
643 659 : }
644 :
645 659 : void TcpServer::GetTxSocketStats(SocketIOStats *socket_stats) const {
646 659 : stats_.GetTxStats(socket_stats);
647 659 : }
648 :
649 : //
650 : // TcpServerManager class routines
651 : //
652 : ServerManager<TcpServer, TcpServerPtr> TcpServerManager::impl_;
653 :
654 17555 : void TcpServerManager::AddServer(TcpServer *server) {
655 17555 : impl_.AddServer(server);
656 17555 : }
657 :
658 17449 : void TcpServerManager::DeleteServer(TcpServer *server) {
659 : // Wait for pending writes to be complete
660 17449 : server->WaitForEmpty();
661 17449 : impl_.DeleteServer(server);
662 17449 : }
663 :
664 1243 : size_t TcpServerManager::GetServerCount() {
665 1243 : return impl_.GetServerCount();
666 : }
|