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