blob: 44916a7ef419ca8241827c0cc2696ad9013d99f4 [file] [log] [blame]
Paul Stewart960d4692013-12-09 07:41:59 -08001// Copyright (c) 2013 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/icmp.h"
6
7#include <netinet/in.h>
8#include <netinet/ip_icmp.h>
9
10#include <gtest/gtest.h>
11
Paul Stewart960d4692013-12-09 07:41:59 -080012#include "shill/mock_log.h"
Peter Qiu8d6b5972014-10-28 15:33:34 -070013#include "shill/net/ip_address.h"
14#include "shill/net/mock_sockets.h"
Paul Stewart960d4692013-12-09 07:41:59 -080015
16using testing::_;
17using testing::HasSubstr;
18using testing::InSequence;
19using testing::Return;
20using testing::StrictMock;
21using testing::Test;
22
23namespace shill {
24
25class IcmpTest : public Test {
26 public:
27 IcmpTest() {}
28 virtual ~IcmpTest() {}
29
30 virtual void SetUp() {
31 sockets_ = new StrictMock<MockSockets>();
32 // Passes ownership.
33 icmp_.sockets_.reset(sockets_);
34 }
35
36 virtual void TearDown() {
37 if (icmp_.IsStarted()) {
38 EXPECT_CALL(*sockets_, Close(kSocketFD));
39 icmp_.Stop();
40 }
41 EXPECT_FALSE(icmp_.IsStarted());
42 }
43
44 protected:
45 static const int kSocketFD;
46 static const char kIPAddress[];
47
48 int GetSocket() { return icmp_.socket_; }
49 bool StartIcmp() { return StartIcmpWithFD(kSocketFD); }
50 bool StartIcmpWithFD(int fd) {
51 EXPECT_CALL(*sockets_, Socket(AF_INET, SOCK_RAW, IPPROTO_ICMP))
52 .WillOnce(Return(fd));
53 EXPECT_CALL(*sockets_, SetNonBlocking(fd)).WillOnce(Return(0));
54 bool start_status = icmp_.Start();
55 EXPECT_TRUE(start_status);
56 EXPECT_EQ(fd, icmp_.socket_);
57 EXPECT_TRUE(icmp_.IsStarted());
58 return start_status;
59 }
60
61 // Owned by Icmp, and tracked here only for mocks.
Paul Stewart3b30ca52015-06-16 13:13:10 -070062 MockSockets* sockets_;
Paul Stewart960d4692013-12-09 07:41:59 -080063
64 Icmp icmp_;
65};
66
67
68const int IcmpTest::kSocketFD = 456;
69const char IcmpTest::kIPAddress[] = "10.0.1.1";
70
71
72TEST_F(IcmpTest, Constructor) {
73 EXPECT_EQ(-1, GetSocket());
74 EXPECT_FALSE(icmp_.IsStarted());
75}
76
77TEST_F(IcmpTest, SocketOpenFail) {
78 ScopedMockLog log;
79 EXPECT_CALL(log,
80 Log(logging::LOG_ERROR, _,
81 HasSubstr("Could not create ICMP socket"))).Times(1);
82
83 EXPECT_CALL(*sockets_, Socket(AF_INET, SOCK_RAW, IPPROTO_ICMP))
84 .WillOnce(Return(-1));
85 EXPECT_FALSE(icmp_.Start());
86 EXPECT_FALSE(icmp_.IsStarted());
87}
88
89TEST_F(IcmpTest, SocketNonBlockingFail) {
90 ScopedMockLog log;
91 EXPECT_CALL(log,
92 Log(logging::LOG_ERROR, _,
93 HasSubstr("Could not set socket to be non-blocking"))).Times(1);
94
95 EXPECT_CALL(*sockets_, Socket(_, _, _)).WillOnce(Return(kSocketFD));
96 EXPECT_CALL(*sockets_, SetNonBlocking(kSocketFD)).WillOnce(Return(-1));
97 EXPECT_CALL(*sockets_, Close(kSocketFD));
98 EXPECT_FALSE(icmp_.Start());
99 EXPECT_FALSE(icmp_.IsStarted());
100}
101
102TEST_F(IcmpTest, StartMultipleTimes) {
103 const int kFirstSocketFD = kSocketFD + 1;
104 StartIcmpWithFD(kFirstSocketFD);
105 EXPECT_CALL(*sockets_, Close(kFirstSocketFD));
106 StartIcmp();
107}
108
109MATCHER_P(IsIcmpHeader, header, "") {
110 return memcmp(arg, &header, sizeof(header)) == 0;
111}
112
113
114MATCHER_P(IsSocketAddress, address, "") {
Paul Stewart3b30ca52015-06-16 13:13:10 -0700115 const struct sockaddr_in* sock_addr =
116 reinterpret_cast<const struct sockaddr_in*>(arg);
Paul Stewart960d4692013-12-09 07:41:59 -0800117 return sock_addr->sin_family == address.family() &&
118 memcmp(&sock_addr->sin_addr.s_addr, address.GetConstData(),
119 address.GetLength()) == 0;
120}
121
122TEST_F(IcmpTest, TransmitEchoRequest) {
123 StartIcmp();
124 // Address isn't valid.
125 EXPECT_FALSE(icmp_.TransmitEchoRequest(IPAddress(IPAddress::kFamilyIPv4)));
126
127 // IPv6 adresses aren't implemented.
128 IPAddress ipv6_destination(IPAddress::kFamilyIPv6);
129 EXPECT_TRUE(ipv6_destination.SetAddressFromString(
130 "fe80::1aa9:5ff:abcd:1234"));
131 EXPECT_FALSE(icmp_.TransmitEchoRequest(ipv6_destination));
132
133 IPAddress ipv4_destination(IPAddress::kFamilyIPv4);
134 EXPECT_TRUE(ipv4_destination.SetAddressFromString(kIPAddress));
135
136 struct icmphdr icmp_header;
Paul Stewarta28487e2015-06-02 10:04:03 -0700137 memset(&icmp_header, 0, sizeof(icmp_header));
Paul Stewart960d4692013-12-09 07:41:59 -0800138 icmp_header.type = ICMP_ECHO;
139 icmp_header.un.echo.id = 1;
140 icmp_header.un.echo.sequence = 1;
141 EXPECT_CALL(*sockets_, SendTo(kSocketFD,
142 IsIcmpHeader(icmp_header),
143 sizeof(icmp_header),
144 0,
145 IsSocketAddress(ipv4_destination),
146 sizeof(sockaddr_in)))
147 .WillOnce(Return(-1))
148 .WillOnce(Return(0))
149 .WillOnce(Return(sizeof(icmp_header) - 1))
150 .WillOnce(Return(sizeof(icmp_header)));
151 {
152 InSequence seq;
153 ScopedMockLog log;
154 EXPECT_CALL(log,
155 Log(logging::LOG_ERROR, _,
156 HasSubstr("Socket sendto failed"))).Times(1);
157 EXPECT_CALL(log,
158 Log(logging::LOG_ERROR, _,
159 HasSubstr("less than the expected result"))).Times(2);
160
161 EXPECT_FALSE(icmp_.TransmitEchoRequest(ipv4_destination));
162 EXPECT_FALSE(icmp_.TransmitEchoRequest(ipv4_destination));
163 EXPECT_FALSE(icmp_.TransmitEchoRequest(ipv4_destination));
164 EXPECT_TRUE(icmp_.TransmitEchoRequest(ipv4_destination));
165 }
166}
167
168} // namespace shill