OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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/basictypes.h" | |
10 #include "base/callback.h" | |
11 #include "base/lazy_instance.h" | |
12 #include "base/logging.h" | |
13 #include "base/message_loop/message_loop.h" | |
14 #include "base/metrics/histogram.h" | |
15 #include "base/metrics/sparse_histogram.h" | |
16 #include "base/profiler/scoped_tracker.h" | |
17 #include "base/rand_util.h" | |
18 #include "net/base/io_buffer.h" | |
19 #include "net/base/ip_endpoint.h" | |
20 #include "net/base/net_errors.h" | |
21 #include "net/base/net_log.h" | |
22 #include "net/base/net_util.h" | |
23 #include "net/base/network_activity_monitor.h" | |
24 #include "net/base/winsock_init.h" | |
25 #include "net/base/winsock_util.h" | |
26 #include "net/socket/socket_descriptor.h" | |
27 #include "net/udp/udp_net_log_parameters.h" | |
28 | |
29 namespace { | |
30 | |
31 const int kBindRetries = 10; | |
32 const int kPortStart = 1024; | |
33 const int kPortEnd = 65535; | |
34 | |
35 } // namespace | |
36 | |
37 namespace net { | |
38 | |
39 // This class encapsulates all the state that has to be preserved as long as | |
40 // there is a network IO operation in progress. If the owner UDPSocketWin | |
41 // is destroyed while an operation is in progress, the Core is detached and it | |
42 // lives until the operation completes and the OS doesn't reference any resource | |
43 // declared on this class anymore. | |
44 class UDPSocketWin::Core : public base::RefCounted<Core> { | |
45 public: | |
46 explicit Core(UDPSocketWin* socket); | |
47 | |
48 // Start watching for the end of a read or write operation. | |
49 void WatchForRead(); | |
50 void WatchForWrite(); | |
51 | |
52 // The UDPSocketWin is going away. | |
53 void Detach() { socket_ = NULL; } | |
54 | |
55 // The separate OVERLAPPED variables for asynchronous operation. | |
56 OVERLAPPED read_overlapped_; | |
57 OVERLAPPED write_overlapped_; | |
58 | |
59 // The buffers used in Read() and Write(). | |
60 scoped_refptr<IOBuffer> read_iobuffer_; | |
61 scoped_refptr<IOBuffer> write_iobuffer_; | |
62 | |
63 // The address storage passed to WSARecvFrom(). | |
64 SockaddrStorage recv_addr_storage_; | |
65 | |
66 private: | |
67 friend class base::RefCounted<Core>; | |
68 | |
69 class ReadDelegate : public base::win::ObjectWatcher::Delegate { | |
70 public: | |
71 explicit ReadDelegate(Core* core) : core_(core) {} | |
72 virtual ~ReadDelegate() {} | |
73 | |
74 // base::ObjectWatcher::Delegate methods: | |
75 virtual void OnObjectSignaled(HANDLE object); | |
76 | |
77 private: | |
78 Core* const core_; | |
79 }; | |
80 | |
81 class WriteDelegate : public base::win::ObjectWatcher::Delegate { | |
82 public: | |
83 explicit WriteDelegate(Core* core) : core_(core) {} | |
84 virtual ~WriteDelegate() {} | |
85 | |
86 // base::ObjectWatcher::Delegate methods: | |
87 virtual void OnObjectSignaled(HANDLE object); | |
88 | |
89 private: | |
90 Core* const core_; | |
91 }; | |
92 | |
93 ~Core(); | |
94 | |
95 // The socket that created this object. | |
96 UDPSocketWin* socket_; | |
97 | |
98 // |reader_| handles the signals from |read_watcher_|. | |
99 ReadDelegate reader_; | |
100 // |writer_| handles the signals from |write_watcher_|. | |
101 WriteDelegate writer_; | |
102 | |
103 // |read_watcher_| watches for events from Read(). | |
104 base::win::ObjectWatcher read_watcher_; | |
105 // |write_watcher_| watches for events from Write(); | |
106 base::win::ObjectWatcher write_watcher_; | |
107 | |
108 DISALLOW_COPY_AND_ASSIGN(Core); | |
109 }; | |
110 | |
111 UDPSocketWin::Core::Core(UDPSocketWin* socket) | |
112 : socket_(socket), | |
113 reader_(this), | |
114 writer_(this) { | |
115 memset(&read_overlapped_, 0, sizeof(read_overlapped_)); | |
116 memset(&write_overlapped_, 0, sizeof(write_overlapped_)); | |
117 | |
118 read_overlapped_.hEvent = WSACreateEvent(); | |
119 write_overlapped_.hEvent = WSACreateEvent(); | |
120 } | |
121 | |
122 UDPSocketWin::Core::~Core() { | |
123 // Make sure the message loop is not watching this object anymore. | |
124 read_watcher_.StopWatching(); | |
125 write_watcher_.StopWatching(); | |
126 | |
127 WSACloseEvent(read_overlapped_.hEvent); | |
128 memset(&read_overlapped_, 0xaf, sizeof(read_overlapped_)); | |
129 WSACloseEvent(write_overlapped_.hEvent); | |
130 memset(&write_overlapped_, 0xaf, sizeof(write_overlapped_)); | |
131 } | |
132 | |
133 void UDPSocketWin::Core::WatchForRead() { | |
134 // We grab an extra reference because there is an IO operation in progress. | |
135 // Balanced in ReadDelegate::OnObjectSignaled(). | |
136 AddRef(); | |
137 read_watcher_.StartWatching(read_overlapped_.hEvent, &reader_); | |
138 } | |
139 | |
140 void UDPSocketWin::Core::WatchForWrite() { | |
141 // We grab an extra reference because there is an IO operation in progress. | |
142 // Balanced in WriteDelegate::OnObjectSignaled(). | |
143 AddRef(); | |
144 write_watcher_.StartWatching(write_overlapped_.hEvent, &writer_); | |
145 } | |
146 | |
147 void UDPSocketWin::Core::ReadDelegate::OnObjectSignaled(HANDLE object) { | |
148 // TODO(vadimt): Remove ScopedTracker below once crbug.com/418183 is fixed. | |
149 tracked_objects::ScopedTracker tracking_profile( | |
150 FROM_HERE_WITH_EXPLICIT_FUNCTION( | |
151 "418183 UDPSocketWin::Core::ReadDelegate::OnObjectSignaled")); | |
152 | |
153 DCHECK_EQ(object, core_->read_overlapped_.hEvent); | |
154 if (core_->socket_) | |
155 core_->socket_->DidCompleteRead(); | |
156 | |
157 core_->Release(); | |
158 } | |
159 | |
160 void UDPSocketWin::Core::WriteDelegate::OnObjectSignaled(HANDLE object) { | |
161 // TODO(vadimt): Remove ScopedTracker below once crbug.com/418183 is fixed. | |
162 tracked_objects::ScopedTracker tracking_profile( | |
163 FROM_HERE_WITH_EXPLICIT_FUNCTION( | |
164 "418183 UDPSocketWin::Core::WriteDelegate::OnObjectSignaled")); | |
165 | |
166 DCHECK_EQ(object, core_->write_overlapped_.hEvent); | |
167 if (core_->socket_) | |
168 core_->socket_->DidCompleteWrite(); | |
169 | |
170 core_->Release(); | |
171 } | |
172 //----------------------------------------------------------------------------- | |
173 | |
174 QwaveAPI::QwaveAPI() : qwave_supported_(false) { | |
175 HMODULE qwave = LoadLibrary(L"qwave.dll"); | |
176 if (!qwave) | |
177 return; | |
178 create_handle_func_ = | |
179 (CreateHandleFn)GetProcAddress(qwave, "QOSCreateHandle"); | |
180 close_handle_func_ = | |
181 (CloseHandleFn)GetProcAddress(qwave, "QOSCloseHandle"); | |
182 add_socket_to_flow_func_ = | |
183 (AddSocketToFlowFn)GetProcAddress(qwave, "QOSAddSocketToFlow"); | |
184 remove_socket_from_flow_func_ = | |
185 (RemoveSocketFromFlowFn)GetProcAddress(qwave, "QOSRemoveSocketFromFlow"); | |
186 set_flow_func_ = (SetFlowFn)GetProcAddress(qwave, "QOSSetFlow"); | |
187 | |
188 if (create_handle_func_ && close_handle_func_ && | |
189 add_socket_to_flow_func_ && remove_socket_from_flow_func_ && | |
190 set_flow_func_) { | |
191 qwave_supported_ = true; | |
192 } | |
193 } | |
194 | |
195 QwaveAPI& QwaveAPI::Get() { | |
196 static base::LazyInstance<QwaveAPI>::Leaky lazy_qwave = | |
197 LAZY_INSTANCE_INITIALIZER; | |
198 return lazy_qwave.Get(); | |
199 } | |
200 | |
201 bool QwaveAPI::qwave_supported() const { | |
202 return qwave_supported_; | |
203 } | |
204 BOOL QwaveAPI::CreateHandle(PQOS_VERSION version, PHANDLE handle) { | |
205 return create_handle_func_(version, handle); | |
206 } | |
207 BOOL QwaveAPI::CloseHandle(HANDLE handle) { | |
208 return close_handle_func_(handle); | |
209 } | |
210 | |
211 BOOL QwaveAPI::AddSocketToFlow(HANDLE handle, | |
212 SOCKET socket, | |
213 PSOCKADDR addr, | |
214 QOS_TRAFFIC_TYPE traffic_type, | |
215 DWORD flags, | |
216 PQOS_FLOWID flow_id) { | |
217 return add_socket_to_flow_func_(handle, | |
218 socket, | |
219 addr, | |
220 traffic_type, | |
221 flags, | |
222 flow_id); | |
223 } | |
224 | |
225 BOOL QwaveAPI::RemoveSocketFromFlow(HANDLE handle, | |
226 SOCKET socket, | |
227 QOS_FLOWID flow_id, | |
228 DWORD reserved) { | |
229 return remove_socket_from_flow_func_(handle, socket, flow_id, reserved); | |
230 } | |
231 | |
232 BOOL QwaveAPI::SetFlow(HANDLE handle, | |
233 QOS_FLOWID flow_id, | |
234 QOS_SET_FLOW op, | |
235 ULONG size, | |
236 PVOID data, | |
237 DWORD reserved, | |
238 LPOVERLAPPED overlapped) { | |
239 return set_flow_func_(handle, | |
240 flow_id, | |
241 op, | |
242 size, | |
243 data, | |
244 reserved, | |
245 overlapped); | |
246 } | |
247 | |
248 | |
249 //----------------------------------------------------------------------------- | |
250 | |
251 UDPSocketWin::UDPSocketWin(DatagramSocket::BindType bind_type, | |
252 const RandIntCallback& rand_int_cb, | |
253 net::NetLog* net_log, | |
254 const net::NetLog::Source& source) | |
255 : socket_(INVALID_SOCKET), | |
256 addr_family_(0), | |
257 is_connected_(false), | |
258 socket_options_(SOCKET_OPTION_MULTICAST_LOOP), | |
259 multicast_interface_(0), | |
260 multicast_time_to_live_(1), | |
261 bind_type_(bind_type), | |
262 rand_int_cb_(rand_int_cb), | |
263 use_non_blocking_io_(false), | |
264 read_iobuffer_len_(0), | |
265 write_iobuffer_len_(0), | |
266 recv_from_address_(NULL), | |
267 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_UDP_SOCKET)), | |
268 qos_handle_(NULL), | |
269 qos_flow_id_(0) { | |
270 EnsureWinsockInit(); | |
271 net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE, | |
272 source.ToEventParametersCallback()); | |
273 if (bind_type == DatagramSocket::RANDOM_BIND) | |
274 DCHECK(!rand_int_cb.is_null()); | |
275 } | |
276 | |
277 UDPSocketWin::~UDPSocketWin() { | |
278 Close(); | |
279 net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE); | |
280 } | |
281 | |
282 int UDPSocketWin::Open(AddressFamily address_family) { | |
283 DCHECK(CalledOnValidThread()); | |
284 DCHECK_EQ(socket_, INVALID_SOCKET); | |
285 | |
286 addr_family_ = ConvertAddressFamily(address_family); | |
287 socket_ = CreatePlatformSocket(addr_family_, SOCK_DGRAM, IPPROTO_UDP); | |
288 if (socket_ == INVALID_SOCKET) | |
289 return MapSystemError(WSAGetLastError()); | |
290 if (!use_non_blocking_io_) { | |
291 core_ = new Core(this); | |
292 } else { | |
293 read_write_event_.Set(WSACreateEvent()); | |
294 WSAEventSelect(socket_, read_write_event_.Get(), FD_READ | FD_WRITE); | |
295 } | |
296 return OK; | |
297 } | |
298 | |
299 void UDPSocketWin::Close() { | |
300 DCHECK(CalledOnValidThread()); | |
301 | |
302 if (socket_ == INVALID_SOCKET) | |
303 return; | |
304 | |
305 if (qos_handle_) { | |
306 QwaveAPI::Get().CloseHandle(qos_handle_); | |
307 } | |
308 | |
309 // Zero out any pending read/write callback state. | |
310 read_callback_.Reset(); | |
311 recv_from_address_ = NULL; | |
312 write_callback_.Reset(); | |
313 | |
314 base::TimeTicks start_time = base::TimeTicks::Now(); | |
315 closesocket(socket_); | |
316 UMA_HISTOGRAM_TIMES("Net.UDPSocketWinClose", | |
317 base::TimeTicks::Now() - start_time); | |
318 socket_ = INVALID_SOCKET; | |
319 addr_family_ = 0; | |
320 is_connected_ = false; | |
321 | |
322 read_write_watcher_.StopWatching(); | |
323 read_write_event_.Close(); | |
324 | |
325 if (core_) { | |
326 core_->Detach(); | |
327 core_ = NULL; | |
328 } | |
329 } | |
330 | |
331 int UDPSocketWin::GetPeerAddress(IPEndPoint* address) const { | |
332 DCHECK(CalledOnValidThread()); | |
333 DCHECK(address); | |
334 if (!is_connected()) | |
335 return ERR_SOCKET_NOT_CONNECTED; | |
336 | |
337 // TODO(szym): Simplify. http://crbug.com/126152 | |
338 if (!remote_address_.get()) { | |
339 SockaddrStorage storage; | |
340 if (getpeername(socket_, storage.addr, &storage.addr_len)) | |
341 return MapSystemError(WSAGetLastError()); | |
342 scoped_ptr<IPEndPoint> remote_address(new IPEndPoint()); | |
343 if (!remote_address->FromSockAddr(storage.addr, storage.addr_len)) | |
344 return ERR_ADDRESS_INVALID; | |
345 remote_address_.reset(remote_address.release()); | |
346 } | |
347 | |
348 *address = *remote_address_; | |
349 return OK; | |
350 } | |
351 | |
352 int UDPSocketWin::GetLocalAddress(IPEndPoint* address) const { | |
353 DCHECK(CalledOnValidThread()); | |
354 DCHECK(address); | |
355 if (!is_connected()) | |
356 return ERR_SOCKET_NOT_CONNECTED; | |
357 | |
358 // TODO(szym): Simplify. http://crbug.com/126152 | |
359 if (!local_address_.get()) { | |
360 SockaddrStorage storage; | |
361 if (getsockname(socket_, storage.addr, &storage.addr_len)) | |
362 return MapSystemError(WSAGetLastError()); | |
363 scoped_ptr<IPEndPoint> local_address(new IPEndPoint()); | |
364 if (!local_address->FromSockAddr(storage.addr, storage.addr_len)) | |
365 return ERR_ADDRESS_INVALID; | |
366 local_address_.reset(local_address.release()); | |
367 net_log_.AddEvent(NetLog::TYPE_UDP_LOCAL_ADDRESS, | |
368 CreateNetLogUDPConnectCallback(local_address_.get())); | |
369 } | |
370 | |
371 *address = *local_address_; | |
372 return OK; | |
373 } | |
374 | |
375 int UDPSocketWin::Read(IOBuffer* buf, | |
376 int buf_len, | |
377 const CompletionCallback& callback) { | |
378 return RecvFrom(buf, buf_len, NULL, callback); | |
379 } | |
380 | |
381 int UDPSocketWin::RecvFrom(IOBuffer* buf, | |
382 int buf_len, | |
383 IPEndPoint* address, | |
384 const CompletionCallback& callback) { | |
385 DCHECK(CalledOnValidThread()); | |
386 DCHECK_NE(INVALID_SOCKET, socket_); | |
387 CHECK(read_callback_.is_null()); | |
388 DCHECK(!recv_from_address_); | |
389 DCHECK(!callback.is_null()); // Synchronous operation not supported. | |
390 DCHECK_GT(buf_len, 0); | |
391 | |
392 int nread = core_ ? InternalRecvFromOverlapped(buf, buf_len, address) | |
393 : InternalRecvFromNonBlocking(buf, buf_len, address); | |
394 if (nread != ERR_IO_PENDING) | |
395 return nread; | |
396 | |
397 read_callback_ = callback; | |
398 recv_from_address_ = address; | |
399 return ERR_IO_PENDING; | |
400 } | |
401 | |
402 int UDPSocketWin::Write(IOBuffer* buf, | |
403 int buf_len, | |
404 const CompletionCallback& callback) { | |
405 return SendToOrWrite(buf, buf_len, NULL, callback); | |
406 } | |
407 | |
408 int UDPSocketWin::SendTo(IOBuffer* buf, | |
409 int buf_len, | |
410 const IPEndPoint& address, | |
411 const CompletionCallback& callback) { | |
412 return SendToOrWrite(buf, buf_len, &address, callback); | |
413 } | |
414 | |
415 int UDPSocketWin::SendToOrWrite(IOBuffer* buf, | |
416 int buf_len, | |
417 const IPEndPoint* address, | |
418 const CompletionCallback& callback) { | |
419 DCHECK(CalledOnValidThread()); | |
420 DCHECK_NE(INVALID_SOCKET, socket_); | |
421 CHECK(write_callback_.is_null()); | |
422 DCHECK(!callback.is_null()); // Synchronous operation not supported. | |
423 DCHECK_GT(buf_len, 0); | |
424 DCHECK(!send_to_address_.get()); | |
425 | |
426 int nwrite = core_ ? InternalSendToOverlapped(buf, buf_len, address) | |
427 : InternalSendToNonBlocking(buf, buf_len, address); | |
428 if (nwrite != ERR_IO_PENDING) | |
429 return nwrite; | |
430 | |
431 if (address) | |
432 send_to_address_.reset(new IPEndPoint(*address)); | |
433 write_callback_ = callback; | |
434 return ERR_IO_PENDING; | |
435 } | |
436 | |
437 int UDPSocketWin::Connect(const IPEndPoint& address) { | |
438 DCHECK_NE(socket_, INVALID_SOCKET); | |
439 net_log_.BeginEvent(NetLog::TYPE_UDP_CONNECT, | |
440 CreateNetLogUDPConnectCallback(&address)); | |
441 int rv = InternalConnect(address); | |
442 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_UDP_CONNECT, rv); | |
443 is_connected_ = (rv == OK); | |
444 return rv; | |
445 } | |
446 | |
447 int UDPSocketWin::InternalConnect(const IPEndPoint& address) { | |
448 DCHECK(!is_connected()); | |
449 DCHECK(!remote_address_.get()); | |
450 | |
451 int rv = 0; | |
452 if (bind_type_ == DatagramSocket::RANDOM_BIND) { | |
453 // Construct IPAddressNumber of appropriate size (IPv4 or IPv6) of 0s, | |
454 // representing INADDR_ANY or in6addr_any. | |
455 size_t addr_size = (address.GetSockAddrFamily() == AF_INET) ? | |
456 kIPv4AddressSize : kIPv6AddressSize; | |
457 IPAddressNumber addr_any(addr_size); | |
458 rv = RandomBind(addr_any); | |
459 } | |
460 // else connect() does the DatagramSocket::DEFAULT_BIND | |
461 | |
462 if (rv < 0) { | |
463 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.UdpSocketRandomBindErrorCode", -rv); | |
464 return rv; | |
465 } | |
466 | |
467 SockaddrStorage storage; | |
468 if (!address.ToSockAddr(storage.addr, &storage.addr_len)) | |
469 return ERR_ADDRESS_INVALID; | |
470 | |
471 rv = connect(socket_, storage.addr, storage.addr_len); | |
472 if (rv < 0) | |
473 return MapSystemError(WSAGetLastError()); | |
474 | |
475 remote_address_.reset(new IPEndPoint(address)); | |
476 return rv; | |
477 } | |
478 | |
479 int UDPSocketWin::Bind(const IPEndPoint& address) { | |
480 DCHECK_NE(socket_, INVALID_SOCKET); | |
481 DCHECK(!is_connected()); | |
482 | |
483 int rv = SetMulticastOptions(); | |
484 if (rv < 0) | |
485 return rv; | |
486 | |
487 rv = DoBind(address); | |
488 if (rv < 0) | |
489 return rv; | |
490 | |
491 local_address_.reset(); | |
492 is_connected_ = true; | |
493 return rv; | |
494 } | |
495 | |
496 int UDPSocketWin::SetReceiveBufferSize(int32 size) { | |
497 DCHECK_NE(socket_, INVALID_SOCKET); | |
498 DCHECK(CalledOnValidThread()); | |
499 int rv = setsockopt(socket_, SOL_SOCKET, SO_RCVBUF, | |
500 reinterpret_cast<const char*>(&size), sizeof(size)); | |
501 if (rv != 0) | |
502 return MapSystemError(WSAGetLastError()); | |
503 | |
504 // According to documentation, setsockopt may succeed, but we need to check | |
505 // the results via getsockopt to be sure it works on Windows. | |
506 int32 actual_size = 0; | |
507 int option_size = sizeof(actual_size); | |
508 rv = getsockopt(socket_, SOL_SOCKET, SO_RCVBUF, | |
509 reinterpret_cast<char*>(&actual_size), &option_size); | |
510 if (rv != 0) | |
511 return MapSystemError(WSAGetLastError()); | |
512 if (actual_size >= size) | |
513 return OK; | |
514 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SocketUnchangeableReceiveBuffer", | |
515 actual_size, 1000, 1000000, 50); | |
516 return ERR_SOCKET_RECEIVE_BUFFER_SIZE_UNCHANGEABLE; | |
517 } | |
518 | |
519 int UDPSocketWin::SetSendBufferSize(int32 size) { | |
520 DCHECK_NE(socket_, INVALID_SOCKET); | |
521 DCHECK(CalledOnValidThread()); | |
522 int rv = setsockopt(socket_, SOL_SOCKET, SO_SNDBUF, | |
523 reinterpret_cast<const char*>(&size), sizeof(size)); | |
524 if (rv != 0) | |
525 return MapSystemError(WSAGetLastError()); | |
526 // According to documentation, setsockopt may succeed, but we need to check | |
527 // the results via getsockopt to be sure it works on Windows. | |
528 int32 actual_size = 0; | |
529 int option_size = sizeof(actual_size); | |
530 rv = getsockopt(socket_, SOL_SOCKET, SO_SNDBUF, | |
531 reinterpret_cast<char*>(&actual_size), &option_size); | |
532 if (rv != 0) | |
533 return MapSystemError(WSAGetLastError()); | |
534 if (actual_size >= size) | |
535 return OK; | |
536 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SocketUnchangeableSendBuffer", | |
537 actual_size, 1000, 1000000, 50); | |
538 return ERR_SOCKET_SEND_BUFFER_SIZE_UNCHANGEABLE; | |
539 } | |
540 | |
541 int UDPSocketWin::AllowAddressReuse() { | |
542 DCHECK_NE(socket_, INVALID_SOCKET); | |
543 DCHECK(CalledOnValidThread()); | |
544 DCHECK(!is_connected()); | |
545 | |
546 BOOL true_value = TRUE; | |
547 int rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, | |
548 reinterpret_cast<const char*>(&true_value), | |
549 sizeof(true_value)); | |
550 return rv == 0 ? OK : MapSystemError(WSAGetLastError()); | |
551 } | |
552 | |
553 int UDPSocketWin::SetBroadcast(bool broadcast) { | |
554 DCHECK_NE(socket_, INVALID_SOCKET); | |
555 DCHECK(CalledOnValidThread()); | |
556 | |
557 BOOL value = broadcast ? TRUE : FALSE; | |
558 int rv = setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, | |
559 reinterpret_cast<const char*>(&value), sizeof(value)); | |
560 return rv == 0 ? OK : MapSystemError(WSAGetLastError()); | |
561 } | |
562 | |
563 void UDPSocketWin::DoReadCallback(int rv) { | |
564 DCHECK_NE(rv, ERR_IO_PENDING); | |
565 DCHECK(!read_callback_.is_null()); | |
566 | |
567 // since Run may result in Read being called, clear read_callback_ up front. | |
568 CompletionCallback c = read_callback_; | |
569 read_callback_.Reset(); | |
570 c.Run(rv); | |
571 } | |
572 | |
573 void UDPSocketWin::DoWriteCallback(int rv) { | |
574 DCHECK_NE(rv, ERR_IO_PENDING); | |
575 DCHECK(!write_callback_.is_null()); | |
576 | |
577 // since Run may result in Write being called, clear write_callback_ up front. | |
578 CompletionCallback c = write_callback_; | |
579 write_callback_.Reset(); | |
580 c.Run(rv); | |
581 } | |
582 | |
583 void UDPSocketWin::DidCompleteRead() { | |
584 DWORD num_bytes, flags; | |
585 BOOL ok = WSAGetOverlappedResult(socket_, &core_->read_overlapped_, | |
586 &num_bytes, FALSE, &flags); | |
587 WSAResetEvent(core_->read_overlapped_.hEvent); | |
588 int result = ok ? num_bytes : MapSystemError(WSAGetLastError()); | |
589 // Convert address. | |
590 IPEndPoint address; | |
591 IPEndPoint* address_to_log = NULL; | |
592 if (result >= 0) { | |
593 if (address.FromSockAddr(core_->recv_addr_storage_.addr, | |
594 core_->recv_addr_storage_.addr_len)) { | |
595 if (recv_from_address_) | |
596 *recv_from_address_ = address; | |
597 address_to_log = &address; | |
598 } else { | |
599 result = ERR_ADDRESS_INVALID; | |
600 } | |
601 } | |
602 LogRead(result, core_->read_iobuffer_->data(), address_to_log); | |
603 core_->read_iobuffer_ = NULL; | |
604 recv_from_address_ = NULL; | |
605 DoReadCallback(result); | |
606 } | |
607 | |
608 void UDPSocketWin::DidCompleteWrite() { | |
609 DWORD num_bytes, flags; | |
610 BOOL ok = WSAGetOverlappedResult(socket_, &core_->write_overlapped_, | |
611 &num_bytes, FALSE, &flags); | |
612 WSAResetEvent(core_->write_overlapped_.hEvent); | |
613 int result = ok ? num_bytes : MapSystemError(WSAGetLastError()); | |
614 LogWrite(result, core_->write_iobuffer_->data(), send_to_address_.get()); | |
615 | |
616 send_to_address_.reset(); | |
617 core_->write_iobuffer_ = NULL; | |
618 DoWriteCallback(result); | |
619 } | |
620 | |
621 void UDPSocketWin::OnObjectSignaled(HANDLE object) { | |
622 DCHECK(object == read_write_event_.Get()); | |
623 WSANETWORKEVENTS network_events; | |
624 int os_error = 0; | |
625 int rv = | |
626 WSAEnumNetworkEvents(socket_, read_write_event_.Get(), &network_events); | |
627 if (rv == SOCKET_ERROR) { | |
628 os_error = WSAGetLastError(); | |
629 rv = MapSystemError(os_error); | |
630 if (read_iobuffer_) { | |
631 read_iobuffer_ = NULL; | |
632 read_iobuffer_len_ = 0; | |
633 recv_from_address_ = NULL; | |
634 DoReadCallback(rv); | |
635 } | |
636 if (write_iobuffer_) { | |
637 write_iobuffer_ = NULL; | |
638 write_iobuffer_len_ = 0; | |
639 send_to_address_.reset(); | |
640 DoWriteCallback(rv); | |
641 } | |
642 return; | |
643 } | |
644 if ((network_events.lNetworkEvents & FD_READ) && read_iobuffer_) { | |
645 OnReadSignaled(); | |
646 } | |
647 if ((network_events.lNetworkEvents & FD_WRITE) && write_iobuffer_) { | |
648 OnWriteSignaled(); | |
649 } | |
650 | |
651 // There's still pending read / write. Watch for further events. | |
652 if (read_iobuffer_ || write_iobuffer_) { | |
653 WatchForReadWrite(); | |
654 } | |
655 } | |
656 | |
657 void UDPSocketWin::OnReadSignaled() { | |
658 int rv = InternalRecvFromNonBlocking(read_iobuffer_.get(), read_iobuffer_len_, | |
659 recv_from_address_); | |
660 if (rv == ERR_IO_PENDING) | |
661 return; | |
662 read_iobuffer_ = NULL; | |
663 read_iobuffer_len_ = 0; | |
664 recv_from_address_ = NULL; | |
665 DoReadCallback(rv); | |
666 } | |
667 | |
668 void UDPSocketWin::OnWriteSignaled() { | |
669 int rv = InternalSendToNonBlocking(write_iobuffer_.get(), write_iobuffer_len_, | |
670 send_to_address_.get()); | |
671 if (rv == ERR_IO_PENDING) | |
672 return; | |
673 write_iobuffer_ = NULL; | |
674 write_iobuffer_len_ = 0; | |
675 send_to_address_.reset(); | |
676 DoWriteCallback(rv); | |
677 } | |
678 | |
679 void UDPSocketWin::WatchForReadWrite() { | |
680 if (read_write_watcher_.IsWatching()) | |
681 return; | |
682 bool watched = | |
683 read_write_watcher_.StartWatching(read_write_event_.Get(), this); | |
684 DCHECK(watched); | |
685 } | |
686 | |
687 void UDPSocketWin::LogRead(int result, | |
688 const char* bytes, | |
689 const IPEndPoint* address) const { | |
690 if (result < 0) { | |
691 net_log_.AddEventWithNetErrorCode(NetLog::TYPE_UDP_RECEIVE_ERROR, result); | |
692 return; | |
693 } | |
694 | |
695 if (net_log_.IsLogging()) { | |
696 net_log_.AddEvent( | |
697 NetLog::TYPE_UDP_BYTES_RECEIVED, | |
698 CreateNetLogUDPDataTranferCallback(result, bytes, address)); | |
699 } | |
700 | |
701 NetworkActivityMonitor::GetInstance()->IncrementBytesReceived(result); | |
702 } | |
703 | |
704 void UDPSocketWin::LogWrite(int result, | |
705 const char* bytes, | |
706 const IPEndPoint* address) const { | |
707 if (result < 0) { | |
708 net_log_.AddEventWithNetErrorCode(NetLog::TYPE_UDP_SEND_ERROR, result); | |
709 return; | |
710 } | |
711 | |
712 if (net_log_.IsLogging()) { | |
713 net_log_.AddEvent( | |
714 NetLog::TYPE_UDP_BYTES_SENT, | |
715 CreateNetLogUDPDataTranferCallback(result, bytes, address)); | |
716 } | |
717 | |
718 NetworkActivityMonitor::GetInstance()->IncrementBytesSent(result); | |
719 } | |
720 | |
721 int UDPSocketWin::InternalRecvFromOverlapped(IOBuffer* buf, | |
722 int buf_len, | |
723 IPEndPoint* address) { | |
724 DCHECK(!core_->read_iobuffer_.get()); | |
725 SockaddrStorage& storage = core_->recv_addr_storage_; | |
726 storage.addr_len = sizeof(storage.addr_storage); | |
727 | |
728 WSABUF read_buffer; | |
729 read_buffer.buf = buf->data(); | |
730 read_buffer.len = buf_len; | |
731 | |
732 DWORD flags = 0; | |
733 DWORD num; | |
734 CHECK_NE(INVALID_SOCKET, socket_); | |
735 AssertEventNotSignaled(core_->read_overlapped_.hEvent); | |
736 int rv = WSARecvFrom(socket_, &read_buffer, 1, &num, &flags, storage.addr, | |
737 &storage.addr_len, &core_->read_overlapped_, NULL); | |
738 if (rv == 0) { | |
739 if (ResetEventIfSignaled(core_->read_overlapped_.hEvent)) { | |
740 int result = num; | |
741 // Convert address. | |
742 IPEndPoint address_storage; | |
743 IPEndPoint* address_to_log = NULL; | |
744 if (result >= 0) { | |
745 if (address_storage.FromSockAddr(core_->recv_addr_storage_.addr, | |
746 core_->recv_addr_storage_.addr_len)) { | |
747 if (address) | |
748 *address = address_storage; | |
749 address_to_log = &address_storage; | |
750 } else { | |
751 result = ERR_ADDRESS_INVALID; | |
752 } | |
753 } | |
754 LogRead(result, buf->data(), address_to_log); | |
755 return result; | |
756 } | |
757 } else { | |
758 int os_error = WSAGetLastError(); | |
759 if (os_error != WSA_IO_PENDING) { | |
760 int result = MapSystemError(os_error); | |
761 LogRead(result, NULL, NULL); | |
762 return result; | |
763 } | |
764 } | |
765 core_->WatchForRead(); | |
766 core_->read_iobuffer_ = buf; | |
767 return ERR_IO_PENDING; | |
768 } | |
769 | |
770 int UDPSocketWin::InternalSendToOverlapped(IOBuffer* buf, | |
771 int buf_len, | |
772 const IPEndPoint* address) { | |
773 DCHECK(!core_->write_iobuffer_.get()); | |
774 SockaddrStorage storage; | |
775 struct sockaddr* addr = storage.addr; | |
776 // Convert address. | |
777 if (!address) { | |
778 addr = NULL; | |
779 storage.addr_len = 0; | |
780 } else { | |
781 if (!address->ToSockAddr(addr, &storage.addr_len)) { | |
782 int result = ERR_ADDRESS_INVALID; | |
783 LogWrite(result, NULL, NULL); | |
784 return result; | |
785 } | |
786 } | |
787 | |
788 WSABUF write_buffer; | |
789 write_buffer.buf = buf->data(); | |
790 write_buffer.len = buf_len; | |
791 | |
792 DWORD flags = 0; | |
793 DWORD num; | |
794 AssertEventNotSignaled(core_->write_overlapped_.hEvent); | |
795 int rv = WSASendTo(socket_, &write_buffer, 1, &num, flags, | |
796 addr, storage.addr_len, &core_->write_overlapped_, NULL); | |
797 if (rv == 0) { | |
798 if (ResetEventIfSignaled(core_->write_overlapped_.hEvent)) { | |
799 int result = num; | |
800 LogWrite(result, buf->data(), address); | |
801 return result; | |
802 } | |
803 } else { | |
804 int os_error = WSAGetLastError(); | |
805 if (os_error != WSA_IO_PENDING) { | |
806 int result = MapSystemError(os_error); | |
807 LogWrite(result, NULL, NULL); | |
808 return result; | |
809 } | |
810 } | |
811 | |
812 core_->WatchForWrite(); | |
813 core_->write_iobuffer_ = buf; | |
814 return ERR_IO_PENDING; | |
815 } | |
816 | |
817 int UDPSocketWin::InternalRecvFromNonBlocking(IOBuffer* buf, | |
818 int buf_len, | |
819 IPEndPoint* address) { | |
820 DCHECK(!read_iobuffer_ || read_iobuffer_.get() == buf); | |
821 SockaddrStorage storage; | |
822 storage.addr_len = sizeof(storage.addr_storage); | |
823 | |
824 CHECK_NE(INVALID_SOCKET, socket_); | |
825 int rv = recvfrom(socket_, buf->data(), buf_len, 0, storage.addr, | |
826 &storage.addr_len); | |
827 if (rv == SOCKET_ERROR) { | |
828 int os_error = WSAGetLastError(); | |
829 if (os_error == WSAEWOULDBLOCK) { | |
830 read_iobuffer_ = buf; | |
831 read_iobuffer_len_ = buf_len; | |
832 WatchForReadWrite(); | |
833 return ERR_IO_PENDING; | |
834 } | |
835 rv = MapSystemError(os_error); | |
836 LogRead(rv, NULL, NULL); | |
837 return rv; | |
838 } | |
839 IPEndPoint address_storage; | |
840 IPEndPoint* address_to_log = NULL; | |
841 if (rv >= 0) { | |
842 if (address_storage.FromSockAddr(storage.addr, storage.addr_len)) { | |
843 if (address) | |
844 *address = address_storage; | |
845 address_to_log = &address_storage; | |
846 } else { | |
847 rv = ERR_ADDRESS_INVALID; | |
848 } | |
849 } | |
850 LogRead(rv, buf->data(), address_to_log); | |
851 return rv; | |
852 } | |
853 | |
854 int UDPSocketWin::InternalSendToNonBlocking(IOBuffer* buf, | |
855 int buf_len, | |
856 const IPEndPoint* address) { | |
857 DCHECK(!write_iobuffer_ || write_iobuffer_.get() == buf); | |
858 SockaddrStorage storage; | |
859 struct sockaddr* addr = storage.addr; | |
860 // Convert address. | |
861 if (address) { | |
862 if (!address->ToSockAddr(addr, &storage.addr_len)) { | |
863 int result = ERR_ADDRESS_INVALID; | |
864 LogWrite(result, NULL, NULL); | |
865 return result; | |
866 } | |
867 } else { | |
868 addr = NULL; | |
869 storage.addr_len = 0; | |
870 } | |
871 | |
872 int rv = sendto(socket_, buf->data(), buf_len, 0, addr, storage.addr_len); | |
873 if (rv == SOCKET_ERROR) { | |
874 int os_error = WSAGetLastError(); | |
875 if (os_error == WSAEWOULDBLOCK) { | |
876 write_iobuffer_ = buf; | |
877 write_iobuffer_len_ = buf_len; | |
878 WatchForReadWrite(); | |
879 return ERR_IO_PENDING; | |
880 } | |
881 rv = MapSystemError(os_error); | |
882 LogWrite(rv, NULL, NULL); | |
883 return rv; | |
884 } | |
885 LogWrite(rv, buf->data(), address); | |
886 return rv; | |
887 } | |
888 | |
889 int UDPSocketWin::SetMulticastOptions() { | |
890 if (!(socket_options_ & SOCKET_OPTION_MULTICAST_LOOP)) { | |
891 DWORD loop = 0; | |
892 int protocol_level = | |
893 addr_family_ == AF_INET ? IPPROTO_IP : IPPROTO_IPV6; | |
894 int option = | |
895 addr_family_ == AF_INET ? IP_MULTICAST_LOOP: IPV6_MULTICAST_LOOP; | |
896 int rv = setsockopt(socket_, protocol_level, option, | |
897 reinterpret_cast<const char*>(&loop), sizeof(loop)); | |
898 if (rv < 0) | |
899 return MapSystemError(WSAGetLastError()); | |
900 } | |
901 if (multicast_time_to_live_ != 1) { | |
902 DWORD hops = multicast_time_to_live_; | |
903 int protocol_level = | |
904 addr_family_ == AF_INET ? IPPROTO_IP : IPPROTO_IPV6; | |
905 int option = | |
906 addr_family_ == AF_INET ? IP_MULTICAST_TTL: IPV6_MULTICAST_HOPS; | |
907 int rv = setsockopt(socket_, protocol_level, option, | |
908 reinterpret_cast<const char*>(&hops), sizeof(hops)); | |
909 if (rv < 0) | |
910 return MapSystemError(WSAGetLastError()); | |
911 } | |
912 if (multicast_interface_ != 0) { | |
913 switch (addr_family_) { | |
914 case AF_INET: { | |
915 in_addr address; | |
916 address.s_addr = htonl(multicast_interface_); | |
917 int rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_IF, | |
918 reinterpret_cast<const char*>(&address), | |
919 sizeof(address)); | |
920 if (rv) | |
921 return MapSystemError(WSAGetLastError()); | |
922 break; | |
923 } | |
924 case AF_INET6: { | |
925 uint32 interface_index = multicast_interface_; | |
926 int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_IF, | |
927 reinterpret_cast<const char*>(&interface_index), | |
928 sizeof(interface_index)); | |
929 if (rv) | |
930 return MapSystemError(WSAGetLastError()); | |
931 break; | |
932 } | |
933 default: | |
934 NOTREACHED() << "Invalid address family"; | |
935 return ERR_ADDRESS_INVALID; | |
936 } | |
937 } | |
938 return OK; | |
939 } | |
940 | |
941 int UDPSocketWin::DoBind(const IPEndPoint& address) { | |
942 SockaddrStorage storage; | |
943 if (!address.ToSockAddr(storage.addr, &storage.addr_len)) | |
944 return ERR_ADDRESS_INVALID; | |
945 int rv = bind(socket_, storage.addr, storage.addr_len); | |
946 if (rv == 0) | |
947 return OK; | |
948 int last_error = WSAGetLastError(); | |
949 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.UdpSocketBindErrorFromWinOS", last_error); | |
950 // Map some codes that are special to bind() separately. | |
951 // * WSAEACCES: If a port is already bound to a socket, WSAEACCES may be | |
952 // returned instead of WSAEADDRINUSE, depending on whether the socket | |
953 // option SO_REUSEADDR or SO_EXCLUSIVEADDRUSE is set and whether the | |
954 // conflicting socket is owned by a different user account. See the MSDN | |
955 // page "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE" for the gory details. | |
956 if (last_error == WSAEACCES || last_error == WSAEADDRNOTAVAIL) | |
957 return ERR_ADDRESS_IN_USE; | |
958 return MapSystemError(last_error); | |
959 } | |
960 | |
961 int UDPSocketWin::RandomBind(const IPAddressNumber& address) { | |
962 DCHECK(bind_type_ == DatagramSocket::RANDOM_BIND && !rand_int_cb_.is_null()); | |
963 | |
964 for (int i = 0; i < kBindRetries; ++i) { | |
965 int rv = DoBind(IPEndPoint( | |
966 address, static_cast<uint16>(rand_int_cb_.Run(kPortStart, kPortEnd)))); | |
967 if (rv == OK || rv != ERR_ADDRESS_IN_USE) | |
968 return rv; | |
969 } | |
970 return DoBind(IPEndPoint(address, 0)); | |
971 } | |
972 | |
973 int UDPSocketWin::JoinGroup( | |
974 const IPAddressNumber& group_address) const { | |
975 DCHECK(CalledOnValidThread()); | |
976 if (!is_connected()) | |
977 return ERR_SOCKET_NOT_CONNECTED; | |
978 | |
979 switch (group_address.size()) { | |
980 case kIPv4AddressSize: { | |
981 if (addr_family_ != AF_INET) | |
982 return ERR_ADDRESS_INVALID; | |
983 ip_mreq mreq; | |
984 mreq.imr_interface.s_addr = htonl(multicast_interface_); | |
985 memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize); | |
986 int rv = setsockopt(socket_, IPPROTO_IP, IP_ADD_MEMBERSHIP, | |
987 reinterpret_cast<const char*>(&mreq), | |
988 sizeof(mreq)); | |
989 if (rv) | |
990 return MapSystemError(WSAGetLastError()); | |
991 return OK; | |
992 } | |
993 case kIPv6AddressSize: { | |
994 if (addr_family_ != AF_INET6) | |
995 return ERR_ADDRESS_INVALID; | |
996 ipv6_mreq mreq; | |
997 mreq.ipv6mr_interface = multicast_interface_; | |
998 memcpy(&mreq.ipv6mr_multiaddr, &group_address[0], kIPv6AddressSize); | |
999 int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, | |
1000 reinterpret_cast<const char*>(&mreq), | |
1001 sizeof(mreq)); | |
1002 if (rv) | |
1003 return MapSystemError(WSAGetLastError()); | |
1004 return OK; | |
1005 } | |
1006 default: | |
1007 NOTREACHED() << "Invalid address family"; | |
1008 return ERR_ADDRESS_INVALID; | |
1009 } | |
1010 } | |
1011 | |
1012 int UDPSocketWin::LeaveGroup( | |
1013 const IPAddressNumber& group_address) const { | |
1014 DCHECK(CalledOnValidThread()); | |
1015 if (!is_connected()) | |
1016 return ERR_SOCKET_NOT_CONNECTED; | |
1017 | |
1018 switch (group_address.size()) { | |
1019 case kIPv4AddressSize: { | |
1020 if (addr_family_ != AF_INET) | |
1021 return ERR_ADDRESS_INVALID; | |
1022 ip_mreq mreq; | |
1023 mreq.imr_interface.s_addr = htonl(multicast_interface_); | |
1024 memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize); | |
1025 int rv = setsockopt(socket_, IPPROTO_IP, IP_DROP_MEMBERSHIP, | |
1026 reinterpret_cast<const char*>(&mreq), sizeof(mreq)); | |
1027 if (rv) | |
1028 return MapSystemError(WSAGetLastError()); | |
1029 return OK; | |
1030 } | |
1031 case kIPv6AddressSize: { | |
1032 if (addr_family_ != AF_INET6) | |
1033 return ERR_ADDRESS_INVALID; | |
1034 ipv6_mreq mreq; | |
1035 mreq.ipv6mr_interface = multicast_interface_; | |
1036 memcpy(&mreq.ipv6mr_multiaddr, &group_address[0], kIPv6AddressSize); | |
1037 int rv = setsockopt(socket_, IPPROTO_IPV6, IP_DROP_MEMBERSHIP, | |
1038 reinterpret_cast<const char*>(&mreq), sizeof(mreq)); | |
1039 if (rv) | |
1040 return MapSystemError(WSAGetLastError()); | |
1041 return OK; | |
1042 } | |
1043 default: | |
1044 NOTREACHED() << "Invalid address family"; | |
1045 return ERR_ADDRESS_INVALID; | |
1046 } | |
1047 } | |
1048 | |
1049 int UDPSocketWin::SetMulticastInterface(uint32 interface_index) { | |
1050 DCHECK(CalledOnValidThread()); | |
1051 if (is_connected()) | |
1052 return ERR_SOCKET_IS_CONNECTED; | |
1053 multicast_interface_ = interface_index; | |
1054 return OK; | |
1055 } | |
1056 | |
1057 int UDPSocketWin::SetMulticastTimeToLive(int time_to_live) { | |
1058 DCHECK(CalledOnValidThread()); | |
1059 if (is_connected()) | |
1060 return ERR_SOCKET_IS_CONNECTED; | |
1061 | |
1062 if (time_to_live < 0 || time_to_live > 255) | |
1063 return ERR_INVALID_ARGUMENT; | |
1064 multicast_time_to_live_ = time_to_live; | |
1065 return OK; | |
1066 } | |
1067 | |
1068 int UDPSocketWin::SetMulticastLoopbackMode(bool loopback) { | |
1069 DCHECK(CalledOnValidThread()); | |
1070 if (is_connected()) | |
1071 return ERR_SOCKET_IS_CONNECTED; | |
1072 | |
1073 if (loopback) | |
1074 socket_options_ |= SOCKET_OPTION_MULTICAST_LOOP; | |
1075 else | |
1076 socket_options_ &= ~SOCKET_OPTION_MULTICAST_LOOP; | |
1077 return OK; | |
1078 } | |
1079 | |
1080 int UDPSocketWin::SetDiffServCodePoint(DiffServCodePoint dscp) { | |
1081 if (dscp == DSCP_NO_CHANGE) { | |
1082 return OK; | |
1083 } | |
1084 | |
1085 if (!is_connected()) | |
1086 return ERR_SOCKET_NOT_CONNECTED; | |
1087 | |
1088 QwaveAPI& qos(QwaveAPI::Get()); | |
1089 | |
1090 if (!qos.qwave_supported()) | |
1091 return ERROR_NOT_SUPPORTED; | |
1092 | |
1093 if (qos_handle_ == NULL) { | |
1094 QOS_VERSION version; | |
1095 version.MajorVersion = 1; | |
1096 version.MinorVersion = 0; | |
1097 qos.CreateHandle(&version, &qos_handle_); | |
1098 if (qos_handle_ == NULL) | |
1099 return ERROR_NOT_SUPPORTED; | |
1100 } | |
1101 | |
1102 QOS_TRAFFIC_TYPE traffic_type = QOSTrafficTypeBestEffort; | |
1103 switch (dscp) { | |
1104 case DSCP_CS0: | |
1105 traffic_type = QOSTrafficTypeBestEffort; | |
1106 break; | |
1107 case DSCP_CS1: | |
1108 traffic_type = QOSTrafficTypeBackground; | |
1109 break; | |
1110 case DSCP_AF11: | |
1111 case DSCP_AF12: | |
1112 case DSCP_AF13: | |
1113 case DSCP_CS2: | |
1114 case DSCP_AF21: | |
1115 case DSCP_AF22: | |
1116 case DSCP_AF23: | |
1117 case DSCP_CS3: | |
1118 case DSCP_AF31: | |
1119 case DSCP_AF32: | |
1120 case DSCP_AF33: | |
1121 case DSCP_CS4: | |
1122 traffic_type = QOSTrafficTypeExcellentEffort; | |
1123 break; | |
1124 case DSCP_AF41: | |
1125 case DSCP_AF42: | |
1126 case DSCP_AF43: | |
1127 case DSCP_CS5: | |
1128 traffic_type = QOSTrafficTypeAudioVideo; | |
1129 break; | |
1130 case DSCP_EF: | |
1131 case DSCP_CS6: | |
1132 traffic_type = QOSTrafficTypeVoice; | |
1133 break; | |
1134 case DSCP_CS7: | |
1135 traffic_type = QOSTrafficTypeControl; | |
1136 break; | |
1137 case DSCP_NO_CHANGE: | |
1138 NOTREACHED(); | |
1139 break; | |
1140 } | |
1141 if (qos_flow_id_ != 0) { | |
1142 qos.RemoveSocketFromFlow(qos_handle_, NULL, qos_flow_id_, 0); | |
1143 qos_flow_id_ = 0; | |
1144 } | |
1145 if (!qos.AddSocketToFlow(qos_handle_, | |
1146 socket_, | |
1147 NULL, | |
1148 traffic_type, | |
1149 QOS_NON_ADAPTIVE_FLOW, | |
1150 &qos_flow_id_)) { | |
1151 DWORD err = GetLastError(); | |
1152 if (err == ERROR_DEVICE_REINITIALIZATION_NEEDED) { | |
1153 qos.CloseHandle(qos_handle_); | |
1154 qos_flow_id_ = 0; | |
1155 qos_handle_ = 0; | |
1156 } | |
1157 return MapSystemError(err); | |
1158 } | |
1159 // This requires admin rights, and may fail, if so we ignore it | |
1160 // as AddSocketToFlow should still do *approximately* the right thing. | |
1161 DWORD buf = dscp; | |
1162 qos.SetFlow(qos_handle_, | |
1163 qos_flow_id_, | |
1164 QOSSetOutgoingDSCPValue, | |
1165 sizeof(buf), | |
1166 &buf, | |
1167 0, | |
1168 NULL); | |
1169 | |
1170 return OK; | |
1171 } | |
1172 | |
1173 void UDPSocketWin::DetachFromThread() { | |
1174 base::NonThreadSafe::DetachFromThread(); | |
1175 } | |
1176 | |
1177 void UDPSocketWin::UseNonBlockingIO() { | |
1178 DCHECK(!core_); | |
1179 use_non_blocking_io_ = true; | |
1180 } | |
1181 | |
1182 } // namespace net | |
OLD | NEW |