title: Boost Asio, console pinger throws exception on socket.send (...)
body: <p>I'm trying to figure out how ICMP and Boost Asio work. There was a problem sending the packet to the endpoint. The entered url is translated into ip and a socket connection is made. The problem is that when a packet is sent via socket.send (...), an exception is thrown.</p>
  <p><strong>Exception: send: Bad address</strong></p>
  <pre><code>#include &lt;algorithm&gt;
  #include &lt;chrono&gt;
  #include &lt;functional&gt;
  #include &lt;iostream&gt;
  #include &lt;memory&gt;
  #include &lt;tuple&gt;
  
  //BOOST
  #include &lt;boost/asio.hpp&gt;
  #include &lt;boost/program_options.hpp&gt;
  #include &lt;boost/log/trivial.hpp&gt;
  
  //CONSTANTS
  #define BUFFER_SIZE_64KB 65536
  #define TTL_DEFAULT 64
  #define ICMP_HDR_SIZE 8
  #define LINUX_PAYLOAD_SIZE 56
  #define TIME_BYTE_SIZE 4
  #define FILL_BYTE 0X8
  
  template &lt;typename T, typename flag_type = int&gt;
  using flagged = std::tuple&lt;flag_type, T&gt;;
  using namespace boost::asio;
  
  typedef boost::system::error_code error_code;
  typedef unsigned char byte;
  
  enum ICMP : uint8_t {
      ECHO_REPLY = 0,
      UNREACH = 3,
      TIME_EXCEEDED = 11,
      ECHO_REQUEST = 8
  };
  
  enum class IPtype {IPV4, IPV6, BOTH};
  
  struct icmp_header_t {
      uint8_t type;
      uint8_t code;
      uint16_t checksum;
      uint16_t id;
      uint16_t seq_num;
  };
  struct ip_header_t {
      uint8_t  ver_ihl;
      uint8_t  tos;
      uint16_t total_length;
      uint16_t id;
      uint16_t flags_fo;
      uint8_t  ttl;
      uint8_t  protocol;
      uint16_t checksum;
      uint32_t   src_addr;
      uint32_t   dst_addr;
  };
  
  ip_header_t ip_load(std::istream&amp; stream, bool ntoh ) {
      ip_header_t header;
      stream.read((char*)&amp;header.ver_ihl,      sizeof(header.ver_ihl));
      stream.read((char*)&amp;header.tos,          sizeof(header.tos));
      stream.read((char*)&amp;header.total_length, sizeof(header.total_length));
      stream.read((char*)&amp;header.id,           sizeof(header.id));
      stream.read((char*)&amp;header.flags_fo,     sizeof(header.flags_fo));
      stream.read((char*)&amp;header.ttl,          sizeof(header.ttl));
      stream.read((char*)&amp;header.protocol,     sizeof(header.protocol));
      stream.read((char*)&amp;header.checksum,     sizeof(header.checksum));
      stream.read((char*)&amp;header.src_addr,     sizeof(header.src_addr));
      stream.read((char*)&amp;header.dst_addr,     sizeof(header.dst_addr));
      if (ntoh) {
        header.total_length = ntohs(header.total_length);
        header.id =           ntohs(header.id);
        header.flags_fo =     ntohs(header.flags_fo);
        header.checksum =     ntohs(header.checksum);
        header.src_addr =     ntohl(header.src_addr);
        header.dst_addr =     ntohl(header.dst_addr);
      }
      return header;
  }
  icmp_header_t icmp_load(std::istream&amp; stream) {
      icmp_header_t header;
      stream.read((char*)&amp;header.type,      sizeof(header.type));
      stream.read((char*)&amp;header.code,          sizeof(header.code));
      stream.read((char*)&amp;header.checksum, sizeof(header.checksum));
      stream.read((char*)&amp;header.id,           sizeof(header.id));
      stream.read((char*)&amp;header.seq_num,     sizeof(header.seq_num));
      return header;
  
  }
  
  flagged&lt;ip::icmp::endpoint&gt; sync_icmp_solver(io_service&amp; ios, std::string host, 
                                      IPtype type = IPtype::BOTH) noexcept {
  
      ip::icmp::resolver::query query(host, &quot;&quot;);
      ip::icmp::resolver resl(ios);
      ip::icmp::endpoint ep;
      error_code ec;  
      auto it = resl.resolve(query, ec);
      if (ec != boost::system::errc::errc_t::success) {
          std::cerr &lt;&lt; &quot;Error message = &quot; &lt;&lt; ec.message() &lt;&lt; std::endl;
          return std::make_tuple(ec.value(), ep);
      }
      
      ip::icmp::resolver::iterator it_end;
      //Finds first available ip.
      while (it != it_end) {
          ip::icmp::endpoint ep = (it++)-&gt;endpoint();
          auto addr = ep.address();
          switch(type) {
              case IPtype::IPV4:
                  if (addr.is_v4()) return std::make_tuple(0, ep);
                  break;
              case IPtype::IPV6:
                  if(addr.is_v6()) return std::make_tuple(0, ep);
                  break;
              case IPtype::BOTH:
                  return std::make_tuple(0, ep);
                  break;
          }
      }
      return std::make_tuple(-1, ep);
  }
   
  unsigned short checksum(void *b, int len) {   
      unsigned short* buf = reinterpret_cast&lt;unsigned short*&gt;(b); 
      unsigned int sum = 0; 
      unsigned short result; 
    
      for (sum = 0; len &gt; 1; len -= 2 ) {
          sum += *buf++;
      }
           
      if (len == 1) sum += *(byte*) buf; 
      sum = (sum &gt;&gt; 16) + (sum &amp; 0xFFFF); 
      sum += (sum &gt;&gt; 16); 
      result = ~sum; 
      return result; 
  } 
  unsigned short get_identifier() {
  #if defined(BOOST_WINDOWS)
      return static_cast&lt;unsigned short&gt;(::GetCurrentProcessId());
  #else
      return static_cast&lt;unsigned short&gt;(::getpid());
  #endif
    }
  struct PingInfo {
      unsigned short seq_num = 0;
      size_t time_out;
      size_t reply_time = 1;
      size_t payload_size = LINUX_PAYLOAD_SIZE; 
      size_t packets_rec = 0; 
      size_t packets_trs = 0;
      size_t reps = 0;
  };
  class PingConnection {
      private:
          ip::icmp::socket sock;
  
          io_service* ios_ptr;
          PingInfo* pi_ptr;
  
          ip::icmp::endpoint dst;
          boost::posix_time::ptime timestamp;
          streambuf input_buf;
          deadline_timer deadtime;
      
          //TODO: Check for memleaks.
          void write_icmp_req(std::ostream&amp; os) {
              byte* pckt = new byte[ICMP_HDR_SIZE + pi_ptr-&gt;payload_size];
              unsigned short pid = get_identifier();
              pckt[0] = 0x8;
              pckt[1] = 0x0;
              pckt[2] = 0x0;
              pckt[3] = 0x0;
              pckt[4] = (byte)((pid &amp; 0xF0) &gt;&gt; 4);
              pckt[5] = (byte)(pid &amp; 0x0F);
              for (size_t i = ICMP_HDR_SIZE; i &lt; ICMP_HDR_SIZE + pi_ptr-&gt;payload_size; i++) {
                  pckt[i] = FILL_BYTE;
              }
              pckt[6] = (byte)((pi_ptr-&gt;seq_num &amp; 0xF0) &gt;&gt; 4);
              pckt[7] = (byte)((pi_ptr-&gt;seq_num)++ &amp; 0x0F);
              unsigned short cs = checksum(pckt, ICMP_HDR_SIZE);
              pckt[2] = (byte)((cs &amp; 0xF0) &gt;&gt; 4);
              pckt[3] = (byte)(cs &amp; 0x0F);
              os &lt;&lt; pckt;
              delete [] pckt;
          }
          void pckt_send() {
              streambuf buf;
              std::ostream os(&amp;buf);
  
              write_icmp_req(os);
              timestamp = boost::posix_time::microsec_clock::universal_time();
              std::cout &lt;&lt; &quot;begin&quot; &lt;&lt; std::endl;
              sock.send(buf.data());
                std::cout &lt;&lt; &quot;sock.send(buf.data())&quot; &lt;&lt; std::endl;
              deadtime.expires_at(timestamp + boost::posix_time::seconds(pi_ptr-&gt;time_out));
              deadtime.async_wait(std::bind(&amp;PingConnection::req_timeout_callback, this));
          }
          void req_timeout_callback() {
              if (pi_ptr-&gt;reps == 0) {
                  std::cout &lt;&lt; &quot;Time Out:echo req&quot; &lt;&lt; std::endl;
              }
              deadtime.expires_at(timestamp + boost::posix_time::seconds(pi_ptr-&gt;reply_time));
              deadtime.async_wait(std::bind(&amp;PingConnection::pckt_send, this));
          }
          void pckt_recv() {
              std::cout &lt;&lt; &quot;pckt_recv&quot; &lt;&lt; std::endl;
              input_buf.consume(input_buf.size());
              sock.async_receive(input_buf.prepare(BUFFER_SIZE_64KB),
                std::bind(&amp;PingConnection::recv_timeout_callback, this, std::placeholders::_2));
          }
          void recv_timeout_callback(size_t sz) {
              std::cout &lt;&lt; &quot;recv_timeout_callback&quot; &lt;&lt; std::endl;
              input_buf.commit(sz);
              std::istream is(&amp;input_buf);
              ip_header_t iph = ip_load(is, false);
              icmp_header_t icmph = icmp_load(is);
              if (is &amp;&amp; 
                  icmph.type == ECHO_REQUEST &amp;&amp; 
                  icmph.id == get_identifier() &amp;&amp; 
                  icmph.seq_num == pi_ptr-&gt;seq_num) {
                  
              // If this is the first reply, interrupt the five second timeout.
              if (pi_ptr-&gt;reps++ == 0) deadtime.cancel();
  
              boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
              std::cout &lt;&lt; sz - iph.total_length
                          &lt;&lt; &quot; bytes from &quot; &lt;&lt; iph.src_addr
                          &lt;&lt; &quot;: icmp_seq=&quot; &lt;&lt; icmph.seq_num
                          &lt;&lt; &quot;, ttl=&quot; &lt;&lt; iph.ttl
                          &lt;&lt; &quot;, time=&quot; &lt;&lt; (now - timestamp).total_milliseconds() &lt;&lt; &quot; ms&quot;
                          &lt;&lt; std::endl;
              }
  
              pckt_recv();
          }
          
      public:
          PingConnection(io_service&amp; ios, PingInfo&amp; pi_add) : deadtime(ios), sock(ios) {
              pi_ptr = &amp;pi_add;
              ios_ptr = &amp;ios;
          }
          void ping(std::string host) {
              int err_flag;
              error_code error; 
              std::tie(err_flag, dst) = sync_icmp_solver(*ios_ptr, host);
              if (err_flag) return;
              std::cout &lt;&lt; dst &lt;&lt; std::endl;
              sock.connect(dst, error);
              if(error) {
                return;
              }
              std::cout &lt;&lt; &quot;sock.connect(dst)&quot; &lt;&lt; error.message() &lt;&lt;std::endl;
              pckt_send();
              pckt_recv();
          }
          
  };
  
  
  int main(int argc, char** argv) {
    try
    { 
      if (argc &lt; 2) {
           std::cerr &lt;&lt; &quot;Usage: ping [args]* destination\n&quot;;
           return -1;
      }
      io_service ios;
      PingInfo pi;
      pi.time_out = 56;
      PingConnection ping(ios, pi);
      ping.ping(argv[1]);
      ios.run();
    } catch(std::exception&amp; e) {
      std::cerr &lt;&lt; &quot;Exception: &quot; &lt;&lt; e.what() &lt;&lt; std::endl;
    }
  
  }
  </code></pre>
  <p><strong>socket.send()</strong> is called in <strong>pckt_send()</strong></p>
  <p>For development I use WSL2 and Ubuntu image.</p>
  <p><a href="https://i.stack.imgur.com/c2uwk.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/c2uwk.png" alt="console output" /></a></p>