blob: 959fa3f2c66576e672d524e00d63475621651b28 [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 <netinet/in.h>
8
9#include <vector>
10
Eric Shienbrood3e20a232012-02-16 11:35:56 -050011#include <base/bind.h>
Paul Stewartf65320c2011-10-13 14:34:52 -070012#include <gtest/gtest.h>
13
14#include "shill/ip_address.h"
15#include "shill/mock_event_dispatcher.h"
16#include "shill/mock_sockets.h"
17
Eric Shienbrood3e20a232012-02-16 11:35:56 -050018using base::Bind;
19using base::Callback;
20using base::Unretained;
Paul Stewartf65320c2011-10-13 14:34:52 -070021using std::string;
22using ::testing::_;
23using ::testing::Return;
24using ::testing::ReturnNew;
25using ::testing::StrEq;
26using ::testing::StrictMock;
27using ::testing::Test;
28
29namespace shill {
30
31namespace {
32const char kInterfaceName[] = "int0";
Peter Qiuf3a8f902014-08-20 10:05:42 -070033const char kIPv4Address[] = "10.11.12.13";
34const char kIPv6Address[] = "2001:db8::1";
Paul Stewartf65320c2011-10-13 14:34:52 -070035const int kConnectPort = 10203;
36const int kErrorNumber = 30405;
37const int kSocketFD = 60708;
Alex Vakulenko8a532292014-06-16 17:18:44 -070038} // namespace
Paul Stewartf65320c2011-10-13 14:34:52 -070039
40class AsyncConnectionTest : public Test {
41 public:
42 AsyncConnectionTest()
Paul Stewart8585b202012-09-21 14:03:01 -070043 : async_connection_(
44 new AsyncConnection(kInterfaceName, &dispatcher_, &sockets_,
45 callback_target_.callback())),
Peter Qiuf3a8f902014-08-20 10:05:42 -070046 ipv4_address_(IPAddress::kFamilyIPv4),
47 ipv6_address_(IPAddress::kFamilyIPv6) { }
Paul Stewartf65320c2011-10-13 14:34:52 -070048
49 virtual void SetUp() {
Peter Qiuf3a8f902014-08-20 10:05:42 -070050 EXPECT_TRUE(ipv4_address_.SetAddressFromString(kIPv4Address));
51 EXPECT_TRUE(ipv6_address_.SetAddressFromString(kIPv6Address));
Paul Stewartf65320c2011-10-13 14:34:52 -070052 }
53 virtual void TearDown() {
Paul Stewart8585b202012-09-21 14:03:01 -070054 if (async_connection_.get() && async_connection_->fd_ >= 0) {
Paul Stewartf65320c2011-10-13 14:34:52 -070055 EXPECT_CALL(sockets(), Close(kSocketFD))
56 .WillOnce(Return(0));
57 }
58 }
Paul Stewart8585b202012-09-21 14:03:01 -070059 void InvokeFreeConnection(bool /*success*/, int /*fd*/) {
60 async_connection_.reset();
61 }
Paul Stewartf65320c2011-10-13 14:34:52 -070062
63 protected:
64 class ConnectCallbackTarget {
65 public:
66 ConnectCallbackTarget()
Eric Shienbrood3e20a232012-02-16 11:35:56 -050067 : callback_(Bind(&ConnectCallbackTarget::CallTarget,
68 Unretained(this))) {}
Paul Stewartf65320c2011-10-13 14:34:52 -070069
70 MOCK_METHOD2(CallTarget, void(bool success, int fd));
Eric Shienbrood3e20a232012-02-16 11:35:56 -050071 const Callback<void(bool, int)> &callback() { return callback_; }
Paul Stewartf65320c2011-10-13 14:34:52 -070072
73 private:
Eric Shienbrood3e20a232012-02-16 11:35:56 -050074 Callback<void(bool, int)> callback_;
Paul Stewartf65320c2011-10-13 14:34:52 -070075 };
76
77 void ExpectReset() {
Paul Stewart8585b202012-09-21 14:03:01 -070078 EXPECT_STREQ(kInterfaceName, async_connection_->interface_name_.c_str());
79 EXPECT_EQ(&dispatcher_, async_connection_->dispatcher_);
80 EXPECT_EQ(&sockets_, async_connection_->sockets_);
Eric Shienbrood3e20a232012-02-16 11:35:56 -050081 EXPECT_TRUE(callback_target_.callback().
Paul Stewart8585b202012-09-21 14:03:01 -070082 Equals(async_connection_->callback_));
83 EXPECT_EQ(-1, async_connection_->fd_);
84 EXPECT_FALSE(async_connection_->connect_completion_callback_.is_null());
85 EXPECT_FALSE(async_connection_->connect_completion_handler_.get());
Paul Stewartf65320c2011-10-13 14:34:52 -070086 }
87
88 void StartConnection() {
89 EXPECT_CALL(sockets_, Socket(_, _, _))
90 .WillOnce(Return(kSocketFD));
91 EXPECT_CALL(sockets_, SetNonBlocking(kSocketFD))
92 .WillOnce(Return(0));
93 EXPECT_CALL(sockets_, BindToDevice(kSocketFD, StrEq(kInterfaceName)))
94 .WillOnce(Return(0));
Eric Shienbrood3e20a232012-02-16 11:35:56 -050095 EXPECT_CALL(sockets(), Connect(kSocketFD, _, _))
96 .WillOnce(Return(-1));
97 EXPECT_CALL(sockets_, Error())
Paul Stewartf65320c2011-10-13 14:34:52 -070098 .WillOnce(Return(EINPROGRESS));
Eric Shienbrood3e20a232012-02-16 11:35:56 -050099 EXPECT_CALL(dispatcher(),
100 CreateReadyHandler(kSocketFD, IOHandler::kModeOutput, _))
Paul Stewartf65320c2011-10-13 14:34:52 -0700101 .WillOnce(ReturnNew<IOHandler>());
Peter Qiuf3a8f902014-08-20 10:05:42 -0700102 EXPECT_TRUE(async_connection().Start(ipv4_address_, kConnectPort));
Paul Stewartf65320c2011-10-13 14:34:52 -0700103 }
104
105 void OnConnectCompletion(int fd) {
Paul Stewart8585b202012-09-21 14:03:01 -0700106 async_connection_->OnConnectCompletion(fd);
Paul Stewartf65320c2011-10-13 14:34:52 -0700107 }
Paul Stewart8585b202012-09-21 14:03:01 -0700108 AsyncConnection &async_connection() { return *async_connection_.get(); }
Paul Stewartf65320c2011-10-13 14:34:52 -0700109 StrictMock<MockSockets> &sockets() { return sockets_; }
110 MockEventDispatcher &dispatcher() { return dispatcher_; }
Peter Qiuf3a8f902014-08-20 10:05:42 -0700111 const IPAddress &ipv4_address() { return ipv4_address_; }
112 const IPAddress &ipv6_address() { return ipv6_address_; }
Paul Stewart8585b202012-09-21 14:03:01 -0700113 int fd() { return async_connection_->fd_; }
114 void set_fd(int fd) { async_connection_->fd_ = fd; }
Paul Stewartf65320c2011-10-13 14:34:52 -0700115 StrictMock<ConnectCallbackTarget> &callback_target() {
116 return callback_target_;
117 }
Paul Stewartf65320c2011-10-13 14:34:52 -0700118
119 private:
120 MockEventDispatcher dispatcher_;
121 StrictMock<MockSockets> sockets_;
122 StrictMock<ConnectCallbackTarget> callback_target_;
Paul Stewart8585b202012-09-21 14:03:01 -0700123 scoped_ptr<AsyncConnection> async_connection_;
Peter Qiuf3a8f902014-08-20 10:05:42 -0700124 IPAddress ipv4_address_;
125 IPAddress ipv6_address_;
Paul Stewartf65320c2011-10-13 14:34:52 -0700126};
127
128TEST_F(AsyncConnectionTest, InitState) {
129 ExpectReset();
130 EXPECT_EQ(string(), async_connection().error());
131}
132
133TEST_F(AsyncConnectionTest, StartSocketFailure) {
134 EXPECT_CALL(sockets(), Socket(_, _, _))
135 .WillOnce(Return(-1));
136 EXPECT_CALL(sockets(), Error())
137 .WillOnce(Return(kErrorNumber));
Peter Qiuf3a8f902014-08-20 10:05:42 -0700138 EXPECT_FALSE(async_connection().Start(ipv4_address(), kConnectPort));
Paul Stewartf65320c2011-10-13 14:34:52 -0700139 ExpectReset();
140 EXPECT_STREQ(strerror(kErrorNumber), async_connection().error().c_str());
141}
142
143TEST_F(AsyncConnectionTest, StartNonBlockingFailure) {
144 EXPECT_CALL(sockets(), Socket(_, _, _))
145 .WillOnce(Return(kSocketFD));
146 EXPECT_CALL(sockets(), SetNonBlocking(kSocketFD))
147 .WillOnce(Return(-1));
148 EXPECT_CALL(sockets(), Error())
149 .WillOnce(Return(kErrorNumber));
150 EXPECT_CALL(sockets(), Close(kSocketFD))
151 .WillOnce(Return(0));
Peter Qiuf3a8f902014-08-20 10:05:42 -0700152 EXPECT_FALSE(async_connection().Start(ipv4_address(), kConnectPort));
Paul Stewartf65320c2011-10-13 14:34:52 -0700153 ExpectReset();
154 EXPECT_STREQ(strerror(kErrorNumber), async_connection().error().c_str());
155}
156
157TEST_F(AsyncConnectionTest, StartBindToDeviceFailure) {
158 EXPECT_CALL(sockets(), Socket(_, _, _))
159 .WillOnce(Return(kSocketFD));
160 EXPECT_CALL(sockets(), SetNonBlocking(kSocketFD))
161 .WillOnce(Return(0));
162 EXPECT_CALL(sockets(), BindToDevice(kSocketFD, StrEq(kInterfaceName)))
163 .WillOnce(Return(-1));
164 EXPECT_CALL(sockets(), Error())
165 .WillOnce(Return(kErrorNumber));
166 EXPECT_CALL(sockets(), Close(kSocketFD))
167 .WillOnce(Return(0));
Peter Qiuf3a8f902014-08-20 10:05:42 -0700168 EXPECT_FALSE(async_connection().Start(ipv4_address(), kConnectPort));
Paul Stewartf65320c2011-10-13 14:34:52 -0700169 ExpectReset();
170 EXPECT_STREQ(strerror(kErrorNumber), async_connection().error().c_str());
171}
172
173TEST_F(AsyncConnectionTest, SynchronousFailure) {
174 EXPECT_CALL(sockets(), Socket(_, _, _))
175 .WillOnce(Return(kSocketFD));
176 EXPECT_CALL(sockets(), SetNonBlocking(kSocketFD))
177 .WillOnce(Return(0));
178 EXPECT_CALL(sockets(), BindToDevice(kSocketFD, StrEq(kInterfaceName)))
179 .WillOnce(Return(0));
180 EXPECT_CALL(sockets(), Connect(kSocketFD, _, _))
181 .WillOnce(Return(-1));
182 EXPECT_CALL(sockets(), Error())
183 .Times(2)
184 .WillRepeatedly(Return(0));
185 EXPECT_CALL(sockets(), Close(kSocketFD))
186 .WillOnce(Return(0));
Peter Qiuf3a8f902014-08-20 10:05:42 -0700187 EXPECT_FALSE(async_connection().Start(ipv4_address(), kConnectPort));
Paul Stewartf65320c2011-10-13 14:34:52 -0700188 ExpectReset();
189}
190
191MATCHER_P2(IsSocketAddress, address, port, "") {
192 const struct sockaddr_in *arg_saddr =
193 reinterpret_cast<const struct sockaddr_in *>(arg);
194 IPAddress arg_addr(IPAddress::kFamilyIPv4,
195 ByteString(reinterpret_cast<const unsigned char *>(
196 &arg_saddr->sin_addr.s_addr),
197 sizeof(arg_saddr->sin_addr.s_addr)));
198 return address.Equals(arg_addr) && arg_saddr->sin_port == htons(port);
199}
200
Peter Qiuf3a8f902014-08-20 10:05:42 -0700201MATCHER_P2(IsSocketIpv6Address, ipv6_address, port, "") {
202 const struct sockaddr_in6 *arg_saddr =
203 reinterpret_cast<const struct sockaddr_in6 *>(arg);
204 IPAddress arg_addr(IPAddress::kFamilyIPv6,
205 ByteString(reinterpret_cast<const unsigned char *>(
206 &arg_saddr->sin6_addr.s6_addr),
207 sizeof(arg_saddr->sin6_addr.s6_addr)));
208 return ipv6_address.Equals(arg_addr) && arg_saddr->sin6_port == htons(port);
209}
210
Paul Stewartf65320c2011-10-13 14:34:52 -0700211TEST_F(AsyncConnectionTest, SynchronousStart) {
212 EXPECT_CALL(sockets(), Socket(_, _, _))
213 .WillOnce(Return(kSocketFD));
214 EXPECT_CALL(sockets(), SetNonBlocking(kSocketFD))
215 .WillOnce(Return(0));
216 EXPECT_CALL(sockets(), BindToDevice(kSocketFD, StrEq(kInterfaceName)))
217 .WillOnce(Return(0));
218 EXPECT_CALL(sockets(), Connect(kSocketFD,
Peter Qiuf3a8f902014-08-20 10:05:42 -0700219 IsSocketAddress(ipv4_address(), kConnectPort),
Paul Stewartf65320c2011-10-13 14:34:52 -0700220 sizeof(struct sockaddr_in)))
221 .WillOnce(Return(-1));
222 EXPECT_CALL(dispatcher(),
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500223 CreateReadyHandler(kSocketFD, IOHandler::kModeOutput, _))
Paul Stewartf65320c2011-10-13 14:34:52 -0700224 .WillOnce(ReturnNew<IOHandler>());
225 EXPECT_CALL(sockets(), Error())
226 .WillOnce(Return(EINPROGRESS));
Peter Qiuf3a8f902014-08-20 10:05:42 -0700227 EXPECT_TRUE(async_connection().Start(ipv4_address(), kConnectPort));
228 EXPECT_EQ(kSocketFD, fd());
229}
230
231TEST_F(AsyncConnectionTest, SynchronousStartIpv6) {
232 EXPECT_CALL(sockets(), Socket(_, _, _))
233 .WillOnce(Return(kSocketFD));
234 EXPECT_CALL(sockets(), SetNonBlocking(kSocketFD))
235 .WillOnce(Return(0));
236 EXPECT_CALL(sockets(), BindToDevice(kSocketFD, StrEq(kInterfaceName)))
237 .WillOnce(Return(0));
238 EXPECT_CALL(sockets(), Connect(kSocketFD,
239 IsSocketIpv6Address(ipv6_address(),
240 kConnectPort),
241 sizeof(struct sockaddr_in6)))
242 .WillOnce(Return(-1));
243 EXPECT_CALL(dispatcher(),
244 CreateReadyHandler(kSocketFD, IOHandler::kModeOutput, _))
245 .WillOnce(ReturnNew<IOHandler>());
246 EXPECT_CALL(sockets(), Error())
247 .WillOnce(Return(EINPROGRESS));
248 EXPECT_TRUE(async_connection().Start(ipv6_address(), kConnectPort));
Paul Stewartf65320c2011-10-13 14:34:52 -0700249 EXPECT_EQ(kSocketFD, fd());
250}
251
252TEST_F(AsyncConnectionTest, AsynchronousFailure) {
253 StartConnection();
254 EXPECT_CALL(sockets(), GetSocketError(kSocketFD))
255 .WillOnce(Return(1));
256 EXPECT_CALL(sockets(), Error())
257 .WillOnce(Return(kErrorNumber));
258 EXPECT_CALL(callback_target(), CallTarget(false, -1));
259 EXPECT_CALL(sockets(), Close(kSocketFD))
260 .WillOnce(Return(0));
261 OnConnectCompletion(kSocketFD);
262 ExpectReset();
263 EXPECT_STREQ(strerror(kErrorNumber), async_connection().error().c_str());
264}
265
266TEST_F(AsyncConnectionTest, AsynchronousSuccess) {
267 StartConnection();
268 EXPECT_CALL(sockets(), GetSocketError(kSocketFD))
269 .WillOnce(Return(0));
270 EXPECT_CALL(callback_target(), CallTarget(true, kSocketFD));
271 OnConnectCompletion(kSocketFD);
272 ExpectReset();
273}
274
275TEST_F(AsyncConnectionTest, SynchronousSuccess) {
276 EXPECT_CALL(sockets(), Socket(_, _, _))
277 .WillOnce(Return(kSocketFD));
278 EXPECT_CALL(sockets(), SetNonBlocking(kSocketFD))
279 .WillOnce(Return(0));
280 EXPECT_CALL(sockets(), BindToDevice(kSocketFD, StrEq(kInterfaceName)))
281 .WillOnce(Return(0));
282 EXPECT_CALL(sockets(), Connect(kSocketFD,
Peter Qiuf3a8f902014-08-20 10:05:42 -0700283 IsSocketAddress(ipv4_address(), kConnectPort),
Paul Stewartf65320c2011-10-13 14:34:52 -0700284 sizeof(struct sockaddr_in)))
285 .WillOnce(Return(0));
286 EXPECT_CALL(callback_target(), CallTarget(true, kSocketFD));
Peter Qiuf3a8f902014-08-20 10:05:42 -0700287 EXPECT_TRUE(async_connection().Start(ipv4_address(), kConnectPort));
288 ExpectReset();
289}
290
291TEST_F(AsyncConnectionTest, SynchronousSuccessIpv6) {
292 EXPECT_CALL(sockets(), Socket(_, _, _))
293 .WillOnce(Return(kSocketFD));
294 EXPECT_CALL(sockets(), SetNonBlocking(kSocketFD))
295 .WillOnce(Return(0));
296 EXPECT_CALL(sockets(), BindToDevice(kSocketFD, StrEq(kInterfaceName)))
297 .WillOnce(Return(0));
298 EXPECT_CALL(sockets(), Connect(kSocketFD,
299 IsSocketIpv6Address(ipv6_address(),
300 kConnectPort),
301 sizeof(struct sockaddr_in6)))
302 .WillOnce(Return(0));
303 EXPECT_CALL(callback_target(), CallTarget(true, kSocketFD));
304 EXPECT_TRUE(async_connection().Start(ipv6_address(), kConnectPort));
Paul Stewartf65320c2011-10-13 14:34:52 -0700305 ExpectReset();
306}
307
Paul Stewart8585b202012-09-21 14:03:01 -0700308TEST_F(AsyncConnectionTest, FreeOnSuccessCallback) {
309 StartConnection();
310 EXPECT_CALL(sockets(), GetSocketError(kSocketFD))
311 .WillOnce(Return(0));
312 EXPECT_CALL(callback_target(), CallTarget(true, kSocketFD))
313 .WillOnce(Invoke(this, &AsyncConnectionTest::InvokeFreeConnection));
314 OnConnectCompletion(kSocketFD);
315}
316
317TEST_F(AsyncConnectionTest, FreeOnFailureCallback) {
318 StartConnection();
319 EXPECT_CALL(sockets(), GetSocketError(kSocketFD))
320 .WillOnce(Return(1));
321 EXPECT_CALL(callback_target(), CallTarget(false, -1))
322 .WillOnce(Invoke(this, &AsyncConnectionTest::InvokeFreeConnection));
323 EXPECT_CALL(sockets(), Error())
324 .WillOnce(Return(kErrorNumber));
325 EXPECT_CALL(sockets(), Close(kSocketFD))
326 .WillOnce(Return(0));
327 OnConnectCompletion(kSocketFD);
328}
329
Paul Stewartf65320c2011-10-13 14:34:52 -0700330} // namespace shill