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 "chrome/browser/extensions/api/socket/udp_socket.h" | |
6 | |
7 #include <algorithm> | |
8 | |
9 #include "chrome/browser/extensions/api/api_resource.h" | |
10 #include "net/base/ip_endpoint.h" | |
11 #include "net/base/net_errors.h" | |
12 #include "net/udp/datagram_socket.h" | |
13 #include "net/udp/udp_client_socket.h" | |
14 | |
15 namespace extensions { | |
16 | |
17 static base::LazyInstance< | |
18 BrowserContextKeyedAPIFactory<ApiResourceManager<ResumableUDPSocket> > > | |
19 g_factory = LAZY_INSTANCE_INITIALIZER; | |
20 | |
21 // static | |
22 template <> | |
23 BrowserContextKeyedAPIFactory<ApiResourceManager<ResumableUDPSocket> >* | |
24 ApiResourceManager<ResumableUDPSocket>::GetFactoryInstance() { | |
25 return g_factory.Pointer(); | |
26 } | |
27 | |
28 UDPSocket::UDPSocket(const std::string& owner_extension_id) | |
29 : Socket(owner_extension_id), | |
30 socket_(net::DatagramSocket::DEFAULT_BIND, | |
31 net::RandIntCallback(), | |
32 NULL, | |
33 net::NetLog::Source()) { | |
34 } | |
35 | |
36 UDPSocket::~UDPSocket() { | |
37 Disconnect(); | |
38 } | |
39 | |
40 void UDPSocket::Connect(const std::string& address, | |
41 int port, | |
42 const CompletionCallback& callback) { | |
43 int result = net::ERR_CONNECTION_FAILED; | |
44 do { | |
45 if (is_connected_) | |
46 break; | |
47 | |
48 net::IPEndPoint ip_end_point; | |
49 if (!StringAndPortToIPEndPoint(address, port, &ip_end_point)) { | |
50 result = net::ERR_ADDRESS_INVALID; | |
51 break; | |
52 } | |
53 | |
54 result = socket_.Connect(ip_end_point); | |
55 is_connected_ = (result == net::OK); | |
56 } while (false); | |
57 | |
58 callback.Run(result); | |
59 } | |
60 | |
61 int UDPSocket::Bind(const std::string& address, int port) { | |
62 if (IsBound()) | |
63 return net::ERR_CONNECTION_FAILED; | |
64 | |
65 net::IPEndPoint ip_end_point; | |
66 if (!StringAndPortToIPEndPoint(address, port, &ip_end_point)) | |
67 return net::ERR_INVALID_ARGUMENT; | |
68 | |
69 return socket_.Bind(ip_end_point); | |
70 } | |
71 | |
72 void UDPSocket::Disconnect() { | |
73 is_connected_ = false; | |
74 socket_.Close(); | |
75 read_callback_.Reset(); | |
76 recv_from_callback_.Reset(); | |
77 send_to_callback_.Reset(); | |
78 multicast_groups_.clear(); | |
79 } | |
80 | |
81 void UDPSocket::Read(int count, | |
82 const ReadCompletionCallback& callback) { | |
83 DCHECK(!callback.is_null()); | |
84 | |
85 if (!read_callback_.is_null()) { | |
86 callback.Run(net::ERR_IO_PENDING, NULL); | |
87 return; | |
88 } else { | |
89 read_callback_ = callback; | |
90 } | |
91 | |
92 int result = net::ERR_FAILED; | |
93 scoped_refptr<net::IOBuffer> io_buffer; | |
94 do { | |
95 if (count < 0) { | |
96 result = net::ERR_INVALID_ARGUMENT; | |
97 break; | |
98 } | |
99 | |
100 if (!socket_.is_connected()) { | |
101 result = net::ERR_SOCKET_NOT_CONNECTED; | |
102 break; | |
103 } | |
104 | |
105 io_buffer = new net::IOBuffer(count); | |
106 result = socket_.Read(io_buffer.get(), count, | |
107 base::Bind(&UDPSocket::OnReadComplete, base::Unretained(this), | |
108 io_buffer)); | |
109 } while (false); | |
110 | |
111 if (result != net::ERR_IO_PENDING) | |
112 OnReadComplete(io_buffer, result); | |
113 } | |
114 | |
115 int UDPSocket::WriteImpl(net::IOBuffer* io_buffer, | |
116 int io_buffer_size, | |
117 const net::CompletionCallback& callback) { | |
118 if (!socket_.is_connected()) | |
119 return net::ERR_SOCKET_NOT_CONNECTED; | |
120 else | |
121 return socket_.Write(io_buffer, io_buffer_size, callback); | |
122 } | |
123 | |
124 void UDPSocket::RecvFrom(int count, | |
125 const RecvFromCompletionCallback& callback) { | |
126 DCHECK(!callback.is_null()); | |
127 | |
128 if (!recv_from_callback_.is_null()) { | |
129 callback.Run(net::ERR_IO_PENDING, NULL, std::string(), 0); | |
130 return; | |
131 } else { | |
132 recv_from_callback_ = callback; | |
133 } | |
134 | |
135 int result = net::ERR_FAILED; | |
136 scoped_refptr<net::IOBuffer> io_buffer; | |
137 scoped_refptr<IPEndPoint> address; | |
138 do { | |
139 if (count < 0) { | |
140 result = net::ERR_INVALID_ARGUMENT; | |
141 break; | |
142 } | |
143 | |
144 if (!socket_.is_connected()) { | |
145 result = net::ERR_SOCKET_NOT_CONNECTED; | |
146 break; | |
147 } | |
148 | |
149 io_buffer = new net::IOBuffer(count); | |
150 address = new IPEndPoint(); | |
151 result = socket_.RecvFrom( | |
152 io_buffer.get(), | |
153 count, | |
154 &address->data, | |
155 base::Bind(&UDPSocket::OnRecvFromComplete, | |
156 base::Unretained(this), | |
157 io_buffer, | |
158 address)); | |
159 } while (false); | |
160 | |
161 if (result != net::ERR_IO_PENDING) | |
162 OnRecvFromComplete(io_buffer, address, result); | |
163 } | |
164 | |
165 void UDPSocket::SendTo(scoped_refptr<net::IOBuffer> io_buffer, | |
166 int byte_count, | |
167 const std::string& address, | |
168 int port, | |
169 const CompletionCallback& callback) { | |
170 DCHECK(!callback.is_null()); | |
171 | |
172 if (!send_to_callback_.is_null()) { | |
173 // TODO(penghuang): Put requests in a pending queue to support multiple | |
174 // sendTo calls. | |
175 callback.Run(net::ERR_IO_PENDING); | |
176 return; | |
177 } else { | |
178 send_to_callback_ = callback; | |
179 } | |
180 | |
181 int result = net::ERR_FAILED; | |
182 do { | |
183 net::IPEndPoint ip_end_point; | |
184 if (!StringAndPortToIPEndPoint(address, port, &ip_end_point)) { | |
185 result = net::ERR_ADDRESS_INVALID; | |
186 break; | |
187 } | |
188 | |
189 if (!socket_.is_connected()) { | |
190 result = net::ERR_SOCKET_NOT_CONNECTED; | |
191 break; | |
192 } | |
193 | |
194 result = socket_.SendTo( | |
195 io_buffer.get(), | |
196 byte_count, | |
197 ip_end_point, | |
198 base::Bind(&UDPSocket::OnSendToComplete, base::Unretained(this))); | |
199 } while (false); | |
200 | |
201 if (result != net::ERR_IO_PENDING) | |
202 OnSendToComplete(result); | |
203 } | |
204 | |
205 bool UDPSocket::IsConnected() { | |
206 return is_connected_; | |
207 } | |
208 | |
209 bool UDPSocket::GetPeerAddress(net::IPEndPoint* address) { | |
210 return !socket_.GetPeerAddress(address); | |
211 } | |
212 | |
213 bool UDPSocket::GetLocalAddress(net::IPEndPoint* address) { | |
214 return !socket_.GetLocalAddress(address); | |
215 } | |
216 | |
217 Socket::SocketType UDPSocket::GetSocketType() const { | |
218 return Socket::TYPE_UDP; | |
219 } | |
220 | |
221 void UDPSocket::OnReadComplete(scoped_refptr<net::IOBuffer> io_buffer, | |
222 int result) { | |
223 DCHECK(!read_callback_.is_null()); | |
224 read_callback_.Run(result, io_buffer); | |
225 read_callback_.Reset(); | |
226 } | |
227 | |
228 void UDPSocket::OnRecvFromComplete(scoped_refptr<net::IOBuffer> io_buffer, | |
229 scoped_refptr<IPEndPoint> address, | |
230 int result) { | |
231 DCHECK(!recv_from_callback_.is_null()); | |
232 std::string ip; | |
233 int port = 0; | |
234 if (result > 0 && address.get()) { | |
235 IPEndPointToStringAndPort(address->data, &ip, &port); | |
236 } | |
237 recv_from_callback_.Run(result, io_buffer, ip, port); | |
238 recv_from_callback_.Reset(); | |
239 } | |
240 | |
241 void UDPSocket::OnSendToComplete(int result) { | |
242 DCHECK(!send_to_callback_.is_null()); | |
243 send_to_callback_.Run(result); | |
244 send_to_callback_.Reset(); | |
245 } | |
246 | |
247 bool UDPSocket::IsBound() { | |
248 return socket_.is_connected(); | |
249 } | |
250 | |
251 int UDPSocket::JoinGroup(const std::string& address) { | |
252 net::IPAddressNumber ip; | |
253 if (!net::ParseIPLiteralToNumber(address, &ip)) | |
254 return net::ERR_ADDRESS_INVALID; | |
255 | |
256 std::string normalized_address = net::IPAddressToString(ip); | |
257 std::vector<std::string>::iterator find_result = | |
258 std::find(multicast_groups_.begin(), | |
259 multicast_groups_.end(), | |
260 normalized_address); | |
261 if (find_result != multicast_groups_.end()) | |
262 return net::ERR_ADDRESS_INVALID; | |
263 | |
264 int rv = socket_.JoinGroup(ip); | |
265 if (rv == 0) | |
266 multicast_groups_.push_back(normalized_address); | |
267 return rv; | |
268 } | |
269 | |
270 int UDPSocket::LeaveGroup(const std::string& address) { | |
271 net::IPAddressNumber ip; | |
272 if (!net::ParseIPLiteralToNumber(address, &ip)) | |
273 return net::ERR_ADDRESS_INVALID; | |
274 | |
275 std::string normalized_address = net::IPAddressToString(ip); | |
276 std::vector<std::string>::iterator find_result = | |
277 std::find(multicast_groups_.begin(), | |
278 multicast_groups_.end(), | |
279 normalized_address); | |
280 if (find_result == multicast_groups_.end()) | |
281 return net::ERR_ADDRESS_INVALID; | |
282 | |
283 int rv = socket_.LeaveGroup(ip); | |
284 if (rv == 0) | |
285 multicast_groups_.erase(find_result); | |
286 return rv; | |
287 } | |
288 | |
289 int UDPSocket::SetMulticastTimeToLive(int ttl) { | |
290 return socket_.SetMulticastTimeToLive(ttl); | |
291 } | |
292 | |
293 int UDPSocket::SetMulticastLoopbackMode(bool loopback) { | |
294 return socket_.SetMulticastLoopbackMode(loopback); | |
295 } | |
296 | |
297 const std::vector<std::string>& UDPSocket::GetJoinedGroups() const { | |
298 return multicast_groups_; | |
299 } | |
300 | |
301 ResumableUDPSocket::ResumableUDPSocket(const std::string& owner_extension_id) | |
302 : UDPSocket(owner_extension_id), | |
303 persistent_(false), | |
304 buffer_size_(0), | |
305 paused_(false) { | |
306 } | |
307 | |
308 bool ResumableUDPSocket::IsPersistent() const { | |
309 return persistent(); | |
310 } | |
311 | |
312 } // namespace extensions | |
OLD | NEW |