title: A semi-concurrent ICMP ping using Boost.Asio on Windows
body: <p>I have modified the example <a href="http://www.boost.org/doc/libs/1_51_0/doc/html/boost_asio/example/icmp/ping.cpp" rel="nofollow">http://www.boost.org/doc/libs/1_51_0/doc/html/boost_asio/example/icmp/ping.cpp</a>
   on how to ping a host periodically to ping several hosts concurrently.
  At first, requests for all hosts are created and send to a socket. Then in the second phase all responses are gathered until timer expires.</p>
  
  <p>The modified example for 3 clients:</p>
  
  <pre><code>// Headers from ping example:
  // http://www.boost.org/doc/libs/1_51_0/doc/html/boost_asio/example/icmp/
  #include "icmp_header.hpp"
  #include "ipv4_header.hpp"
  
  #include &lt;boost/asio.hpp&gt;
  #include &lt;iostream&gt;
  
  using boost::asio::ip::icmp;
  using boost::asio::deadline_timer;
  using boost::asio::io_service;
  using boost::asio::streambuf;
  using boost::system::error_code;
  using std::cout;
  using std::endl;
  namespace posix_time = boost::posix_time;
  
  static const std::string BODY = "ping";
  static const auto PROCESS = GetCurrentProcessId();
  
  static int gSequence;
  static io_service gService;
  static icmp::socket gSocket(gService, icmp::v4());
  static deadline_timer gTimer(gService);
  static streambuf gReply;
  static icmp::endpoint gReceiver;
  
  void StartReceive()
  {
      gSocket.async_receive_from(gReply.prepare(65536), gReceiver,
          [&amp;](const error_code&amp; error, size_t length)
      {
          gReply.commit(length);
  
          ipv4_header ipv4Hdr;
          icmp_header icmpHdr;
          std::string body(BODY.size(), 0);
  
          std::istream is(&amp;gReply);
          is &gt;&gt; ipv4Hdr &gt;&gt; icmpHdr;
          is.read(&amp;body[0], BODY.size());
  
          auto ip = ipv4Hdr.source_address().to_string();
          auto rc = gReceiver.address().to_string();
          auto id = icmpHdr.identifier();
          auto process = PROCESS;
          auto sn = icmpHdr.sequence_number();
          auto type = icmpHdr.type();
  
          cout &lt;&lt; "  Length              = " &lt;&lt; length &lt;&lt; endl;
          cout &lt;&lt; "  Error               = " &lt;&lt; error &lt;&lt; endl;
          cout &lt;&lt; "  IP checksum         = " &lt;&lt; ipv4Hdr.header_checksum() &lt;&lt; endl;
          cout &lt;&lt; "  IP address          = " &lt;&lt; ip &lt;&lt; endl;
          cout &lt;&lt; "  Receiver address    = " &lt;&lt; rc &lt;&lt; endl;
          cout &lt;&lt; "  ICMP identification = " &lt;&lt; id &lt;&lt; endl;
          cout &lt;&lt; "  ICMP type           = " &lt;&lt; (int)type &lt;&lt; endl;
          cout &lt;&lt; "  Process             = " &lt;&lt; process &lt;&lt; endl;
          cout &lt;&lt; "  Sequence            = " &lt;&lt; sn &lt;&lt; endl;
  
          if (is
              &amp;&amp; icmpHdr.type() == icmp_header::echo_reply
              &amp;&amp; icmpHdr.identifier() == PROCESS
              &amp;&amp; icmpHdr.sequence_number() == gSequence
              &amp;&amp; body == BODY)
          {
              cout &lt;&lt; "    &gt; " &lt;&lt; ip &lt;&lt; endl;
          }
  
          cout &lt;&lt; endl;
  
          gReply.consume(length);
  
          StartReceive();
      });
  }
  
  int main()
  {
      icmp::resolver resolver(gService);
  
      icmp_header echoRequest;
      echoRequest.type(icmp_header::echo_request);
      echoRequest.identifier(PROCESS);
  
      for (gSequence = 0; gSequence &lt; 3; ++gSequence)
      {
          cout &lt;&lt; "----------------------------------------------------------" &lt;&lt; endl;
          cout &lt;&lt; "Iteration = " &lt;&lt; gSequence &lt;&lt; endl;
          cout &lt;&lt; "----------------------------------------------------------" &lt;&lt; endl;
  
          echoRequest.sequence_number(gSequence);
          compute_checksum(echoRequest, BODY.begin(), BODY.end());
  
          streambuf request;
          std::ostream os(&amp;request);
          os &lt;&lt; echoRequest &lt;&lt; BODY;
  
          gService.reset();
  
          StartReceive();
  
          std::vector&lt;std::string&gt; pool
          {
              "10.170.110.29",
              "10.170.97.39",
              "10.170.7.52"
          };
  
          for (const auto &amp; ip : pool)
          {
              icmp::resolver::query query(icmp::v4(), ip, "");
              auto dest = *resolver.resolve(query);
  
              gSocket.send_to(request.data(), dest);
          }
  
          gTimer.expires_from_now(posix_time::millisec(2000));
          gTimer.async_wait([&amp;](const error_code&amp; error) { gService.stop(); });
  
          gService.run();
          gReply.commit(gReply.size());
          gReply.consume(gReply.size());
      }
  
      return 0;
  }
  </code></pre>
  
  <p>The first iteration (0) works each time as expected although the first packet received has always zero length. However, in all subsequent iterations the responses from one or more clients are not delivered but a response from another client is delivered multiple times instead. Using Wireshark I can see that all hosts in the example very promptly send exactly one response to the request.</p>
  
  <p>This is one of the produced outputs:</p>
  
  <pre><code>----------------------------------------------------------
  Iteration = 0
  ----------------------------------------------------------
    Length              = 0
    Error               = system:10022
    IP checksum         = 0
    IP address          = 0.0.0.0
    Receiver address    = 0.0.0.0
    ICMP identification = 0
    ICMP type           = 0
    Process             = 20464
    Sequence            = 0
  
    Length              = 32
    Error               = system:0
    IP checksum         = 595
    IP address          = 10.170.97.39
    Receiver address    = 10.170.97.39
    ICMP identification = 20464
    ICMP type           = 0
    Process             = 20464
    Sequence            = 0
      &gt; 10.170.97.39
  
    Length              = 32
    Error               = system:0
    IP checksum         = 31034
    IP address          = 10.170.110.29
    Receiver address    = 10.170.110.29
    ICMP identification = 20464
    ICMP type           = 0
    Process             = 20464
    Sequence            = 0
      &gt; 10.170.110.29
  
    Length              = 32
    Error               = system:0
    IP checksum         = 51432
    IP address          = 10.170.7.52
    Receiver address    = 10.170.7.52
    ICMP identification = 20464
    ICMP type           = 0
    Process             = 20464
    Sequence            = 0
      &gt; 10.170.7.52
  
  ----------------------------------------------------------
  Iteration = 1
  ----------------------------------------------------------
    Length              = 32
    Error               = system:0
    IP checksum         = 594
    IP address          = 10.170.97.39
    Receiver address    = 10.170.97.39
    ICMP identification = 20464
    ICMP type           = 0
    Process             = 20464
    Sequence            = 1
      &gt; 10.170.97.39
  
    Length              = 32
    Error               = system:0
    IP checksum         = 51419
    IP address          = 10.170.7.52
    Receiver address    = 10.170.7.52
    ICMP identification = 20464
    ICMP type           = 0
    Process             = 20464
    Sequence            = 1
      &gt; 10.170.7.52
  
    Length              = 32
    Error               = system:0
    IP checksum         = 51419
    IP address          = 10.170.7.52
    Receiver address    = 10.170.7.52
    ICMP identification = 20464
    ICMP type           = 0
    Process             = 20464
    Sequence            = 1
      &gt; 10.170.7.52    
  
  ----------------------------------------------------------
  Iteration = 2
  ----------------------------------------------------------
    Length              = 32
    Error               = system:0
    IP checksum         = 593
    IP address          = 10.170.97.39
    Receiver address    = 10.170.97.39
    ICMP identification = 20464
    ICMP type           = 0
    Process             = 20464
    Sequence            = 2
      &gt; 10.170.97.39
  
    Length              = 32
    Error               = system:0
    IP checksum         = 51407
    IP address          = 10.170.7.52
    Receiver address    = 10.170.7.52
    ICMP identification = 20464
    ICMP type           = 0
    Process             = 20464
    Sequence            = 2
      &gt; 10.170.7.52
  
    Length              = 32
    Error               = system:0
    IP checksum         = 51407
    IP address          = 10.170.7.52
    Receiver address    = 10.170.7.52
    ICMP identification = 20464
    ICMP type           = 0
    Process             = 20464
    Sequence            = 2
      &gt; 10.170.7.52
  </code></pre>
  
  <p>Is this a correct usage and behavior of Boost.Asio ?</p>
  
  <p>Thanks</p>