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/win32socketserver.h" 29 #include "talk/base/byteorder.h" 30 #include "talk/base/common.h" 31 #include "talk/base/logging.h" 32 #include "talk/base/winping.h" 33 #include "talk/base/win32window.h" 34 #include <ws2tcpip.h> // NOLINT 35 36 namespace talk_base { 37 38 /////////////////////////////////////////////////////////////////////////////// 39 // Win32Socket 40 /////////////////////////////////////////////////////////////////////////////// 41 42 // TODO: Move this to a common place where PhysicalSocketServer can 43 // share it. 44 // Standard MTUs 45 static const uint16 PACKET_MAXIMUMS[] = { 46 65535, // Theoretical maximum, Hyperchannel 47 32000, // Nothing 48 17914, // 16Mb IBM Token Ring 49 8166, // IEEE 802.4 50 // 4464 // IEEE 802.5 (4Mb max) 51 4352, // FDDI 52 // 2048, // Wideband Network 53 2002, // IEEE 802.5 (4Mb recommended) 54 // 1536, // Expermental Ethernet Networks 55 // 1500, // Ethernet, Point-to-Point (default) 56 1492, // IEEE 802.3 57 1006, // SLIP, ARPANET 58 // 576, // X.25 Networks 59 // 544, // DEC IP Portal 60 // 512, // NETBIOS 61 508, // IEEE 802/Source-Rt Bridge, ARCNET 62 296, // Point-to-Point (low delay) 63 68, // Official minimum 64 0, // End of list marker 65 }; 66 67 static const int IP_HEADER_SIZE = 20u; 68 static const int ICMP_HEADER_SIZE = 8u; 69 static const int ICMP_PING_TIMEOUT_MILLIS = 10000u; 70 71 // TODO: Enable for production builds also? Use FormatMessage? 72 #ifdef _DEBUG 73 LPCSTR WSAErrorToString(int error, LPCSTR *description_result) { 74 LPCSTR string = "Unspecified"; 75 LPCSTR description = "Unspecified description"; 76 switch (error) { 77 case ERROR_SUCCESS: 78 string = "SUCCESS"; 79 description = "Operation succeeded"; 80 break; 81 case WSAEWOULDBLOCK: 82 string = "WSAEWOULDBLOCK"; 83 description = "Using a non-blocking socket, will notify later"; 84 break; 85 case WSAEACCES: 86 string = "WSAEACCES"; 87 description = "Access denied, or sharing violation"; 88 break; 89 case WSAEADDRNOTAVAIL: 90 string = "WSAEADDRNOTAVAIL"; 91 description = "Address is not valid in this context"; 92 break; 93 case WSAENETDOWN: 94 string = "WSAENETDOWN"; 95 description = "Network is down"; 96 break; 97 case WSAENETUNREACH: 98 string = "WSAENETUNREACH"; 99 description = "Network is up, but unreachable"; 100 break; 101 case WSAENETRESET: 102 string = "WSANETRESET"; 103 description = "Connection has been reset due to keep-alive activity"; 104 break; 105 case WSAECONNABORTED: 106 string = "WSAECONNABORTED"; 107 description = "Aborted by host"; 108 break; 109 case WSAECONNRESET: 110 string = "WSAECONNRESET"; 111 description = "Connection reset by host"; 112 break; 113 case WSAETIMEDOUT: 114 string = "WSAETIMEDOUT"; 115 description = "Timed out, host failed to respond"; 116 break; 117 case WSAECONNREFUSED: 118 string = "WSAECONNREFUSED"; 119 description = "Host actively refused connection"; 120 break; 121 case WSAEHOSTDOWN: 122 string = "WSAEHOSTDOWN"; 123 description = "Host is down"; 124 break; 125 case WSAEHOSTUNREACH: 126 string = "WSAEHOSTUNREACH"; 127 description = "Host is unreachable"; 128 break; 129 case WSAHOST_NOT_FOUND: 130 string = "WSAHOST_NOT_FOUND"; 131 description = "No such host is known"; 132 break; 133 } 134 if (description_result) { 135 *description_result = description; 136 } 137 return string; 138 } 139 140 void ReportWSAError(LPCSTR context, int error, const SocketAddress& address) { 141 LPCSTR description_string; 142 LPCSTR error_string = WSAErrorToString(error, &description_string); 143 LOG(LS_INFO) << context << " = " << error 144 << " (" << error_string << ":" << description_string << ") [" 145 << address.ToString() << "]"; 146 } 147 #else 148 void ReportWSAError(LPCSTR context, int error, const SocketAddress& address) {} 149 #endif 150 151 ///////////////////////////////////////////////////////////////////////////// 152 // Win32Socket::EventSink 153 ///////////////////////////////////////////////////////////////////////////// 154 155 #define WM_SOCKETNOTIFY (WM_USER + 50) 156 #define WM_DNSNOTIFY (WM_USER + 51) 157 158 struct Win32Socket::DnsLookup { 159 HANDLE handle; 160 uint16 port; 161 char buffer[MAXGETHOSTSTRUCT]; 162 }; 163 164 class Win32Socket::EventSink : public Win32Window { 165 public: 166 explicit EventSink(Win32Socket * parent) : parent_(parent) { } 167 168 void Dispose(); 169 170 virtual bool OnMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, 171 LRESULT& result); 172 virtual void OnNcDestroy(); 173 174 private: 175 bool OnSocketNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& result); 176 bool OnDnsNotify(WPARAM wParam, LPARAM lParam, LRESULT& result); 177 178 Win32Socket * parent_; 179 }; 180 181 void Win32Socket::EventSink::Dispose() { 182 parent_ = NULL; 183 if (::IsWindow(handle())) { 184 ::DestroyWindow(handle()); 185 } else { 186 delete this; 187 } 188 } 189 190 bool Win32Socket::EventSink::OnMessage(UINT uMsg, WPARAM wParam, 191 LPARAM lParam, LRESULT& result) { 192 switch (uMsg) { 193 case WM_SOCKETNOTIFY: 194 case WM_TIMER: 195 return OnSocketNotify(uMsg, wParam, lParam, result); 196 case WM_DNSNOTIFY: 197 return OnDnsNotify(wParam, lParam, result); 198 } 199 return false; 200 } 201 202 bool Win32Socket::EventSink::OnSocketNotify(UINT uMsg, WPARAM wParam, 203 LPARAM lParam, LRESULT& result) { 204 result = 0; 205 206 int wsa_event = WSAGETSELECTEVENT(lParam); 207 int wsa_error = WSAGETSELECTERROR(lParam); 208 209 // Treat connect timeouts as close notifications 210 if (uMsg == WM_TIMER) { 211 wsa_event = FD_CLOSE; 212 wsa_error = WSAETIMEDOUT; 213 } 214 215 if (parent_) 216 parent_->OnSocketNotify(static_cast<SOCKET>(wParam), wsa_event, wsa_error); 217 return true; 218 } 219 220 bool Win32Socket::EventSink::OnDnsNotify(WPARAM wParam, LPARAM lParam, 221 LRESULT& result) { 222 result = 0; 223 224 int error = WSAGETASYNCERROR(lParam); 225 if (parent_) 226 parent_->OnDnsNotify(reinterpret_cast<HANDLE>(wParam), error); 227 return true; 228 } 229 230 void Win32Socket::EventSink::OnNcDestroy() { 231 if (parent_) { 232 LOG(LS_ERROR) << "EventSink hwnd is being destroyed, but the event sink" 233 " hasn't yet been disposed."; 234 } else { 235 delete this; 236 } 237 } 238 239 ///////////////////////////////////////////////////////////////////////////// 240 // Win32Socket 241 ///////////////////////////////////////////////////////////////////////////// 242 243 Win32Socket::Win32Socket() 244 : socket_(INVALID_SOCKET), error_(0), state_(CS_CLOSED), connect_time_(0), 245 closing_(false), close_error_(0), sink_(NULL), dns_(NULL) { 246 } 247 248 Win32Socket::~Win32Socket() { 249 Close(); 250 } 251 252 bool Win32Socket::CreateT(int family, int type) { 253 Close(); 254 int proto = (SOCK_DGRAM == type) ? IPPROTO_UDP : IPPROTO_TCP; 255 socket_ = ::WSASocket(family, type, proto, NULL, NULL, 0); 256 if (socket_ == INVALID_SOCKET) { 257 UpdateLastError(); 258 return false; 259 } 260 if ((SOCK_DGRAM == type) && !SetAsync(FD_READ | FD_WRITE)) { 261 return false; 262 } 263 return true; 264 } 265 266 int Win32Socket::Attach(SOCKET s) { 267 ASSERT(socket_ == INVALID_SOCKET); 268 if (socket_ != INVALID_SOCKET) 269 return SOCKET_ERROR; 270 271 ASSERT(s != INVALID_SOCKET); 272 if (s == INVALID_SOCKET) 273 return SOCKET_ERROR; 274 275 socket_ = s; 276 state_ = CS_CONNECTED; 277 278 if (!SetAsync(FD_READ | FD_WRITE | FD_CLOSE)) 279 return SOCKET_ERROR; 280 281 return 0; 282 } 283 284 void Win32Socket::SetTimeout(int ms) { 285 if (sink_) 286 ::SetTimer(sink_->handle(), 1, ms, 0); 287 } 288 289 SocketAddress Win32Socket::GetLocalAddress() const { 290 sockaddr_storage addr = {0}; 291 socklen_t addrlen = sizeof(addr); 292 int result = ::getsockname(socket_, reinterpret_cast<sockaddr*>(&addr), 293 &addrlen); 294 SocketAddress address; 295 if (result >= 0) { 296 SocketAddressFromSockAddrStorage(addr, &address); 297 } else { 298 LOG(LS_WARNING) << "GetLocalAddress: unable to get local addr, socket=" 299 << socket_; 300 } 301 return address; 302 } 303 304 SocketAddress Win32Socket::GetRemoteAddress() const { 305 sockaddr_storage addr = {0}; 306 socklen_t addrlen = sizeof(addr); 307 int result = ::getpeername(socket_, reinterpret_cast<sockaddr*>(&addr), 308 &addrlen); 309 SocketAddress address; 310 if (result >= 0) { 311 SocketAddressFromSockAddrStorage(addr, &address); 312 } else { 313 LOG(LS_WARNING) << "GetRemoteAddress: unable to get remote addr, socket=" 314 << socket_; 315 } 316 return address; 317 } 318 319 int Win32Socket::Bind(const SocketAddress& addr) { 320 ASSERT(socket_ != INVALID_SOCKET); 321 if (socket_ == INVALID_SOCKET) 322 return SOCKET_ERROR; 323 324 sockaddr_storage saddr; 325 size_t len = addr.ToSockAddrStorage(&saddr); 326 int err = ::bind(socket_, 327 reinterpret_cast<sockaddr*>(&saddr), 328 static_cast<int>(len)); 329 UpdateLastError(); 330 return err; 331 } 332 333 int Win32Socket::Connect(const SocketAddress& addr) { 334 if (state_ != CS_CLOSED) { 335 SetError(EALREADY); 336 return SOCKET_ERROR; 337 } 338 339 if (!addr.IsUnresolvedIP()) { 340 return DoConnect(addr); 341 } 342 343 LOG_F(LS_INFO) << "async dns lookup (" << addr.hostname() << ")"; 344 DnsLookup * dns = new DnsLookup; 345 if (!sink_) { 346 // Explicitly create the sink ourselves here; we can't rely on SetAsync 347 // because we don't have a socket_ yet. 348 CreateSink(); 349 } 350 // TODO: Replace with IPv6 compatible lookup. 351 dns->handle = WSAAsyncGetHostByName(sink_->handle(), WM_DNSNOTIFY, 352 addr.hostname().c_str(), dns->buffer, 353 sizeof(dns->buffer)); 354 355 if (!dns->handle) { 356 LOG_F(LS_ERROR) << "WSAAsyncGetHostByName error: " << WSAGetLastError(); 357 delete dns; 358 UpdateLastError(); 359 Close(); 360 return SOCKET_ERROR; 361 } 362 363 dns->port = addr.port(); 364 dns_ = dns; 365 state_ = CS_CONNECTING; 366 return 0; 367 } 368 369 int Win32Socket::DoConnect(const SocketAddress& addr) { 370 if ((socket_ == INVALID_SOCKET) && !CreateT(addr.family(), SOCK_STREAM)) { 371 return SOCKET_ERROR; 372 } 373 if (!SetAsync(FD_READ | FD_WRITE | FD_CONNECT | FD_CLOSE)) { 374 return SOCKET_ERROR; 375 } 376 377 sockaddr_storage saddr = {0}; 378 size_t len = addr.ToSockAddrStorage(&saddr); 379 connect_time_ = Time(); 380 int result = connect(socket_, 381 reinterpret_cast<SOCKADDR*>(&saddr), 382 static_cast<int>(len)); 383 if (result != SOCKET_ERROR) { 384 state_ = CS_CONNECTED; 385 } else { 386 int code = WSAGetLastError(); 387 if (code == WSAEWOULDBLOCK) { 388 state_ = CS_CONNECTING; 389 } else { 390 ReportWSAError("WSAAsync:connect", code, addr); 391 error_ = code; 392 Close(); 393 return SOCKET_ERROR; 394 } 395 } 396 addr_ = addr; 397 398 return 0; 399 } 400 401 int Win32Socket::GetError() const { 402 return error_; 403 } 404 405 void Win32Socket::SetError(int error) { 406 error_ = error; 407 } 408 409 Socket::ConnState Win32Socket::GetState() const { 410 return state_; 411 } 412 413 int Win32Socket::GetOption(Option opt, int* value) { 414 int slevel; 415 int sopt; 416 if (TranslateOption(opt, &slevel, &sopt) == -1) 417 return -1; 418 419 char* p = reinterpret_cast<char*>(value); 420 int optlen = sizeof(value); 421 return ::getsockopt(socket_, slevel, sopt, p, &optlen); 422 } 423 424 int Win32Socket::SetOption(Option opt, int value) { 425 int slevel; 426 int sopt; 427 if (TranslateOption(opt, &slevel, &sopt) == -1) 428 return -1; 429 430 const char* p = reinterpret_cast<const char*>(&value); 431 return ::setsockopt(socket_, slevel, sopt, p, sizeof(value)); 432 } 433 434 int Win32Socket::Send(const void* buffer, size_t length) { 435 int sent = ::send(socket_, 436 reinterpret_cast<const char*>(buffer), 437 static_cast<int>(length), 438 0); 439 UpdateLastError(); 440 return sent; 441 } 442 443 int Win32Socket::SendTo(const void* buffer, size_t length, 444 const SocketAddress& addr) { 445 sockaddr_storage saddr; 446 size_t addr_len = addr.ToSockAddrStorage(&saddr); 447 int sent = ::sendto(socket_, reinterpret_cast<const char*>(buffer), 448 static_cast<int>(length), 0, 449 reinterpret_cast<sockaddr*>(&saddr), 450 static_cast<int>(addr_len)); 451 UpdateLastError(); 452 return sent; 453 } 454 455 int Win32Socket::Recv(void* buffer, size_t length) { 456 int received = ::recv(socket_, static_cast<char*>(buffer), 457 static_cast<int>(length), 0); 458 UpdateLastError(); 459 if (closing_ && received <= static_cast<int>(length)) 460 PostClosed(); 461 return received; 462 } 463 464 int Win32Socket::RecvFrom(void* buffer, size_t length, 465 SocketAddress* out_addr) { 466 sockaddr_storage saddr; 467 socklen_t addr_len = sizeof(saddr); 468 int received = ::recvfrom(socket_, static_cast<char*>(buffer), 469 static_cast<int>(length), 0, 470 reinterpret_cast<sockaddr*>(&saddr), &addr_len); 471 UpdateLastError(); 472 if (received != SOCKET_ERROR) 473 SocketAddressFromSockAddrStorage(saddr, out_addr); 474 if (closing_ && received <= static_cast<int>(length)) 475 PostClosed(); 476 return received; 477 } 478 479 int Win32Socket::Listen(int backlog) { 480 int err = ::listen(socket_, backlog); 481 if (!SetAsync(FD_ACCEPT)) 482 return SOCKET_ERROR; 483 484 UpdateLastError(); 485 if (err == 0) 486 state_ = CS_CONNECTING; 487 return err; 488 } 489 490 Win32Socket* Win32Socket::Accept(SocketAddress* out_addr) { 491 sockaddr_storage saddr; 492 socklen_t addr_len = sizeof(saddr); 493 SOCKET s = ::accept(socket_, reinterpret_cast<sockaddr*>(&saddr), &addr_len); 494 UpdateLastError(); 495 if (s == INVALID_SOCKET) 496 return NULL; 497 if (out_addr) 498 SocketAddressFromSockAddrStorage(saddr, out_addr); 499 Win32Socket* socket = new Win32Socket; 500 if (0 == socket->Attach(s)) 501 return socket; 502 delete socket; 503 return NULL; 504 } 505 506 int Win32Socket::Close() { 507 int err = 0; 508 if (socket_ != INVALID_SOCKET) { 509 err = ::closesocket(socket_); 510 socket_ = INVALID_SOCKET; 511 closing_ = false; 512 close_error_ = 0; 513 UpdateLastError(); 514 } 515 if (dns_) { 516 WSACancelAsyncRequest(dns_->handle); 517 delete dns_; 518 dns_ = NULL; 519 } 520 if (sink_) { 521 sink_->Dispose(); 522 sink_ = NULL; 523 } 524 addr_.Clear(); 525 state_ = CS_CLOSED; 526 return err; 527 } 528 529 int Win32Socket::EstimateMTU(uint16* mtu) { 530 SocketAddress addr = GetRemoteAddress(); 531 if (addr.IsAny()) { 532 error_ = ENOTCONN; 533 return -1; 534 } 535 536 WinPing ping; 537 if (!ping.IsValid()) { 538 error_ = EINVAL; // can't think of a better error ID 539 return -1; 540 } 541 542 for (int level = 0; PACKET_MAXIMUMS[level + 1] > 0; ++level) { 543 int32 size = PACKET_MAXIMUMS[level] - IP_HEADER_SIZE - ICMP_HEADER_SIZE; 544 WinPing::PingResult result = ping.Ping(addr.ipaddr(), size, 545 ICMP_PING_TIMEOUT_MILLIS, 1, false); 546 if (result == WinPing::PING_FAIL) { 547 error_ = EINVAL; // can't think of a better error ID 548 return -1; 549 } 550 if (result != WinPing::PING_TOO_LARGE) { 551 *mtu = PACKET_MAXIMUMS[level]; 552 return 0; 553 } 554 } 555 556 ASSERT(false); 557 return 0; 558 } 559 560 void Win32Socket::CreateSink() { 561 ASSERT(NULL == sink_); 562 563 // Create window 564 sink_ = new EventSink(this); 565 sink_->Create(NULL, L"EventSink", 0, 0, 0, 0, 10, 10); 566 } 567 568 bool Win32Socket::SetAsync(int events) { 569 if (NULL == sink_) { 570 CreateSink(); 571 ASSERT(NULL != sink_); 572 } 573 574 // start the async select 575 if (WSAAsyncSelect(socket_, sink_->handle(), WM_SOCKETNOTIFY, events) 576 == SOCKET_ERROR) { 577 UpdateLastError(); 578 Close(); 579 return false; 580 } 581 582 return true; 583 } 584 585 bool Win32Socket::HandleClosed(int close_error) { 586 // WM_CLOSE will be received before all data has been read, so we need to 587 // hold on to it until the read buffer has been drained. 588 char ch; 589 closing_ = true; 590 close_error_ = close_error; 591 return (::recv(socket_, &ch, 1, MSG_PEEK) <= 0); 592 } 593 594 void Win32Socket::PostClosed() { 595 // If we see that the buffer is indeed drained, then send the close. 596 closing_ = false; 597 ::PostMessage(sink_->handle(), WM_SOCKETNOTIFY, 598 socket_, WSAMAKESELECTREPLY(FD_CLOSE, close_error_)); 599 } 600 601 void Win32Socket::UpdateLastError() { 602 error_ = WSAGetLastError(); 603 } 604 605 int Win32Socket::TranslateOption(Option opt, int* slevel, int* sopt) { 606 switch (opt) { 607 case OPT_DONTFRAGMENT: 608 *slevel = IPPROTO_IP; 609 *sopt = IP_DONTFRAGMENT; 610 break; 611 case OPT_RCVBUF: 612 *slevel = SOL_SOCKET; 613 *sopt = SO_RCVBUF; 614 break; 615 case OPT_SNDBUF: 616 *slevel = SOL_SOCKET; 617 *sopt = SO_SNDBUF; 618 break; 619 case OPT_NODELAY: 620 *slevel = IPPROTO_TCP; 621 *sopt = TCP_NODELAY; 622 break; 623 case OPT_DSCP: 624 LOG(LS_WARNING) << "Socket::OPT_DSCP not supported."; 625 return -1; 626 default: 627 ASSERT(false); 628 return -1; 629 } 630 return 0; 631 } 632 633 void Win32Socket::OnSocketNotify(SOCKET socket, int event, int error) { 634 // Ignore events if we're already closed. 635 if (socket != socket_) 636 return; 637 638 error_ = error; 639 switch (event) { 640 case FD_CONNECT: 641 if (error != ERROR_SUCCESS) { 642 ReportWSAError("WSAAsync:connect notify", error, addr_); 643 #ifdef _DEBUG 644 int32 duration = TimeSince(connect_time_); 645 LOG(LS_INFO) << "WSAAsync:connect error (" << duration 646 << " ms), faking close"; 647 #endif 648 state_ = CS_CLOSED; 649 // If you get an error connecting, close doesn't really do anything 650 // and it certainly doesn't send back any close notification, but 651 // we really only maintain a few states, so it is easiest to get 652 // back into a known state by pretending that a close happened, even 653 // though the connect event never did occur. 654 SignalCloseEvent(this, error); 655 } else { 656 #ifdef _DEBUG 657 int32 duration = TimeSince(connect_time_); 658 LOG(LS_INFO) << "WSAAsync:connect (" << duration << " ms)"; 659 #endif 660 state_ = CS_CONNECTED; 661 SignalConnectEvent(this); 662 } 663 break; 664 665 case FD_ACCEPT: 666 case FD_READ: 667 if (error != ERROR_SUCCESS) { 668 ReportWSAError("WSAAsync:read notify", error, addr_); 669 } else { 670 SignalReadEvent(this); 671 } 672 break; 673 674 case FD_WRITE: 675 if (error != ERROR_SUCCESS) { 676 ReportWSAError("WSAAsync:write notify", error, addr_); 677 } else { 678 SignalWriteEvent(this); 679 } 680 break; 681 682 case FD_CLOSE: 683 if (HandleClosed(error)) { 684 ReportWSAError("WSAAsync:close notify", error, addr_); 685 state_ = CS_CLOSED; 686 SignalCloseEvent(this, error); 687 } 688 break; 689 } 690 } 691 692 void Win32Socket::OnDnsNotify(HANDLE task, int error) { 693 if (!dns_ || dns_->handle != task) 694 return; 695 696 uint32 ip = 0; 697 if (error == 0) { 698 hostent* pHost = reinterpret_cast<hostent*>(dns_->buffer); 699 uint32 net_ip = *reinterpret_cast<uint32*>(pHost->h_addr_list[0]); 700 ip = NetworkToHost32(net_ip); 701 } 702 703 LOG_F(LS_INFO) << "(" << IPAddress(ip).ToSensitiveString() 704 << ", " << error << ")"; 705 706 if (error == 0) { 707 SocketAddress address(ip, dns_->port); 708 error = DoConnect(address); 709 } else { 710 Close(); 711 } 712 713 if (error) { 714 error_ = error; 715 SignalCloseEvent(this, error_); 716 } else { 717 delete dns_; 718 dns_ = NULL; 719 } 720 } 721 722 /////////////////////////////////////////////////////////////////////////////// 723 // Win32SocketServer 724 // Provides cricket base services on top of a win32 gui thread 725 /////////////////////////////////////////////////////////////////////////////// 726 727 static UINT s_wm_wakeup_id = 0; 728 const TCHAR Win32SocketServer::kWindowName[] = L"libjingle Message Window"; 729 730 Win32SocketServer::Win32SocketServer(MessageQueue* message_queue) 731 : message_queue_(message_queue), 732 wnd_(this), 733 posted_(false), 734 hdlg_(NULL) { 735 if (s_wm_wakeup_id == 0) 736 s_wm_wakeup_id = RegisterWindowMessage(L"WM_WAKEUP"); 737 if (!wnd_.Create(NULL, kWindowName, 0, 0, 0, 0, 0, 0)) { 738 LOG_GLE(LS_ERROR) << "Failed to create message window."; 739 } 740 } 741 742 Win32SocketServer::~Win32SocketServer() { 743 if (wnd_.handle() != NULL) { 744 KillTimer(wnd_.handle(), 1); 745 wnd_.Destroy(); 746 } 747 } 748 749 Socket* Win32SocketServer::CreateSocket(int type) { 750 return CreateSocket(AF_INET, type); 751 } 752 753 Socket* Win32SocketServer::CreateSocket(int family, int type) { 754 return CreateAsyncSocket(family, type); 755 } 756 757 AsyncSocket* Win32SocketServer::CreateAsyncSocket(int type) { 758 return CreateAsyncSocket(AF_INET, type); 759 } 760 761 AsyncSocket* Win32SocketServer::CreateAsyncSocket(int family, int type) { 762 Win32Socket* socket = new Win32Socket; 763 if (socket->CreateT(family, type)) { 764 return socket; 765 } 766 delete socket; 767 return NULL; 768 } 769 770 void Win32SocketServer::SetMessageQueue(MessageQueue* queue) { 771 message_queue_ = queue; 772 } 773 774 bool Win32SocketServer::Wait(int cms, bool process_io) { 775 BOOL b; 776 if (process_io) { 777 // Spin the Win32 message pump at least once, and as long as requested. 778 // This is the Thread::ProcessMessages case. 779 uint32 start = Time(); 780 do { 781 MSG msg; 782 SetTimer(wnd_.handle(), 0, cms, NULL); 783 // Get the next available message. If we have a modeless dialog, give 784 // give the message to IsDialogMessage, which will return true if it 785 // was a message for the dialog that it handled internally. 786 // Otherwise, dispatch as usual via Translate/DispatchMessage. 787 b = GetMessage(&msg, NULL, 0, 0); 788 if (b == -1) { 789 LOG_GLE(LS_ERROR) << "GetMessage failed."; 790 return false; 791 } else if(b) { 792 if (!hdlg_ || !IsDialogMessage(hdlg_, &msg)) { 793 TranslateMessage(&msg); 794 DispatchMessage(&msg); 795 } 796 } 797 KillTimer(wnd_.handle(), 0); 798 } while (b && TimeSince(start) < cms); 799 } else if (cms != 0) { 800 // Sit and wait forever for a WakeUp. This is the Thread::Send case. 801 ASSERT(cms == -1); 802 MSG msg; 803 b = GetMessage(&msg, NULL, s_wm_wakeup_id, s_wm_wakeup_id); 804 { 805 CritScope scope(&cs_); 806 posted_ = false; 807 } 808 } else { 809 // No-op (cms == 0 && !process_io). This is the Pump case. 810 b = TRUE; 811 } 812 return (b != FALSE); 813 } 814 815 void Win32SocketServer::WakeUp() { 816 if (wnd_.handle()) { 817 // Set the "message pending" flag, if not already set. 818 { 819 CritScope scope(&cs_); 820 if (posted_) 821 return; 822 posted_ = true; 823 } 824 825 PostMessage(wnd_.handle(), s_wm_wakeup_id, 0, 0); 826 } 827 } 828 829 void Win32SocketServer::Pump() { 830 // Clear the "message pending" flag. 831 { 832 CritScope scope(&cs_); 833 posted_ = false; 834 } 835 836 // Dispatch all the messages that are currently in our queue. If new messages 837 // are posted during the dispatch, they will be handled in the next Pump. 838 // We use max(1, ...) to make sure we try to dispatch at least once, since 839 // this allow us to process "sent" messages, not included in the size() count. 840 Message msg; 841 for (size_t max_messages_to_process = _max<size_t>(1, message_queue_->size()); 842 max_messages_to_process > 0 && message_queue_->Get(&msg, 0, false); 843 --max_messages_to_process) { 844 message_queue_->Dispatch(&msg); 845 } 846 847 // Anything remaining? 848 int delay = message_queue_->GetDelay(); 849 if (delay == -1) { 850 KillTimer(wnd_.handle(), 1); 851 } else { 852 SetTimer(wnd_.handle(), 1, delay, NULL); 853 } 854 } 855 856 bool Win32SocketServer::MessageWindow::OnMessage(UINT wm, WPARAM wp, 857 LPARAM lp, LRESULT& lr) { 858 bool handled = false; 859 if (wm == s_wm_wakeup_id || (wm == WM_TIMER && wp == 1)) { 860 ss_->Pump(); 861 lr = 0; 862 handled = true; 863 } 864 return handled; 865 } 866 867 } // namespace talk_base 868