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

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: Created 8 years, 4 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 TCPSocket::TCPSocket(ApiResourceEventNotifier* event_notifier) 17 TCPSocket::TCPSocket(ApiResourceEventNotifier* event_notifier)
18 : Socket(event_notifier) { 18 : Socket(event_notifier),
19 is_client_socket_(false),
20 is_server_socket_(false) {
21 }
22
23 TCPSocket::TCPSocket(ApiResourceEventNotifier* event_notifier,
24 net::TCPClientSocket* client_socket)
25 : Socket(event_notifier),
26 socket_(client_socket),
27 is_client_socket_(true),
28 is_server_socket_(false) {
29 this->is_connected_ = true;
19 } 30 }
20 31
21 // For testing. 32 // For testing.
22 TCPSocket::TCPSocket(net::TCPClientSocket* tcp_client_socket, 33 TCPSocket::TCPSocket(net::TCPClientSocket* tcp_client_socket,
23 ApiResourceEventNotifier* event_notifier) 34 ApiResourceEventNotifier* event_notifier)
24 : Socket(event_notifier), 35 : Socket(event_notifier),
25 socket_(tcp_client_socket) { 36 socket_(tcp_client_socket),
37 is_client_socket_(false),
38 is_server_socket_(false) {
26 } 39 }
27 40
28 // static 41 // static
29 TCPSocket* TCPSocket::CreateSocketForTesting( 42 TCPSocket* TCPSocket::CreateSocketForTesting(
30 net::TCPClientSocket* tcp_client_socket, 43 net::TCPClientSocket* tcp_client_socket,
31 ApiResourceEventNotifier* event_notifier) { 44 ApiResourceEventNotifier* event_notifier) {
32 return new TCPSocket(tcp_client_socket, event_notifier); 45 return new TCPSocket(tcp_client_socket, event_notifier);
33 } 46 }
34 47
35 TCPSocket::~TCPSocket() { 48 TCPSocket::~TCPSocket() {
36 if (is_connected_) { 49 if (is_connected_) {
37 Disconnect(); 50 Disconnect();
38 } 51 }
39 } 52 }
40 53
41 void TCPSocket::Connect(const std::string& address, 54 void TCPSocket::Connect(const std::string& address,
42 int port, 55 int port,
43 const CompletionCallback& callback) { 56 const CompletionCallback& callback) {
44 DCHECK(!callback.is_null()); 57 DCHECK(!callback.is_null());
45 58
46 if (!connect_callback_.is_null()) { 59 if (!connect_callback_.is_null() || is_server_socket_) {
47 callback.Run(net::ERR_CONNECTION_FAILED); 60 callback.Run(net::ERR_CONNECTION_FAILED);
48 return; 61 return;
49 } 62 }
63 DCHECK(server_socket_.get() == NULL);
64 is_client_socket_ = true;
50 connect_callback_ = callback; 65 connect_callback_ = callback;
66 // TODO(justinlin): I think this should destroy any previously connected
67 // socket, otherwise we might run into binding issues.
51 68
52 int result = net::ERR_CONNECTION_FAILED; 69 int result = net::ERR_CONNECTION_FAILED;
53 do { 70 do {
54 if (is_connected_) 71 if (is_connected_)
55 break; 72 break;
56 73
57 net::AddressList address_list; 74 net::AddressList address_list;
58 if (!StringAndPortToAddressList(address, port, &address_list)) { 75 if (!StringAndPortToAddressList(address, port, &address_list)) {
59 result = net::ERR_ADDRESS_INVALID; 76 result = net::ERR_ADDRESS_INVALID;
60 break; 77 break;
61 } 78 }
62 79
63 socket_.reset(new net::TCPClientSocket(address_list, NULL, 80 socket_.reset(new net::TCPClientSocket(address_list, NULL,
64 net::NetLog::Source())); 81 net::NetLog::Source()));
82
83 if (bind_address_.get() != NULL) {
84 if (socket_->Bind(*bind_address_) != 0) {
85 socket_.reset();
86 OnConnectComplete(net::ERR_ADDRESS_IN_USE);
87 return;
88 };
89 }
90
65 connect_callback_ = callback; 91 connect_callback_ = callback;
66 result = socket_->Connect(base::Bind( 92 result = socket_->Connect(base::Bind(
67 &TCPSocket::OnConnectComplete, base::Unretained(this))); 93 &TCPSocket::OnConnectComplete, base::Unretained(this)));
68 } while (false); 94 } while (false);
69 95
70 if (result != net::ERR_IO_PENDING) 96 if (result != net::ERR_IO_PENDING)
71 OnConnectComplete(result); 97 OnConnectComplete(result);
72 } 98 }
73 99
74 void TCPSocket::Disconnect() { 100 void TCPSocket::Disconnect() {
75 is_connected_ = false; 101 is_connected_ = false;
76 socket_->Disconnect(); 102 socket_->Disconnect();
77 } 103 }
78 104
79 int TCPSocket::Bind(const std::string& address, int port) { 105 int TCPSocket::Bind(const std::string& address, int port) {
80 // TODO(penghuang): Supports bind for tcp? 106 // TODO(justinlin): Allow binding to multiple interfaces?
81 return net::ERR_FAILED; 107 if (bind_address_.get() != NULL) {
108 return net::ERR_FAILED;
109 }
110
111 scoped_ptr<net::IPEndPoint> ip_end_point(new net::IPEndPoint());
112 if (!StringAndPortToIPEndPoint(address, port, ip_end_point.get()))
113 return net::ERR_INVALID_ARGUMENT;
114
115 bind_address_.swap(ip_end_point);
116 return true;
82 } 117 }
83 118
84 void TCPSocket::Read(int count, 119 void TCPSocket::Read(int count,
85 const ReadCompletionCallback& callback) { 120 const ReadCompletionCallback& callback) {
86 DCHECK(!callback.is_null()); 121 DCHECK(!callback.is_null());
87 122
123 if (!is_client_socket_) {
124 callback.Run(net::ERR_FAILED, NULL);
125 return;
126 }
127
88 if (!read_callback_.is_null()) { 128 if (!read_callback_.is_null()) {
89 callback.Run(net::ERR_IO_PENDING, NULL); 129 callback.Run(net::ERR_IO_PENDING, NULL);
90 return; 130 return;
91 } else { 131 } else {
92 read_callback_ = callback; 132 read_callback_ = callback;
93 } 133 }
94 134
95 int result = net::ERR_FAILED; 135 int result = net::ERR_FAILED;
96 scoped_refptr<net::IOBuffer> io_buffer; 136 scoped_refptr<net::IOBuffer> io_buffer;
97 do { 137 do {
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
133 return false; 173 return false;
134 return socket_->SetKeepAlive(enable, delay); 174 return socket_->SetKeepAlive(enable, delay);
135 } 175 }
136 176
137 bool TCPSocket::SetNoDelay(bool no_delay) { 177 bool TCPSocket::SetNoDelay(bool no_delay) {
138 if (!socket_.get()) 178 if (!socket_.get())
139 return false; 179 return false;
140 return socket_->SetNoDelay(no_delay); 180 return socket_->SetNoDelay(no_delay);
141 } 181 }
142 182
183 bool TCPSocket::Listen(int backlog) {
184 if (is_client_socket_) {
185 return false;
miket_OOO 2012/08/31 23:18:01 An error message would be nice.
justinlin 2012/09/11 04:32:32 Done.
186 }
187 DCHECK(socket_.get() == NULL);
188 is_server_socket_ = true;
189
190 if (bind_address_.get() == NULL) {
191 return net::ERR_FAILED;
192 }
193
194 server_socket_.reset(new net::TCPServerSocket(NULL,
195 net::NetLog::Source()));
196 return server_socket_->Listen(*bind_address_, backlog);
197 }
198
199 void TCPSocket::Accept(const AcceptCompletionCallback &callback) {
200 // This also makes it so you can't accept before listening, but that's
201 // probably OK?
202 if (!is_server_socket_ || server_socket_.get() == NULL) {
203 callback.Run(net::ERR_FAILED, NULL);
204 return;
205 }
206
207 // Limits to only 1 blocked accept call.
miket_OOO 2012/08/31 23:18:01 Should this be a TODO to allow multiple? (I'm not
justinlin 2012/09/11 04:32:32 Yea, the number of connections held in the queue i
208 if (!accept_callback_.is_null()) {
209 callback.Run(net::ERR_FAILED, NULL);
210 return;
211 }
212
213 int result = server_socket_->Accept(&accept_socket_, base::Bind(
214 &TCPSocket::OnAccept, base::Unretained(this)));
215 if (result == net::ERR_IO_PENDING) {
216 accept_callback_ = callback;
217 return;
218 } else if (result == net::OK) {
219 accept_callback_ = callback;
220 this->OnAccept(result);
221 return;
222 } else {
223 callback.Run(result, NULL);
224 return;
225 }
226 }
227
143 bool TCPSocket::IsTCPSocket() { 228 bool TCPSocket::IsTCPSocket() {
144 return true; 229 return true;
145 } 230 }
146 231
147 bool TCPSocket::GetPeerAddress(net::IPEndPoint* address) { 232 bool TCPSocket::GetPeerAddress(net::IPEndPoint* address) {
148 if (!socket_.get()) 233 if (!socket_.get())
149 return false; 234 return false;
150 return !socket_->GetPeerAddress(address); 235 return !socket_->GetPeerAddress(address);
151 } 236 }
152 237
153 bool TCPSocket::GetLocalAddress(net::IPEndPoint* address) { 238 bool TCPSocket::GetLocalAddress(net::IPEndPoint* address) {
154 if (!socket_.get()) 239 if (socket_.get() != NULL) {
240 return !socket_->GetLocalAddress(address);
241 } else if (server_socket_.get() != NULL) {
242 return !server_socket_->GetLocalAddress(address);
243 } else {
155 return false; 244 return false;
156 return !socket_->GetLocalAddress(address); 245 }
157 } 246 }
158 247
159 248
160 int TCPSocket::WriteImpl(net::IOBuffer* io_buffer, 249 int TCPSocket::WriteImpl(net::IOBuffer* io_buffer,
161 int io_buffer_size, 250 int io_buffer_size,
162 const net::CompletionCallback& callback) { 251 const net::CompletionCallback& callback) {
163 if (!socket_.get() || !socket_->IsConnected()) 252 if (!is_client_socket_) {
253 return net::ERR_FAILED;
254 } else if (!socket_.get() || !socket_->IsConnected())
164 return net::ERR_SOCKET_NOT_CONNECTED; 255 return net::ERR_SOCKET_NOT_CONNECTED;
165 else 256 else
166 return socket_->Write(io_buffer, io_buffer_size, callback); 257 return socket_->Write(io_buffer, io_buffer_size, callback);
167 } 258 }
168 259
169 void TCPSocket::OnConnectComplete(int result) { 260 void TCPSocket::OnConnectComplete(int result) {
170 DCHECK(!connect_callback_.is_null()); 261 DCHECK(!connect_callback_.is_null());
171 DCHECK(!is_connected_); 262 DCHECK(!is_connected_);
172 is_connected_ = result == net::OK; 263 is_connected_ = result == net::OK;
173 connect_callback_.Run(result); 264 connect_callback_.Run(result);
174 connect_callback_.Reset(); 265 connect_callback_.Reset();
175 } 266 }
176 267
177 void TCPSocket::OnReadComplete(scoped_refptr<net::IOBuffer> io_buffer, 268 void TCPSocket::OnReadComplete(scoped_refptr<net::IOBuffer> io_buffer,
178 int result) { 269 int result) {
179 DCHECK(!read_callback_.is_null()); 270 DCHECK(!read_callback_.is_null());
180 read_callback_.Run(result, io_buffer); 271 read_callback_.Run(result, io_buffer);
181 read_callback_.Reset(); 272 read_callback_.Reset();
182 } 273 }
183 274
275 void TCPSocket::OnAccept(int result) {
276 DCHECK(!accept_callback_.is_null());
277 if (result == net::OK) {
278 DCHECK(accept_socket_.get() != NULL);
279
280 accept_callback_.Run(
281 result, static_cast<net::TCPClientSocket*>(accept_socket_.release()));
282 } else {
283 accept_callback_.Run(result, NULL);
284 }
285 accept_callback_.Reset();
286 }
287
184 } // namespace extensions 288 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698