Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(93)

Side by Side Diff: chrome/browser/sync/notifier/base/win/async_network_alive_win32.cc

Issue 1956001: Moved XMPP notifier library from chrome/browser/sync to chrome/common.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/sync/notifier/base/async_network_alive.h"
6
7 #include <winsock2.h>
8
9 #include "base/scoped_handle_win.h"
10 #include "chrome/browser/sync/notifier/base/utils.h"
11 #include "talk/base/common.h"
12 #include "talk/base/criticalsection.h"
13 #include "talk/base/logging.h"
14 #include "talk/base/physicalsocketserver.h"
15 #include "talk/base/scoped_ptr.h"
16
17 namespace notifier {
18
19 class PlatformNetworkInfo {
20 public:
21 PlatformNetworkInfo() : ws_handle_(NULL), event_handle_(NULL) {
22 }
23
24 ~PlatformNetworkInfo() {
25 Close();
26 }
27
28 void Close() {
29 talk_base::CritScope crit_scope(&crit_sect_);
30 if (ws_handle_) {
31 if (event_handle_.IsValid()) // Unblock any waiting for network changes.
32 SetEvent(event_handle_.Get());
33 // finishes the iteration.
34 VERIFY(WSALookupServiceEnd(ws_handle_) == 0);
35 ws_handle_ = NULL;
36 LOG(INFO) << "WSACleanup 1";
37 ::WSACleanup();
38 }
39 }
40
41 bool IsAlive(bool* error) {
42 ASSERT(error);
43 *error = false;
44
45 // If IsAlive was previously called, we need a new handle.
46 // Why? If we use the same handle, we only get diffs on what changed
47 // which isn't what we want.
48 Close();
49 int result = Initialize();
50 if (result != 0) {
51 LOG(ERROR) << "failed:" << result;
52 // Default to alive on error.
53 *error = true;
54 return true;
55 }
56
57 bool alive = false;
58
59 // Retrieve network info and move to next one. In this function, we only
60 // need to know whether or not there is network connection.
61 // allocate 256 bytes for name, it should be enough for most cases.
62 // If the name is longer, it is OK as we will check the code returned and
63 // set correct network status.
64 char result_buffer[sizeof(WSAQUERYSET) + 256] = {0};
65 bool flush_previous_result = false;
66 do {
67 DWORD control_flags = LUP_RETURN_NAME;
68 if (flush_previous_result) {
69 control_flags |= LUP_FLUSHPREVIOUS;
70 }
71 DWORD length = sizeof(result_buffer);
72 reinterpret_cast<WSAQUERYSET*>(&result_buffer[0])->dwSize =
73 sizeof(WSAQUERYSET);
74 // ws_handle_ may be NULL (if exiting), but the call will simply fail
75 int result = ::WSALookupServiceNext(
76 ws_handle_,
77 control_flags,
78 &length,
79 reinterpret_cast<WSAQUERYSET*>(&result_buffer[0]));
80
81 if (result == 0) {
82 // get at least one connection, return "connected".
83 alive = true;
84 } else {
85 ASSERT(result == SOCKET_ERROR);
86 result = ::WSAGetLastError();
87 if (result == WSA_E_NO_MORE || result == WSAENOMORE) {
88 break;
89 }
90
91 // Error code WSAEFAULT means there is a network connection but the
92 // result_buffer size is too small to contain the results. The
93 // variable "length" returned from WSALookupServiceNext is the minimum
94 // number of bytes required. We do not need to retrieve detail info.
95 // Return "alive" in this case.
96 if (result == WSAEFAULT) {
97 alive = true;
98 flush_previous_result = true;
99 } else {
100 LOG(WARNING) << "failed:" << result;
101 *error = true;
102 break;
103 }
104 }
105 } while (true);
106
107 LOG(INFO) << "alive: " << alive;
108 return alive;
109 }
110
111 bool WaitForChange() {
112 // IsAlive must be called first.
113 int junk1 = 0, junk2 = 0;
114 DWORD bytes_returned = 0;
115 int result = SOCKET_ERROR;
116 {
117 talk_base::CritScope crit_scope(&crit_sect_);
118 if (!ws_handle_)
119 return false;
120 ASSERT(!event_handle_.IsValid());
121 event_handle_.Set(CreateEvent(NULL, FALSE, FALSE, NULL));
122 if (!event_handle_.IsValid()) {
123 LOG(WARNING) << "failed to CreateEvent";
124 return false;
125 }
126 WSAOVERLAPPED overlapped = {0};
127 overlapped.hEvent = event_handle_.Get();
128 WSACOMPLETION completion;
129 ::SetZero(completion);
130 completion.Type = NSP_NOTIFY_EVENT;
131 completion.Parameters.Event.lpOverlapped = &overlapped;
132
133 LOG(INFO) << "calling WSANSPIoctl";
134 // Do a non-blocking request for change notification. event_handle_
135 // will get signaled when there is a change, so we wait on it later.
136 // It can also be signaled by Close() in order allow clean termination.
137 result = ::WSANSPIoctl(ws_handle_,
138 SIO_NSP_NOTIFY_CHANGE,
139 &junk1,
140 0,
141 &junk2,
142 0,
143 &bytes_returned,
144 &completion);
145 }
146 if (NO_ERROR != result) {
147 result = ::WSAGetLastError();
148 if (WSA_IO_PENDING != result) {
149 LOG(WARNING) << "failed: " << result;
150 event_handle_.Close();
151 return false;
152 }
153 }
154 LOG(INFO) << "waiting";
155 WaitForSingleObject(event_handle_.Get(), INFINITE);
156 event_handle_.Close();
157 LOG(INFO) << "changed";
158 return true;
159 }
160
161 private:
162 int Initialize() {
163 WSADATA wsa_data;
164 LOG(INFO) << "calling WSAStartup";
165 int result = ::WSAStartup(MAKEWORD(2, 2), &wsa_data);
166 if (result != ERROR_SUCCESS) {
167 LOG(ERROR) << "failed:" << result;
168 return result;
169 }
170
171 WSAQUERYSET query_set = {0};
172 query_set.dwSize = sizeof(WSAQUERYSET);
173 query_set.dwNameSpace = NS_NLA;
174 // Initiate a client query to iterate through the
175 // currently connected networks.
176 if (0 != ::WSALookupServiceBegin(&query_set, LUP_RETURN_ALL,
177 &ws_handle_)) {
178 result = ::WSAGetLastError();
179 LOG(INFO) << "WSACleanup 2";
180 ::WSACleanup();
181 ASSERT(ws_handle_ == NULL);
182 ws_handle_ = NULL;
183 return result;
184 }
185 return 0;
186 }
187 talk_base::CriticalSection crit_sect_;
188 HANDLE ws_handle_;
189 ScopedHandle event_handle_;
190 DISALLOW_COPY_AND_ASSIGN(PlatformNetworkInfo);
191 };
192
193 class AsyncNetworkAliveWin32 : public AsyncNetworkAlive {
194 public:
195 AsyncNetworkAliveWin32() {
196 }
197
198 virtual ~AsyncNetworkAliveWin32() {
199 if (network_info_) {
200 delete network_info_;
201 network_info_ = NULL;
202 }
203 }
204
205 protected:
206 // SignalThread Interface
207 virtual void DoWork() {
208 if (!network_info_) {
209 network_info_ = new PlatformNetworkInfo();
210 } else {
211 // Since network_info is set, it means that
212 // we are suppose to wait for network state changes.
213 if (!network_info_->WaitForChange()) {
214 // The wait was aborted so we must be shutting down.
215 alive_ = false;
216 error_ = true;
217 return;
218 }
219 }
220
221 if (network_info_->IsAlive(&error_)) {
222 // If there is an active connection, check that www.google.com:80
223 // is reachable.
224 talk_base::PhysicalSocketServer physical;
225 scoped_ptr<talk_base::Socket> socket(physical.CreateSocket(SOCK_STREAM));
226 if (socket->Connect(talk_base::SocketAddress("talk.google.com", 5222))) {
227 alive_ = false;
228 } else {
229 alive_ = true;
230 }
231 } else {
232 // If there are no available connections, then we aren't alive.
233 alive_ = false;
234 }
235 }
236
237 virtual void OnWorkStop() {
238 if (network_info_) {
239 network_info_->Close();
240 }
241 }
242
243 private:
244 DISALLOW_COPY_AND_ASSIGN(AsyncNetworkAliveWin32);
245 };
246
247 AsyncNetworkAlive* AsyncNetworkAlive::Create() {
248 return new AsyncNetworkAliveWin32();
249 }
250
251 } // namespace notifier
OLDNEW
« no previous file with comments | « chrome/browser/sync/notifier/base/utils.h ('k') | chrome/browser/sync/notifier/base/win/time_win32.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698