give HostStatus analyzer more info: details on ping success/failure and ping duration
[pingcheck] / src / icmp / icmppinger.cpp
CommitLineData
0c0bb697
TJ
1// Boost pinger (c) 2011 by Guilherme Maciel Ferreira / Intra2net AG
2// Based upon work copyright (c) 2003-2010 Christopher M. Kohlhoff (ping.cpp)
3//
4// Distributed under the Boost Software License, Version 1.0.
5// (See accompanying file LICENSE_1_0.txt or copy at
6// http://www.boost.org/LICENSE_1_0.txt)
511ced78 7#include "icmp/icmppinger.h"
9c55ecd3 8
47848853 9#include <errno.h>
47848853 10
4ea9706c
GMF
11#include <ostream>
12
9c55ecd3 13#include <boost/bind.hpp>
451c9121
GMF
14#include <boost/date_time/posix_time/posix_time.hpp>
15#include <boost/date_time/posix_time/posix_time_types.hpp>
55978089
TJ
16#include <boost/uuid/uuid.hpp>
17#include <boost/uuid/uuid_generators.hpp>
41d175b0 18#include <boost/foreach.hpp>
55978089 19
301610ca
GMF
20#include <logfunc.hpp>
21
780b0bca 22#include "boost_assert_handler.h"
af68f845 23#include "icmp/icmppacketfactory.h"
41d175b0 24#include "host/networkinterface.hpp"
4ea9706c 25
a7c2eb51 26using namespace std;
2bf8720f
GMF
27using boost::asio::const_buffers_1;
28using boost::asio::io_service;
29using boost::asio::ip::address;
30using boost::asio::ip::icmp;
cd395966 31using boost::function;
2bf8720f 32using boost::posix_time::microsec_clock;
2bf8720f 33using boost::posix_time::seconds;
e58d7507 34using boost::shared_ptr;
301610ca 35using I2n::Logger::GlobalLogger;
2d591235 36
f076f8d4
CH
37using boost::asio::ip::icmp;
38
4ea9706c 39//-----------------------------------------------------------------------------
87e525ff 40// IcmpPinger
4ea9706c
GMF
41//-----------------------------------------------------------------------------
42
1ece191b
CH
43/**
44 * @brief factory function for IcmpPingers, ensures that set_myself is set
45 *
46 * @returns a shared pointer to a Pinger
47 */
48PingerItem IcmpPinger::create(
49 const IoServiceItem io_serv,
50 const icmp::socket::protocol_type &protocol,
51 const string &source_network_interface,
52 const int echo_reply_timeout_in_sec )
53{
54 // get distributor
55 IcmpPacketDistributorItem distributor = IcmpPacketDistributor::get_distributor(
8f00b3df 56 protocol, source_network_interface, io_serv);
1ece191b
CH
57
58 // create pinger
f076f8d4 59 IcmpPinger *ptr = new IcmpPinger(io_serv, protocol, echo_reply_timeout_in_sec, distributor);
1ece191b 60 IcmpPingerItem shared_ptr_(ptr);
1ece191b
CH
61
62 // keep weak pointer to self
63 //shared_ptr_->set_myself( weak_ptr ); //Error: Pinger::set_myself is protected
d3bb7afe 64 ptr->set_myself( shared_ptr_ );
1ece191b
CH
65
66 // register in distributor
67 distributor->register_pinger(shared_ptr_);
68
69 // done, return shared ptr
70 return shared_ptr_;
71}
9ae5d9cb 72
0697580f
GMF
73/**
74 * @brief Parameterized constructor.
5b008ada 75 *
ab2cb1ef 76 * @param io_serv The one @c io_service object that controls async processing
5b008ada
GMF
77 * @param protocol The network layer protocol to use.
78 * @param source_network_interface The network interface name from where to
79 * send the packets.
80 * @param echo_reply_timeout_in_sec The amount of time to wait for a reply.
0697580f 81 */
87e525ff 82IcmpPinger::IcmpPinger(
365036be 83 const IoServiceItem io_serv,
fc3754b0 84 const icmp::socket::protocol_type &protocol,
f076f8d4
CH
85 const int echo_reply_timeout_in_sec,
86 const IcmpPacketDistributorItem distributor
ced28dc7 87) :
e0a99ac4 88 PacketDistributor( distributor ),
33f408b1 89 DestinationEndpoint(),
5b008ada 90 Protocol( protocol ),
365036be 91 IcmpPacketReceiveTimer( *io_serv ),
87e525ff 92 Identifier( 0 ),
33f408b1 93 SequenceNumber( 0 ),
a7c2eb51 94 TimeSent( microsec_clock::universal_time() ),
0697580f 95 ReplyReceived( false ),
e08ab6c9 96 EchoReplyTimeoutInSec( echo_reply_timeout_in_sec ),
24e706c4 97 PingerStatus( PingStatus_NotSent ),
20a8838c
CH
98 PingDoneCallback(),
99 LogPrefix("IcmpPinger")
4ea9706c 100{
55978089
TJ
101 // Create "unique" identifier
102 boost::uuids::random_generator random_gen;
103 boost::uuids::uuid random_tag = random_gen();
104
da44f50a
GMF
105 BOOST_ASSERT( sizeof(Identifier) <= random_tag.size() );
106 memcpy( &Identifier, random_tag.data, sizeof(Identifier) );
20a8838c
CH
107
108 LogPrefix = "IPing(no IP yet): ";
ced28dc7
GMF
109}
110
0697580f
GMF
111/**
112 * @brief Destructor.
113 */
87e525ff 114IcmpPinger::~IcmpPinger()
ced28dc7
GMF
115{
116}
117
e08ab6c9 118/**
d8b4a7e7 119 * @brief Ping a destination address from an available local source.
e08ab6c9 120 *
2035d00e 121 * @param destination_ip The address of the host to ping.
1309d0e4
GMF
122 * @param destination_port The port at the destination host to ping.
123 * @param done_handler Done handler will be called on successful ping or timeout.
124 *
125 * @return void.
b1a82632 126 */
87e525ff 127void IcmpPinger::ping(
23f51766 128 const address &destination_ip,
080ca508 129 const uint16_t /*destination_port*/, // the ICMP protocol does not use ports
96c4e7a4 130 function<void(PingStatus)> ping_done_callback
87e525ff 131)
ced28dc7 132{
24e706c4
TJ
133 PingDoneCallback = ping_done_callback;
134
e1e27b3c 135 // Prepare ping
c0950a05 136 set_ping_status( PingStatus_NotSent );
e1e27b3c 137
39e10382 138 set_destination_endpoint( destination_ip );
4ea9706c 139
1ece191b 140 start_send();
5c670f6b
GMF
141}
142
5a9bc2d1
CH
143void IcmpPinger::stop_pinging()
144{
20a8838c 145 GlobalLogger.debug() << LogPrefix << "stop_pinging" << endl;
f076f8d4 146
20a8838c 147 GlobalLogger.debug() << LogPrefix << "cancel timer" << endl;
f076f8d4 148 IcmpPacketReceiveTimer.cancel();
f076f8d4 149
20a8838c 150 GlobalLogger.debug() << LogPrefix << "unregister" << endl;
4aad91a4
TJ
151
152 IcmpPingerItem icmp_item = boost::static_pointer_cast<IcmpPinger>( get_myself().lock() );
153 if ( icmp_item )
154 {
155 PacketDistributor->unregister_pinger( icmp_item );
156 } else
157 {
20a8838c
CH
158 GlobalLogger.warning() << LogPrefix
159 << "weak pointer to pinger broken is empty. Huh?" << endl;
4aad91a4 160 }
5a9bc2d1
CH
161}
162
163
23f51766 164void IcmpPinger::set_destination_endpoint( const address &destination_ip )
39e10382 165{
39e10382 166 uint16_t port = 0;
23f51766 167 DestinationEndpoint = icmp::endpoint( destination_ip, port );
20a8838c
CH
168
169 // update LogPrefix
170 std::stringstream temp;
171 temp << "IPing(" << DestinationEndpoint.address().to_string() << "): ";
172 LogPrefix = temp.str();
39e10382
GMF
173}
174
ba5d41fe 175bool IcmpPinger::start_send()
4ea9706c 176{
83d87183 177 ++SequenceNumber;
5c670f6b 178
af68f845 179 IcmpPacketItem icmp_packet_echo_request = IcmpPacketFactory::create_icmp_packet_echo_request(
5b008ada 180 Protocol, Identifier, SequenceNumber );
83d87183 181
24e706c4 182 BOOST_ASSERT( PingerStatus == PingStatus_NotSent );
ba5d41fe 183 return send_echo_request( icmp_packet_echo_request );
5c670f6b
GMF
184}
185
ba5d41fe 186bool IcmpPinger::send_echo_request( const IcmpPacketItem icmp_packet )
a8d411d6 187{
cb60ed91 188 boost::asio::streambuf request_buffer;
a7c2eb51 189 ostream os( &request_buffer );
080ca508
GMF
190 if ( !icmp_packet->write( os ) )
191 {
20a8838c 192 GlobalLogger.error() << LogPrefix << "fail writing ping data." << endl;
080ca508 193 }
cb60ed91 194
a7c2eb51 195 TimeSent = microsec_clock::universal_time();
040ffdf2 196
040ffdf2
GMF
197 string dest_address_string = DestinationEndpoint.address().to_string();
198 BOOST_ASSERT( !dest_address_string.empty() );
a4049623 199
822e4991 200 // Send the request
ba5d41fe 201 size_t bytes_sent = 0;
822e4991
GMF
202 try
203 {
20a8838c 204 GlobalLogger.info() << LogPrefix << "sending ping" << endl;
822e4991 205 const_buffers_1 data = request_buffer.data();
747c13ca 206
39e10382 207 // Block until send the data
1ece191b 208 bytes_sent = PacketDistributor->get_socket()->send_to( data, DestinationEndpoint );
822e4991
GMF
209 if ( bytes_sent != buffer_size( data ) )
210 {
20a8838c
CH
211 GlobalLogger.error() << LogPrefix << "fail sending ping data."
212 << endl;
822e4991
GMF
213 }
214 }
215 catch ( const exception &ex )
a4049623 216 {
20a8838c
CH
217 GlobalLogger.error() << LogPrefix << "fail sending ping data. "
218 << ex.what() << endl;
a4049623 219 }
4ea9706c 220
e0a99ac4 221 ReplyReceived = false;
2210b856 222 schedule_timeout_echo_reply();
ba5d41fe
CH
223
224 return (bytes_sent > 0);
2210b856
GMF
225}
226
87e525ff 227void IcmpPinger::schedule_timeout_echo_reply()
2210b856
GMF
228{
229 // Wait up to N seconds for a reply.
2b5520bc
GMF
230 (void) IcmpPacketReceiveTimer.expires_at(
231 TimeSent + seconds( EchoReplyTimeoutInSec )
232 );
233 IcmpPacketReceiveTimer.async_wait(
d26dce11 234 boost::bind( &IcmpPinger::handle_timeout, this, boost::asio::placeholders::error )
040ffdf2 235 );
4ea9706c
GMF
236}
237
24e706c4
TJ
238/**
239 * @brief Gets called when the ping is finished: Either on timeout or on ping reply
240 *
96c4e7a4 241 * @return void (but calls PingDoneCallback)
24e706c4 242 **/
d26dce11 243void IcmpPinger::handle_timeout(const boost::system::error_code& error)
bd1a2231 244{
d26dce11
CH
245 if (error)
246 {
247 if ( error == boost::asio::error::operation_aborted )
248 {
249 if (! ReplyReceived)
96c4e7a4 250 {
20a8838c
CH
251 GlobalLogger.notice() << LogPrefix
252 << "Timer waiting for ICMP echo reply was cancelled!"
253 << endl;
96c4e7a4
CH
254 set_ping_status( PingStatus_FailureAsyncCancel );
255 }
20a8838c
CH
256 // otherwise probably called by IcmpPacketReceiveTimer.cancel in
257 // handle_receive_icmp_packet!
d26dce11
CH
258 }
259 else
96c4e7a4 260 {
20a8838c
CH
261 GlobalLogger.notice() << LogPrefix << "Error " << error
262 << " waiting for ICMP echo reply!" << endl;
96c4e7a4
CH
263 set_ping_status( PingStatus_FailureAsyncError );
264 }
d26dce11
CH
265
266 // Still continue with rest of function, so PingStatus is updated and Callback executed
267 // when timer was cancelled
268 }
96c4e7a4
CH
269 else if ( !ReplyReceived )
270 { // Check ReplyReceived since the timer handler is also called by Timer.cancel();
20a8838c 271 GlobalLogger.info() << LogPrefix << "Request timed out" << endl;
bd1a2231
GMF
272
273 set_ping_status( PingStatus_FailureTimeout );
274 }
24e706c4
TJ
275
276 // Call ping-done handler
96c4e7a4 277 PingDoneCallback( PingerStatus );
bd1a2231
GMF
278}
279
bd1a2231 280
49d66375
TJ
281/**
282 * @brief Receive ICMP packets
c0950a05 283 * @param bytes_transferred Number of bytes transferred.
1ece191b 284 * @return true if packet matches a request from this pinger, false otherwise
49d66375 285 **/
1ece191b
CH
286bool IcmpPinger::handle_receive_icmp_packet(const IcmpPacketItem icmp_packet,
287 const size_t bytes_transferred )
4ea9706c 288{
e0a99ac4
CH
289 bool does_match = false;
290
d9bbc1d7 291 if ( ReplyReceived )
e0a99ac4 292 {
1ece191b
CH
293 // continue, might be an old packet
294 // or return false right away, do not want packet anyway...
e0a99ac4
CH
295 return does_match;
296 }
130a7eda
CH
297 else if ( DestinationEndpoint.address() == address() )
298 { // we have no IP set yet
130a7eda
CH
299 return does_match;
300 }
1ece191b
CH
301
302 // We can receive all ICMP packets received by the host, so we need to
303 // filter out only the echo replies that match our identifier,
304 // expected sequence number, and destination host address (receive just
305 // the ICMP packets from the host we had ping).
306
6d80c0be 307 try
d9bbc1d7 308 {
6d80c0be
CH
309 if ( icmp_packet->match_echo_reply(
310 Identifier, SequenceNumber,
311 DestinationEndpoint.address() ) )
312 {
20a8838c 313 GlobalLogger.info() << LogPrefix << "Received reply" << endl;
d9bbc1d7 314
6d80c0be
CH
315 ReplyReceived = true;
316 does_match = true;
644e2ef7 317
6d80c0be 318 icmp_packet->print( bytes_transferred, TimeSent );
c85c0309 319
6d80c0be 320 set_ping_status( PingStatus_SuccessReply );
83d87183 321
6d80c0be
CH
322 IcmpPacketReceiveTimer.cancel(); //lint !e534
323 }
324 else if ( icmp_packet->match_destination_unreachable(
325 Identifier, SequenceNumber,
326 DestinationEndpoint.address() ) )
327 {
20a8838c
CH
328 GlobalLogger.info() << LogPrefix
329 << "Received destination unreachable" << endl;
d9bbc1d7 330
6d80c0be
CH
331 ReplyReceived = true;
332 does_match = true;
644e2ef7 333
6d80c0be 334 icmp_packet->print( bytes_transferred, TimeSent );
15023b99 335
6d80c0be 336 set_ping_status( PingStatus_FailureDestinationUnreachable );
15023b99 337
6d80c0be
CH
338 IcmpPacketReceiveTimer.cancel(); //lint !e534
339 }
340 else if ( icmp_packet->match_time_exceeded(
341 Identifier, SequenceNumber,
342 DestinationEndpoint.address() ) )
343 {
20a8838c
CH
344 GlobalLogger.info() << LogPrefix
345 << "Received time exceeded" << endl;
15023b99 346
6d80c0be
CH
347 ReplyReceived = true;
348 does_match = true;
15023b99 349
6d80c0be 350 icmp_packet->print( bytes_transferred, TimeSent );
49d66375 351
6d80c0be 352 set_ping_status( PingStatus_FailureDestinationUnreachable );
2b5520bc 353
6d80c0be
CH
354 IcmpPacketReceiveTimer.cancel(); //lint !e534
355 }
356 else
357 {
20a8838c
CH
358 GlobalLogger.debug() << LogPrefix
359 << "Received packet that does not match or has wrong seq.nr"
6d80c0be
CH
360 << endl;
361 }
d9a7f2f3 362 }
6d80c0be 363 catch ( std::exception &exc)
83e1eae2 364 {
20a8838c
CH
365 GlobalLogger.warning() << LogPrefix
366 << "Caught exception in packet interpretation: " << exc.what()
6d80c0be
CH
367 << std::endl;
368 if ( IcmpPacketFactory::PacketDumpMode == DUMP_ALWAYS ||
369 IcmpPacketFactory::PacketDumpMode == DUMP_IF_ERROR )
370 IcmpPacketFactory::dump_packet(*icmp_packet);
371 does_match = true; // avoid the same procedure in all other pingers
372 }
373 catch ( ... )
374 {
20a8838c
CH
375 GlobalLogger.warning() << LogPrefix
376 << "Caught unspecified exception in packet interpretation!"
6d80c0be
CH
377 << std::endl;
378 if ( IcmpPacketFactory::PacketDumpMode == DUMP_ALWAYS ||
379 IcmpPacketFactory::PacketDumpMode == DUMP_IF_ERROR )
380 IcmpPacketFactory::dump_packet(*icmp_packet);
381 does_match = true; // avoid the same procedure in all other pingers
2b5520bc 382 }
1ece191b
CH
383
384 return does_match;
f442d5f5
GMF
385}
386
f5c0f0d0 387void IcmpPinger::set_ping_status( PingStatus ping_status )
83d87183
GMF
388{
389 PingerStatus = ping_status;
390}
f076f8d4
CH
391
392//------------------------------------------------------------------------
393// IcmpPacketDistributor
394//------------------------------------------------------------------------
395
396static const std::size_t SOCKET_BUFFER_SIZE = 65536; // 64kB
397
398typedef std::set<IcmpPingerItem>::iterator PingerListIterator;
399
400
401bool IcmpPacketDistributor::InstanceIdentifierComparator::operator() (
402 const IcmpPacketDistributor::DistributorInstanceIdentifier &a,
403 const IcmpPacketDistributor::DistributorInstanceIdentifier &b )
404 const
405{
406 if ( a.first == boost::asio::ip::icmp::v4() )
407 {
408 if ( b.first == boost::asio::ip::icmp::v4() )
409 return a.second < b.second; // v4 == v4
410 else
411 BOOST_ASSERT( b.first == boost::asio::ip::icmp::v6() );
412 return true; // a(v4) < b(b6)
413 }
414 else
415 {
416 BOOST_ASSERT( a.first == boost::asio::ip::icmp::v6() );
417
418 if ( b.first == boost::asio::ip::icmp::v4() )
419 return false; // a(v6) > b(v4)
420 else
421 BOOST_ASSERT( b.first == boost::asio::ip::icmp::v6() );
422 return a.second < b.second; // v6 == v6
423 }
424}
425
426//-----------------------------------------------------------------------------
427// Definition of IcmpPacketDistributor
428//-----------------------------------------------------------------------------
429
430IcmpPacketDistributor::map_type IcmpPacketDistributor::Instances; // initialize
431
432
433IcmpPacketDistributorItem IcmpPacketDistributor::get_distributor(
434 const icmp::socket::protocol_type &protocol,
435 const std::string &network_interface,
436 const IoServiceItem io_serv )
437{
438 IcmpPacketDistributor::DistributorInstanceIdentifier identifier(
439 protocol, network_interface);
440
441 // check if there is an instance for this protocol and interface
442 if ( Instances.count(identifier) == 0 )
443 { // need to create an instance for this protocol and network interface
8f00b3df
CH
444 std::string protocol_str;
445 if (protocol == icmp::v4())
446 protocol_str = "ICMPv4";
447 else if (protocol == icmp::v6())
448 protocol_str = "ICMPv6";
449 else
450 protocol_str = "unknown protocol!";
451
f076f8d4 452 GlobalLogger.info() << "Creating IcmpPacketDistributor for interface "
8f00b3df
CH
453 << network_interface << " and protocol "
454 << protocol_str << std::endl;
f076f8d4
CH
455 IcmpPacketDistributorItem new_instance( new IcmpPacketDistributor(
456 protocol, network_interface, io_serv ) );
457 Instances[identifier] = new_instance;
458 }
459
460 BOOST_ASSERT( Instances.count(identifier) == 1 );
461
462 // return the one instance for this protocol and interface
463 return Instances[identifier];
464}
465
466
467IcmpPacketDistributorItem IcmpPacketDistributor::get_distributor(
468 const icmp::socket::protocol_type &protocol,
469 const std::string &network_interface )
470{
471 IcmpPacketDistributor::DistributorInstanceIdentifier identifier(
472 protocol, network_interface);
473
474 BOOST_ASSERT( Instances.count(identifier) == 1 );
475
476 // return the one instance for this protocol and interface
477 return Instances[identifier];
478}
479
480
481IcmpPacketDistributor::IcmpPacketDistributor(
482 const icmp::socket::protocol_type &protocol,
483 const std::string &network_interface,
484 const IoServiceItem io_serv ):
485 Protocol( protocol ),
e0a99ac4 486 Socket( new icmp::socket(*io_serv, protocol) ),
f076f8d4
CH
487 ReplyBuffer(),
488 PingerList()
489{
7edd33cf
CH
490 // set TTL for testing
491 //const boost::asio::ip::unicast::hops option( 3 );
492 //Socket->set_option(option);
493
f076f8d4
CH
494 NetworkInterface<icmp::socket, boost::asio::ip::icmp>
495 NetInterface( network_interface, *Socket );
496
497 if ( !NetInterface.bind() )
498 {
499 GlobalLogger.error()
500 << "Trouble creating IcmpPacketDistributor for interface "
501 << network_interface// << " and protocol " << protocol
502 << ": could not bind the socket with the local interface. "
503 << ::strerror( errno ) << std::endl;
504 }
505
506 register_receive_handler();
507}
508
509
510void IcmpPacketDistributor::register_receive_handler()
511{
512 // wait for reply, prepare buffer to receive up to SOCKET_BUFFER_SIZE bytes
513 Socket->async_receive(
514 ReplyBuffer.prepare( SOCKET_BUFFER_SIZE ),
515 boost::bind( &IcmpPacketDistributor::handle_receive, this,
516 boost::asio::placeholders::error,
517 boost::asio::placeholders::bytes_transferred )
518 );
519}
520
521void IcmpPacketDistributor::handle_receive(
522 const boost::system::error_code &error,
523 const size_t &bytes_transferred )
524{
525 if ( error )
526 {
527 GlobalLogger.warning()
528 << ": Received error " << error
529 << " in ICMP packet distributor; end handler and schedule another.";
530 register_receive_handler();
531 return;
532 }
533
534 // The actual number of bytes received is committed to the buffer so that we
535 // can extract it using a std::istream object.
536 ReplyBuffer.commit( bytes_transferred );
537
538 GlobalLogger.info() << "received packet in distributor" << std::endl;
539
e75a59e7
CH
540 std::istream is( &ReplyBuffer );
541 if ( !is )
f076f8d4 542 {
e75a59e7
CH
543 GlobalLogger.error() << "Can't handle ReplyBuffer" << std::endl;
544 return;
f076f8d4 545 }
e75a59e7
CH
546
547 // Decode the reply packet.
548 IcmpPacketItem icmp_packet = IcmpPacketFactory::create_icmp_packet(
549 Protocol, is );
550 if ( !icmp_packet )
7edd33cf 551 {
e75a59e7
CH
552 GlobalLogger.warning() << "Ignoring broken ICMP packet"
553 << std::endl;
7edd33cf 554 }
e75a59e7 555 else
f076f8d4 556 {
e75a59e7
CH
557 GlobalLogger.debug() << "Succesfully parsed ICMP packet"
558 << std::endl;
559
560 // check which pinger wants this packet
561 bool packet_matches = false;
562 BOOST_FOREACH( const IcmpPingerItem &pinger, PingerList )
563 {
564 packet_matches = pinger->handle_receive_icmp_packet(
565 icmp_packet, bytes_transferred);
566 if (packet_matches)
567 break;
568 }
569 if (!packet_matches)
570 GlobalLogger.info() << "Packet did not match any pinger"
6d80c0be 571 << std::endl;
f076f8d4
CH
572 }
573
574 // re-register receive handler
575 register_receive_handler();
576}
577
578bool IcmpPacketDistributor::register_pinger( const IcmpPingerItem &new_pinger )
579{
580 std::pair<PingerListIterator, bool> result = PingerList.insert(new_pinger);
581 bool was_new = result.second;
582 if (was_new)
583 GlobalLogger.info() << "Register new pinger with IcmpPacketDistributor"
584 << std::endl;
585 else
586 GlobalLogger.warning()
587 << "Pinger to register was already known in IcmpPacketDistributor"
588 << std::endl;
589 return was_new;
590}
591
592
593bool IcmpPacketDistributor::unregister_pinger( const IcmpPingerItem &old_pinger )
594{
595 int n_erased = PingerList.erase(old_pinger);
596 bool was_erased = n_erased > 0;
597 if (was_erased)
598 GlobalLogger.info() << "Removed pinger from IcmpPacketDistributor"
599 << std::endl;
600 else
601 GlobalLogger.warning()
602 << "Could not find pinger to remove from IcmpPacketDistributor"
603 << std::endl;
604 return was_erased;
605}
606
607/**
608 * @brief for all instances: close sockets, unregister all pingers
609 */
610void IcmpPacketDistributor::clean_up_all()
611{
612 BOOST_FOREACH( IcmpPacketDistributor::map_type::value_type &instance,
613 Instances )
1ea5fa63 614 {
f076f8d4 615 instance.second->clean_up();
1ea5fa63 616 }
f076f8d4
CH
617
618 Instances.clear();
619}
620
621void IcmpPacketDistributor::clean_up()
622{
fd62d09f 623 if (PingerList.size() == 0)
49b82a1d
CH
624 GlobalLogger.info() << "All IcmpPingers have de-registered"
625 << std::endl;
fd62d09f 626 else
f076f8d4
CH
627 GlobalLogger.warning() << "There were still " << PingerList.size()
628 << " pingers registered in IcmpPacketDistributor!" << std::endl;
629 PingerList.clear();
630
631 boost::system::error_code error;
632 //Socket->shutdown(icmp::socket::shutdown_both, error); //both=send&receive
633 //if ( error )
634 // GlobalLogger.warning() << "Received error " << error
635 // << " when shutting down ICMP socket";
636 // always gave an error system:9 (probably EBADF: Bad file descriptor)
637
638 Socket->close(error);
639 if ( error )
640 GlobalLogger.warning() << "Received error " << error
641 << " when closing ICMP socket";
642}
643
644IcmpPacketDistributor::~IcmpPacketDistributor()
645{
646 GlobalLogger.info() << "Destroying IcmpPacketDistributor" << std::endl;
647}
648
649SocketItem IcmpPacketDistributor::get_socket() const
650{
651 return Socket;
652}