Home | History | Annotate | Download | only in base
      1 /*
      2  * libjingle
      3  * Copyright 2004--2005, Google Inc.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are met:
      7  *
      8  *  1. Redistributions of source code must retain the above copyright notice,
      9  *     this list of conditions and the following disclaimer.
     10  *  2. Redistributions in binary form must reproduce the above copyright notice,
     11  *     this list of conditions and the following disclaimer in the documentation
     12  *     and/or other materials provided with the distribution.
     13  *  3. The name of the author may not be used to endorse or promote products
     14  *     derived from this software without specific prior written permission.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
     17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
     19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
     25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 #include "talk/base/byteorder.h"
     29 #include "talk/base/common.h"
     30 #include "talk/base/socketaddress.h"
     31 #include "talk/base/winping.h"
     32 #include "talk/base/logging.h"
     33 #include <cassert>
     34 
     35 namespace talk_base {
     36 
     37 //////////////////////////////////////////////////////////////////////
     38 // Found in IPExport.h
     39 //////////////////////////////////////////////////////////////////////
     40 
     41 typedef struct icmp_echo_reply {
     42     ULONG   Address;            // Replying address
     43     ULONG   Status;             // Reply IP_STATUS
     44     ULONG   RoundTripTime;      // RTT in milliseconds
     45     USHORT  DataSize;           // Reply data size in bytes
     46     USHORT  Reserved;           // Reserved for system use
     47     PVOID   Data;               // Pointer to the reply data
     48     struct ip_option_information Options; // Reply options
     49 } ICMP_ECHO_REPLY, * PICMP_ECHO_REPLY;
     50 
     51 //
     52 // IP_STATUS codes returned from IP APIs
     53 //
     54 
     55 #define IP_STATUS_BASE              11000
     56 
     57 #define IP_SUCCESS                  0
     58 #define IP_BUF_TOO_SMALL            (IP_STATUS_BASE + 1)
     59 #define IP_DEST_NET_UNREACHABLE     (IP_STATUS_BASE + 2)
     60 #define IP_DEST_HOST_UNREACHABLE    (IP_STATUS_BASE + 3)
     61 #define IP_DEST_PROT_UNREACHABLE    (IP_STATUS_BASE + 4)
     62 #define IP_DEST_PORT_UNREACHABLE    (IP_STATUS_BASE + 5)
     63 #define IP_NO_RESOURCES             (IP_STATUS_BASE + 6)
     64 #define IP_BAD_OPTION               (IP_STATUS_BASE + 7)
     65 #define IP_HW_ERROR                 (IP_STATUS_BASE + 8)
     66 #define IP_PACKET_TOO_BIG           (IP_STATUS_BASE + 9)
     67 #define IP_REQ_TIMED_OUT            (IP_STATUS_BASE + 10)
     68 #define IP_BAD_REQ                  (IP_STATUS_BASE + 11)
     69 #define IP_BAD_ROUTE                (IP_STATUS_BASE + 12)
     70 #define IP_TTL_EXPIRED_TRANSIT      (IP_STATUS_BASE + 13)
     71 #define IP_TTL_EXPIRED_REASSEM      (IP_STATUS_BASE + 14)
     72 #define IP_PARAM_PROBLEM            (IP_STATUS_BASE + 15)
     73 #define IP_SOURCE_QUENCH            (IP_STATUS_BASE + 16)
     74 #define IP_OPTION_TOO_BIG           (IP_STATUS_BASE + 17)
     75 #define IP_BAD_DESTINATION          (IP_STATUS_BASE + 18)
     76 
     77 #define IP_ADDR_DELETED             (IP_STATUS_BASE + 19)
     78 #define IP_SPEC_MTU_CHANGE          (IP_STATUS_BASE + 20)
     79 #define IP_MTU_CHANGE               (IP_STATUS_BASE + 21)
     80 #define IP_UNLOAD                   (IP_STATUS_BASE + 22)
     81 #define IP_ADDR_ADDED               (IP_STATUS_BASE + 23)
     82 #define IP_MEDIA_CONNECT            (IP_STATUS_BASE + 24)
     83 #define IP_MEDIA_DISCONNECT         (IP_STATUS_BASE + 25)
     84 #define IP_BIND_ADAPTER             (IP_STATUS_BASE + 26)
     85 #define IP_UNBIND_ADAPTER           (IP_STATUS_BASE + 27)
     86 #define IP_DEVICE_DOES_NOT_EXIST    (IP_STATUS_BASE + 28)
     87 #define IP_DUPLICATE_ADDRESS        (IP_STATUS_BASE + 29)
     88 #define IP_INTERFACE_METRIC_CHANGE  (IP_STATUS_BASE + 30)
     89 #define IP_RECONFIG_SECFLTR         (IP_STATUS_BASE + 31)
     90 #define IP_NEGOTIATING_IPSEC        (IP_STATUS_BASE + 32)
     91 #define IP_INTERFACE_WOL_CAPABILITY_CHANGE  (IP_STATUS_BASE + 33)
     92 #define IP_DUPLICATE_IPADD          (IP_STATUS_BASE + 34)
     93 
     94 #define IP_GENERAL_FAILURE          (IP_STATUS_BASE + 50)
     95 #define MAX_IP_STATUS               IP_GENERAL_FAILURE
     96 #define IP_PENDING                  (IP_STATUS_BASE + 255)
     97 
     98 //
     99 // Values used in the IP header Flags field.
    100 //
    101 #define IP_FLAG_DF      0x2         // Don't fragment this packet.
    102 
    103 //
    104 // Supported IP Option Types.
    105 //
    106 // These types define the options which may be used in the OptionsData field
    107 // of the ip_option_information structure.  See RFC 791 for a complete
    108 // description of each.
    109 //
    110 #define IP_OPT_EOL      0          // End of list option
    111 #define IP_OPT_NOP      1          // No operation
    112 #define IP_OPT_SECURITY 0x82       // Security option
    113 #define IP_OPT_LSRR     0x83       // Loose source route
    114 #define IP_OPT_SSRR     0x89       // Strict source route
    115 #define IP_OPT_RR       0x7        // Record route
    116 #define IP_OPT_TS       0x44       // Timestamp
    117 #define IP_OPT_SID      0x88       // Stream ID (obsolete)
    118 #define IP_OPT_ROUTER_ALERT 0x94  // Router Alert Option
    119 
    120 #define MAX_OPT_SIZE    40         // Maximum length of IP options in bytes
    121 
    122 //////////////////////////////////////////////////////////////////////
    123 // Global Constants and Types
    124 //////////////////////////////////////////////////////////////////////
    125 
    126 const char * const ICMP_DLL_NAME = "icmp.dll";
    127 const char * const ICMP_CREATE_FUNC = "IcmpCreateFile";
    128 const char * const ICMP_CLOSE_FUNC = "IcmpCloseHandle";
    129 const char * const ICMP_SEND_FUNC = "IcmpSendEcho";
    130 
    131 inline uint32 ReplySize(uint32 data_size) {
    132   // A ping error message is 8 bytes long, so make sure we allow for at least
    133   // 8 bytes of reply data.
    134   return sizeof(ICMP_ECHO_REPLY) + talk_base::_max<uint32>(8, data_size);
    135 }
    136 
    137 //////////////////////////////////////////////////////////////////////
    138 // WinPing
    139 //////////////////////////////////////////////////////////////////////
    140 
    141 WinPing::WinPing()
    142     : dll_(0), hping_(INVALID_HANDLE_VALUE), create_(0), close_(0), send_(0),
    143       data_(0), dlen_(0), reply_(0), rlen_(0), valid_(false) {
    144 
    145   dll_ = LoadLibraryA(ICMP_DLL_NAME);
    146   if (!dll_) {
    147     LOG(LERROR) << "LoadLibrary: " << GetLastError();
    148     return;
    149   }
    150 
    151   create_ = (PIcmpCreateFile) GetProcAddress(dll_, ICMP_CREATE_FUNC);
    152   close_ = (PIcmpCloseHandle) GetProcAddress(dll_, ICMP_CLOSE_FUNC);
    153   send_ = (PIcmpSendEcho) GetProcAddress(dll_, ICMP_SEND_FUNC);
    154   if (!create_ || !close_ || !send_) {
    155     LOG(LERROR) << "GetProcAddress(ICMP_*): " << GetLastError();
    156     return;
    157   }
    158 
    159   hping_ = create_();
    160   if (hping_ == INVALID_HANDLE_VALUE) {
    161     LOG(LERROR) << "IcmpCreateFile: " << GetLastError();
    162     return;
    163   }
    164 
    165   dlen_ = 0;
    166   rlen_ = ReplySize(dlen_);
    167   data_ = new char[dlen_];
    168   reply_ = new char[rlen_];
    169 
    170   valid_ = true;
    171 }
    172 
    173 WinPing::~WinPing() {
    174   if (dll_)
    175     FreeLibrary(dll_);
    176 
    177   if ((hping_ != INVALID_HANDLE_VALUE) && close_) {
    178     if (!close_(hping_))
    179       LOG(WARNING) << "IcmpCloseHandle: " << GetLastError();
    180   }
    181 
    182   delete[] data_;
    183   delete reply_;
    184 }
    185 
    186 WinPing::PingResult WinPing::Ping(
    187     uint32 ip, uint32 data_size, uint32 timeout, uint8 ttl,
    188     bool allow_fragments) {
    189 
    190   assert(IsValid());
    191 
    192   IP_OPTION_INFORMATION ipopt;
    193   memset(&ipopt, 0, sizeof(ipopt));
    194   if (!allow_fragments)
    195     ipopt.Flags |= IP_FLAG_DF;
    196   ipopt.Ttl = ttl;
    197 
    198   uint32 reply_size = ReplySize(data_size);
    199 
    200   if (data_size > dlen_) {
    201     delete [] data_;
    202     dlen_ = data_size;
    203     data_ = new char[dlen_];
    204     memset(data_, 'z', dlen_);
    205   }
    206 
    207   if (reply_size > rlen_) {
    208     delete [] reply_;
    209     rlen_ = reply_size;
    210     reply_ = new char[rlen_];
    211   }
    212 
    213   DWORD result = send_(hping_, talk_base::HostToNetwork32(ip),
    214                        data_, uint16(data_size), &ipopt,
    215                        reply_, reply_size, timeout);
    216   if (result == 0) {
    217     long error = GetLastError();
    218     if (error == IP_PACKET_TOO_BIG)
    219       return PING_TOO_LARGE;
    220     if (error == IP_REQ_TIMED_OUT)
    221       return PING_TIMEOUT;
    222     LOG(LERROR) << "IcmpSendEcho(" << talk_base::SocketAddress::IPToString(ip)
    223                 << ", " << data_size << "): " << error;
    224     return PING_FAIL;
    225   }
    226 
    227   return PING_SUCCESS;
    228 }
    229 
    230 //////////////////////////////////////////////////////////////////////
    231 // Microsoft Documenation
    232 //////////////////////////////////////////////////////////////////////
    233 //
    234 // Routine Name:
    235 //
    236 //     IcmpCreateFile
    237 //
    238 // Routine Description:
    239 //
    240 //     Opens a handle on which ICMP Echo Requests can be issued.
    241 //
    242 // Arguments:
    243 //
    244 //     None.
    245 //
    246 // Return Value:
    247 //
    248 //     An open file handle or INVALID_HANDLE_VALUE. Extended error information
    249 //     is available by calling GetLastError().
    250 //
    251 //////////////////////////////////////////////////////////////////////
    252 //
    253 // Routine Name:
    254 //
    255 //     IcmpCloseHandle
    256 //
    257 // Routine Description:
    258 //
    259 //     Closes a handle opened by ICMPOpenFile.
    260 //
    261 // Arguments:
    262 //
    263 //     IcmpHandle  - The handle to close.
    264 //
    265 // Return Value:
    266 //
    267 //     TRUE if the handle was closed successfully, otherwise FALSE. Extended
    268 //     error information is available by calling GetLastError().
    269 //
    270 //////////////////////////////////////////////////////////////////////
    271 //
    272 // Routine Name:
    273 //
    274 //     IcmpSendEcho
    275 //
    276 // Routine Description:
    277 //
    278 //     Sends an ICMP Echo request and returns any replies. The
    279 //     call returns when the timeout has expired or the reply buffer
    280 //     is filled.
    281 //
    282 // Arguments:
    283 //
    284 //     IcmpHandle           - An open handle returned by ICMPCreateFile.
    285 //
    286 //     DestinationAddress   - The destination of the echo request.
    287 //
    288 //     RequestData          - A buffer containing the data to send in the
    289 //                            request.
    290 //
    291 //     RequestSize          - The number of bytes in the request data buffer.
    292 //
    293 //     RequestOptions       - Pointer to the IP header options for the request.
    294 //                            May be NULL.
    295 //
    296 //     ReplyBuffer          - A buffer to hold any replies to the request.
    297 //                            On return, the buffer will contain an array of
    298 //                            ICMP_ECHO_REPLY structures followed by the
    299 //                            options and data for the replies. The buffer
    300 //                            should be large enough to hold at least one
    301 //                            ICMP_ECHO_REPLY structure plus
    302 //                            MAX(RequestSize, 8) bytes of data since an ICMP
    303 //                            error message contains 8 bytes of data.
    304 //
    305 //     ReplySize            - The size in bytes of the reply buffer.
    306 //
    307 //     Timeout              - The time in milliseconds to wait for replies.
    308 //
    309 // Return Value:
    310 //
    311 //     Returns the number of ICMP_ECHO_REPLY structures stored in ReplyBuffer.
    312 //     The status of each reply is contained in the structure. If the return
    313 //     value is zero, extended error information is available via
    314 //     GetLastError().
    315 //
    316 //////////////////////////////////////////////////////////////////////
    317 
    318 } // namespace talk_base
    319