OLD | NEW |
| (Empty) |
1 // Copyright 2013 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/sockets_tcp/sockets_tcp_api.h" | |
6 | |
7 #include "chrome/browser/extensions/api/socket/tcp_socket.h" | |
8 #include "chrome/browser/extensions/api/sockets_tcp/tcp_socket_event_dispatcher.
h" | |
9 #include "chrome/common/extensions/api/sockets/sockets_manifest_data.h" | |
10 #include "content/public/common/socket_permission_request.h" | |
11 #include "net/base/net_errors.h" | |
12 | |
13 using extensions::ResumableTCPSocket; | |
14 using extensions::api::sockets_tcp::SocketInfo; | |
15 using extensions::api::sockets_tcp::SocketProperties; | |
16 | |
17 namespace { | |
18 | |
19 const char kSocketNotFoundError[] = "Socket not found"; | |
20 const char kPermissionError[] = "Does not have permission"; | |
21 | |
22 linked_ptr<SocketInfo> CreateSocketInfo(int socket_id, | |
23 ResumableTCPSocket* socket) { | |
24 linked_ptr<SocketInfo> socket_info(new SocketInfo()); | |
25 // This represents what we know about the socket, and does not call through | |
26 // to the system. | |
27 socket_info->socket_id = socket_id; | |
28 if (!socket->name().empty()) { | |
29 socket_info->name.reset(new std::string(socket->name())); | |
30 } | |
31 socket_info->persistent = socket->persistent(); | |
32 if (socket->buffer_size() > 0) { | |
33 socket_info->buffer_size.reset(new int(socket->buffer_size())); | |
34 } | |
35 socket_info->paused = socket->paused(); | |
36 socket_info->connected = socket->IsConnected(); | |
37 | |
38 // Grab the local address as known by the OS. | |
39 net::IPEndPoint localAddress; | |
40 if (socket->GetLocalAddress(&localAddress)) { | |
41 socket_info->local_address.reset( | |
42 new std::string(localAddress.ToStringWithoutPort())); | |
43 socket_info->local_port.reset(new int(localAddress.port())); | |
44 } | |
45 | |
46 // Grab the peer address as known by the OS. This and the call below will | |
47 // always succeed while the socket is connected, even if the socket has | |
48 // been remotely closed by the peer; only reading the socket will reveal | |
49 // that it should be closed locally. | |
50 net::IPEndPoint peerAddress; | |
51 if (socket->GetPeerAddress(&peerAddress)) { | |
52 socket_info->peer_address.reset( | |
53 new std::string(peerAddress.ToStringWithoutPort())); | |
54 socket_info->peer_port.reset(new int(peerAddress.port())); | |
55 } | |
56 | |
57 return socket_info; | |
58 } | |
59 | |
60 void SetSocketProperties(ResumableTCPSocket* socket, | |
61 SocketProperties* properties) { | |
62 if (properties->name.get()) { | |
63 socket->set_name(*properties->name.get()); | |
64 } | |
65 if (properties->persistent.get()) { | |
66 socket->set_persistent(*properties->persistent.get()); | |
67 } | |
68 if (properties->buffer_size.get()) { | |
69 // buffer size is validated when issuing the actual Recv operation | |
70 // on the socket. | |
71 socket->set_buffer_size(*properties->buffer_size.get()); | |
72 } | |
73 } | |
74 | |
75 } // namespace | |
76 | |
77 namespace extensions { | |
78 namespace api { | |
79 | |
80 using content::SocketPermissionRequest; | |
81 | |
82 TCPSocketAsyncApiFunction::~TCPSocketAsyncApiFunction() {} | |
83 | |
84 scoped_ptr<SocketResourceManagerInterface> | |
85 TCPSocketAsyncApiFunction::CreateSocketResourceManager() { | |
86 return scoped_ptr<SocketResourceManagerInterface>( | |
87 new SocketResourceManager<ResumableTCPSocket>()).Pass(); | |
88 } | |
89 | |
90 ResumableTCPSocket* TCPSocketAsyncApiFunction::GetTcpSocket(int socket_id) { | |
91 return static_cast<ResumableTCPSocket*>(GetSocket(socket_id)); | |
92 } | |
93 | |
94 TCPSocketExtensionWithDnsLookupFunction:: | |
95 ~TCPSocketExtensionWithDnsLookupFunction() {} | |
96 | |
97 scoped_ptr<SocketResourceManagerInterface> | |
98 TCPSocketExtensionWithDnsLookupFunction::CreateSocketResourceManager() { | |
99 return scoped_ptr<SocketResourceManagerInterface>( | |
100 new SocketResourceManager<ResumableTCPSocket>()).Pass(); | |
101 } | |
102 | |
103 ResumableTCPSocket* TCPSocketExtensionWithDnsLookupFunction::GetTcpSocket( | |
104 int socket_id) { | |
105 return static_cast<ResumableTCPSocket*>(GetSocket(socket_id)); | |
106 } | |
107 | |
108 SocketsTcpCreateFunction::SocketsTcpCreateFunction() {} | |
109 | |
110 SocketsTcpCreateFunction::~SocketsTcpCreateFunction() {} | |
111 | |
112 bool SocketsTcpCreateFunction::Prepare() { | |
113 params_ = sockets_tcp::Create::Params::Create(*args_); | |
114 EXTENSION_FUNCTION_VALIDATE(params_.get()); | |
115 return true; | |
116 } | |
117 | |
118 void SocketsTcpCreateFunction::Work() { | |
119 ResumableTCPSocket* socket = new ResumableTCPSocket(extension_->id()); | |
120 | |
121 sockets_tcp::SocketProperties* properties = params_.get()->properties.get(); | |
122 if (properties) { | |
123 SetSocketProperties(socket, properties); | |
124 } | |
125 | |
126 sockets_tcp::CreateInfo create_info; | |
127 create_info.socket_id = AddSocket(socket); | |
128 results_ = sockets_tcp::Create::Results::Create(create_info); | |
129 } | |
130 | |
131 SocketsTcpUpdateFunction::SocketsTcpUpdateFunction() {} | |
132 | |
133 SocketsTcpUpdateFunction::~SocketsTcpUpdateFunction() {} | |
134 | |
135 bool SocketsTcpUpdateFunction::Prepare() { | |
136 params_ = sockets_tcp::Update::Params::Create(*args_); | |
137 EXTENSION_FUNCTION_VALIDATE(params_.get()); | |
138 return true; | |
139 } | |
140 | |
141 void SocketsTcpUpdateFunction::Work() { | |
142 ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id); | |
143 if (!socket) { | |
144 error_ = kSocketNotFoundError; | |
145 return; | |
146 } | |
147 | |
148 SetSocketProperties(socket, ¶ms_.get()->properties); | |
149 results_ = sockets_tcp::Update::Results::Create(); | |
150 } | |
151 | |
152 SocketsTcpSetPausedFunction::SocketsTcpSetPausedFunction() | |
153 : socket_event_dispatcher_(NULL) {} | |
154 | |
155 SocketsTcpSetPausedFunction::~SocketsTcpSetPausedFunction() {} | |
156 | |
157 bool SocketsTcpSetPausedFunction::Prepare() { | |
158 params_ = api::sockets_tcp::SetPaused::Params::Create(*args_); | |
159 EXTENSION_FUNCTION_VALIDATE(params_.get()); | |
160 | |
161 socket_event_dispatcher_ = TCPSocketEventDispatcher::Get(browser_context()); | |
162 DCHECK(socket_event_dispatcher_) << "There is no socket event dispatcher. " | |
163 "If this assertion is failing during a test, then it is likely that " | |
164 "TestExtensionSystem is failing to provide an instance of " | |
165 "TCPSocketEventDispatcher."; | |
166 return socket_event_dispatcher_ != NULL; | |
167 } | |
168 | |
169 void SocketsTcpSetPausedFunction::Work() { | |
170 ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id); | |
171 if (!socket) { | |
172 error_ = kSocketNotFoundError; | |
173 return; | |
174 } | |
175 | |
176 if (socket->paused() != params_->paused) { | |
177 socket->set_paused(params_->paused); | |
178 if (socket->IsConnected() && !params_->paused) { | |
179 socket_event_dispatcher_->OnSocketResume(extension_->id(), | |
180 params_->socket_id); | |
181 } | |
182 } | |
183 | |
184 results_ = sockets_tcp::SetPaused::Results::Create(); | |
185 } | |
186 | |
187 SocketsTcpSetKeepAliveFunction::SocketsTcpSetKeepAliveFunction() {} | |
188 | |
189 SocketsTcpSetKeepAliveFunction::~SocketsTcpSetKeepAliveFunction() {} | |
190 | |
191 bool SocketsTcpSetKeepAliveFunction::Prepare() { | |
192 params_ = api::sockets_tcp::SetKeepAlive::Params::Create(*args_); | |
193 EXTENSION_FUNCTION_VALIDATE(params_.get()); | |
194 return true; | |
195 } | |
196 | |
197 void SocketsTcpSetKeepAliveFunction::Work() { | |
198 ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id); | |
199 if (!socket) { | |
200 error_ = kSocketNotFoundError; | |
201 return; | |
202 } | |
203 | |
204 int delay = params_->delay ? *params_->delay.get() : 0; | |
205 | |
206 bool success = socket->SetKeepAlive(params_->enable, delay); | |
207 int net_result = (success ? net::OK : net::ERR_FAILED); | |
208 if (net_result != net::OK) | |
209 error_ = net::ErrorToString(net_result); | |
210 results_ = sockets_tcp::SetKeepAlive::Results::Create(net_result); | |
211 } | |
212 | |
213 SocketsTcpSetNoDelayFunction::SocketsTcpSetNoDelayFunction() {} | |
214 | |
215 SocketsTcpSetNoDelayFunction::~SocketsTcpSetNoDelayFunction() {} | |
216 | |
217 bool SocketsTcpSetNoDelayFunction::Prepare() { | |
218 params_ = api::sockets_tcp::SetNoDelay::Params::Create(*args_); | |
219 EXTENSION_FUNCTION_VALIDATE(params_.get()); | |
220 return true; | |
221 } | |
222 | |
223 void SocketsTcpSetNoDelayFunction::Work() { | |
224 ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id); | |
225 if (!socket) { | |
226 error_ = kSocketNotFoundError; | |
227 return; | |
228 } | |
229 | |
230 bool success = socket->SetNoDelay(params_->no_delay); | |
231 int net_result = (success ? net::OK : net::ERR_FAILED); | |
232 if (net_result != net::OK) | |
233 error_ = net::ErrorToString(net_result); | |
234 results_ = sockets_tcp::SetNoDelay::Results::Create(net_result); | |
235 } | |
236 | |
237 SocketsTcpConnectFunction::SocketsTcpConnectFunction() | |
238 : socket_event_dispatcher_(NULL) {} | |
239 | |
240 SocketsTcpConnectFunction::~SocketsTcpConnectFunction() {} | |
241 | |
242 bool SocketsTcpConnectFunction::Prepare() { | |
243 params_ = sockets_tcp::Connect::Params::Create(*args_); | |
244 EXTENSION_FUNCTION_VALIDATE(params_.get()); | |
245 | |
246 socket_event_dispatcher_ = TCPSocketEventDispatcher::Get(browser_context()); | |
247 DCHECK(socket_event_dispatcher_) << "There is no socket event dispatcher. " | |
248 "If this assertion is failing during a test, then it is likely that " | |
249 "TestExtensionSystem is failing to provide an instance of " | |
250 "TCPSocketEventDispatcher."; | |
251 return socket_event_dispatcher_ != NULL; | |
252 } | |
253 | |
254 void SocketsTcpConnectFunction::AsyncWorkStart() { | |
255 ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id); | |
256 if (!socket) { | |
257 error_ = kSocketNotFoundError; | |
258 AsyncWorkCompleted(); | |
259 return; | |
260 } | |
261 | |
262 content::SocketPermissionRequest param( | |
263 SocketPermissionRequest::TCP_CONNECT, | |
264 params_->peer_address, | |
265 params_->peer_port); | |
266 if (!SocketsManifestData::CheckRequest(GetExtension(), param)) { | |
267 error_ = kPermissionError; | |
268 AsyncWorkCompleted(); | |
269 return; | |
270 } | |
271 | |
272 StartDnsLookup(params_->peer_address); | |
273 } | |
274 | |
275 void SocketsTcpConnectFunction::AfterDnsLookup(int lookup_result) { | |
276 if (lookup_result == net::OK) { | |
277 StartConnect(); | |
278 } else { | |
279 OnCompleted(lookup_result); | |
280 } | |
281 } | |
282 | |
283 void SocketsTcpConnectFunction::StartConnect() { | |
284 ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id); | |
285 if (!socket) { | |
286 error_ = kSocketNotFoundError; | |
287 AsyncWorkCompleted(); | |
288 return; | |
289 } | |
290 | |
291 socket->Connect(resolved_address_, params_->peer_port, | |
292 base::Bind(&SocketsTcpConnectFunction::OnCompleted, this)); | |
293 } | |
294 | |
295 void SocketsTcpConnectFunction::OnCompleted(int net_result) { | |
296 if (net_result == net::OK) { | |
297 socket_event_dispatcher_->OnSocketConnect(extension_->id(), | |
298 params_->socket_id); | |
299 } | |
300 | |
301 if (net_result != net::OK) | |
302 error_ = net::ErrorToString(net_result); | |
303 results_ = sockets_tcp::Connect::Results::Create(net_result); | |
304 AsyncWorkCompleted(); | |
305 } | |
306 | |
307 SocketsTcpDisconnectFunction::SocketsTcpDisconnectFunction() {} | |
308 | |
309 SocketsTcpDisconnectFunction::~SocketsTcpDisconnectFunction() {} | |
310 | |
311 bool SocketsTcpDisconnectFunction::Prepare() { | |
312 params_ = sockets_tcp::Disconnect::Params::Create(*args_); | |
313 EXTENSION_FUNCTION_VALIDATE(params_.get()); | |
314 return true; | |
315 } | |
316 | |
317 void SocketsTcpDisconnectFunction::Work() { | |
318 ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id); | |
319 if (!socket) { | |
320 error_ = kSocketNotFoundError; | |
321 return; | |
322 } | |
323 | |
324 socket->Disconnect(); | |
325 results_ = sockets_tcp::Disconnect::Results::Create(); | |
326 } | |
327 | |
328 SocketsTcpSendFunction::SocketsTcpSendFunction() | |
329 : io_buffer_size_(0) {} | |
330 | |
331 SocketsTcpSendFunction::~SocketsTcpSendFunction() {} | |
332 | |
333 bool SocketsTcpSendFunction::Prepare() { | |
334 params_ = sockets_tcp::Send::Params::Create(*args_); | |
335 EXTENSION_FUNCTION_VALIDATE(params_.get()); | |
336 io_buffer_size_ = params_->data.size(); | |
337 io_buffer_ = new net::WrappedIOBuffer(params_->data.data()); | |
338 return true; | |
339 } | |
340 | |
341 void SocketsTcpSendFunction::AsyncWorkStart() { | |
342 ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id); | |
343 if (!socket) { | |
344 error_ = kSocketNotFoundError; | |
345 AsyncWorkCompleted(); | |
346 return; | |
347 } | |
348 | |
349 socket->Write(io_buffer_, io_buffer_size_, | |
350 base::Bind(&SocketsTcpSendFunction::OnCompleted, this)); | |
351 } | |
352 | |
353 void SocketsTcpSendFunction::OnCompleted(int net_result) { | |
354 if (net_result >= net::OK) { | |
355 SetSendResult(net::OK, net_result); | |
356 } else { | |
357 SetSendResult(net_result, -1); | |
358 } | |
359 } | |
360 | |
361 void SocketsTcpSendFunction::SetSendResult(int net_result, int bytes_sent) { | |
362 CHECK(net_result <= net::OK) << "Network status code must be <= net::OK"; | |
363 | |
364 sockets_tcp::SendInfo send_info; | |
365 send_info.result_code = net_result; | |
366 if (net_result == net::OK) { | |
367 send_info.bytes_sent.reset(new int(bytes_sent)); | |
368 } | |
369 | |
370 if (net_result != net::OK) | |
371 error_ = net::ErrorToString(net_result); | |
372 results_ = sockets_tcp::Send::Results::Create(send_info); | |
373 AsyncWorkCompleted(); | |
374 } | |
375 | |
376 SocketsTcpCloseFunction::SocketsTcpCloseFunction() {} | |
377 | |
378 SocketsTcpCloseFunction::~SocketsTcpCloseFunction() {} | |
379 | |
380 bool SocketsTcpCloseFunction::Prepare() { | |
381 params_ = sockets_tcp::Close::Params::Create(*args_); | |
382 EXTENSION_FUNCTION_VALIDATE(params_.get()); | |
383 return true; | |
384 } | |
385 | |
386 void SocketsTcpCloseFunction::Work() { | |
387 ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id); | |
388 if (!socket) { | |
389 error_ = kSocketNotFoundError; | |
390 return; | |
391 } | |
392 | |
393 RemoveSocket(params_->socket_id); | |
394 results_ = sockets_tcp::Close::Results::Create(); | |
395 } | |
396 | |
397 SocketsTcpGetInfoFunction::SocketsTcpGetInfoFunction() {} | |
398 | |
399 SocketsTcpGetInfoFunction::~SocketsTcpGetInfoFunction() {} | |
400 | |
401 bool SocketsTcpGetInfoFunction::Prepare() { | |
402 params_ = sockets_tcp::GetInfo::Params::Create(*args_); | |
403 EXTENSION_FUNCTION_VALIDATE(params_.get()); | |
404 return true; | |
405 } | |
406 | |
407 void SocketsTcpGetInfoFunction::Work() { | |
408 ResumableTCPSocket* socket = GetTcpSocket(params_->socket_id); | |
409 if (!socket) { | |
410 error_ = kSocketNotFoundError; | |
411 return; | |
412 } | |
413 | |
414 linked_ptr<sockets_tcp::SocketInfo> socket_info = | |
415 CreateSocketInfo(params_->socket_id, socket); | |
416 results_ = sockets_tcp::GetInfo::Results::Create(*socket_info); | |
417 } | |
418 | |
419 SocketsTcpGetSocketsFunction::SocketsTcpGetSocketsFunction() {} | |
420 | |
421 SocketsTcpGetSocketsFunction::~SocketsTcpGetSocketsFunction() {} | |
422 | |
423 bool SocketsTcpGetSocketsFunction::Prepare() { | |
424 return true; | |
425 } | |
426 | |
427 void SocketsTcpGetSocketsFunction::Work() { | |
428 std::vector<linked_ptr<sockets_tcp::SocketInfo> > socket_infos; | |
429 base::hash_set<int>* resource_ids = GetSocketIds(); | |
430 if (resource_ids != NULL) { | |
431 for (base::hash_set<int>::iterator it = resource_ids->begin(); | |
432 it != resource_ids->end(); ++it) { | |
433 int socket_id = *it; | |
434 ResumableTCPSocket* socket = GetTcpSocket(socket_id); | |
435 if (socket) { | |
436 socket_infos.push_back(CreateSocketInfo(socket_id, socket)); | |
437 } | |
438 } | |
439 } | |
440 results_ = sockets_tcp::GetSockets::Results::Create(socket_infos); | |
441 } | |
442 | |
443 } // namespace api | |
444 } // namespace extensions | |
OLD | NEW |