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