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