std::memcpy -> memcpy for instance. This change was motivated by a compile report complaining that std::rand() was used instead of rand(), probably with a stdlib.h include instead of cstdlib. Use of C functions without the std:: prefix is a lot more common, so removing std:: to address this. BUG= R=tommi@webrtc.org Review URL: https://webrtc-codereview.appspot.com/9559004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@5657 4adac7df-926f-26a2-2b94-8c16560cd09d
		
			
				
	
	
		
			377 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			377 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
 * libjingle
 | 
						|
 * Copyright 2004--2005, Google Inc.
 | 
						|
 *
 | 
						|
 * Redistribution and use in source and binary forms, with or without
 | 
						|
 * modification, are permitted provided that the following conditions are met:
 | 
						|
 *
 | 
						|
 *  1. Redistributions of source code must retain the above copyright notice,
 | 
						|
 *     this list of conditions and the following disclaimer.
 | 
						|
 *  2. Redistributions in binary form must reproduce the above copyright notice,
 | 
						|
 *     this list of conditions and the following disclaimer in the documentation
 | 
						|
 *     and/or other materials provided with the distribution.
 | 
						|
 *  3. The name of the author may not be used to endorse or promote products
 | 
						|
 *     derived from this software without specific prior written permission.
 | 
						|
 *
 | 
						|
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 | 
						|
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 | 
						|
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 | 
						|
 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
						|
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 | 
						|
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 | 
						|
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | 
						|
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 | 
						|
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 | 
						|
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
						|
 */
 | 
						|
 | 
						|
#include "talk/base/winping.h"
 | 
						|
 | 
						|
#include <assert.h>
 | 
						|
#include <Iphlpapi.h>
 | 
						|
 | 
						|
#include "talk/base/byteorder.h"
 | 
						|
#include "talk/base/common.h"
 | 
						|
#include "talk/base/ipaddress.h"
 | 
						|
#include "talk/base/logging.h"
 | 
						|
#include "talk/base/nethelpers.h"
 | 
						|
#include "talk/base/socketaddress.h"
 | 
						|
 | 
						|
namespace talk_base {
 | 
						|
 | 
						|
//////////////////////////////////////////////////////////////////////
 | 
						|
// Found in IPExport.h
 | 
						|
//////////////////////////////////////////////////////////////////////
 | 
						|
 | 
						|
typedef struct icmp_echo_reply {
 | 
						|
    ULONG   Address;            // Replying address
 | 
						|
    ULONG   Status;             // Reply IP_STATUS
 | 
						|
    ULONG   RoundTripTime;      // RTT in milliseconds
 | 
						|
    USHORT  DataSize;           // Reply data size in bytes
 | 
						|
    USHORT  Reserved;           // Reserved for system use
 | 
						|
    PVOID   Data;               // Pointer to the reply data
 | 
						|
    struct ip_option_information Options; // Reply options
 | 
						|
} ICMP_ECHO_REPLY, * PICMP_ECHO_REPLY;
 | 
						|
 | 
						|
typedef struct icmpv6_echo_reply_lh {
 | 
						|
  sockaddr_in6    Address;
 | 
						|
  ULONG           Status;
 | 
						|
  unsigned int    RoundTripTime;
 | 
						|
} ICMPV6_ECHO_REPLY, *PICMPV6_ECHO_REPLY;
 | 
						|
 | 
						|
//
 | 
						|
// IP_STATUS codes returned from IP APIs
 | 
						|
//
 | 
						|
 | 
						|
#define IP_STATUS_BASE              11000
 | 
						|
 | 
						|
#define IP_SUCCESS                  0
 | 
						|
#define IP_BUF_TOO_SMALL            (IP_STATUS_BASE + 1)
 | 
						|
#define IP_DEST_NET_UNREACHABLE     (IP_STATUS_BASE + 2)
 | 
						|
#define IP_DEST_HOST_UNREACHABLE    (IP_STATUS_BASE + 3)
 | 
						|
#define IP_DEST_PROT_UNREACHABLE    (IP_STATUS_BASE + 4)
 | 
						|
#define IP_DEST_PORT_UNREACHABLE    (IP_STATUS_BASE + 5)
 | 
						|
#define IP_NO_RESOURCES             (IP_STATUS_BASE + 6)
 | 
						|
#define IP_BAD_OPTION               (IP_STATUS_BASE + 7)
 | 
						|
#define IP_HW_ERROR                 (IP_STATUS_BASE + 8)
 | 
						|
#define IP_PACKET_TOO_BIG           (IP_STATUS_BASE + 9)
 | 
						|
#define IP_REQ_TIMED_OUT            (IP_STATUS_BASE + 10)
 | 
						|
#define IP_BAD_REQ                  (IP_STATUS_BASE + 11)
 | 
						|
#define IP_BAD_ROUTE                (IP_STATUS_BASE + 12)
 | 
						|
#define IP_TTL_EXPIRED_TRANSIT      (IP_STATUS_BASE + 13)
 | 
						|
#define IP_TTL_EXPIRED_REASSEM      (IP_STATUS_BASE + 14)
 | 
						|
#define IP_PARAM_PROBLEM            (IP_STATUS_BASE + 15)
 | 
						|
#define IP_SOURCE_QUENCH            (IP_STATUS_BASE + 16)
 | 
						|
#define IP_OPTION_TOO_BIG           (IP_STATUS_BASE + 17)
 | 
						|
#define IP_BAD_DESTINATION          (IP_STATUS_BASE + 18)
 | 
						|
 | 
						|
#define IP_ADDR_DELETED             (IP_STATUS_BASE + 19)
 | 
						|
#define IP_SPEC_MTU_CHANGE          (IP_STATUS_BASE + 20)
 | 
						|
#define IP_MTU_CHANGE               (IP_STATUS_BASE + 21)
 | 
						|
#define IP_UNLOAD                   (IP_STATUS_BASE + 22)
 | 
						|
#define IP_ADDR_ADDED               (IP_STATUS_BASE + 23)
 | 
						|
#define IP_MEDIA_CONNECT            (IP_STATUS_BASE + 24)
 | 
						|
#define IP_MEDIA_DISCONNECT         (IP_STATUS_BASE + 25)
 | 
						|
#define IP_BIND_ADAPTER             (IP_STATUS_BASE + 26)
 | 
						|
#define IP_UNBIND_ADAPTER           (IP_STATUS_BASE + 27)
 | 
						|
#define IP_DEVICE_DOES_NOT_EXIST    (IP_STATUS_BASE + 28)
 | 
						|
#define IP_DUPLICATE_ADDRESS        (IP_STATUS_BASE + 29)
 | 
						|
#define IP_INTERFACE_METRIC_CHANGE  (IP_STATUS_BASE + 30)
 | 
						|
#define IP_RECONFIG_SECFLTR         (IP_STATUS_BASE + 31)
 | 
						|
#define IP_NEGOTIATING_IPSEC        (IP_STATUS_BASE + 32)
 | 
						|
#define IP_INTERFACE_WOL_CAPABILITY_CHANGE  (IP_STATUS_BASE + 33)
 | 
						|
#define IP_DUPLICATE_IPADD          (IP_STATUS_BASE + 34)
 | 
						|
 | 
						|
#define IP_GENERAL_FAILURE          (IP_STATUS_BASE + 50)
 | 
						|
#define MAX_IP_STATUS               IP_GENERAL_FAILURE
 | 
						|
#define IP_PENDING                  (IP_STATUS_BASE + 255)
 | 
						|
 | 
						|
//
 | 
						|
// Values used in the IP header Flags field.
 | 
						|
//
 | 
						|
#define IP_FLAG_DF      0x2         // Don't fragment this packet.
 | 
						|
 | 
						|
//
 | 
						|
// Supported IP Option Types.
 | 
						|
//
 | 
						|
// These types define the options which may be used in the OptionsData field
 | 
						|
// of the ip_option_information structure.  See RFC 791 for a complete
 | 
						|
// description of each.
 | 
						|
//
 | 
						|
#define IP_OPT_EOL      0          // End of list option
 | 
						|
#define IP_OPT_NOP      1          // No operation
 | 
						|
#define IP_OPT_SECURITY 0x82       // Security option
 | 
						|
#define IP_OPT_LSRR     0x83       // Loose source route
 | 
						|
#define IP_OPT_SSRR     0x89       // Strict source route
 | 
						|
#define IP_OPT_RR       0x7        // Record route
 | 
						|
#define IP_OPT_TS       0x44       // Timestamp
 | 
						|
#define IP_OPT_SID      0x88       // Stream ID (obsolete)
 | 
						|
#define IP_OPT_ROUTER_ALERT 0x94  // Router Alert Option
 | 
						|
 | 
						|
#define MAX_OPT_SIZE    40         // Maximum length of IP options in bytes
 | 
						|
 | 
						|
//////////////////////////////////////////////////////////////////////
 | 
						|
// Global Constants and Types
 | 
						|
//////////////////////////////////////////////////////////////////////
 | 
						|
 | 
						|
const char * const ICMP_DLL_NAME = "Iphlpapi.dll";
 | 
						|
const char * const ICMP_CREATE_FUNC = "IcmpCreateFile";
 | 
						|
const char * const ICMP_CLOSE_FUNC = "IcmpCloseHandle";
 | 
						|
const char * const ICMP_SEND_FUNC = "IcmpSendEcho";
 | 
						|
const char * const ICMP6_CREATE_FUNC = "Icmp6CreateFile";
 | 
						|
const char * const ICMP6_CLOSE_FUNC = "Icmp6CloseHandle";
 | 
						|
const char * const ICMP6_SEND_FUNC = "Icmp6SendEcho2";
 | 
						|
 | 
						|
inline uint32 ReplySize(uint32 data_size, int family) {
 | 
						|
  if (family == AF_INET) {
 | 
						|
    // A ping error message is 8 bytes long, so make sure we allow for at least
 | 
						|
    // 8 bytes of reply data.
 | 
						|
    return sizeof(ICMP_ECHO_REPLY) + talk_base::_max<uint32>(8, data_size);
 | 
						|
  } else if (family == AF_INET6) {
 | 
						|
    // Per MSDN, Send6IcmpEcho2 needs at least one ICMPV6_ECHO_REPLY,
 | 
						|
    // 8 bytes for ICMP header, _and_ an IO_BLOCK_STATUS (2 pointers),
 | 
						|
    // in addition to the data size.
 | 
						|
    return sizeof(ICMPV6_ECHO_REPLY) + data_size + 8 + (2 * sizeof(DWORD*));
 | 
						|
  } else {
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
//////////////////////////////////////////////////////////////////////
 | 
						|
// WinPing
 | 
						|
//////////////////////////////////////////////////////////////////////
 | 
						|
 | 
						|
WinPing::WinPing()
 | 
						|
    : dll_(0), hping_(INVALID_HANDLE_VALUE), create_(0), close_(0), send_(0),
 | 
						|
      create6_(0), send6_(0), data_(0), dlen_(0), reply_(0),
 | 
						|
      rlen_(0), valid_(false) {
 | 
						|
 | 
						|
  dll_ = LoadLibraryA(ICMP_DLL_NAME);
 | 
						|
  if (!dll_) {
 | 
						|
    LOG(LERROR) << "LoadLibrary: " << GetLastError();
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  create_ = (PIcmpCreateFile) GetProcAddress(dll_, ICMP_CREATE_FUNC);
 | 
						|
  close_ = (PIcmpCloseHandle) GetProcAddress(dll_, ICMP_CLOSE_FUNC);
 | 
						|
  send_ = (PIcmpSendEcho) GetProcAddress(dll_, ICMP_SEND_FUNC);
 | 
						|
  if (!create_ || !close_ || !send_) {
 | 
						|
    LOG(LERROR) << "GetProcAddress(ICMP_*): " << GetLastError();
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  hping_ = create_();
 | 
						|
  if (hping_ == INVALID_HANDLE_VALUE) {
 | 
						|
    LOG(LERROR) << "IcmpCreateFile: " << GetLastError();
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (HasIPv6Enabled()) {
 | 
						|
    create6_ = (PIcmp6CreateFile) GetProcAddress(dll_, ICMP6_CREATE_FUNC);
 | 
						|
    send6_ = (PIcmp6SendEcho2) GetProcAddress(dll_, ICMP6_SEND_FUNC);
 | 
						|
    if (!create6_ || !send6_) {
 | 
						|
      LOG(LERROR) << "GetProcAddress(ICMP6_*): " << GetLastError();
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    hping6_ = create6_();
 | 
						|
    if (hping6_ == INVALID_HANDLE_VALUE) {
 | 
						|
      LOG(LERROR) << "Icmp6CreateFile: " << GetLastError();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  dlen_ = 0;
 | 
						|
  rlen_ = ReplySize(dlen_, AF_INET);
 | 
						|
  data_ = new char[dlen_];
 | 
						|
  reply_ = new char[rlen_];
 | 
						|
 | 
						|
  valid_ = true;
 | 
						|
}
 | 
						|
 | 
						|
WinPing::~WinPing() {
 | 
						|
  if ((hping_ != INVALID_HANDLE_VALUE) && close_) {
 | 
						|
    if (!close_(hping_))
 | 
						|
      LOG(WARNING) << "IcmpCloseHandle: " << GetLastError();
 | 
						|
  }
 | 
						|
  if ((hping6_ != INVALID_HANDLE_VALUE) && close_) {
 | 
						|
    if (!close_(hping6_)) {
 | 
						|
      LOG(WARNING) << "Icmp6CloseHandle: " << GetLastError();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (dll_)
 | 
						|
    FreeLibrary(dll_);
 | 
						|
 | 
						|
  delete[] data_;
 | 
						|
  delete[] reply_;
 | 
						|
}
 | 
						|
 | 
						|
WinPing::PingResult WinPing::Ping(
 | 
						|
    IPAddress ip, uint32 data_size, uint32 timeout, uint8 ttl,
 | 
						|
    bool allow_fragments) {
 | 
						|
 | 
						|
  if (data_size == 0 || timeout == 0 || ttl == 0) {
 | 
						|
    LOG(LERROR) << "IcmpSendEcho: data_size/timeout/ttl is 0.";
 | 
						|
    return PING_INVALID_PARAMS;
 | 
						|
  }
 | 
						|
 | 
						|
  assert(IsValid());
 | 
						|
 | 
						|
  IP_OPTION_INFORMATION ipopt;
 | 
						|
  memset(&ipopt, 0, sizeof(ipopt));
 | 
						|
  if (!allow_fragments)
 | 
						|
    ipopt.Flags |= IP_FLAG_DF;
 | 
						|
  ipopt.Ttl = ttl;
 | 
						|
 | 
						|
  uint32 reply_size = ReplySize(data_size, ip.family());
 | 
						|
 | 
						|
  if (data_size > dlen_) {
 | 
						|
    delete [] data_;
 | 
						|
    dlen_ = data_size;
 | 
						|
    data_ = new char[dlen_];
 | 
						|
    memset(data_, 'z', dlen_);
 | 
						|
  }
 | 
						|
 | 
						|
  if (reply_size > rlen_) {
 | 
						|
    delete [] reply_;
 | 
						|
    rlen_ = reply_size;
 | 
						|
    reply_ = new char[rlen_];
 | 
						|
  }
 | 
						|
  DWORD result = 0;
 | 
						|
  if (ip.family() == AF_INET) {
 | 
						|
    result = send_(hping_, ip.ipv4_address().S_un.S_addr,
 | 
						|
                   data_, uint16(data_size), &ipopt,
 | 
						|
                   reply_, reply_size, timeout);
 | 
						|
  } else if (ip.family() == AF_INET6) {
 | 
						|
    sockaddr_in6 src = {0};
 | 
						|
    sockaddr_in6 dst = {0};
 | 
						|
    src.sin6_family = AF_INET6;
 | 
						|
    dst.sin6_family = AF_INET6;
 | 
						|
    dst.sin6_addr = ip.ipv6_address();
 | 
						|
    result = send6_(hping6_, NULL, NULL, NULL,
 | 
						|
                    &src, &dst,
 | 
						|
                    data_, int16(data_size), &ipopt,
 | 
						|
                    reply_, reply_size, timeout);
 | 
						|
  }
 | 
						|
  if (result == 0) {
 | 
						|
    DWORD error = GetLastError();
 | 
						|
    if (error == IP_PACKET_TOO_BIG)
 | 
						|
      return PING_TOO_LARGE;
 | 
						|
    if (error == IP_REQ_TIMED_OUT)
 | 
						|
      return PING_TIMEOUT;
 | 
						|
    LOG(LERROR) << "IcmpSendEcho(" << ip.ToSensitiveString()
 | 
						|
                << ", " << data_size << "): " << error;
 | 
						|
    return PING_FAIL;
 | 
						|
  }
 | 
						|
 | 
						|
  return PING_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
//////////////////////////////////////////////////////////////////////
 | 
						|
// Microsoft Documenation
 | 
						|
//////////////////////////////////////////////////////////////////////
 | 
						|
//
 | 
						|
// Routine Name:
 | 
						|
//
 | 
						|
//     IcmpCreateFile
 | 
						|
//
 | 
						|
// Routine Description:
 | 
						|
//
 | 
						|
//     Opens a handle on which ICMP Echo Requests can be issued.
 | 
						|
//
 | 
						|
// Arguments:
 | 
						|
//
 | 
						|
//     None.
 | 
						|
//
 | 
						|
// Return Value:
 | 
						|
//
 | 
						|
//     An open file handle or INVALID_HANDLE_VALUE. Extended error information
 | 
						|
//     is available by calling GetLastError().
 | 
						|
//
 | 
						|
//////////////////////////////////////////////////////////////////////
 | 
						|
//
 | 
						|
// Routine Name:
 | 
						|
//
 | 
						|
//     IcmpCloseHandle
 | 
						|
//
 | 
						|
// Routine Description:
 | 
						|
//
 | 
						|
//     Closes a handle opened by ICMPOpenFile.
 | 
						|
//
 | 
						|
// Arguments:
 | 
						|
//
 | 
						|
//     IcmpHandle  - The handle to close.
 | 
						|
//
 | 
						|
// Return Value:
 | 
						|
//
 | 
						|
//     TRUE if the handle was closed successfully, otherwise FALSE. Extended
 | 
						|
//     error information is available by calling GetLastError().
 | 
						|
//
 | 
						|
//////////////////////////////////////////////////////////////////////
 | 
						|
//
 | 
						|
// Routine Name:
 | 
						|
//
 | 
						|
//     IcmpSendEcho
 | 
						|
//
 | 
						|
// Routine Description:
 | 
						|
//
 | 
						|
//     Sends an ICMP Echo request and returns any replies. The
 | 
						|
//     call returns when the timeout has expired or the reply buffer
 | 
						|
//     is filled.
 | 
						|
//
 | 
						|
// Arguments:
 | 
						|
//
 | 
						|
//     IcmpHandle           - An open handle returned by ICMPCreateFile.
 | 
						|
//
 | 
						|
//     DestinationAddress   - The destination of the echo request.
 | 
						|
//
 | 
						|
//     RequestData          - A buffer containing the data to send in the
 | 
						|
//                            request.
 | 
						|
//
 | 
						|
//     RequestSize          - The number of bytes in the request data buffer.
 | 
						|
//
 | 
						|
//     RequestOptions       - Pointer to the IP header options for the request.
 | 
						|
//                            May be NULL.
 | 
						|
//
 | 
						|
//     ReplyBuffer          - A buffer to hold any replies to the request.
 | 
						|
//                            On return, the buffer will contain an array of
 | 
						|
//                            ICMP_ECHO_REPLY structures followed by the
 | 
						|
//                            options and data for the replies. The buffer
 | 
						|
//                            should be large enough to hold at least one
 | 
						|
//                            ICMP_ECHO_REPLY structure plus
 | 
						|
//                            MAX(RequestSize, 8) bytes of data since an ICMP
 | 
						|
//                            error message contains 8 bytes of data.
 | 
						|
//
 | 
						|
//     ReplySize            - The size in bytes of the reply buffer.
 | 
						|
//
 | 
						|
//     Timeout              - The time in milliseconds to wait for replies.
 | 
						|
//
 | 
						|
// Return Value:
 | 
						|
//
 | 
						|
//     Returns the number of ICMP_ECHO_REPLY structures stored in ReplyBuffer.
 | 
						|
//     The status of each reply is contained in the structure. If the return
 | 
						|
//     value is zero, extended error information is available via
 | 
						|
//     GetLastError().
 | 
						|
//
 | 
						|
//////////////////////////////////////////////////////////////////////
 | 
						|
 | 
						|
} // namespace talk_base
 |