OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "net/udp/udp_socket_win.h" | |
6 | |
7 #include <mstcpip.h> | |
8 | |
9 #include "base/eintr_wrapper.h" | |
10 #include "base/logging.h" | |
11 #include "base/message_loop.h" | |
12 #include "base/memory_debug.h" | |
13 #include "base/metrics/stats_counters.h" | |
14 #include "net/base/io_buffer.h" | |
15 #include "net/base/ip_endpoint.h" | |
16 #include "net/base/net_errors.h" | |
17 #include "net/base/net_log.h" | |
18 #include "net/base/net_util.h" | |
19 #include "net/base/winsock_init.h" | |
20 #include "net/base/winsock_util.h" | |
21 | |
22 namespace net { | |
23 | |
24 void UDPSocketWin::ReadDelegate::OnObjectSignaled(HANDLE object) { | |
25 DCHECK_EQ(object, socket_->read_overlapped_.hEvent); | |
26 socket_->DidCompleteRead(); | |
27 } | |
28 | |
29 void UDPSocketWin::WriteDelegate::OnObjectSignaled(HANDLE object) { | |
30 DCHECK_EQ(object, socket_->write_overlapped_.hEvent); | |
31 socket_->DidCompleteWrite(); | |
32 } | |
33 | |
34 UDPSocketWin::UDPSocketWin(net::NetLog* net_log, | |
35 const net::NetLog::Source& source) | |
36 : socket_(INVALID_SOCKET), | |
37 ALLOW_THIS_IN_INITIALIZER_LIST(read_delegate_(this)), | |
38 ALLOW_THIS_IN_INITIALIZER_LIST(write_delegate_(this)), | |
39 recv_from_address_(NULL), | |
40 read_callback_(NULL), | |
41 write_callback_(NULL), | |
42 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)) { | |
43 EnsureWinsockInit(); | |
44 scoped_refptr<NetLog::EventParameters> params; | |
45 if (source.is_valid()) | |
46 params = new NetLogSourceParameter("source_dependency", source); | |
47 net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE, params); | |
48 memset(&read_overlapped_, 0, sizeof(read_overlapped_)); | |
49 read_overlapped_.hEvent = WSACreateEvent(); | |
50 memset(&write_overlapped_, 0, sizeof(write_overlapped_)); | |
51 write_overlapped_.hEvent = WSACreateEvent(); | |
52 } | |
53 | |
54 UDPSocketWin::~UDPSocketWin() { | |
55 Close(); | |
56 net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE, NULL); | |
57 } | |
58 | |
59 void UDPSocketWin::Close() { | |
60 DCHECK(CalledOnValidThread()); | |
61 | |
62 if (!is_connected()) | |
63 return; | |
64 | |
65 if (read_callback_) | |
66 DoReadCallback(ERR_ABORTED); | |
67 if (write_callback_) | |
68 DoReadCallback(ERR_ABORTED); | |
69 | |
70 read_watcher_.StopWatching(); | |
71 write_watcher_.StopWatching(); | |
72 | |
73 closesocket(socket_); | |
74 socket_ = INVALID_SOCKET; | |
75 } | |
76 | |
77 int UDPSocketWin::GetPeerAddress(IPEndPoint* address) const { | |
78 DCHECK(CalledOnValidThread()); | |
79 DCHECK(address); | |
80 if (!is_connected()) | |
81 return ERR_SOCKET_NOT_CONNECTED; | |
82 | |
83 if (!remote_address_.get()) { | |
84 struct sockaddr_storage addr_storage; | |
85 int addr_len = sizeof(addr_storage); | |
86 struct sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addr_storage); | |
87 if (getpeername(socket_, addr, &addr_len)) | |
88 return MapWinsockError(WSAGetLastError()); | |
89 scoped_ptr<IPEndPoint> address(new IPEndPoint()); | |
90 if (!address->FromSockAddr(addr, addr_len)) | |
91 return ERR_FAILED; | |
92 remote_address_.reset(address.release()); | |
93 } | |
94 | |
95 *address = *remote_address_; | |
96 return OK; | |
97 } | |
98 | |
99 int UDPSocketWin::GetLocalAddress(IPEndPoint* address) const { | |
100 DCHECK(CalledOnValidThread()); | |
101 DCHECK(address); | |
102 if (!is_connected()) | |
103 return ERR_SOCKET_NOT_CONNECTED; | |
104 | |
105 if (!local_address_.get()) { | |
106 struct sockaddr_storage addr_storage; | |
107 socklen_t addr_len = sizeof(addr_storage); | |
108 struct sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addr_storage); | |
109 if (getsockname(socket_, addr, &addr_len)) | |
110 return MapWinsockError(WSAGetLastError()); | |
111 scoped_ptr<IPEndPoint> address(new IPEndPoint()); | |
112 if (!address->FromSockAddr(addr, addr_len)) | |
113 return ERR_FAILED; | |
114 local_address_.reset(address.release()); | |
115 } | |
116 | |
117 *address = *local_address_; | |
118 return OK; | |
119 } | |
120 | |
121 int UDPSocketWin::RecvFrom(IOBuffer* buf, | |
122 int buf_len, | |
123 IPEndPoint* address, | |
124 CompletionCallback* callback) { | |
125 DCHECK(!recv_from_address_); | |
126 recv_from_address_ = address; | |
127 return Read(buf, buf_len, callback); | |
128 } | |
129 | |
130 int UDPSocketWin::Read(IOBuffer* buf, | |
131 int buf_len, | |
132 CompletionCallback* callback) { | |
133 DCHECK(CalledOnValidThread()); | |
134 DCHECK_NE(INVALID_SOCKET, socket_); | |
135 DCHECK(!read_callback_); | |
136 DCHECK(callback); // Synchronous operation not supported. | |
137 DCHECK_GT(buf_len, 0); | |
138 | |
139 int nread = InternalRead(buf, buf_len); | |
140 if (nread != ERR_IO_PENDING) | |
141 return nread; | |
142 | |
143 read_iobuffer_ = buf; | |
144 read_callback_ = callback; | |
145 return ERR_IO_PENDING; | |
146 } | |
147 | |
148 int UDPSocketWin::SendTo(IOBuffer* buf, | |
149 int buf_len, | |
150 const IPEndPoint& address, | |
151 CompletionCallback* callback) { | |
152 send_to_address_.reset(new IPEndPoint(address)); | |
153 return Write(buf, buf_len, callback); | |
154 } | |
155 | |
156 int UDPSocketWin::Write(IOBuffer* buf, | |
157 int buf_len, | |
158 CompletionCallback* callback) { | |
159 DCHECK(CalledOnValidThread()); | |
160 DCHECK_NE(INVALID_SOCKET, socket_); | |
161 DCHECK(!write_callback_); | |
162 DCHECK(callback); // Synchronous operation not supported. | |
163 DCHECK_GT(buf_len, 0); | |
164 | |
165 int nwrite = InternalWrite(buf, buf_len); | |
166 if (nwrite != ERR_IO_PENDING) | |
167 return nwrite; | |
168 | |
169 write_iobuffer_ = buf; | |
170 write_callback_ = callback; | |
171 return ERR_IO_PENDING; | |
172 } | |
173 | |
174 int UDPSocketWin::Connect(const IPEndPoint& address) { | |
175 DCHECK(!is_connected()); | |
176 DCHECK(!remote_address_.get()); | |
177 int rv = CreateSocket(address); | |
178 if (rv < 0) | |
179 return rv; | |
180 | |
181 struct sockaddr_storage addr_storage; | |
182 size_t addr_len = sizeof(addr_storage); | |
183 struct sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addr_storage); | |
184 if (!address.ToSockAddr(addr, &addr_len)) | |
185 return ERR_FAILED; | |
186 | |
187 rv = connect(socket_, addr, addr_len); | |
188 if (rv < 0) | |
189 return MapWinsockError(WSAGetLastError()); | |
190 | |
191 remote_address_.reset(new IPEndPoint(address)); | |
192 return rv; | |
193 } | |
194 | |
195 int UDPSocketWin::Bind(const IPEndPoint& address) { | |
196 DCHECK(!is_connected()); | |
197 DCHECK(!local_address_.get()); | |
198 int rv = CreateSocket(address); | |
199 if (rv < 0) | |
200 return rv; | |
201 | |
202 struct sockaddr_storage addr_storage; | |
203 size_t addr_len = sizeof(addr_storage); | |
204 struct sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addr_storage); | |
205 if (!address.ToSockAddr(addr, &addr_len)) | |
206 return ERR_FAILED; | |
207 | |
208 rv = bind(socket_, addr, addr_len); | |
209 if (rv < 0) | |
210 return MapWinsockError(WSAGetLastError()); | |
211 | |
212 local_address_.reset(new IPEndPoint(address)); | |
213 return rv; | |
214 } | |
215 | |
216 int UDPSocketWin::CreateSocket(const IPEndPoint& address) { | |
217 socket_ = WSASocket(address.GetFamily(), SOCK_DGRAM, IPPROTO_UDP, NULL, 0, | |
218 WSA_FLAG_OVERLAPPED); | |
219 if (socket_ == INVALID_SOCKET) | |
220 return MapWinsockError(WSAGetLastError()); | |
221 return OK; | |
222 } | |
223 | |
224 void UDPSocketWin::DoReadCallback(int rv) { | |
225 DCHECK_NE(rv, ERR_IO_PENDING); | |
226 DCHECK(read_callback_); | |
227 | |
228 // since Run may result in Read being called, clear read_callback_ up front. | |
229 CompletionCallback* c = read_callback_; | |
230 read_callback_ = NULL; | |
231 recv_from_address_ = NULL; | |
232 c->Run(rv); | |
233 } | |
234 | |
235 void UDPSocketWin::DoWriteCallback(int rv) { | |
236 DCHECK_NE(rv, ERR_IO_PENDING); | |
237 DCHECK(write_callback_); | |
238 | |
239 // since Run may result in Write being called, clear write_callback_ up front. | |
240 CompletionCallback* c = write_callback_; | |
241 write_callback_ = NULL; | |
242 send_to_address_.reset(); | |
243 c->Run(rv); | |
244 } | |
245 | |
246 void UDPSocketWin::DidCompleteRead() { | |
247 DWORD num_bytes, flags; | |
248 BOOL ok = WSAGetOverlappedResult(socket_, &read_overlapped_, | |
249 &num_bytes, FALSE, &flags); | |
250 WSAResetEvent(read_overlapped_.hEvent); | |
251 int result = ok ? num_bytes : MapWinsockError(WSAGetLastError()); | |
252 if (ok) { | |
253 if (!ProcessSuccessfulRead(num_bytes)) | |
254 result = ERR_FAILED; | |
255 } | |
256 read_iobuffer_ = NULL; | |
257 DoReadCallback(result); | |
258 } | |
259 | |
260 bool UDPSocketWin::ProcessSuccessfulRead(int num_bytes) { | |
261 static base::StatsCounter read_bytes("udp.read_bytes"); | |
262 read_bytes.Add(num_bytes); | |
263 | |
264 // Convert address. | |
265 if (recv_from_address_) { | |
266 struct sockaddr* addr = | |
267 reinterpret_cast<struct sockaddr*>(&recv_addr_storage_); | |
268 if (!recv_from_address_->FromSockAddr(addr, recv_addr_len_)) | |
269 return false; | |
270 } | |
271 | |
272 return true; | |
273 } | |
274 | |
275 void UDPSocketWin::DidCompleteWrite() { | |
276 DWORD num_bytes, flags; | |
277 BOOL ok = WSAGetOverlappedResult(socket_, &write_overlapped_, | |
278 &num_bytes, FALSE, &flags); | |
279 WSAResetEvent(write_overlapped_.hEvent); | |
280 int result = ok ? num_bytes : MapWinsockError(WSAGetLastError()); | |
281 if (ok) | |
282 ProcessSuccessfulWrite(num_bytes); | |
283 write_iobuffer_ = NULL; | |
284 DoWriteCallback(result); | |
285 } | |
286 | |
287 void UDPSocketWin::ProcessSuccessfulWrite(int num_bytes) { | |
288 static base::StatsCounter write_bytes("udp.write_bytes"); | |
289 write_bytes.Add(num_bytes); | |
290 } | |
291 | |
292 int UDPSocketWin::InternalRead(IOBuffer* buf, int buf_len) { | |
293 recv_addr_len_ = sizeof(recv_addr_storage_); | |
294 struct sockaddr* addr = | |
295 reinterpret_cast<struct sockaddr*>(&recv_addr_storage_); | |
296 | |
297 WSABUF read_buffer; | |
298 read_buffer.buf = buf->data(); | |
299 read_buffer.len = buf_len; | |
Mike Belshe
2011/03/11 14:31:28
Ah - this is even better. Great.
| |
300 | |
301 DWORD flags = 0; | |
302 DWORD num; | |
303 AssertEventNotSignaled(read_overlapped_.hEvent); | |
304 int rv = WSARecvFrom(socket_, &read_buffer, 1, &num, &flags, addr, | |
305 &recv_addr_len_, &read_overlapped_, NULL); | |
306 if (rv == 0) { | |
307 if (ResetEventIfSignaled(read_overlapped_.hEvent)) { | |
308 // Because of how WSARecv fills memory when used asynchronously, Purify | |
309 // isn't able to detect that it's been initialized, so it scans for 0xcd | |
310 // in the buffer and reports UMRs (uninitialized memory reads) for those | |
311 // individual bytes. We override that in PURIFY builds to avoid the | |
312 // false error reports. | |
313 // See bug 5297. | |
314 base::MemoryDebug::MarkAsInitialized(read_buffer.buf, num); | |
315 if (!ProcessSuccessfulRead(num)) | |
316 return ERR_FAILED; | |
317 return static_cast<int>(num); | |
318 } | |
319 } else { | |
320 int os_error = WSAGetLastError(); | |
321 if (os_error != WSA_IO_PENDING) | |
322 return MapWinsockError(os_error); | |
323 } | |
324 read_watcher_.StartWatching(read_overlapped_.hEvent, &read_delegate_); | |
325 return ERR_IO_PENDING; | |
326 } | |
327 | |
328 int UDPSocketWin::InternalWrite(IOBuffer* buf, int buf_len) { | |
329 struct sockaddr_storage addr_storage; | |
330 size_t addr_len = sizeof(addr_storage); | |
331 struct sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addr_storage); | |
332 | |
333 // Convert address. | |
334 if (!send_to_address_.get()) { | |
335 addr = NULL; | |
336 addr_len = 0; | |
337 } else { | |
338 if (!send_to_address_->ToSockAddr(addr, &addr_len)) | |
339 return ERR_FAILED; | |
340 } | |
341 | |
342 WSABUF write_buffer; | |
343 write_buffer.buf = buf->data(); | |
344 write_buffer.len = buf_len; | |
345 | |
346 DWORD flags = 0; | |
347 DWORD num; | |
348 AssertEventNotSignaled(write_overlapped_.hEvent); | |
349 int rv = WSASendTo(socket_, &write_buffer, 1, &num, flags, | |
350 addr, addr_len, &write_overlapped_, NULL); | |
351 if (rv == 0) { | |
352 if (ResetEventIfSignaled(write_overlapped_.hEvent)) { | |
353 ProcessSuccessfulWrite(num); | |
354 return static_cast<int>(num); | |
355 } | |
356 } else { | |
357 int os_error = WSAGetLastError(); | |
358 if (os_error != WSA_IO_PENDING) | |
359 return MapWinsockError(os_error); | |
360 } | |
361 | |
362 write_watcher_.StartWatching(write_overlapped_.hEvent, &write_delegate_); | |
363 return ERR_IO_PENDING; | |
364 } | |
365 | |
366 } // namespace net | |
OLD | NEW |