OLD | NEW |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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 "net/base/tcp_client_socket.h" | 5 #include "net/base/tcp_client_socket.h" |
6 | 6 |
7 #include <errno.h> | 7 #include <errno.h> |
8 #include <fcntl.h> | 8 #include <fcntl.h> |
9 #include <netdb.h> | 9 #include <netdb.h> |
10 #include <sys/socket.h> | 10 #include <sys/socket.h> |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
60 return ERR_FAILED; | 60 return ERR_FAILED; |
61 } | 61 } |
62 } | 62 } |
63 | 63 |
64 //----------------------------------------------------------------------------- | 64 //----------------------------------------------------------------------------- |
65 | 65 |
66 TCPClientSocket::TCPClientSocket(const AddressList& addresses) | 66 TCPClientSocket::TCPClientSocket(const AddressList& addresses) |
67 : socket_(kInvalidSocket), | 67 : socket_(kInvalidSocket), |
68 addresses_(addresses), | 68 addresses_(addresses), |
69 current_ai_(addresses_.head()), | 69 current_ai_(addresses_.head()), |
70 wait_state_(NOT_WAITING), | 70 waiting_connect_(false), |
71 event_(new event) { | 71 event_(new event), |
| 72 write_callback_(NULL), |
| 73 callback_(NULL) { |
72 } | 74 } |
73 | 75 |
74 TCPClientSocket::~TCPClientSocket() { | 76 TCPClientSocket::~TCPClientSocket() { |
75 Disconnect(); | 77 Disconnect(); |
76 } | 78 } |
77 | 79 |
78 int TCPClientSocket::Connect(CompletionCallback* callback) { | 80 int TCPClientSocket::Connect(CompletionCallback* callback) { |
79 // If already connected, then just return OK. | 81 // If already connected, then just return OK. |
80 if (socket_ != kInvalidSocket) | 82 if (socket_ != kInvalidSocket) |
81 return OK; | 83 return OK; |
82 | 84 |
83 DCHECK(wait_state_ == NOT_WAITING); | 85 DCHECK(!waiting_connect_); |
84 | 86 |
85 const addrinfo* ai = current_ai_; | 87 const addrinfo* ai = current_ai_; |
86 DCHECK(ai); | 88 DCHECK(ai); |
87 | 89 |
88 int rv = CreateSocket(ai); | 90 int rv = CreateSocket(ai); |
89 if (rv != OK) | 91 if (rv != OK) |
90 return rv; | 92 return rv; |
91 | 93 |
92 if (!connect(socket_, ai->ai_addr, static_cast<int>(ai->ai_addrlen))) { | 94 if (!connect(socket_, ai->ai_addr, static_cast<int>(ai->ai_addrlen))) { |
93 // Connected without waiting! | 95 // Connected without waiting! |
94 return OK; | 96 return OK; |
95 } | 97 } |
96 | 98 |
97 // Synchronous operation not supported | 99 // Synchronous operation not supported |
98 DCHECK(callback); | 100 DCHECK(callback); |
99 | 101 |
100 if (errno != EINPROGRESS) { | 102 if (errno != EINPROGRESS) { |
101 LOG(ERROR) << "connect failed: " << errno; | 103 DLOG(INFO) << "connect failed: " << errno; |
102 return MapPosixError(errno); | 104 return MapPosixError(errno); |
103 } | 105 } |
104 | 106 |
105 // Initialize event_ and link it to our MessagePump. | 107 // Initialize event_ and link it to our MessagePump. |
106 // POLLOUT is set if the connection is established. | 108 // POLLOUT is set if the connection is established. |
107 // POLLIN is set if the connection fails, | 109 // POLLIN is set if the connection fails, |
108 // so select for both read and write. | 110 // so select for both read and write. |
109 MessageLoopForIO::current()->WatchSocket( | 111 MessageLoopForIO::current()->WatchSocket( |
110 socket_, EV_READ|EV_WRITE|EV_PERSIST, event_.get(), this); | 112 socket_, EV_READ|EV_WRITE|EV_PERSIST, event_.get(), this); |
111 | 113 |
112 wait_state_ = WAITING_CONNECT; | 114 waiting_connect_ = true; |
113 callback_ = callback; | 115 callback_ = callback; |
114 return ERR_IO_PENDING; | 116 return ERR_IO_PENDING; |
115 } | 117 } |
116 | 118 |
117 int TCPClientSocket::ReconnectIgnoringLastError(CompletionCallback* callback) { | 119 int TCPClientSocket::ReconnectIgnoringLastError(CompletionCallback* callback) { |
118 // No ignorable errors! | 120 // No ignorable errors! |
119 return ERR_UNEXPECTED; | 121 return ERR_UNEXPECTED; |
120 } | 122 } |
121 | 123 |
122 void TCPClientSocket::Disconnect() { | 124 void TCPClientSocket::Disconnect() { |
123 if (socket_ == kInvalidSocket) | 125 if (socket_ == kInvalidSocket) |
124 return; | 126 return; |
125 | 127 |
126 MessageLoopForIO::current()->UnwatchSocket(event_.get()); | 128 MessageLoopForIO::current()->UnwatchSocket(event_.get()); |
127 close(socket_); | 129 close(socket_); |
128 socket_ = kInvalidSocket; | 130 socket_ = kInvalidSocket; |
| 131 waiting_connect_ = false; |
129 | 132 |
130 // Reset for next time. | 133 // Reset for next time. |
131 current_ai_ = addresses_.head(); | 134 current_ai_ = addresses_.head(); |
132 } | 135 } |
133 | 136 |
134 bool TCPClientSocket::IsConnected() const { | 137 bool TCPClientSocket::IsConnected() const { |
135 if (socket_ == kInvalidSocket || wait_state_ == WAITING_CONNECT) | 138 if (socket_ == kInvalidSocket || waiting_connect_) |
136 return false; | 139 return false; |
137 | 140 |
138 // Check if connection is alive. | 141 // Check if connection is alive. |
139 char c; | 142 char c; |
140 int rv = recv(socket_, &c, 1, MSG_PEEK); | 143 int rv = recv(socket_, &c, 1, MSG_PEEK); |
141 if (rv == 0) | 144 if (rv == 0) |
142 return false; | 145 return false; |
143 if (rv == -1 && errno != EAGAIN && errno != EWOULDBLOCK) | 146 if (rv == -1 && errno != EAGAIN && errno != EWOULDBLOCK) |
144 return false; | 147 return false; |
145 | 148 |
146 return true; | 149 return true; |
147 } | 150 } |
148 | 151 |
149 int TCPClientSocket::Read(char* buf, | 152 int TCPClientSocket::Read(char* buf, |
150 int buf_len, | 153 int buf_len, |
151 CompletionCallback* callback) { | 154 CompletionCallback* callback) { |
152 DCHECK(socket_ != kInvalidSocket); | 155 DCHECK(socket_ != kInvalidSocket); |
153 DCHECK(wait_state_ == NOT_WAITING); | 156 DCHECK(!waiting_connect_); |
154 DCHECK(!callback_); | 157 DCHECK(!callback_); |
155 // Synchronous operation not supported | 158 // Synchronous operation not supported |
156 DCHECK(callback); | 159 DCHECK(callback); |
157 DCHECK(buf_len > 0); | 160 DCHECK(buf_len > 0); |
158 | 161 |
159 int nread = read(socket_, buf, buf_len); | 162 int nread = read(socket_, buf, buf_len); |
160 if (nread >= 0) { | 163 if (nread >= 0) { |
161 return nread; | 164 return nread; |
162 } | 165 } |
163 if (errno != EAGAIN && errno != EWOULDBLOCK) | 166 if (errno != EAGAIN && errno != EWOULDBLOCK) { |
| 167 DLOG(INFO) << "read failed, errno " << errno; |
164 return MapPosixError(errno); | 168 return MapPosixError(errno); |
| 169 } |
165 | 170 |
166 MessageLoopForIO::current()->WatchSocket( | 171 MessageLoopForIO::current()->WatchSocket( |
167 socket_, EV_READ|EV_PERSIST, event_.get(), this); | 172 socket_, EV_READ|EV_PERSIST, event_.get(), this); |
168 | 173 |
169 buf_ = buf; | 174 buf_ = buf; |
170 buf_len_ = buf_len; | 175 buf_len_ = buf_len; |
171 wait_state_ = WAITING_READ; | |
172 callback_ = callback; | 176 callback_ = callback; |
173 return ERR_IO_PENDING; | 177 return ERR_IO_PENDING; |
174 } | 178 } |
175 | 179 |
176 int TCPClientSocket::Write(const char* buf, | 180 int TCPClientSocket::Write(const char* buf, |
177 int buf_len, | 181 int buf_len, |
178 CompletionCallback* callback) { | 182 CompletionCallback* callback) { |
179 DCHECK(socket_ != kInvalidSocket); | 183 DCHECK(socket_ != kInvalidSocket); |
180 DCHECK(wait_state_ == NOT_WAITING); | 184 DCHECK(!waiting_connect_); |
181 DCHECK(!callback_); | 185 DCHECK(!write_callback_); |
182 // Synchronous operation not supported | 186 // Synchronous operation not supported |
183 DCHECK(callback); | 187 DCHECK(callback); |
184 DCHECK(buf_len > 0); | 188 DCHECK(buf_len > 0); |
185 | 189 |
186 int nwrite = write(socket_, buf, buf_len); | 190 int nwrite = write(socket_, buf, buf_len); |
187 if (nwrite >= 0) { | 191 if (nwrite >= 0) { |
188 return nwrite; | 192 return nwrite; |
189 } | 193 } |
190 if (errno != EAGAIN && errno != EWOULDBLOCK) | 194 if (errno != EAGAIN && errno != EWOULDBLOCK) |
191 return MapPosixError(errno); | 195 return MapPosixError(errno); |
192 | 196 |
193 MessageLoopForIO::current()->WatchSocket( | 197 MessageLoopForIO::current()->WatchSocket( |
194 socket_, EV_WRITE|EV_PERSIST, event_.get(), this); | 198 socket_, EV_WRITE|EV_PERSIST, event_.get(), this); |
195 | 199 |
196 buf_ = const_cast<char*>(buf); | 200 write_buf_ = buf; |
197 buf_len_ = buf_len; | 201 write_buf_len_ = buf_len; |
198 wait_state_ = WAITING_WRITE; | 202 write_callback_ = callback; |
199 callback_ = callback; | |
200 return ERR_IO_PENDING; | 203 return ERR_IO_PENDING; |
201 } | 204 } |
202 | 205 |
203 int TCPClientSocket::CreateSocket(const addrinfo* ai) { | 206 int TCPClientSocket::CreateSocket(const addrinfo* ai) { |
204 socket_ = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); | 207 socket_ = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); |
205 if (socket_ == kInvalidSocket) | 208 if (socket_ == kInvalidSocket) |
206 return MapPosixError(errno); | 209 return MapPosixError(errno); |
207 | 210 |
208 // All our socket I/O is nonblocking | 211 // All our socket I/O is nonblocking |
209 if (SetNonBlocking(socket_)) | 212 if (SetNonBlocking(socket_)) |
210 return MapPosixError(errno); | 213 return MapPosixError(errno); |
211 | 214 |
212 return OK; | 215 return OK; |
213 } | 216 } |
214 | 217 |
215 void TCPClientSocket::DoCallback(int rv) { | 218 void TCPClientSocket::DoCallback(int rv) { |
216 DCHECK(rv != ERR_IO_PENDING); | 219 DCHECK(rv != ERR_IO_PENDING); |
217 DCHECK(callback_); | 220 DCHECK(callback_); |
218 | 221 |
219 // since Run may result in Read being called, clear callback_ up front. | 222 // since Run may result in Read being called, clear callback_ up front. |
220 CompletionCallback* c = callback_; | 223 CompletionCallback* c = callback_; |
221 callback_ = NULL; | 224 callback_ = NULL; |
222 c->Run(rv); | 225 c->Run(rv); |
223 } | 226 } |
224 | 227 |
| 228 void TCPClientSocket::DoWriteCallback(int rv) { |
| 229 DCHECK(rv != ERR_IO_PENDING); |
| 230 DCHECK(write_callback_); |
| 231 |
| 232 // since Run may result in Write being called, clear write_callback_ up front. |
| 233 CompletionCallback* c = write_callback_; |
| 234 write_callback_ = NULL; |
| 235 c->Run(rv); |
| 236 } |
| 237 |
225 void TCPClientSocket::DidCompleteConnect() { | 238 void TCPClientSocket::DidCompleteConnect() { |
226 int result = ERR_UNEXPECTED; | 239 int result = ERR_UNEXPECTED; |
227 | 240 |
228 wait_state_ = NOT_WAITING; | |
229 | |
230 // Check to see if connect succeeded | 241 // Check to see if connect succeeded |
231 int error_code = 0; | 242 int error_code = 0; |
232 socklen_t len = sizeof(error_code); | 243 socklen_t len = sizeof(error_code); |
233 if (getsockopt(socket_, SOL_SOCKET, SO_ERROR, &error_code, &len) < 0) | 244 if (getsockopt(socket_, SOL_SOCKET, SO_ERROR, &error_code, &len) < 0) |
234 error_code = errno; | 245 error_code = errno; |
235 | 246 |
236 if (error_code == EINPROGRESS || error_code == EALREADY) { | 247 if (error_code == EINPROGRESS || error_code == EALREADY) { |
237 NOTREACHED(); // This indicates a bug in libevent or our code. | 248 NOTREACHED(); // This indicates a bug in libevent or our code. |
238 result = ERR_IO_PENDING; | 249 result = ERR_IO_PENDING; |
239 wait_state_ = WAITING_CONNECT; // And await next callback. | |
240 } else if (current_ai_->ai_next && ( | 250 } else if (current_ai_->ai_next && ( |
241 error_code == EADDRNOTAVAIL || | 251 error_code == EADDRNOTAVAIL || |
242 error_code == EAFNOSUPPORT || | 252 error_code == EAFNOSUPPORT || |
243 error_code == ECONNREFUSED || | 253 error_code == ECONNREFUSED || |
244 error_code == ENETUNREACH || | 254 error_code == ENETUNREACH || |
245 error_code == EHOSTUNREACH || | 255 error_code == EHOSTUNREACH || |
246 error_code == ETIMEDOUT)) { | 256 error_code == ETIMEDOUT)) { |
247 // This address failed, try next one in list. | 257 // This address failed, try next one in list. |
248 const addrinfo* next = current_ai_->ai_next; | 258 const addrinfo* next = current_ai_->ai_next; |
249 Disconnect(); | 259 Disconnect(); |
250 current_ai_ = next; | 260 current_ai_ = next; |
251 result = Connect(callback_); | 261 result = Connect(callback_); |
252 } else { | 262 } else { |
253 result = MapPosixError(error_code); | 263 result = MapPosixError(error_code); |
254 MessageLoopForIO::current()->UnwatchSocket(event_.get()); | 264 MessageLoopForIO::current()->UnwatchSocket(event_.get()); |
| 265 waiting_connect_ = false; |
255 } | 266 } |
256 | 267 |
257 if (result != ERR_IO_PENDING) | 268 if (result != ERR_IO_PENDING) |
258 DoCallback(result); | 269 DoCallback(result); |
259 } | 270 } |
260 | 271 |
261 void TCPClientSocket::DidCompleteIO() { | 272 void TCPClientSocket::DidCompleteRead() { |
262 int bytes_transferred; | 273 int bytes_transferred; |
263 switch (wait_state_) { | 274 bytes_transferred = read(socket_, buf_, buf_len_); |
264 case WAITING_READ: | |
265 bytes_transferred = read(socket_, buf_, buf_len_); | |
266 break; | |
267 case WAITING_WRITE: | |
268 bytes_transferred = write(socket_, buf_, buf_len_); | |
269 break; | |
270 default: | |
271 NOTREACHED(); | |
272 return; | |
273 } | |
274 | 275 |
275 int result; | 276 int result; |
276 if (bytes_transferred >= 0) { | 277 if (bytes_transferred >= 0) { |
277 result = bytes_transferred; | 278 result = bytes_transferred; |
278 } else { | 279 } else { |
279 result = MapPosixError(errno); | 280 result = MapPosixError(errno); |
280 } | 281 } |
281 | 282 |
282 if (result != ERR_IO_PENDING) { | 283 if (result != ERR_IO_PENDING) { |
283 wait_state_ = NOT_WAITING; | 284 buf_ = NULL; |
| 285 buf_len_ = 0; |
284 MessageLoopForIO::current()->UnwatchSocket(event_.get()); | 286 MessageLoopForIO::current()->UnwatchSocket(event_.get()); |
285 DoCallback(result); | 287 DoCallback(result); |
286 } | 288 } |
287 } | 289 } |
288 | 290 |
| 291 void TCPClientSocket::DidCompleteWrite() { |
| 292 int bytes_transferred; |
| 293 bytes_transferred = write(socket_, write_buf_, write_buf_len_); |
| 294 |
| 295 int result; |
| 296 if (bytes_transferred >= 0) { |
| 297 result = bytes_transferred; |
| 298 } else { |
| 299 result = MapPosixError(errno); |
| 300 } |
| 301 |
| 302 if (result != ERR_IO_PENDING) { |
| 303 write_buf_ = NULL; |
| 304 write_buf_len_ = 0; |
| 305 MessageLoopForIO::current()->UnwatchSocket(event_.get()); |
| 306 DoWriteCallback(result); |
| 307 } |
| 308 } |
| 309 |
289 void TCPClientSocket::OnSocketReady(short flags) { | 310 void TCPClientSocket::OnSocketReady(short flags) { |
290 switch (wait_state_) { | 311 // the only used bits of flags are EV_READ and EV_WRITE |
291 case WAITING_CONNECT: | 312 |
292 DidCompleteConnect(); | 313 if (waiting_connect_) { |
293 break; | 314 DidCompleteConnect(); |
294 case WAITING_READ: | 315 } else { |
295 case WAITING_WRITE: | 316 if ((flags & EV_WRITE) && write_callback_) |
296 DidCompleteIO(); | 317 DidCompleteWrite(); |
297 break; | 318 if ((flags & EV_READ) && callback_) |
298 default: | 319 DidCompleteRead(); |
299 NOTREACHED(); | |
300 break; | |
301 } | 320 } |
302 } | 321 } |
303 | 322 |
| 323 int TCPClientSocket::GetPeerName(struct sockaddr *name, socklen_t *namelen) { |
| 324 return ::getpeername(socket_, name, namelen); |
| 325 } |
| 326 |
304 } // namespace net | 327 } // namespace net |
305 | 328 |
OLD | NEW |