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

Side by Side Diff: net/udp/udp_socket_win.cc

Issue 6658027: UDP sockets implementation for windows. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: - Created 9 years, 9 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
« net/udp/udp_socket_win.h ('K') | « net/udp/udp_socket_win.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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
OLDNEW
« net/udp/udp_socket_win.h ('K') | « net/udp/udp_socket_win.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698