1 /* 2 * Copyright 2004 The WebRTC Project Authors. All rights reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include "webrtc/base/win32.h" 12 13 #include <winsock2.h> 14 #include <ws2tcpip.h> 15 #include <algorithm> 16 17 #include "webrtc/base/arraysize.h" 18 #include "webrtc/base/basictypes.h" 19 #include "webrtc/base/byteorder.h" 20 #include "webrtc/base/common.h" 21 #include "webrtc/base/logging.h" 22 23 namespace rtc { 24 25 // Helper function declarations for inet_ntop/inet_pton. 26 static const char* inet_ntop_v4(const void* src, char* dst, socklen_t size); 27 static const char* inet_ntop_v6(const void* src, char* dst, socklen_t size); 28 static int inet_pton_v4(const char* src, void* dst); 29 static int inet_pton_v6(const char* src, void* dst); 30 31 // Implementation of inet_ntop (create a printable representation of an 32 // ip address). XP doesn't have its own inet_ntop, and 33 // WSAAddressToString requires both IPv6 to be installed and for Winsock 34 // to be initialized. 35 const char* win32_inet_ntop(int af, const void *src, 36 char* dst, socklen_t size) { 37 if (!src || !dst) { 38 return NULL; 39 } 40 switch (af) { 41 case AF_INET: { 42 return inet_ntop_v4(src, dst, size); 43 } 44 case AF_INET6: { 45 return inet_ntop_v6(src, dst, size); 46 } 47 } 48 return NULL; 49 } 50 51 // As above, but for inet_pton. Implements inet_pton for v4 and v6. 52 // Note that our inet_ntop will output normal 'dotted' v4 addresses only. 53 int win32_inet_pton(int af, const char* src, void* dst) { 54 if (!src || !dst) { 55 return 0; 56 } 57 if (af == AF_INET) { 58 return inet_pton_v4(src, dst); 59 } else if (af == AF_INET6) { 60 return inet_pton_v6(src, dst); 61 } 62 return -1; 63 } 64 65 // Helper function for inet_ntop for IPv4 addresses. 66 // Outputs "dotted-quad" decimal notation. 67 const char* inet_ntop_v4(const void* src, char* dst, socklen_t size) { 68 if (size < INET_ADDRSTRLEN) { 69 return NULL; 70 } 71 const struct in_addr* as_in_addr = 72 reinterpret_cast<const struct in_addr*>(src); 73 rtc::sprintfn(dst, size, "%d.%d.%d.%d", 74 as_in_addr->S_un.S_un_b.s_b1, 75 as_in_addr->S_un.S_un_b.s_b2, 76 as_in_addr->S_un.S_un_b.s_b3, 77 as_in_addr->S_un.S_un_b.s_b4); 78 return dst; 79 } 80 81 // Helper function for inet_ntop for IPv6 addresses. 82 const char* inet_ntop_v6(const void* src, char* dst, socklen_t size) { 83 if (size < INET6_ADDRSTRLEN) { 84 return NULL; 85 } 86 const uint16_t* as_shorts = reinterpret_cast<const uint16_t*>(src); 87 int runpos[8]; 88 int current = 1; 89 int max = 0; 90 int maxpos = -1; 91 int run_array_size = arraysize(runpos); 92 // Run over the address marking runs of 0s. 93 for (int i = 0; i < run_array_size; ++i) { 94 if (as_shorts[i] == 0) { 95 runpos[i] = current; 96 if (current > max) { 97 maxpos = i; 98 max = current; 99 } 100 ++current; 101 } else { 102 runpos[i] = -1; 103 current = 1; 104 } 105 } 106 107 if (max > 0) { 108 int tmpmax = maxpos; 109 // Run back through, setting -1 for all but the longest run. 110 for (int i = run_array_size - 1; i >= 0; i--) { 111 if (i > tmpmax) { 112 runpos[i] = -1; 113 } else if (runpos[i] == -1) { 114 // We're less than maxpos, we hit a -1, so the 'good' run is done. 115 // Setting tmpmax -1 means all remaining positions get set to -1. 116 tmpmax = -1; 117 } 118 } 119 } 120 121 char* cursor = dst; 122 // Print IPv4 compatible and IPv4 mapped addresses using the IPv4 helper. 123 // These addresses have an initial run of either eight zero-bytes followed 124 // by 0xFFFF, or an initial run of ten zero-bytes. 125 if (runpos[0] == 1 && (maxpos == 5 || 126 (maxpos == 4 && as_shorts[5] == 0xFFFF))) { 127 *cursor++ = ':'; 128 *cursor++ = ':'; 129 if (maxpos == 4) { 130 cursor += rtc::sprintfn(cursor, INET6_ADDRSTRLEN - 2, "ffff:"); 131 } 132 const struct in_addr* as_v4 = 133 reinterpret_cast<const struct in_addr*>(&(as_shorts[6])); 134 inet_ntop_v4(as_v4, cursor, 135 static_cast<socklen_t>(INET6_ADDRSTRLEN - (cursor - dst))); 136 } else { 137 for (int i = 0; i < run_array_size; ++i) { 138 if (runpos[i] == -1) { 139 cursor += rtc::sprintfn(cursor, 140 INET6_ADDRSTRLEN - (cursor - dst), 141 "%x", NetworkToHost16(as_shorts[i])); 142 if (i != 7 && runpos[i + 1] != 1) { 143 *cursor++ = ':'; 144 } 145 } else if (runpos[i] == 1) { 146 // Entered the run; print the colons and skip the run. 147 *cursor++ = ':'; 148 *cursor++ = ':'; 149 i += (max - 1); 150 } 151 } 152 } 153 return dst; 154 } 155 156 // Helper function for inet_pton for IPv4 addresses. 157 // |src| points to a character string containing an IPv4 network address in 158 // dotted-decimal format, "ddd.ddd.ddd.ddd", where ddd is a decimal number 159 // of up to three digits in the range 0 to 255. 160 // The address is converted and copied to dst, 161 // which must be sizeof(struct in_addr) (4) bytes (32 bits) long. 162 int inet_pton_v4(const char* src, void* dst) { 163 const int kIpv4AddressSize = 4; 164 int found = 0; 165 const char* src_pos = src; 166 unsigned char result[kIpv4AddressSize] = {0}; 167 168 while (*src_pos != '\0') { 169 // strtol won't treat whitespace characters in the begining as an error, 170 // so check to ensure this is started with digit before passing to strtol. 171 if (!isdigit(*src_pos)) { 172 return 0; 173 } 174 char* end_pos; 175 long value = strtol(src_pos, &end_pos, 10); 176 if (value < 0 || value > 255 || src_pos == end_pos) { 177 return 0; 178 } 179 ++found; 180 if (found > kIpv4AddressSize) { 181 return 0; 182 } 183 result[found - 1] = static_cast<unsigned char>(value); 184 src_pos = end_pos; 185 if (*src_pos == '.') { 186 // There's more. 187 ++src_pos; 188 } else if (*src_pos != '\0') { 189 // If it's neither '.' nor '\0' then return fail. 190 return 0; 191 } 192 } 193 if (found != kIpv4AddressSize) { 194 return 0; 195 } 196 memcpy(dst, result, sizeof(result)); 197 return 1; 198 } 199 200 // Helper function for inet_pton for IPv6 addresses. 201 int inet_pton_v6(const char* src, void* dst) { 202 // sscanf will pick any other invalid chars up, but it parses 0xnnnn as hex. 203 // Check for literal x in the input string. 204 const char* readcursor = src; 205 char c = *readcursor++; 206 while (c) { 207 if (c == 'x') { 208 return 0; 209 } 210 c = *readcursor++; 211 } 212 readcursor = src; 213 214 struct in6_addr an_addr; 215 memset(&an_addr, 0, sizeof(an_addr)); 216 217 uint16_t* addr_cursor = reinterpret_cast<uint16_t*>(&an_addr.s6_addr[0]); 218 uint16_t* addr_end = reinterpret_cast<uint16_t*>(&an_addr.s6_addr[16]); 219 bool seencompressed = false; 220 221 // Addresses that start with "::" (i.e., a run of initial zeros) or 222 // "::ffff:" can potentially be IPv4 mapped or compatibility addresses. 223 // These have dotted-style IPv4 addresses on the end (e.g. "::192.168.7.1"). 224 if (*readcursor == ':' && *(readcursor+1) == ':' && 225 *(readcursor + 2) != 0) { 226 // Check for periods, which we'll take as a sign of v4 addresses. 227 const char* addrstart = readcursor + 2; 228 if (rtc::strchr(addrstart, ".")) { 229 const char* colon = rtc::strchr(addrstart, "::"); 230 if (colon) { 231 uint16_t a_short; 232 int bytesread = 0; 233 if (sscanf(addrstart, "%hx%n", &a_short, &bytesread) != 1 || 234 a_short != 0xFFFF || bytesread != 4) { 235 // Colons + periods means has to be ::ffff:a.b.c.d. But it wasn't. 236 return 0; 237 } else { 238 an_addr.s6_addr[10] = 0xFF; 239 an_addr.s6_addr[11] = 0xFF; 240 addrstart = colon + 1; 241 } 242 } 243 struct in_addr v4; 244 if (inet_pton_v4(addrstart, &v4.s_addr)) { 245 memcpy(&an_addr.s6_addr[12], &v4, sizeof(v4)); 246 memcpy(dst, &an_addr, sizeof(an_addr)); 247 return 1; 248 } else { 249 // Invalid v4 address. 250 return 0; 251 } 252 } 253 } 254 255 // For addresses without a trailing IPv4 component ('normal' IPv6 addresses). 256 while (*readcursor != 0 && addr_cursor < addr_end) { 257 if (*readcursor == ':') { 258 if (*(readcursor + 1) == ':') { 259 if (seencompressed) { 260 // Can only have one compressed run of zeroes ("::") per address. 261 return 0; 262 } 263 // Hit a compressed run. Count colons to figure out how much of the 264 // address is skipped. 265 readcursor += 2; 266 const char* coloncounter = readcursor; 267 int coloncount = 0; 268 if (*coloncounter == 0) { 269 // Special case - trailing ::. 270 addr_cursor = addr_end; 271 } else { 272 while (*coloncounter) { 273 if (*coloncounter == ':') { 274 ++coloncount; 275 } 276 ++coloncounter; 277 } 278 // (coloncount + 1) is the number of shorts left in the address. 279 addr_cursor = addr_end - (coloncount + 1); 280 seencompressed = true; 281 } 282 } else { 283 ++readcursor; 284 } 285 } else { 286 uint16_t word; 287 int bytesread = 0; 288 if (sscanf(readcursor, "%hx%n", &word, &bytesread) != 1) { 289 return 0; 290 } else { 291 *addr_cursor = HostToNetwork16(word); 292 ++addr_cursor; 293 readcursor += bytesread; 294 if (*readcursor != ':' && *readcursor != '\0') { 295 return 0; 296 } 297 } 298 } 299 } 300 301 if (*readcursor != '\0' || addr_cursor < addr_end) { 302 // Catches addresses too short or too long. 303 return 0; 304 } 305 memcpy(dst, &an_addr, sizeof(an_addr)); 306 return 1; 307 } 308 309 // 310 // Unix time is in seconds relative to 1/1/1970. So we compute the windows 311 // FILETIME of that time/date, then we add/subtract in appropriate units to 312 // convert to/from unix time. 313 // The units of FILETIME are 100ns intervals, so by multiplying by or dividing 314 // by 10000000, we can convert to/from seconds. 315 // 316 // FileTime = UnixTime*10000000 + FileTime(1970) 317 // UnixTime = (FileTime-FileTime(1970))/10000000 318 // 319 320 void FileTimeToUnixTime(const FILETIME& ft, time_t* ut) { 321 ASSERT(NULL != ut); 322 323 // FILETIME has an earlier date base than time_t (1/1/1970), so subtract off 324 // the difference. 325 SYSTEMTIME base_st; 326 memset(&base_st, 0, sizeof(base_st)); 327 base_st.wDay = 1; 328 base_st.wMonth = 1; 329 base_st.wYear = 1970; 330 331 FILETIME base_ft; 332 SystemTimeToFileTime(&base_st, &base_ft); 333 334 ULARGE_INTEGER base_ul, current_ul; 335 memcpy(&base_ul, &base_ft, sizeof(FILETIME)); 336 memcpy(¤t_ul, &ft, sizeof(FILETIME)); 337 338 // Divide by big number to convert to seconds, then subtract out the 1970 339 // base date value. 340 const ULONGLONG RATIO = 10000000; 341 *ut = static_cast<time_t>((current_ul.QuadPart - base_ul.QuadPart) / RATIO); 342 } 343 344 void UnixTimeToFileTime(const time_t& ut, FILETIME* ft) { 345 ASSERT(NULL != ft); 346 347 // FILETIME has an earlier date base than time_t (1/1/1970), so add in 348 // the difference. 349 SYSTEMTIME base_st; 350 memset(&base_st, 0, sizeof(base_st)); 351 base_st.wDay = 1; 352 base_st.wMonth = 1; 353 base_st.wYear = 1970; 354 355 FILETIME base_ft; 356 SystemTimeToFileTime(&base_st, &base_ft); 357 358 ULARGE_INTEGER base_ul; 359 memcpy(&base_ul, &base_ft, sizeof(FILETIME)); 360 361 // Multiply by big number to convert to 100ns units, then add in the 1970 362 // base date value. 363 const ULONGLONG RATIO = 10000000; 364 ULARGE_INTEGER current_ul; 365 current_ul.QuadPart = base_ul.QuadPart + static_cast<int64_t>(ut) * RATIO; 366 memcpy(ft, ¤t_ul, sizeof(FILETIME)); 367 } 368 369 bool Utf8ToWindowsFilename(const std::string& utf8, std::wstring* filename) { 370 // TODO: Integrate into fileutils.h 371 // TODO: Handle wide and non-wide cases via TCHAR? 372 // TODO: Skip \\?\ processing if the length is not > MAX_PATH? 373 // TODO: Write unittests 374 375 // Convert to Utf16 376 int wlen = ::MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), 377 static_cast<int>(utf8.length() + 1), NULL, 378 0); 379 if (0 == wlen) { 380 return false; 381 } 382 wchar_t* wfilename = STACK_ARRAY(wchar_t, wlen); 383 if (0 == ::MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), 384 static_cast<int>(utf8.length() + 1), 385 wfilename, wlen)) { 386 return false; 387 } 388 // Replace forward slashes with backslashes 389 std::replace(wfilename, wfilename + wlen, L'/', L'\\'); 390 // Convert to complete filename 391 DWORD full_len = ::GetFullPathName(wfilename, 0, NULL, NULL); 392 if (0 == full_len) { 393 return false; 394 } 395 wchar_t* filepart = NULL; 396 wchar_t* full_filename = STACK_ARRAY(wchar_t, full_len + 6); 397 wchar_t* start = full_filename + 6; 398 if (0 == ::GetFullPathName(wfilename, full_len, start, &filepart)) { 399 return false; 400 } 401 // Add long-path prefix 402 const wchar_t kLongPathPrefix[] = L"\\\\?\\UNC"; 403 if ((start[0] != L'\\') || (start[1] != L'\\')) { 404 // Non-unc path: <pathname> 405 // Becomes: \\?\<pathname> 406 start -= 4; 407 ASSERT(start >= full_filename); 408 memcpy(start, kLongPathPrefix, 4 * sizeof(wchar_t)); 409 } else if (start[2] != L'?') { 410 // Unc path: \\<server>\<pathname> 411 // Becomes: \\?\UNC\<server>\<pathname> 412 start -= 6; 413 ASSERT(start >= full_filename); 414 memcpy(start, kLongPathPrefix, 7 * sizeof(wchar_t)); 415 } else { 416 // Already in long-path form. 417 } 418 filename->assign(start); 419 return true; 420 } 421 422 bool GetOsVersion(int* major, int* minor, int* build) { 423 OSVERSIONINFO info = {0}; 424 info.dwOSVersionInfoSize = sizeof(info); 425 if (GetVersionEx(&info)) { 426 if (major) *major = info.dwMajorVersion; 427 if (minor) *minor = info.dwMinorVersion; 428 if (build) *build = info.dwBuildNumber; 429 return true; 430 } 431 return false; 432 } 433 434 bool GetCurrentProcessIntegrityLevel(int* level) { 435 bool ret = false; 436 HANDLE process = ::GetCurrentProcess(), token; 437 if (OpenProcessToken(process, TOKEN_QUERY | TOKEN_QUERY_SOURCE, &token)) { 438 DWORD size; 439 if (!GetTokenInformation(token, TokenIntegrityLevel, NULL, 0, &size) && 440 GetLastError() == ERROR_INSUFFICIENT_BUFFER) { 441 442 char* buf = STACK_ARRAY(char, size); 443 TOKEN_MANDATORY_LABEL* til = 444 reinterpret_cast<TOKEN_MANDATORY_LABEL*>(buf); 445 if (GetTokenInformation(token, TokenIntegrityLevel, til, size, &size)) { 446 447 DWORD count = *GetSidSubAuthorityCount(til->Label.Sid); 448 *level = *GetSidSubAuthority(til->Label.Sid, count - 1); 449 ret = true; 450 } 451 } 452 CloseHandle(token); 453 } 454 return ret; 455 } 456 457 } // namespace rtc 458