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

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

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

Powered by Google App Engine
This is Rietveld 408576698