Adds a modified copy of talk/base to webrtc/base. It is the first step in
migrating talk/base to webrtc/base.

BUG=N/A
R=niklas.enbom@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/17479005

git-svn-id: http://webrtc.googlecode.com/svn/trunk/webrtc@6129 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/base/winping.cc b/base/winping.cc
new file mode 100644
index 0000000..cbb0847
--- /dev/null
+++ b/base/winping.cc
@@ -0,0 +1,359 @@
+/*
+ *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/base/winping.h"
+
+#include <assert.h>
+#include <Iphlpapi.h>
+
+#include "webrtc/base/byteorder.h"
+#include "webrtc/base/common.h"
+#include "webrtc/base/ipaddress.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/nethelpers.h"
+#include "webrtc/base/socketaddress.h"
+
+namespace rtc {
+
+//////////////////////////////////////////////////////////////////////
+// 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) + rtc::_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 rtc