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