blob: 68111edea76d8c22206d966adee8fd41a369e2ee [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
Paul Stewart960d4692013-12-09 07:41:59 -080010#include "shill/logging.h"
Peter Qiu8d6b5972014-10-28 15:33:34 -070011#include "shill/net/ip_address.h"
12#include "shill/net/sockets.h"
Paul Stewart960d4692013-12-09 07:41:59 -080013
14namespace shill {
15
16Icmp::Icmp()
17 : sockets_(new Sockets()),
18 socket_(-1) {}
19
20Icmp::~Icmp() {}
21
22bool Icmp::Start() {
23 int socket = sockets_->Socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
24 if (socket == -1) {
25 PLOG(ERROR) << "Could not create ICMP socket";
26 Stop();
27 return false;
28 }
29 socket_ = socket;
30 socket_closer_.reset(new ScopedSocketCloser(sockets_.get(), socket_));
31
32 if (sockets_->SetNonBlocking(socket_) != 0) {
33 PLOG(ERROR) << "Could not set socket to be non-blocking";
34 Stop();
35 return false;
36 }
37
38 return true;
39}
40
41void Icmp::Stop() {
42 socket_closer_.reset();
43 socket_ = -1;
44}
45
46bool Icmp::IsStarted() const {
47 return socket_closer_.get();
48}
49
50bool Icmp::TransmitEchoRequest(const IPAddress &destination) {
51 if (!IsStarted() && !Start()) {
52 return false;
53 }
54
55 if (!destination.IsValid()) {
56 LOG(ERROR) << "Destination address is not valid.";
57 return false;
58 }
59
60 if (destination.family() != IPAddress::kFamilyIPv4) {
61 NOTIMPLEMENTED() << "Only IPv4 destination addresses are implemented.";
62 return false;
63 }
64
65 struct icmphdr icmp_header;
66 memset(&icmp_header, 0, sizeof(icmp_header));
67 icmp_header.type = ICMP_ECHO;
68 icmp_header.un.echo.id = 1;
69 icmp_header.un.echo.sequence = 1;
70
71 struct sockaddr_in destination_address;
72 destination_address.sin_family = AF_INET;
73 CHECK_EQ(sizeof(destination_address.sin_addr.s_addr),
74 destination.GetLength());
75 memcpy(&destination_address.sin_addr.s_addr,
76 destination.address().GetConstData(),
77 sizeof(destination_address.sin_addr.s_addr));
78
79 int result = sockets_->SendTo(
80 socket_,
81 &icmp_header,
82 sizeof(icmp_header),
83 0,
84 reinterpret_cast<struct sockaddr *>(&destination_address),
85 sizeof(destination_address));
86 int expected_result = sizeof(icmp_header);
87 if (result != expected_result) {
88 if (result < 0) {
89 PLOG(ERROR) << "Socket sendto failed";
90 } else if (result < expected_result) {
91 LOG(ERROR) << "Socket sendto returned "
92 << result
93 << " which is less than the expected result "
94 << expected_result;
95 }
96 return false;
97 }
98
99 return true;
100}
101
102} // namespace shill