Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(224)

Side by Side Diff: chrome/browser/extensions/api/socket/tcp_socket.cc

Issue 10827390: Implement chrome.socket.bind/listen/accept for TCP server socket. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Add error if trying to bind TCP socket, remove TCP client socket bind. Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/extensions/api/socket/tcp_socket.h" 5 #include "chrome/browser/extensions/api/socket/tcp_socket.h"
6 6
7 #include "chrome/browser/extensions/api/api_resource.h" 7 #include "chrome/browser/extensions/api/api_resource.h"
8 #include "chrome/browser/extensions/api/api_resource_event_notifier.h" 8 #include "chrome/browser/extensions/api/api_resource_event_notifier.h"
9 #include "net/base/address_list.h" 9 #include "net/base/address_list.h"
10 #include "net/base/ip_endpoint.h" 10 #include "net/base/ip_endpoint.h"
11 #include "net/base/net_errors.h" 11 #include "net/base/net_errors.h"
12 #include "net/base/rand_callback.h" 12 #include "net/base/rand_callback.h"
13 #include "net/socket/tcp_client_socket.h" 13 #include "net/socket/tcp_client_socket.h"
14 14
15 namespace extensions { 15 namespace extensions {
16 16
17 const char kTCPSocketTypeInvalidError[] =
18 "Cannot call both connect and listen on the same socket.";
19 const char kSocketListenError[] = "Could not listen on the specified port.";
20 const char kSocketRebindError[] = "Rebinding a listening socket not supported";
21
17 TCPSocket::TCPSocket(const std::string& owner_extension_id, 22 TCPSocket::TCPSocket(const std::string& owner_extension_id,
18 ApiResourceEventNotifier* event_notifier) 23 ApiResourceEventNotifier* event_notifier)
19 : Socket(owner_extension_id, event_notifier) { 24 : Socket(owner_extension_id, event_notifier),
25 socket_mode_(UNKNOWN) {
20 } 26 }
21 27
22 // For testing.
23 TCPSocket::TCPSocket(net::TCPClientSocket* tcp_client_socket, 28 TCPSocket::TCPSocket(net::TCPClientSocket* tcp_client_socket,
24 const std::string& owner_extension_id, 29 const std::string& owner_extension_id,
25 ApiResourceEventNotifier* event_notifier) 30 ApiResourceEventNotifier* event_notifier,
31 bool is_connected)
26 : Socket(owner_extension_id, event_notifier), 32 : Socket(owner_extension_id, event_notifier),
27 socket_(tcp_client_socket) { 33 socket_(tcp_client_socket),
34 socket_mode_(CLIENT) {
35 this->is_connected_ = is_connected;
36 }
37
38 TCPSocket::TCPSocket(net::TCPServerSocket* tcp_server_socket,
39 const std::string& owner_extension_id)
40 : Socket(owner_extension_id, NULL),
41 server_socket_(tcp_server_socket),
42 socket_mode_(SERVER) {
28 } 43 }
29 44
30 // static 45 // static
31 TCPSocket* TCPSocket::CreateSocketForTesting( 46 TCPSocket* TCPSocket::CreateSocketForTesting(
32 net::TCPClientSocket* tcp_client_socket, 47 net::TCPClientSocket* tcp_client_socket,
33 const std::string& owner_extension_id, 48 const std::string& owner_extension_id,
34 ApiResourceEventNotifier* event_notifier) { 49 ApiResourceEventNotifier* event_notifier) {
35 return new TCPSocket(tcp_client_socket, owner_extension_id, event_notifier); 50 return new TCPSocket(tcp_client_socket, owner_extension_id, event_notifier);
36 } 51 }
37 52
53 // static
54 TCPSocket* TCPSocket::CreateServerSocketForTesting(
55 net::TCPServerSocket* tcp_server_socket,
56 const std::string& owner_extension_id) {
57 return new TCPSocket(tcp_server_socket, owner_extension_id);
58 }
59
38 TCPSocket::~TCPSocket() { 60 TCPSocket::~TCPSocket() {
39 if (is_connected_) { 61 if (is_connected_) {
40 Disconnect(); 62 Disconnect();
41 } 63 }
64 server_socket_.reset(NULL);
42 } 65 }
43 66
44 void TCPSocket::Connect(const std::string& address, 67 void TCPSocket::Connect(const std::string& address,
45 int port, 68 int port,
46 const CompletionCallback& callback) { 69 const CompletionCallback& callback) {
47 DCHECK(!callback.is_null()); 70 DCHECK(!callback.is_null());
48 71
49 if (!connect_callback_.is_null()) { 72 if (socket_mode_ == SERVER || !connect_callback_.is_null()) {
50 callback.Run(net::ERR_CONNECTION_FAILED); 73 callback.Run(net::ERR_CONNECTION_FAILED);
51 return; 74 return;
52 } 75 }
76 DCHECK(!server_socket_.get());
77 socket_mode_ = CLIENT;
53 connect_callback_ = callback; 78 connect_callback_ = callback;
54 79
55 int result = net::ERR_CONNECTION_FAILED; 80 int result = net::ERR_CONNECTION_FAILED;
56 do { 81 do {
57 if (is_connected_) 82 if (is_connected_)
58 break; 83 break;
59 84
60 net::AddressList address_list; 85 net::AddressList address_list;
61 if (!StringAndPortToAddressList(address, port, &address_list)) { 86 if (!StringAndPortToAddressList(address, port, &address_list)) {
62 result = net::ERR_ADDRESS_INVALID; 87 result = net::ERR_ADDRESS_INVALID;
63 break; 88 break;
64 } 89 }
65 90
66 socket_.reset(new net::TCPClientSocket(address_list, NULL, 91 socket_.reset(new net::TCPClientSocket(address_list, NULL,
67 net::NetLog::Source())); 92 net::NetLog::Source()));
93
68 connect_callback_ = callback; 94 connect_callback_ = callback;
69 result = socket_->Connect(base::Bind( 95 result = socket_->Connect(base::Bind(
70 &TCPSocket::OnConnectComplete, base::Unretained(this))); 96 &TCPSocket::OnConnectComplete, base::Unretained(this)));
71 } while (false); 97 } while (false);
72 98
73 if (result != net::ERR_IO_PENDING) 99 if (result != net::ERR_IO_PENDING)
74 OnConnectComplete(result); 100 OnConnectComplete(result);
75 } 101 }
76 102
77 void TCPSocket::Disconnect() { 103 void TCPSocket::Disconnect() {
78 is_connected_ = false; 104 is_connected_ = false;
79 socket_->Disconnect(); 105 socket_->Disconnect();
80 } 106 }
81 107
82 int TCPSocket::Bind(const std::string& address, int port) { 108 int TCPSocket::Bind(const std::string& address, int port) {
83 // TODO(penghuang): Supports bind for tcp?
84 return net::ERR_FAILED; 109 return net::ERR_FAILED;
85 } 110 }
86 111
87 void TCPSocket::Read(int count, 112 void TCPSocket::Read(int count,
88 const ReadCompletionCallback& callback) { 113 const ReadCompletionCallback& callback) {
89 DCHECK(!callback.is_null()); 114 DCHECK(!callback.is_null());
90 115
116 if (socket_mode_ != CLIENT) {
117 callback.Run(net::ERR_FAILED, NULL);
118 return;
119 }
120
91 if (!read_callback_.is_null()) { 121 if (!read_callback_.is_null()) {
92 callback.Run(net::ERR_IO_PENDING, NULL); 122 callback.Run(net::ERR_IO_PENDING, NULL);
93 return; 123 return;
94 } else { 124 } else {
95 read_callback_ = callback; 125 read_callback_ = callback;
96 } 126 }
97 127
98 int result = net::ERR_FAILED; 128 int result = net::ERR_FAILED;
99 scoped_refptr<net::IOBuffer> io_buffer; 129 scoped_refptr<net::IOBuffer> io_buffer;
100 do { 130 do {
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
136 return false; 166 return false;
137 return socket_->SetKeepAlive(enable, delay); 167 return socket_->SetKeepAlive(enable, delay);
138 } 168 }
139 169
140 bool TCPSocket::SetNoDelay(bool no_delay) { 170 bool TCPSocket::SetNoDelay(bool no_delay) {
141 if (!socket_.get()) 171 if (!socket_.get())
142 return false; 172 return false;
143 return socket_->SetNoDelay(no_delay); 173 return socket_->SetNoDelay(no_delay);
144 } 174 }
145 175
176 int TCPSocket::Listen(const std::string& address, int port, int backlog,
177 std::string* error_msg) {
178 if (socket_mode_ == CLIENT) {
179 *error_msg = kTCPSocketTypeInvalidError;
180 return net::ERR_NOT_IMPLEMENTED;
181 }
182 DCHECK(!socket_.get());
183 socket_mode_ = SERVER;
184
185 scoped_ptr<net::IPEndPoint> bind_address(new net::IPEndPoint());
186 if (!StringAndPortToIPEndPoint(address, port, bind_address.get()))
187 return net::ERR_INVALID_ARGUMENT;
188
189 if (server_socket_.get()) {
190 *error_msg = kSocketRebindError;
191 return net::ERR_ADDRESS_IN_USE;
192 }
193 server_socket_.reset(new net::TCPServerSocket(NULL,
194 net::NetLog::Source()));
195 server_socket_->AllowAddressReuse();
196 int result = server_socket_->Listen(*bind_address, backlog);
197 if (result) {
198 *error_msg = kSocketListenError;
miket_OOO 2012/09/24 18:14:21 No braces.
justinlin 2012/09/26 08:59:59 Done.
199 }
200 return result;
201 }
202
203 void TCPSocket::Accept(const AcceptCompletionCallback &callback) {
204 if (socket_mode_ != SERVER || !server_socket_.get()) {
205 callback.Run(net::ERR_FAILED, NULL);
206 return;
207 }
208
209 // Limits to only 1 blocked accept call.
210 if (!accept_callback_.is_null()) {
211 callback.Run(net::ERR_FAILED, NULL);
212 return;
213 }
214
215 int result = server_socket_->Accept(&accept_socket_, base::Bind(
216 &TCPSocket::OnAccept, base::Unretained(this)));
miket_OOO 2012/09/24 18:14:21 This indentation is nonstandard.
justinlin 2012/09/26 08:59:59 Done.
217 if (result == net::ERR_IO_PENDING) {
218 accept_callback_ = callback;
219 return;
miket_OOO 2012/09/24 18:14:21 Are the returns necessary?
justinlin 2012/09/26 08:59:59 Done.
220 } else if (result == net::OK) {
221 accept_callback_ = callback;
222 this->OnAccept(result);
223 return;
224 } else {
225 callback.Run(result, NULL);
226 return;
227 }
228 }
229
146 bool TCPSocket::GetPeerAddress(net::IPEndPoint* address) { 230 bool TCPSocket::GetPeerAddress(net::IPEndPoint* address) {
147 if (!socket_.get()) 231 if (!socket_.get())
148 return false; 232 return false;
149 return !socket_->GetPeerAddress(address); 233 return !socket_->GetPeerAddress(address);
150 } 234 }
151 235
152 bool TCPSocket::GetLocalAddress(net::IPEndPoint* address) { 236 bool TCPSocket::GetLocalAddress(net::IPEndPoint* address) {
153 if (!socket_.get()) 237 if (socket_.get()) {
238 return !socket_->GetLocalAddress(address);
239 } else if (server_socket_.get()) {
240 return !server_socket_->GetLocalAddress(address);
241 } else {
154 return false; 242 return false;
155 return !socket_->GetLocalAddress(address); 243 }
156 } 244 }
157 245
158 Socket::SocketType TCPSocket::GetSocketType() const { 246 Socket::SocketType TCPSocket::GetSocketType() const {
159 return Socket::TYPE_TCP; 247 return Socket::TYPE_TCP;
160 } 248 }
161 249
162 int TCPSocket::WriteImpl(net::IOBuffer* io_buffer, 250 int TCPSocket::WriteImpl(net::IOBuffer* io_buffer,
163 int io_buffer_size, 251 int io_buffer_size,
164 const net::CompletionCallback& callback) { 252 const net::CompletionCallback& callback) {
165 if (!socket_.get() || !socket_->IsConnected()) 253 if (socket_mode_ != CLIENT)
miket_OOO 2012/09/24 18:14:21 If this can actually happen (i.e., an application
justinlin 2012/09/26 08:59:59 This is actually tricky. I think to do this, we wo
254 return net::ERR_FAILED;
255 else if (!socket_.get() || !socket_->IsConnected())
166 return net::ERR_SOCKET_NOT_CONNECTED; 256 return net::ERR_SOCKET_NOT_CONNECTED;
167 else 257 else
168 return socket_->Write(io_buffer, io_buffer_size, callback); 258 return socket_->Write(io_buffer, io_buffer_size, callback);
169 } 259 }
170 260
171 void TCPSocket::OnConnectComplete(int result) { 261 void TCPSocket::OnConnectComplete(int result) {
172 DCHECK(!connect_callback_.is_null()); 262 DCHECK(!connect_callback_.is_null());
173 DCHECK(!is_connected_); 263 DCHECK(!is_connected_);
174 is_connected_ = result == net::OK; 264 is_connected_ = result == net::OK;
175 connect_callback_.Run(result); 265 connect_callback_.Run(result);
176 connect_callback_.Reset(); 266 connect_callback_.Reset();
177 } 267 }
178 268
179 void TCPSocket::OnReadComplete(scoped_refptr<net::IOBuffer> io_buffer, 269 void TCPSocket::OnReadComplete(scoped_refptr<net::IOBuffer> io_buffer,
180 int result) { 270 int result) {
181 DCHECK(!read_callback_.is_null()); 271 DCHECK(!read_callback_.is_null());
182 read_callback_.Run(result, io_buffer); 272 read_callback_.Run(result, io_buffer);
183 read_callback_.Reset(); 273 read_callback_.Reset();
184 } 274 }
185 275
276 void TCPSocket::OnAccept(int result) {
277 DCHECK(!accept_callback_.is_null());
278 if (result == net::OK) {
279 DCHECK(accept_socket_.get() != NULL);
280
281 accept_callback_.Run(
282 result, static_cast<net::TCPClientSocket*>(accept_socket_.release()));
283 } else {
284 accept_callback_.Run(result, NULL);
285 }
286 accept_callback_.Reset();
287 }
288
186 } // namespace extensions 289 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698