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