OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2011 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 "net/udp/udp_socket_win.h" | |
6 | |
7 #include <mstcpip.h> | |
8 | |
9 #include "base/eintr_wrapper.h" | |
10 #include "base/logging.h" | |
11 #include "base/message_loop.h" | |
12 #include "base/memory_debug.h" | |
13 #include "base/metrics/stats_counters.h" | |
14 #include "net/base/io_buffer.h" | |
15 #include "net/base/ip_endpoint.h" | |
16 #include "net/base/net_errors.h" | |
17 #include "net/base/net_log.h" | |
18 #include "net/base/net_util.h" | |
19 #include "net/base/winsock_init.h" | |
20 | |
21 namespace net { | |
22 | |
23 namespace { | |
24 | |
25 // Assert that the (manual-reset) event object is not signaled. | |
26 void AssertEventNotSignaled(WSAEVENT hEvent) { | |
Mike Belshe
2011/03/10 06:53:38
Since this code (AssertEventNotSignaled and Resaet
Sergey Ulanov
2011/03/11 00:54:37
Moved it all to net/base/winsock_util.cc .
| |
27 DWORD wait_rv = WaitForSingleObject(hEvent, 0); | |
28 if (wait_rv != WAIT_TIMEOUT) { | |
29 DWORD err = ERROR_SUCCESS; | |
30 if (wait_rv == WAIT_FAILED) | |
31 err = GetLastError(); | |
32 CHECK(false); // Crash. | |
33 // This LOG statement is unreachable since we have already crashed, but it | |
34 // should prevent the compiler from optimizing away the |wait_rv| and | |
35 // |err| variables so they appear nicely on the stack in crash dumps. | |
36 VLOG(1) << "wait_rv=" << wait_rv << ", err=" << err; | |
37 } | |
38 } | |
39 | |
40 // If the (manual-reset) event object is signaled, resets it and returns true. | |
41 // Otherwise, does nothing and returns false. Called after a Winsock function | |
42 // succeeds synchronously | |
43 // | |
44 // Our testing shows that except in rare cases (when running inside QEMU), | |
45 // the event object is already signaled at this point, so we call this method | |
46 // to avoid a context switch in common cases. This is just a performance | |
47 // optimization. The code still works if this function simply returns false. | |
48 bool ResetEventIfSignaled(WSAEVENT hEvent) { | |
49 // TODO(wtc): Remove the CHECKs after enough testing. | |
50 DWORD wait_rv = WaitForSingleObject(hEvent, 0); | |
51 if (wait_rv == WAIT_TIMEOUT) | |
52 return false; // The event object is not signaled. | |
53 CHECK_EQ(WAIT_OBJECT_0, wait_rv); | |
54 BOOL ok = WSAResetEvent(hEvent); | |
55 CHECK(ok); | |
56 return true; | |
57 } | |
58 | |
59 //----------------------------------------------------------------------------- | |
60 | |
61 int MapWinsockError(int os_error) { | |
62 // There are numerous Winsock error codes, but these are the ones we thus far | |
63 // find interesting. | |
64 switch (os_error) { | |
65 case WSAEACCES: | |
66 return ERR_ACCESS_DENIED; | |
67 case WSAENETDOWN: | |
68 return ERR_INTERNET_DISCONNECTED; | |
69 case WSAETIMEDOUT: | |
70 return ERR_TIMED_OUT; | |
71 case WSAECONNRESET: | |
72 case WSAENETRESET: // Related to keep-alive | |
73 return ERR_CONNECTION_RESET; | |
74 case WSAECONNABORTED: | |
75 return ERR_CONNECTION_ABORTED; | |
76 case WSAECONNREFUSED: | |
77 return ERR_CONNECTION_REFUSED; | |
78 case WSA_IO_INCOMPLETE: | |
79 case WSAEDISCON: | |
80 // WSAEDISCON is returned by WSARecv or WSARecvFrom for message-oriented | |
81 // sockets (where a return value of zero means a zero-byte message) to | |
82 // indicate graceful connection shutdown. We should not ever see this | |
83 // error code for TCP sockets, which are byte stream oriented. | |
84 LOG(DFATAL) << "Unexpected error " << os_error | |
85 << " mapped to net::ERR_UNEXPECTED"; | |
86 return ERR_UNEXPECTED; | |
87 case WSAEHOSTUNREACH: | |
88 case WSAENETUNREACH: | |
89 return ERR_ADDRESS_UNREACHABLE; | |
90 case WSAEADDRNOTAVAIL: | |
91 return ERR_ADDRESS_INVALID; | |
92 case WSAENOTCONN: | |
93 return ERR_SOCKET_NOT_CONNECTED; | |
94 case ERROR_SUCCESS: | |
95 return OK; | |
96 default: | |
97 LOG(WARNING) << "Unknown error " << os_error | |
98 << " mapped to net::ERR_FAILED"; | |
99 return ERR_FAILED; | |
100 } | |
101 } | |
102 | |
103 } // namespace | |
104 | |
105 //----------------------------------------------------------------------------- | |
106 | |
107 void UDPSocketWin::ReadDelegate::OnObjectSignaled(HANDLE object) { | |
108 DCHECK_EQ(object, socket_->read_overlapped_.hEvent); | |
109 socket_->DidCompleteRead(); | |
110 } | |
111 | |
112 void UDPSocketWin::WriteDelegate::OnObjectSignaled(HANDLE object) { | |
113 DCHECK_EQ(object, socket_->write_overlapped_.hEvent); | |
114 socket_->DidCompleteWrite(); | |
115 } | |
116 | |
117 UDPSocketWin::UDPSocketWin(net::NetLog* net_log, | |
118 const net::NetLog::Source& source) | |
119 : socket_(INVALID_SOCKET), | |
120 read_buf_len_(0), | |
121 recv_from_address_(NULL), | |
122 write_buf_len_(0), | |
123 ALLOW_THIS_IN_INITIALIZER_LIST(read_delegate_(this)), | |
Mike Belshe
2011/03/10 06:53:38
nit: for argument ordering, read_delegate should f
Sergey Ulanov
2011/03/11 00:54:37
Done.
| |
124 ALLOW_THIS_IN_INITIALIZER_LIST(write_delegate_(this)), | |
125 read_callback_(NULL), | |
126 write_callback_(NULL), | |
127 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)) { | |
128 EnsureWinsockInit(); | |
129 scoped_refptr<NetLog::EventParameters> params; | |
130 if (source.is_valid()) | |
131 params = new NetLogSourceParameter("source_dependency", source); | |
132 net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE, params); | |
133 memset(&read_overlapped_, 0, sizeof(read_overlapped_)); | |
134 read_overlapped_.hEvent = WSACreateEvent(); | |
135 memset(&write_overlapped_, 0, sizeof(write_overlapped_)); | |
136 write_overlapped_.hEvent = WSACreateEvent(); | |
Mike Belshe
2011/03/10 06:53:38
should we also:
memset(&read_buffer_, 0, sizeof(
Sergey Ulanov
2011/03/11 00:54:37
I don't think it is neccessary: WSABUF has only tw
| |
137 } | |
138 | |
139 UDPSocketWin::~UDPSocketWin() { | |
140 Close(); | |
141 net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE, NULL); | |
142 } | |
143 | |
144 void UDPSocketWin::Close() { | |
145 DCHECK(CalledOnValidThread()); | |
146 | |
147 if (!is_connected()) | |
148 return; | |
149 | |
150 if (read_callback_) | |
151 DoReadCallback(ERR_ABORTED); | |
152 if (write_callback_) | |
153 DoReadCallback(ERR_ABORTED); | |
154 | |
155 read_watcher_.StopWatching(); | |
156 write_watcher_.StopWatching(); | |
157 | |
158 closesocket(socket_); | |
159 socket_ = INVALID_SOCKET; | |
160 } | |
161 | |
162 int UDPSocketWin::GetPeerAddress(IPEndPoint* address) const { | |
163 DCHECK(CalledOnValidThread()); | |
164 DCHECK(address); | |
165 if (!is_connected()) | |
166 return ERR_SOCKET_NOT_CONNECTED; | |
167 | |
168 if (!remote_address_.get()) { | |
169 struct sockaddr_storage addr_storage; | |
170 int addr_len = sizeof(addr_storage); | |
171 struct sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addr_storage); | |
172 if (getpeername(socket_, addr, &addr_len)) | |
173 return MapWinsockError(WSAGetLastError()); | |
174 scoped_ptr<IPEndPoint> address(new IPEndPoint()); | |
175 if (!address->FromSockAddr(addr, addr_len)) | |
176 return ERR_FAILED; | |
177 remote_address_.reset(address.release()); | |
178 } | |
179 | |
180 *address = *remote_address_; | |
181 return OK; | |
182 } | |
183 | |
184 int UDPSocketWin::GetLocalAddress(IPEndPoint* address) const { | |
185 DCHECK(CalledOnValidThread()); | |
186 DCHECK(address); | |
187 if (!is_connected()) | |
188 return ERR_SOCKET_NOT_CONNECTED; | |
189 | |
190 if (!local_address_.get()) { | |
191 struct sockaddr_storage addr_storage; | |
192 socklen_t addr_len = sizeof(addr_storage); | |
193 struct sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addr_storage); | |
194 if (getsockname(socket_, addr, &addr_len)) | |
195 return MapWinsockError(WSAGetLastError()); | |
196 scoped_ptr<IPEndPoint> address(new IPEndPoint()); | |
197 if (!address->FromSockAddr(addr, addr_len)) | |
198 return ERR_FAILED; | |
199 local_address_.reset(address.release()); | |
200 } | |
201 | |
202 *address = *local_address_; | |
203 return OK; | |
204 } | |
205 | |
206 int UDPSocketWin::RecvFrom(IOBuffer* buf, | |
207 int buf_len, | |
208 IPEndPoint* address, | |
209 CompletionCallback* callback) { | |
210 DCHECK(!recv_from_address_); | |
211 recv_from_address_ = address; | |
212 return Read(buf, buf_len, callback); | |
213 } | |
214 | |
215 int UDPSocketWin::Read(IOBuffer* buf, | |
216 int buf_len, | |
217 CompletionCallback* callback) { | |
218 DCHECK(CalledOnValidThread()); | |
219 DCHECK_NE(INVALID_SOCKET, socket_); | |
220 DCHECK(!read_callback_); | |
221 DCHECK(callback); // Synchronous operation not supported. | |
222 DCHECK_GT(buf_len, 0); | |
223 | |
224 read_buffer_.buf = buf->data(); | |
225 read_buffer_.len = buf_len; | |
Mike Belshe
2011/03/10 06:53:38
Note: I liked what you did in the libevent.cc cha
Sergey Ulanov
2011/03/11 00:54:37
Added the same arguments in InternalRead() here
| |
226 | |
227 int nread = InternalRead(); | |
228 if (nread != ERR_IO_PENDING) | |
229 return nread; | |
230 | |
231 read_iobuffer_ = buf; | |
232 read_callback_ = callback; | |
233 return ERR_IO_PENDING; | |
234 } | |
235 | |
236 int UDPSocketWin::SendTo(IOBuffer* buf, | |
237 int buf_len, | |
Mike Belshe
2011/03/10 06:53:38
nit spacing
Sergey Ulanov
2011/03/11 00:54:37
Done.
| |
238 const IPEndPoint& address, | |
239 CompletionCallback* callback) { | |
240 send_to_address_.reset(new IPEndPoint(address)); | |
241 return Write(buf, buf_len, callback); | |
242 } | |
243 | |
244 int UDPSocketWin::Write(IOBuffer* buf, | |
245 int buf_len, | |
246 CompletionCallback* callback) { | |
247 DCHECK(CalledOnValidThread()); | |
248 DCHECK_NE(INVALID_SOCKET, socket_); | |
249 DCHECK(!write_callback_); | |
250 DCHECK(callback); // Synchronous operation not supported. | |
251 DCHECK_GT(buf_len, 0); | |
252 | |
253 write_buffer_.buf = buf->data(); | |
254 write_buffer_.len = buf_len; | |
255 | |
256 int nwrite = InternalWrite(); | |
257 if (nwrite != ERR_IO_PENDING) | |
258 return nwrite; | |
259 | |
260 write_iobuffer_ = buf; | |
261 write_callback_ = callback; | |
262 return ERR_IO_PENDING; | |
263 } | |
264 | |
265 int UDPSocketWin::Connect(const IPEndPoint& address) { | |
266 DCHECK(!is_connected()); | |
267 DCHECK(!remote_address_.get()); | |
268 int rv = CreateSocket(address); | |
269 if (rv < 0) | |
270 return rv; | |
271 | |
272 struct sockaddr_storage addr_storage; | |
273 size_t addr_len = sizeof(addr_storage); | |
274 struct sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addr_storage); | |
275 if (!address.ToSockAddr(addr, &addr_len)) | |
276 return ERR_FAILED; | |
277 | |
278 rv = connect(socket_, addr, addr_len); | |
279 if (rv < 0) | |
280 return MapWinsockError(WSAGetLastError()); | |
281 | |
282 remote_address_.reset(new IPEndPoint(address)); | |
283 return rv; | |
284 } | |
285 | |
286 int UDPSocketWin::Bind(const IPEndPoint& address) { | |
287 DCHECK(!is_connected()); | |
288 DCHECK(!local_address_.get()); | |
289 int rv = CreateSocket(address); | |
290 if (rv < 0) | |
291 return rv; | |
292 | |
293 struct sockaddr_storage addr_storage; | |
294 size_t addr_len = sizeof(addr_storage); | |
295 struct sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addr_storage); | |
296 if (!address.ToSockAddr(addr, &addr_len)) | |
297 return ERR_FAILED; | |
298 | |
299 rv = bind(socket_, addr, addr_len); | |
300 if (rv < 0) | |
301 return MapWinsockError(WSAGetLastError()); | |
302 | |
303 local_address_.reset(new IPEndPoint(address)); | |
304 return rv; | |
305 } | |
306 | |
307 int UDPSocketWin::CreateSocket(const IPEndPoint& address) { | |
308 socket_ = socket(address.GetFamily(), SOCK_DGRAM, 0); | |
309 if (socket_ == INVALID_SOCKET) | |
310 return MapWinsockError(WSAGetLastError()); | |
311 if (SetNonBlocking(socket_)) { | |
Mike Belshe
2011/03/10 06:53:38
I don't think we want this SetNonBlocking call - i
Sergey Ulanov
2011/03/11 00:54:37
Done.
| |
312 const int err = MapWinsockError(WSAGetLastError()); | |
313 Close(); | |
314 return err; | |
315 } | |
316 return OK; | |
317 } | |
318 | |
319 void UDPSocketWin::DoReadCallback(int rv) { | |
320 DCHECK_NE(rv, ERR_IO_PENDING); | |
321 DCHECK(read_callback_); | |
322 | |
323 // since Run may result in Read being called, clear read_callback_ up front. | |
324 CompletionCallback* c = read_callback_; | |
325 read_callback_ = NULL; | |
326 recv_from_address_ = NULL; | |
327 c->Run(rv); | |
328 } | |
329 | |
330 void UDPSocketWin::DoWriteCallback(int rv) { | |
331 DCHECK_NE(rv, ERR_IO_PENDING); | |
332 DCHECK(write_callback_); | |
333 | |
334 // since Run may result in Write being called, clear write_callback_ up front. | |
335 CompletionCallback* c = write_callback_; | |
336 write_callback_ = NULL; | |
337 send_to_address_.reset(); | |
338 c->Run(rv); | |
339 } | |
340 | |
341 void UDPSocketWin::DidCompleteRead() { | |
342 DWORD num_bytes, flags; | |
343 BOOL ok = WSAGetOverlappedResult(socket_, &read_overlapped_, | |
344 &num_bytes, FALSE, &flags); | |
345 WSAResetEvent(read_overlapped_.hEvent); | |
346 int result = ok ? num_bytes : MapWinsockError(WSAGetLastError()); | |
347 if (ok) { | |
348 if (!ProcessSuccessfulRead(num_bytes)) | |
349 result = ERR_FAILED; | |
350 } | |
351 read_iobuffer_ = NULL; | |
Mike Belshe
2011/03/10 06:53:38
I think you should zero out the read_buffer_ in he
Sergey Ulanov
2011/03/11 00:54:37
Oh, I've found this in MSDN:
If this function is
| |
352 DoReadCallback(result); | |
353 } | |
354 | |
355 bool UDPSocketWin::ProcessSuccessfulRead(int num_bytes) { | |
356 static base::StatsCounter read_bytes("udp.read_bytes"); | |
357 read_bytes.Add(num_bytes); | |
358 | |
359 // Convert address. | |
360 if (recv_from_address_) { | |
361 struct sockaddr* addr = | |
362 reinterpret_cast<struct sockaddr*>(&recv_addr_storage_); | |
363 if (!recv_from_address_->FromSockAddr(addr, recv_addr_len_)) | |
364 return false; | |
365 } | |
366 | |
367 return true; | |
368 } | |
369 | |
370 void UDPSocketWin::DidCompleteWrite() { | |
371 DWORD num_bytes, flags; | |
372 BOOL ok = WSAGetOverlappedResult(socket_, &write_overlapped_, | |
373 &num_bytes, FALSE, &flags); | |
374 WSAResetEvent(write_overlapped_.hEvent); | |
375 int result = ok ? num_bytes : MapWinsockError(WSAGetLastError()); | |
376 if (ok) | |
377 ProcessSuccessfulWrite(num_bytes); | |
378 write_iobuffer_ = NULL; | |
379 DoWriteCallback(result); | |
380 } | |
381 | |
382 void UDPSocketWin::ProcessSuccessfulWrite(int num_bytes) { | |
383 static base::StatsCounter write_bytes("udp.write_bytes"); | |
384 write_bytes.Add(num_bytes); | |
385 } | |
386 | |
387 int UDPSocketWin::InternalRead() { | |
Mike Belshe
2011/03/10 06:53:38
DCHECK(read_buffer_.buf)
Sergey Ulanov
2011/03/11 00:54:37
Not needed anymore, as I removed read_buffer_
| |
388 recv_addr_len_ = sizeof(recv_addr_storage_); | |
389 struct sockaddr* addr = | |
390 reinterpret_cast<struct sockaddr*>(&recv_addr_storage_); | |
391 DWORD flags = 0; | |
392 DWORD num; | |
393 AssertEventNotSignaled(read_overlapped_.hEvent); | |
394 int rv = WSARecvFrom(socket_, &read_buffer_, 1, &num, &flags, | |
395 addr, &recv_addr_len_, &read_overlapped_, NULL); | |
396 if (rv == 0) { | |
397 if (ResetEventIfSignaled(read_overlapped_.hEvent)) { | |
398 // Because of how WSARecv fills memory when used asynchronously, Purify | |
399 // isn't able to detect that it's been initialized, so it scans for 0xcd | |
400 // in the buffer and reports UMRs (uninitialized memory reads) for those | |
401 // individual bytes. We override that in PURIFY builds to avoid the | |
402 // false error reports. | |
403 // See bug 5297. | |
404 base::MemoryDebug::MarkAsInitialized(read_buffer_.buf, num); | |
405 if (!ProcessSuccessfulRead(num)) | |
406 return ERR_FAILED; | |
407 return static_cast<int>(num); | |
408 } | |
409 } else { | |
410 int os_error = WSAGetLastError(); | |
411 if (os_error != WSA_IO_PENDING) | |
412 return MapWinsockError(os_error); | |
413 } | |
414 read_watcher_.StartWatching(read_overlapped_.hEvent, &read_delegate_); | |
415 return ERR_IO_PENDING; | |
416 } | |
417 | |
418 int UDPSocketWin::InternalWrite() { | |
Mike Belshe
2011/03/10 06:53:38
DCHECK(write_buffer_.buf);
Sergey Ulanov
2011/03/11 00:54:37
same here.
| |
419 struct sockaddr_storage addr_storage; | |
420 size_t addr_len = sizeof(addr_storage); | |
421 struct sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addr_storage); | |
422 | |
423 // Convert address. | |
424 if (!send_to_address_.get()) { | |
425 addr = NULL; | |
426 addr_len = 0; | |
427 } else { | |
428 if (!send_to_address_->ToSockAddr(addr, &addr_len)) | |
429 return ERR_FAILED; | |
430 } | |
431 | |
432 DWORD flags = 0; | |
433 DWORD num; | |
434 AssertEventNotSignaled(write_overlapped_.hEvent); | |
435 int rv = WSASendTo(socket_, &write_buffer_, 1, &num, flags, | |
436 addr, addr_len, &write_overlapped_, NULL); | |
437 if (rv == 0) { | |
438 if (ResetEventIfSignaled(write_overlapped_.hEvent)) { | |
439 ProcessSuccessfulWrite(num); | |
440 return static_cast<int>(num); | |
441 } | |
442 } else { | |
443 int os_error = WSAGetLastError(); | |
444 if (os_error != WSA_IO_PENDING) | |
445 return MapWinsockError(os_error); | |
446 } | |
447 | |
448 write_watcher_.StartWatching(write_overlapped_.hEvent, &write_delegate_); | |
449 return ERR_IO_PENDING; | |
450 } | |
451 | |
452 } // namespace net | |
OLD | NEW |