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