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

Side by Side Diff: net/socket/sctp_client_socket_libevent.cc

Issue 6800009: Attn: Mike Belshe Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: Created 9 years, 8 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
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // Copyright (c) 2011 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 "net/socket/sctp_client_socket.h"
6 #include "net/socket/sctp_support.h"
7
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <netdb.h>
11 #include <sys/socket.h>
12 #include <sys/types.h>
13 #include <netinet/sctp.h>
14 #include <netinet/tcp.h>
15 #if defined(OS_POSIX)
16 #include <netinet/in.h>
17 #include <arpa/inet.h>
18 #endif
19
20 #include "base/eintr_wrapper.h"
21 #include "base/logging.h"
22 #include "base/message_loop.h"
23 #include "base/metrics/stats_counters.h"
24 #include "base/string_util.h"
25 #include "net/base/address_list_net_log_param.h"
26 #include "net/base/connection_type_histograms.h"
27 #include "net/base/io_buffer.h"
28 #include "net/base/net_errors.h"
29 #include "net/base/net_log.h"
30 #include "net/base/net_util.h"
31 #include "net/base/network_change_notifier.h"
32 #if defined(USE_SYSTEM_LIBEVENT)
33 #include <event.h>
34 #else
35 #include "third_party/libevent/event.h"
36 #endif
37
38 namespace net {
39
40 namespace {
41
42 const int kInvalidSocket = -1;
43
44 // These values need to be reviewed and set based on experimental results.
45 // TODO(jtl): Need to come up with a rationale for choosing this value.
46 const int kSctpMaxBurst = 4096; // Arbitrary value, but high enough so
47 // that maxburst has no effect.
48 const uint16 kNumberOfSctpStreamsToRequest = 50;
49
50 // DisableNagle turns off buffering in the kernel. By default, SCTP sockets will
51 // wait up to 200ms for more data to complete a packet before transmitting.
52 // After calling this function, the kernel will not wait. See SCTP_NODELAY in
53 // `man 7 sctp`.
54 void DisableNagle(int fd) {
55 int on = 1;
56 if (setsockopt(fd, IPPROTO_SCTP, SCTP_NODELAY, &on, sizeof(on)) < 0)
57 PLOG(ERROR) << "Failed to set SCTP_NODELAY on fd: " << fd;
58 return;
59 }
60
61 // This is SCTP's equivalent to TCP's keepalive interval
62 void SetSCTPHeartbeatInterval(int fd) {
63 struct sctp_paddrparams params;
64 socklen_t params_len = sizeof(params);
65 memset(&params, 0, params_len);
66 if (getsockopt(fd, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, &params,
67 &params_len)) {
68 PLOG(ERROR) << "Failed to get SCTP_PEER_ADDR_PARAMS on fd: " << fd;
69 return;
70 }
71 // Increase hearbeat interval to 45 seconds.
72 params.spp_hbinterval = 45000;
73 if (setsockopt(fd, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, &params,
74 params_len)) {
75 PLOG(ERROR) << "Failed to set SCTP_PEER_ADDR_PARAMS on fd: " << fd;
76 return;
77 }
78 return;
79 }
80
81 void SetSCTPMaxBurst(int fd) {
82 int maxburst = kSctpMaxBurst;
83 socklen_t maxburst_len = sizeof(maxburst);
84 if (setsockopt(fd, IPPROTO_SCTP, SCTP_MAX_BURST, &maxburst,
85 maxburst_len) < 0) {
86 PLOG(ERROR) << "Failed to set SCTP_MAX_BURST on fd: " << fd << "\n";
87 }
88 return;
89 }
90
91 // Set number of outgoing SCTP streams to request
92 void SetSCTPInitMsg(int fd) {
Mike Belshe 2011/04/06 18:32:53 I would rename to "SetSCTPInitialStreams"
93 struct sctp_initmsg initmsg;
94 socklen_t initmsg_len = sizeof(initmsg);
95 memset(&initmsg, 0, initmsg_len);
96 if (getsockopt(fd, IPPROTO_SCTP, SCTP_INITMSG, &initmsg, &initmsg_len) < 0) {
97 PLOG(ERROR) << "Failed to get SCTP_INITMSG on fd:" << fd << "\n";
98 return;
99 }
100 initmsg.sinit_num_ostreams = kNumberOfSctpStreamsToRequest;
101 initmsg_len = sizeof(initmsg);
102 if (setsockopt(fd, IPPROTO_SCTP, SCTP_INITMSG, &initmsg, initmsg_len) < 0)
103 PLOG(ERROR) << "Failed to set SCTP_INITMSG on fd:" << fd << "\n";
104
Mike Belshe 2011/04/06 18:32:53 nit: remove lines 104/105
105 return;
106 }
107
108 // Convert values from <errno.h> to values from "net/base/net_errors.h"
109 int MapPosixError(int os_error) {
110 // There are numerous posix error codes, but these are the ones we thus far
111 // find interesting.
112 switch (os_error) {
113 case EAGAIN:
114 #if EWOULDBLOCK != EAGAIN
115 case EWOULDBLOCK:
116 #endif
117 return ERR_IO_PENDING;
118 case EACCES:
119 return ERR_ACCESS_DENIED;
120 case ENETDOWN:
121 return ERR_INTERNET_DISCONNECTED;
122 case ETIMEDOUT:
123 return ERR_TIMED_OUT;
124 case ECONNRESET:
125 case ENETRESET: // Related to keep-alive
126 case EPIPE:
127 return ERR_CONNECTION_RESET;
128 case ECONNABORTED:
129 return ERR_CONNECTION_ABORTED;
130 case ECONNREFUSED:
131 return ERR_CONNECTION_REFUSED;
132 case EHOSTUNREACH:
133 case EHOSTDOWN:
134 case ENETUNREACH:
135 return ERR_ADDRESS_UNREACHABLE;
136 case EADDRNOTAVAIL:
137 return ERR_ADDRESS_INVALID;
138 case 0:
139 return OK;
140 default:
141 LOG(WARNING) << "Unknown error " << os_error
142 << " mapped to net::ERR_FAILED";
143 return ERR_FAILED;
144 }
145 }
146
147 int MapConnectError(int os_error) {
148 switch (os_error) {
149 case EACCES:
150 return ERR_NETWORK_ACCESS_DENIED;
151 case ETIMEDOUT:
152 return ERR_CONNECTION_TIMED_OUT;
153 default: {
154 int net_error = MapPosixError(os_error);
155 if (net_error == ERR_FAILED)
156 return ERR_CONNECTION_FAILED; // More specific than ERR_FAILED.
157
158 // Give a more specific error when the user is offline.
159 if (net_error == ERR_ADDRESS_UNREACHABLE &&
160 NetworkChangeNotifier::IsOffline()) {
161 return ERR_INTERNET_DISCONNECTED;
162 }
163 return net_error;
164 }
165 }
166 }
167
168 } // namespace
169
170 //-----------------------------------------------------------------------------
171
172 SCTPClientSocketLibevent::SCTPClientSocketLibevent(
173 const AddressList& addresses,
174 net::NetLog* net_log,
175 const net::NetLog::Source& source)
176 : socket_(kInvalidSocket),
177 addresses_(addresses),
178 current_ai_(NULL),
179 using_sctp_control_stream_(sctp_control_stream_enabled()),
180 max_sctp_streams_(0),
181 read_watcher_(this),
Mike Belshe 2011/04/06 18:32:53 nit: missed read_buf_len_(0) write_buf_len_(0
182 write_watcher_(this),
183 read_callback_(NULL),
184 write_callback_(NULL),
185 next_connect_state_(CONNECT_STATE_NONE),
186 connect_os_error_(0),
187 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)),
188 previously_disconnected_(false) {
189 scoped_refptr<NetLog::EventParameters> params;
190 if (source.is_valid())
191 params = new NetLogSourceParameter("source_dependency", source);
192 net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE, params);
193 }
194
195 SCTPClientSocketLibevent::~SCTPClientSocketLibevent() {
196 Disconnect();
197 net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE, NULL);
198 }
199
200 void SCTPClientSocketLibevent::AdoptSocket(int socket) {
201 DCHECK_EQ(socket_, kInvalidSocket);
202 socket_ = socket;
203 int error = SetupSocket();
204 DCHECK_EQ(0, error);
205 // This is to make GetPeerAddress work. It's up to the test that is calling
206 // this function to ensure that address_ contains a reasonable address for
207 // this socket. (i.e. at least match IPv4 vs IPv6!).
208 current_ai_ = addresses_.head();
209 use_history_.set_was_ever_connected();
210 }
211
212 int SCTPClientSocketLibevent::Connect(CompletionCallback* callback) {
213 DCHECK(CalledOnValidThread());
214
215 // If already connected, then just return OK.
216 if (socket_ != kInvalidSocket)
217 return OK;
218
219 static base::StatsCounter connects("sctp.connect");
220 connects.Increment();
221
222 DCHECK(!waiting_connect());
223
224 net_log_.BeginEvent(
225 NetLog::TYPE_SCTP_CONNECT,
226 make_scoped_refptr(new AddressListNetLogParam(addresses_)));
227
228 // We will try to connect to each address in addresses_. Start with the
229 // first one in the list.
230 next_connect_state_ = CONNECT_STATE_CONNECT;
231 current_ai_ = addresses_.head();
232
233 int rv = DoConnectLoop(OK);
234 if (rv == ERR_IO_PENDING) {
235 // Synchronous operation not supported.
236 DCHECK(callback);
237 write_callback_ = callback;
238 } else {
239 LogConnectCompletion(rv);
240 }
241
242 return rv;
243 }
244
245 int SCTPClientSocketLibevent::DoConnectLoop(int result) {
246 DCHECK_NE(next_connect_state_, CONNECT_STATE_NONE);
247
248 int rv = result;
249 do {
250 ConnectState state = next_connect_state_;
251 next_connect_state_ = CONNECT_STATE_NONE;
252 switch (state) {
253 case CONNECT_STATE_CONNECT:
254 DCHECK_EQ(OK, rv);
255 rv = DoConnect();
256 break;
257 case CONNECT_STATE_CONNECT_COMPLETE:
258 rv = DoConnectComplete(rv);
259 break;
260 default:
261 LOG(DFATAL) << "bad state";
262 rv = ERR_UNEXPECTED;
263 break;
264 }
265 } while (rv != ERR_IO_PENDING && next_connect_state_ != CONNECT_STATE_NONE);
266
267 return rv;
268 }
269
270 int SCTPClientSocketLibevent::DoConnect() {
271 DCHECK(current_ai_);
272
273 DCHECK_EQ(0, connect_os_error_);
274
275 if (previously_disconnected_) {
276 use_history_.Reset();
277 previously_disconnected_ = false;
278 }
279
280 net_log_.BeginEvent(NetLog::TYPE_SCTP_CONNECT_ATTEMPT,
281 make_scoped_refptr(new NetLogStringParameter(
282 "address", NetAddressToStringWithPort(current_ai_))));
283
284 next_connect_state_ = CONNECT_STATE_CONNECT_COMPLETE;
285
286 // Create a non-blocking socket.
287 connect_os_error_ = CreateSocket(current_ai_);
288 if (connect_os_error_)
289 return MapPosixError(connect_os_error_);
290
291 // Connect the socket.
292 if (!HANDLE_EINTR(connect(socket_, current_ai_->ai_addr,
293 static_cast<int>(current_ai_->ai_addrlen)))) {
294 // Connected without waiting!
295 return OK;
296 }
297
298 // Check if the connect() failed synchronously.
299 connect_os_error_ = errno;
300 if (connect_os_error_ != EINPROGRESS)
301 return MapConnectError(connect_os_error_);
302
303 // Otherwise the connect() is going to complete asynchronously, so watch
304 // for its completion.
305 if (!MessageLoopForIO::current()->WatchFileDescriptor(
306 socket_, true, MessageLoopForIO::WATCH_WRITE, &write_socket_watcher_,
307 &write_watcher_)) {
308 connect_os_error_ = errno;
309 DVLOG(1) << "WatchFileDescriptor failed: " << connect_os_error_;
310 return MapPosixError(connect_os_error_);
311 }
312
313 return ERR_IO_PENDING;
314 }
315
316 int SCTPClientSocketLibevent::DoConnectComplete(int result) {
317 // Log the end of this attempt (and any OS error it threw).
318 int os_error = connect_os_error_;
319 connect_os_error_ = 0;
320 scoped_refptr<NetLog::EventParameters> params;
321 if (result != OK)
322 params = new NetLogIntegerParameter("os_error", os_error);
323 net_log_.EndEvent(NetLog::TYPE_SCTP_CONNECT_ATTEMPT, params);
324
325 write_socket_watcher_.StopWatchingFileDescriptor();
326
327 if (result == OK) {
328 use_history_.set_was_ever_connected();
329
330 // Get number of allowable outgoing SCTP streams and set max_sctp_streams_.
331 struct sctp_status status;
332 socklen_t status_len = sizeof(status);
333 int rv;
334 memset(&status, 0, status_len);
335 rv = getsockopt(socket_, IPPROTO_SCTP, SCTP_STATUS, &status, &status_len);
336 if (rv < 0 )
Mike Belshe 2011/04/06 18:32:53 This must be a bug - missing curly braces, causes
337 LOG(ERROR) << "Unable to get status of SCTP socket.";
338 rv = ERR_UNEXPECTED;
339
340 if (status.sstat_state == SCTP_ESTABLISHED) {
341 max_sctp_streams_ = status.sstat_instrms <= status.sstat_outstrms ?
342 status.sstat_instrms : status.sstat_outstrms;
343 return OK; // Done!
344 } else if (status.sstat_state == SCTP_COOKIE_WAIT) {
345 // TODO(jtl): Need to figure out how and where to best handle this case.
346 // This is actually the prefered outcome because it potentially saves an
347 // RTT, and it can occur on FreeBSD and Mac OS X.
348 LOG(ERROR) << "Unable to set max_sctp_streams_ until association is "
349 << "established.";
350 rv = ERR_UNEXPECTED;
Mike Belshe 2011/04/06 18:32:53 the return value is |result| not |rv|, so these ar
351 } else {
352 LOG(ERROR) << "Unexpected association state " << status.sstat_state
353 << " on connecting socket " << socket_;
354 rv = ERR_UNEXPECTED;
355 }
356 }
357
358 // Close whatever partially connected socket we currently have.
359 DoDisconnect();
360
361 // Try to fall back to the next address in the list.
362 if (current_ai_->ai_next) {
363 next_connect_state_ = CONNECT_STATE_CONNECT;
364 current_ai_ = current_ai_->ai_next;
365 return OK;
366 }
367
368 // Otherwise there is nothing to fall back to, so give up.
369 return result;
370 }
371
372 void SCTPClientSocketLibevent::Disconnect() {
373 DCHECK(CalledOnValidThread());
374
375 DoDisconnect();
376 current_ai_ = NULL;
377 }
378
379 void SCTPClientSocketLibevent::DoDisconnect() {
380 if (socket_ == kInvalidSocket)
381 return;
382
383 bool ok = read_socket_watcher_.StopWatchingFileDescriptor();
384 DCHECK(ok);
385 ok = write_socket_watcher_.StopWatchingFileDescriptor();
386 DCHECK(ok);
387 if (HANDLE_EINTR(close(socket_)) < 0)
388 PLOG(ERROR) << "close";
389 socket_ = kInvalidSocket;
390 previously_disconnected_ = true;
391 }
392
393 bool SCTPClientSocketLibevent::IsConnected() const {
394 DCHECK(CalledOnValidThread());
395
396 if (socket_ == kInvalidSocket || waiting_connect())
397 return false;
398
399 // Check if connection is alive.
400 char c;
401 int rv = HANDLE_EINTR(recv(socket_, &c, 1, MSG_PEEK));
402 if (rv == 0)
403 return false;
404 if (rv == -1 && errno != EAGAIN && errno != EWOULDBLOCK)
405 return false;
406
407 return true;
408 }
409
410 bool SCTPClientSocketLibevent::IsConnectedAndIdle() const {
411 DCHECK(CalledOnValidThread());
412
413 if (socket_ == kInvalidSocket || waiting_connect())
414 return false;
415
416 // Check if connection is alive and we haven't received any data
417 // unexpectedly.
418 char c;
419 int rv = HANDLE_EINTR(recv(socket_, &c, 1, MSG_PEEK));
420 if (rv >= 0)
421 return false;
422 if (errno != EAGAIN && errno != EWOULDBLOCK)
423 return false;
424
425 return true;
426 }
427
428 uint16 SCTPClientSocketLibevent::MapSpdyToSctp(uint32 stream_id) {
429 DCHECK_GT(max_sctp_streams_, 0);
430
431 uint16 value = max_sctp_streams_;
432 if (!(stream_id & 0x00000001))
Mike Belshe 2011/04/06 18:32:53 What is this doing?
433 value -= 1;
434
435 return (stream_id - 1) % (value & 0xfffe) + 1;
436 }
437
438 int SCTPClientSocketLibevent::Read(IOBuffer* buf,
439 int buf_len,
440 CompletionCallback* callback) {
441 DCHECK(CalledOnValidThread());
442 DCHECK_NE(kInvalidSocket, socket_);
443 DCHECK(!waiting_connect());
444 DCHECK(!read_callback_);
445 // Synchronous operation not supported
446 DCHECK(callback);
447 DCHECK_GT(buf_len, 0);
448
449 int nread = HANDLE_EINTR(read(socket_, buf->data(), buf_len));
Mike Belshe 2011/04/06 18:32:53 I was surprised to see we didn't need to know the
450 if (nread >= 0) {
451 static base::StatsCounter read_bytes("sctp.read_bytes");
452 read_bytes.Add(nread);
453 if (nread > 0)
454 use_history_.set_was_used_to_convey_data();
455 LogByteTransfer(
456 net_log_, NetLog::TYPE_SOCKET_BYTES_RECEIVED, nread, buf->data());
457 return nread;
458 }
459 if (errno != EAGAIN && errno != EWOULDBLOCK) {
460 DVLOG(1) << "read failed, errno " << errno;
461 return MapPosixError(errno);
462 }
463
464 if (!MessageLoopForIO::current()->WatchFileDescriptor(
465 socket_, true, MessageLoopForIO::WATCH_READ,
466 &read_socket_watcher_, &read_watcher_)) {
467 DVLOG(1) << "WatchFileDescriptor failed on read, errno " << errno;
468 return MapPosixError(errno);
469 }
470
471 read_buf_ = buf;
472 read_buf_len_ = buf_len;
473 read_callback_ = callback;
474 return ERR_IO_PENDING;
475 }
476
477 int SCTPClientSocketLibevent::Write(IOBuffer* buf,
478 int buf_len,
479 CompletionCallback* callback) {
480 DCHECK(CalledOnValidThread());
481 DCHECK_NE(kInvalidSocket, socket_);
482 DCHECK(!waiting_connect());
483 DCHECK(!write_callback_);
484 // Synchronous operation not supported
485 DCHECK(callback);
486 DCHECK_GT(buf_len, 0);
487
488 int nwrite = InternalWrite(buf, buf_len);
489 if (nwrite >= 0) {
490 static base::StatsCounter write_bytes("sctp.write_bytes");
491 write_bytes.Add(nwrite);
492 if (nwrite > 0)
493 use_history_.set_was_used_to_convey_data();
494 LogByteTransfer(
495 net_log_, NetLog::TYPE_SOCKET_BYTES_SENT, nwrite, buf->data());
496 return nwrite;
497 }
498 if (errno != EAGAIN && errno != EWOULDBLOCK)
499 return MapPosixError(errno);
500
501 if (!MessageLoopForIO::current()->WatchFileDescriptor(
502 socket_, true, MessageLoopForIO::WATCH_WRITE,
503 &write_socket_watcher_, &write_watcher_)) {
504 DVLOG(1) << "WatchFileDescriptor failed on write, errno " << errno;
505 return MapPosixError(errno);
506 }
507
508 write_buf_ = buf;
509 write_buf_len_ = buf_len;
510 write_callback_ = callback;
511 return ERR_IO_PENDING;
512 }
513
514 int SCTPClientSocketLibevent::InternalWrite(IOBuffer* buf, int buf_len) {
515 return HANDLE_EINTR(sctp_sendmsg(socket_, buf->data(), buf_len,
516 NULL, 0, 0, 0, buf->sctp_stream_id(), 0, 0));
517 }
518
519 bool SCTPClientSocketLibevent::SetReceiveBufferSize(int32 size) {
520 DCHECK(CalledOnValidThread());
521 int rv = setsockopt(socket_, SOL_SOCKET, SO_RCVBUF,
522 reinterpret_cast<const char*>(&size),
523 sizeof(size));
524 DCHECK(!rv) << "Could not set socket receive buffer size: " << errno;
525 return rv == 0;
526 }
527
528 bool SCTPClientSocketLibevent::SetSendBufferSize(int32 size) {
529 DCHECK(CalledOnValidThread());
530 int rv = setsockopt(socket_, SOL_SOCKET, SO_SNDBUF,
531 reinterpret_cast<const char*>(&size),
532 sizeof(size));
533 DCHECK(!rv) << "Could not set socket send buffer size: " << errno;
534 return rv == 0;
535 }
536
537
538 int SCTPClientSocketLibevent::CreateSocket(const addrinfo* ai) {
539 socket_ = socket(ai->ai_family, ai->ai_socktype, IPPROTO_SCTP);
540 if (socket_ == kInvalidSocket)
541 return errno;
542 return SetupSocket();
543 }
544
545 int SCTPClientSocketLibevent::SetupSocket() {
546 // Linux SCTP has a bug which causes retransmissions to go to unconfirmed
547 // addresses. Since the default behaviour, when calling connect() with an
548 // unbound socket, is to bind the socket to all local addresses, the server
549 // may retransmit packets to some or all of these interfaces even if they are
550 // unreachable. One work around is to bind the socket to a single local
551 // address prior to calling connect(). An alternative is to use sctp_bindx()
552 // to bind only those addresses that are reachable.
553 // The bug exists in 2.6.31 and persists at least through 2.6.34. I do not
554 // know about earlier or later versions.
555 // TODO(jtl): Need to implement a way to select a single local IP address to
556 // bind to.
557 struct sockaddr_in sin;
558 sin.sin_family = AF_INET;
559 sin.sin_port = htons(0); // let system choose ephemeral port number
560 //inet_aton("127.0.0.1", &(sin.sin_addr));
Mike Belshe 2011/04/06 18:32:53 Wow - what a mess! Not sure what to do to make th
561 inet_aton("10.1.207.2", &(sin.sin_addr));
562 //inet_aton("128.4.30.27", &(sin.sin_addr));
563 if (bind(socket_, (struct sockaddr*) &sin, sizeof(sin)) < 0) {
564 const int bind_os_error_ = errno;
565 printf("SCTPClientSocketLibevent::SetupSocket: bind() failed with errno = "
566 "%d (%s)\n", errno, strerror(errno));
567 return bind_os_error_;
568 }
569
570 if (SetNonBlocking(socket_)) {
571 const int err = errno;
572 close(socket_);
573 socket_ = kInvalidSocket;
574 return err;
575 }
576
577 // This mirrors the behaviour on Windows. See the comment in
578 // tcp_client_socket_win.cc after searching for "NODELAY".
579 DisableNagle(socket_); // If DisableNagle fails, we don't care.
580
581 // Heartbeats are SCTP's equivalent to TCP's keepalive, and they're always on.
582 SetSCTPHeartbeatInterval(socket_);
583
584 // TODO(jtl): Make this a command line option.
585 // set max_burst
586 SetSCTPMaxBurst(socket_);
587
588 // Set the number of outgoing sctp streams to request.
589 SetSCTPInitMsg(socket_);
590 return 0;
591 }
592
593 void SCTPClientSocketLibevent::LogConnectCompletion(int net_error) {
594 if (net_error != OK) {
595 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_SCTP_CONNECT, net_error);
596 return;
597 }
598
599 struct sockaddr_storage source_address;
600 socklen_t addrlen = sizeof(source_address);
601 int rv = getsockname(
602 socket_, reinterpret_cast<struct sockaddr*>(&source_address), &addrlen);
603 if (rv != 0) {
604 PLOG(ERROR) << "getsockname() [rv: " << rv << "] error: ";
605 NOTREACHED();
606 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_SCTP_CONNECT, rv);
607 return;
608 }
609
610 const std::string source_address_str =
611 NetAddressToStringWithPort(
612 reinterpret_cast<const struct sockaddr*>(&source_address),
613 sizeof(source_address));
614 net_log_.EndEvent(NetLog::TYPE_SCTP_CONNECT,
615 make_scoped_refptr(new NetLogStringParameter(
616 "source address",
617 source_address_str)));
618 }
619
620 void SCTPClientSocketLibevent::DoReadCallback(int rv) {
621 DCHECK_NE(rv, ERR_IO_PENDING);
622 DCHECK(read_callback_);
623
624 // since Run may result in Read being called, clear read_callback_ up front.
625 CompletionCallback* c = read_callback_;
626 read_callback_ = NULL;
627 c->Run(rv);
628 }
629
630 void SCTPClientSocketLibevent::DoWriteCallback(int rv) {
631 DCHECK_NE(rv, ERR_IO_PENDING);
632 DCHECK(write_callback_);
633
634 // since Run may result in Write being called, clear write_callback_ up front.
635 CompletionCallback* c = write_callback_;
636 write_callback_ = NULL;
637 c->Run(rv);
638 }
639
640 void SCTPClientSocketLibevent::DidCompleteConnect() {
641 DCHECK_EQ(next_connect_state_, CONNECT_STATE_CONNECT_COMPLETE);
642
643 // Get the error that connect() completed with.
644 int os_error = 0;
645 socklen_t len = sizeof(os_error);
646 if (getsockopt(socket_, SOL_SOCKET, SO_ERROR, &os_error, &len) < 0)
647 os_error = errno;
648
649 // TODO(eroman): Is this check really necessary?
650 if (os_error == EINPROGRESS || os_error == EALREADY) {
651 NOTREACHED(); // This indicates a bug in libevent or our code.
652 return;
653 }
654
655 connect_os_error_ = os_error;
656 int rv = DoConnectLoop(MapConnectError(os_error));
657 if (rv != ERR_IO_PENDING) {
658 LogConnectCompletion(rv);
659 DoWriteCallback(rv);
660 }
661 }
662
663 void SCTPClientSocketLibevent::DidCompleteRead() {
664 int bytes_transferred;
665 bytes_transferred = HANDLE_EINTR(read(socket_, read_buf_->data(),
666 read_buf_len_));
667
668 int result;
669 if (bytes_transferred >= 0) {
670 result = bytes_transferred;
671 static base::StatsCounter read_bytes("sctp.read_bytes");
672 read_bytes.Add(bytes_transferred);
673 if (bytes_transferred > 0)
674 use_history_.set_was_used_to_convey_data();
675 LogByteTransfer(net_log_, NetLog::TYPE_SOCKET_BYTES_RECEIVED, result,
676 read_buf_->data());
677 } else {
678 result = MapPosixError(errno);
679 }
680
681 if (result != ERR_IO_PENDING) {
682 read_buf_ = NULL;
683 read_buf_len_ = 0;
684 bool ok = read_socket_watcher_.StopWatchingFileDescriptor();
685 DCHECK(ok);
686 DoReadCallback(result);
687 }
688 }
689
690 void SCTPClientSocketLibevent::DidCompleteWrite() {
691 int bytes_transferred;
692 // TODO(jtl): Need to fix this to use sctp_sendmsg and need to get SCTP stream
693 // ID. Perhaps use a form of IOBuffer that includes the SCTP stream ID?
694 bytes_transferred = HANDLE_EINTR(write(socket_, write_buf_->data(),
Mike Belshe 2011/04/06 18:32:53 i think this should be InternalWrite()?
695 write_buf_len_));
696
697 int result;
698 if (bytes_transferred >= 0) {
699 result = bytes_transferred;
700 static base::StatsCounter write_bytes("sctp.write_bytes");
701 write_bytes.Add(bytes_transferred);
702 if (bytes_transferred > 0)
703 use_history_.set_was_used_to_convey_data();
704 LogByteTransfer(net_log_, NetLog::TYPE_SOCKET_BYTES_SENT, result,
705 write_buf_->data());
706 } else {
707 result = MapPosixError(errno);
708 }
709
710 if (result != ERR_IO_PENDING) {
711 write_buf_ = NULL;
712 write_buf_len_ = 0;
713 write_socket_watcher_.StopWatchingFileDescriptor();
714 DoWriteCallback(result);
715 }
716 }
717
718 int SCTPClientSocketLibevent::GetPeerAddress(AddressList* address) const {
719 DCHECK(CalledOnValidThread());
720 DCHECK(address);
721 if (!IsConnected())
722 return ERR_SOCKET_NOT_CONNECTED;
723 address->Copy(current_ai_, false);
724 return OK;
725 }
726
727 const BoundNetLog& SCTPClientSocketLibevent::NetLog() const {
728 return net_log_;
729 }
730
731 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698