blob: e897b1cbe00a3a09e7e3798937211dc9991af10a [file] [log] [blame]
Eric Shienbrood3e20a232012-02-16 11:35:56 -05001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Paul Stewartf65320c2011-10-13 14:34:52 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "shill/async_connection.h"
6
Eric Shienbrood3e20a232012-02-16 11:35:56 -05007#include <base/bind.h>
Paul Stewartf65320c2011-10-13 14:34:52 -07008#include <errno.h>
9#include <netinet/in.h>
10
11#include <string>
12
13#include "shill/event_dispatcher.h"
14#include "shill/ip_address.h"
15#include "shill/sockets.h"
16
Eric Shienbrood3e20a232012-02-16 11:35:56 -050017using base::Bind;
18using base::Callback;
19using base::Unretained;
Paul Stewartf65320c2011-10-13 14:34:52 -070020using std::string;
21
22namespace shill {
23
24AsyncConnection::AsyncConnection(const string &interface_name,
25 EventDispatcher *dispatcher,
26 Sockets *sockets,
Eric Shienbrood3e20a232012-02-16 11:35:56 -050027 const Callback<void(bool, int)> &callback)
Paul Stewartf65320c2011-10-13 14:34:52 -070028 : interface_name_(interface_name),
29 dispatcher_(dispatcher),
30 sockets_(sockets),
31 callback_(callback),
32 fd_(-1),
33 connect_completion_callback_(
Eric Shienbrood3e20a232012-02-16 11:35:56 -050034 Bind(&AsyncConnection::OnConnectCompletion, Unretained(this))) { }
Paul Stewartf65320c2011-10-13 14:34:52 -070035
36AsyncConnection::~AsyncConnection() {
37 Stop();
38}
39
40bool AsyncConnection::Start(const IPAddress &address, int port) {
41 DCHECK(fd_ < 0);
42
43 fd_ = sockets_->Socket(PF_INET, SOCK_STREAM, 0);
44 if (fd_ < 0 ||
45 sockets_->SetNonBlocking(fd_) < 0) {
46 error_ = sockets_->ErrorString();
47 PLOG(ERROR) << "Async socket setup failed";
48 Stop();
49 return false;
50 }
51
52 if (!interface_name_.empty() &&
53 sockets_->BindToDevice(fd_, interface_name_) < 0) {
54 error_ = sockets_->ErrorString();
55 PLOG(ERROR) << "Async socket failed to bind to device";
56 Stop();
57 return false;
58 }
59
60 struct sockaddr_in iaddr;
61 CHECK_EQ(sizeof(iaddr.sin_addr.s_addr), address.GetLength());
62
63 memset(&iaddr, 0, sizeof(iaddr));
64 iaddr.sin_family = AF_INET;
65 memcpy(&iaddr.sin_addr.s_addr, address.address().GetConstData(),
66 sizeof(iaddr.sin_addr.s_addr));
67 iaddr.sin_port = htons(port);
68
69 socklen_t addrlen = sizeof(iaddr);
70 int ret = sockets_->Connect(fd_,
71 reinterpret_cast<struct sockaddr *>(&iaddr),
72 addrlen);
73 if (ret == 0) {
Eric Shienbrood3e20a232012-02-16 11:35:56 -050074 callback_.Run(true, fd_); // Passes ownership
Paul Stewartf65320c2011-10-13 14:34:52 -070075 fd_ = -1;
76 return true;
77 }
78
79 if (sockets_->Error() != EINPROGRESS) {
80 error_ = sockets_->ErrorString();
81 PLOG(ERROR) << "Async socket connection failed";
82 Stop();
83 return false;
84 }
85
86 connect_completion_handler_.reset(
87 dispatcher_->CreateReadyHandler(fd_,
88 IOHandler::kModeOutput,
Eric Shienbrood3e20a232012-02-16 11:35:56 -050089 connect_completion_callback_));
Paul Stewartf65320c2011-10-13 14:34:52 -070090 error_ = string();
91
92 return true;
93}
94
95void AsyncConnection::Stop() {
96 connect_completion_handler_.reset();
97 if (fd_ >= 0) {
98 sockets_->Close(fd_);
99 fd_ = -1;
100 }
101}
102
103void AsyncConnection::OnConnectCompletion(int fd) {
104 CHECK_EQ(fd_, fd);
105
106 if (sockets_->GetSocketError(fd_) != 0) {
107 error_ = sockets_->ErrorString();
108 PLOG(ERROR) << "Async GetSocketError returns failure";
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500109 callback_.Run(false, -1);
Paul Stewartf65320c2011-10-13 14:34:52 -0700110 } else {
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500111 callback_.Run(true, fd_); // Passes ownership
Paul Stewartf65320c2011-10-13 14:34:52 -0700112 fd_ = -1;
113 }
114 Stop();
115}
116
117} // namespace shill