blob: 63530ec7f661fdbd85798e2db66dfbe9b4385c56 [file] [log] [blame]
Paul Stewartf65320c2011-10-13 14:34:52 -07001// Copyright (c) 2011 The Chromium OS 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 "shill/async_connection.h"
6
7#include <errno.h>
8#include <netinet/in.h>
9
10#include <string>
11
12#include "shill/event_dispatcher.h"
13#include "shill/ip_address.h"
14#include "shill/sockets.h"
15
16using std::string;
17
18namespace shill {
19
20AsyncConnection::AsyncConnection(const string &interface_name,
21 EventDispatcher *dispatcher,
22 Sockets *sockets,
23 Callback2<bool, int>::Type *callback)
24 : interface_name_(interface_name),
25 dispatcher_(dispatcher),
26 sockets_(sockets),
27 callback_(callback),
28 fd_(-1),
29 connect_completion_callback_(
30 NewCallback(this, &AsyncConnection::OnConnectCompletion)) { }
31
32AsyncConnection::~AsyncConnection() {
33 Stop();
34}
35
36bool AsyncConnection::Start(const IPAddress &address, int port) {
37 DCHECK(fd_ < 0);
38
39 fd_ = sockets_->Socket(PF_INET, SOCK_STREAM, 0);
40 if (fd_ < 0 ||
41 sockets_->SetNonBlocking(fd_) < 0) {
42 error_ = sockets_->ErrorString();
43 PLOG(ERROR) << "Async socket setup failed";
44 Stop();
45 return false;
46 }
47
48 if (!interface_name_.empty() &&
49 sockets_->BindToDevice(fd_, interface_name_) < 0) {
50 error_ = sockets_->ErrorString();
51 PLOG(ERROR) << "Async socket failed to bind to device";
52 Stop();
53 return false;
54 }
55
56 struct sockaddr_in iaddr;
57 CHECK_EQ(sizeof(iaddr.sin_addr.s_addr), address.GetLength());
58
59 memset(&iaddr, 0, sizeof(iaddr));
60 iaddr.sin_family = AF_INET;
61 memcpy(&iaddr.sin_addr.s_addr, address.address().GetConstData(),
62 sizeof(iaddr.sin_addr.s_addr));
63 iaddr.sin_port = htons(port);
64
65 socklen_t addrlen = sizeof(iaddr);
66 int ret = sockets_->Connect(fd_,
67 reinterpret_cast<struct sockaddr *>(&iaddr),
68 addrlen);
69 if (ret == 0) {
70 callback_->Run(true, fd_); // Passes ownership
71 fd_ = -1;
72 return true;
73 }
74
75 if (sockets_->Error() != EINPROGRESS) {
76 error_ = sockets_->ErrorString();
77 PLOG(ERROR) << "Async socket connection failed";
78 Stop();
79 return false;
80 }
81
82 connect_completion_handler_.reset(
83 dispatcher_->CreateReadyHandler(fd_,
84 IOHandler::kModeOutput,
85 connect_completion_callback_.get()));
86 error_ = string();
87
88 return true;
89}
90
91void AsyncConnection::Stop() {
92 connect_completion_handler_.reset();
93 if (fd_ >= 0) {
94 sockets_->Close(fd_);
95 fd_ = -1;
96 }
97}
98
99void AsyncConnection::OnConnectCompletion(int fd) {
100 CHECK_EQ(fd_, fd);
101
102 if (sockets_->GetSocketError(fd_) != 0) {
103 error_ = sockets_->ErrorString();
104 PLOG(ERROR) << "Async GetSocketError returns failure";
105 callback_->Run(false, -1);
106 } else {
107 callback_->Run(true, fd_); // Passes ownership
108 fd_ = -1;
109 }
110 Stop();
111}
112
113} // namespace shill