dhcp client: create class SocketUtil to simplify class DHCPV4 am: 702e099
am: 1ef994e
* commit '1ef994e226f95a71c494425edb1d42fe0352003c':
dhcp client: create class SocketUtil to simplify class DHCPV4
Change-Id: Ib95effbbedf0767816167473f0f4c323425006fd
diff --git a/dhcp.h b/dhcp.h
index 74f66ad..1129773 100644
--- a/dhcp.h
+++ b/dhcp.h
@@ -42,6 +42,9 @@
REBOOT,
RELEASE
};
+ // UDP port numbers for DHCP.
+ const static uint16_t kDHCPServerPort = 67;
+ const static uint16_t kDHCPClientPort = 68;
};
} // namespace dhcp_client
diff --git a/dhcp_client.gyp b/dhcp_client.gyp
index 7ed15aa..48897e9 100644
--- a/dhcp_client.gyp
+++ b/dhcp_client.gyp
@@ -85,6 +85,7 @@
'message_loop_event_dispatcher.cc',
'manager.cc',
'service.cc',
+ 'socket_util.cc',
],
},
{
diff --git a/dhcpv4.cc b/dhcpv4.cc
index 2b0a7b4..721609a 100644
--- a/dhcpv4.cc
+++ b/dhcpv4.cc
@@ -17,11 +17,9 @@
#include "dhcp_client/dhcpv4.h"
#include <arpa/inet.h>
-#include <linux/filter.h>
#include <linux/if_packet.h>
#include <net/ethernet.h>
#include <net/if.h>
-#include <net/if_arp.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
@@ -36,6 +34,7 @@
#include "dhcp_client/dhcp_options.h"
#include "dhcp_client/file_io.h"
#include "dhcp_client/service_adaptor_interface.h"
+#include "dhcp_client/socket_util.h"
#include "shill/net/arp_packet.h"
#include "shill/net/ip_address.h"
@@ -47,9 +46,6 @@
namespace dhcp_client {
namespace {
-// UDP port numbers for DHCP.
-const uint16_t kDHCPServerPort = 67;
-const uint16_t kDHCPClientPort = 68;
// Max length of a DHCP message.
const size_t kDHCPMessageMaxLength = 548;
// Renewal time in terms of lease duration percentage.
@@ -76,22 +72,6 @@
const uint8_t kZeroHardwareAddress[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
const int kArpProbeReplyTimeoutSeconds = 1;
-// Socket filter for dhcp packet.
-const sock_filter dhcp_bpf_filter[] = {
- BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 23 - ETH_HLEN),
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 6),
- BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20 - ETH_HLEN),
- BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 4, 0),
- BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14 - ETH_HLEN),
- BPF_STMT(BPF_LD + BPF_H + BPF_IND, 16 - ETH_HLEN),
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, kDHCPClientPort, 0, 1),
- BPF_STMT(BPF_RET + BPF_K, 0x0fffffff),
- BPF_STMT(BPF_RET + BPF_K, 0),
-};
-
-const int dhcp_bpf_filter_len =
- sizeof(dhcp_bpf_filter) / sizeof(dhcp_bpf_filter[0]);
-
// TODO(nywang): find a place for the lease file.
const char kIPV4LeaseFilePathFormat[] =
"/tmp/lease-ipv4-%s.conf";
@@ -142,6 +122,7 @@
raw_socket_(kInvalidSocketDescriptor),
udp_socket_(kInvalidSocketDescriptor),
sockets_(new shill::Sockets()),
+ socket_util_(new SocketUtil(interface_name_, interface_index_)),
random_engine_(time(nullptr)) {
ResetState();
}
@@ -225,7 +206,7 @@
}
bool DHCPV4::Start() {
- if (!CreateRawSocket()) {
+ if (!socket_util_->CreateRawSocket(&raw_socket_)) {
return false;
}
input_handler_.reset(io_handler_factory_->CreateIOInputHandler(
@@ -287,100 +268,6 @@
arp_client_->Stop();
}
-bool DHCPV4::CreateRawSocket() {
- int fd = sockets_->Socket(PF_PACKET,
- SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
- htons(ETHERTYPE_IP));
- if (fd == kInvalidSocketDescriptor) {
- PLOG(ERROR) << "Failed to create socket";
- return false;
- }
- shill::ScopedSocketCloser socket_closer(sockets_.get(), fd);
-
- // Apply the socket filter.
- sock_fprog pf;
- memset(&pf, 0, sizeof(pf));
- pf.filter = const_cast<sock_filter*>(dhcp_bpf_filter);
- pf.len = dhcp_bpf_filter_len;
-
- if (sockets_->AttachFilter(fd, &pf) != 0) {
- PLOG(ERROR) << "Failed to attach filter";
- return false;
- }
-
- if (sockets_->ReuseAddress(fd) == -1) {
- PLOG(ERROR) << "Failed to reuse socket address";
- return false;
- }
-
- if (sockets_->BindToDevice(fd, interface_name_) < 0) {
- PLOG(ERROR) << "Failed to bind socket to device";
- return false;
- }
-
- struct sockaddr_ll local;
- memset(&local, 0, sizeof(local));
- local.sll_family = PF_PACKET;
- local.sll_protocol = htons(ETHERTYPE_IP);
- local.sll_ifindex = static_cast<int>(interface_index_);
-
- if (sockets_->Bind(fd,
- reinterpret_cast<struct sockaddr*>(&local),
- sizeof(local)) < 0) {
- PLOG(ERROR) << "Failed to bind to address";
- return false;
- }
-
- raw_socket_ = socket_closer.Release();
- return true;
-}
-
-bool DHCPV4::CreateUdpSocket() {
- // Close previous Udp Socket.
- if (udp_socket_ != kInvalidSocketDescriptor) {
- sockets_->Close(udp_socket_);
- udp_socket_ = kInvalidSocketDescriptor;
- }
-
- int fd = sockets_->Socket(PF_INET,
- SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
- IPPROTO_IP);
- if (fd == kInvalidSocketDescriptor) {
- PLOG(ERROR) << "Failed to create socket";
- return false;
- }
- shill::ScopedSocketCloser socket_closer(sockets_.get(), fd);
-
- if (sockets_->ReuseAddress(fd) == -1) {
- PLOG(ERROR) << "Failed to reuse socket address";
- return false;
- }
-
- if (sockets_->BindToDevice(fd, interface_name_) < 0) {
- PLOG(ERROR) << "Failed to bind socket to device";
- return false;
- }
-
- struct sockaddr_in local;
- memset(&local, 0, sizeof(local));
- local.sin_family = PF_INET;
- // We do not receive packet from this socket.
- // At this time the ip address may not be setup by shill yet.
- // It is a safe choice to use INADDR_ANY.
- local.sin_addr.s_addr = htonl(INADDR_ANY);
- local.sin_port = htons(kDHCPClientPort);
-
- if (sockets_->Bind(fd,
- reinterpret_cast<struct sockaddr*>(&local),
- sizeof(local)) < 0) {
- PLOG(ERROR) << "Failed to bind to address";
- return false;
- }
-
- udp_socket_ = socket_closer.Release();
- return true;
-}
-
void DHCPV4::HandleOffer(const DHCPMessage& msg) {
LOG(INFO) << __func__;
if (state_ != State::SELECT) {
@@ -483,7 +370,7 @@
// Set the option parameters.
subnet_mask_ = msg.subnet_mask();
interface_mtu_ = msg.interface_mtu();
- broadcast_address = msg.broadcast_address();
+ broadcast_address_ = msg.broadcast_address();
router_ = msg.router();
dns_server_ = msg.dns_server();
vendor_specific_info_ = msg.vendor_specific_info();
@@ -494,7 +381,7 @@
}
// Send the DHCP configuration to Shill.
EmitEvent(kReasonBound);
- CreateUdpSocket();
+ socket_util_->CreateUdpSocket(&udp_socket_);
}
void DHCPV4::HandleNak(const DHCPMessage& msg) {
@@ -551,7 +438,7 @@
LOG(ERROR) << "Failed to serialize a DHCP discover message";
return false;
}
- if (!SendBroadcastPacket(packet)) {
+ if (!socket_util_->SendBroadcastPacket(raw_socket_, packet)) {
LOG(ERROR) << "Failed to send a DHCP discover packet";
return false;
}
@@ -656,7 +543,7 @@
LOG(ERROR) << "Failed to make a DHCP request packet";
return false;
}
- if (!SendUnicastPacket(packet)) {
+ if (!socket_util_->SendUnicastPacket(udp_socket_, packet, server_ip_)) {
LOG(ERROR) << "Failed to send a DHCP request packet";
return false;
}
@@ -666,7 +553,7 @@
LOG(ERROR) << "Failed to make a DHCP request raw packet";
return false;
}
- if (!SendBroadcastPacket(packet)) {
+ if (!socket_util_->SendBroadcastPacket(raw_socket_, packet)) {
LOG(ERROR) << "Failed to send a DHCP request packet";
return false;
}
@@ -698,7 +585,7 @@
"there is no socket for unicast";
return false;
}
- if (!SendUnicastPacket(packet)) {
+ if (!socket_util_->SendUnicastPacket(udp_socket_, packet, server_ip_)) {
LOG(ERROR) << "Failed to send a DHCP release packet";
return false;
}
@@ -780,53 +667,6 @@
return true;
}
-bool DHCPV4::SendBroadcastPacket(const ByteString& packet) {
- LOG(INFO) << __func__;
- struct sockaddr_ll remote;
- memset(&remote, 0, sizeof(remote));
- remote.sll_family = AF_PACKET;
- remote.sll_protocol = htons(ETHERTYPE_IP);
- remote.sll_ifindex = interface_index_;
- remote.sll_hatype = htons(ARPHRD_ETHER);
- // Use broadcast hardware address.
- remote.sll_halen = IFHWADDRLEN;
- memset(remote.sll_addr, 0xff, IFHWADDRLEN);
-
- size_t result = sockets_->SendTo(raw_socket_,
- packet.GetConstData(),
- packet.GetLength(),
- 0,
- reinterpret_cast<struct sockaddr *>(&remote),
- sizeof(remote));
-
- if (result != packet.GetLength()) {
- PLOG(ERROR) << "Socket sento failed";
- return false;
- }
- return true;
-}
-
-bool DHCPV4::SendUnicastPacket(const ByteString& packet) {
- LOG(INFO) << __func__;
- struct sockaddr_in remote;
- memset(&remote, 0, sizeof(remote));
- remote.sin_family = AF_INET;
- remote.sin_port = htons(kDHCPServerPort);
- remote.sin_addr.s_addr = htonl(server_ip_);
-
- size_t result = sockets_->SendTo(udp_socket_,
- packet.GetConstData(),
- packet.GetLength(),
- 0,
- reinterpret_cast<struct sockaddr *>(&remote),
- sizeof(remote));
-
- if (result != packet.GetLength()) {
- PLOG(ERROR) << "Socket sento failed";
- return false;
- }
- return true;
-}
bool DHCPV4::ValidateOptions(const DHCPMessage& msg) {
uint32_t lease_time = msg.lease_time();
@@ -978,4 +818,3 @@
}
} // namespace dhcp_client
-
diff --git a/dhcpv4.h b/dhcpv4.h
index 8631cc5..6fd5949 100644
--- a/dhcpv4.h
+++ b/dhcpv4.h
@@ -36,6 +36,7 @@
namespace dhcp_client {
class ServiceAdaptorInterface;
+class SocketUtil;
class DHCPV4 : public DHCP {
public:
@@ -58,8 +59,6 @@
void ArpProbeReplyReceivedTask(int fd);
void ArpProbeReplyTimeoutTask();
void CheckIpCollision();
- bool CreateRawSocket();
- bool CreateUdpSocket();
bool HasALease();
bool MakePacket(const DHCPMessage& message, shill::ByteString* buffer);
bool MakeRawPacket(const DHCPMessage& message, shill::ByteString* buffer);
@@ -70,8 +69,6 @@
bool SendDiscover();
bool SendRequest();
bool SendRelease();
- bool SendBroadcastPacket(const shill::ByteString& buffer);
- bool SendUnicastPacket(const shill::ByteString& buffer);
// Validate the IP and UDP header and return the total headers length.
// Return -1 if any header is invalid.
int ValidatePacketHeader(const unsigned char* buffer, size_t len);
@@ -157,6 +154,8 @@
int udp_socket_;
// Helper class with wrapped socket relavent functions.
std::unique_ptr<shill::Sockets> sockets_;
+ // Helper class handling sockets for DHCP.
+ SocketUtil* socket_util_;
std::default_random_engine random_engine_;
diff --git a/socket_util.cc b/socket_util.cc
new file mode 100644
index 0000000..d4fa1f0
--- /dev/null
+++ b/socket_util.cc
@@ -0,0 +1,206 @@
+//
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "dhcp_client/socket_util.h"
+
+#include <linux/filter.h>
+#include <linux/if_packet.h>
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+
+#include <base/logging.h>
+
+#include "dhcp_client/dhcp.h"
+#include "shill/net/byte_string.h"
+#include "shill/net/sockets.h"
+
+namespace dhcp_client {
+
+namespace {
+
+// Socket filter for dhcp packet.
+const sock_filter dhcp_bpf_filter[] = {
+ BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 23 - ETH_HLEN),
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 6),
+ BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20 - ETH_HLEN),
+ BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 4, 0),
+ BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14 - ETH_HLEN),
+ BPF_STMT(BPF_LD + BPF_H + BPF_IND, 16 - ETH_HLEN),
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP::kDHCPClientPort, 0, 1),
+ BPF_STMT(BPF_RET + BPF_K, 0x0fffffff),
+ BPF_STMT(BPF_RET + BPF_K, 0),
+};
+
+const int dhcp_bpf_filter_len =
+ sizeof(dhcp_bpf_filter) / sizeof(dhcp_bpf_filter[0]);
+
+} // namespace
+
+SocketUtil::SocketUtil(const std::string& interface_name,
+ unsigned int interface_index)
+ : sockets_(new shill::Sockets()),
+ interface_name_(interface_name),
+ interface_index_(interface_index) {
+}
+
+SocketUtil::~SocketUtil() {}
+
+bool SocketUtil::CreateUdpSocket(int* udp_socket) {
+ // Close previous Udp Socket.
+ if (*udp_socket != shill::Sockets::kInvalidFileDescriptor) {
+ sockets_->Close(*udp_socket);
+ *udp_socket = shill::Sockets::kInvalidFileDescriptor;
+ }
+ int fd = sockets_->Socket(PF_INET,
+ SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
+ IPPROTO_IP);
+ if (fd == shill::Sockets::kInvalidFileDescriptor) {
+ PLOG(ERROR) << "Failed to create socket";
+ return false;
+ }
+ shill::ScopedSocketCloser socket_closer(sockets_, fd);
+
+ if (sockets_->ReuseAddress(fd) == -1) {
+ PLOG(ERROR) << "Failed to reuse socket address";
+ return false;
+ }
+
+ if (sockets_->BindToDevice(fd, interface_name_) < 0) {
+ PLOG(ERROR) << "Failed to bind socket to device";
+ return false;
+ }
+
+ struct sockaddr_in local;
+ memset(&local, 0, sizeof(local));
+ local.sin_family = PF_INET;
+ // We do not receive packet from this socket.
+ // At this time the ip address may not be setup by shill yet.
+ // It is a safe choice to use INADDR_ANY.
+ local.sin_addr.s_addr = htonl(INADDR_ANY);
+ local.sin_port = htons(DHCP::kDHCPServerPort);
+
+ if (sockets_->Bind(fd,
+ reinterpret_cast<struct sockaddr*>(&local),
+ sizeof(local)) < 0) {
+ PLOG(ERROR) << "Failed to bind to address";
+ return false;
+ }
+
+ *udp_socket = socket_closer.Release();
+ return true;
+}
+
+bool SocketUtil::CreateRawSocket(int* raw_socket) {
+ int fd = sockets_->Socket(PF_PACKET,
+ SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
+ htons(ETHERTYPE_IP));
+ if (fd == shill::Sockets::kInvalidFileDescriptor) {
+ PLOG(ERROR) << "Failed to create socket";
+ return false;
+ }
+ shill::ScopedSocketCloser socket_closer(sockets_, fd);
+
+ // Apply the socket filter.
+ sock_fprog pf;
+ memset(&pf, 0, sizeof(pf));
+ pf.filter = const_cast<sock_filter*>(dhcp_bpf_filter);
+ pf.len = dhcp_bpf_filter_len;
+
+ if (sockets_->AttachFilter(fd, &pf) != 0) {
+ PLOG(ERROR) << "Failed to attach filter";
+ return false;
+ }
+
+ if (sockets_->ReuseAddress(fd) == -1) {
+ PLOG(ERROR) << "Failed to reuse socket address";
+ return false;
+ }
+
+ if (sockets_->BindToDevice(fd, interface_name_) < 0) {
+ PLOG(ERROR) << "Failed to bind socket to device";
+ return false;
+ }
+
+ struct sockaddr_ll local;
+ memset(&local, 0, sizeof(local));
+ local.sll_family = PF_PACKET;
+ local.sll_protocol = htons(ETHERTYPE_IP);
+ local.sll_ifindex = static_cast<int>(interface_index_);
+
+ if (sockets_->Bind(fd,
+ reinterpret_cast<struct sockaddr*>(&local),
+ sizeof(local)) < 0) {
+ PLOG(ERROR) << "Failed to bind to address";
+ return false;
+ }
+
+ *raw_socket = socket_closer.Release();
+ return true;
+}
+
+bool SocketUtil::SendBroadcastPacket(int raw_socket,
+ const shill::ByteString& packet) {
+ LOG(INFO) << __func__;
+ struct sockaddr_ll remote;
+ memset(&remote, 0, sizeof(remote));
+ remote.sll_family = AF_PACKET;
+ remote.sll_protocol = htons(ETHERTYPE_IP);
+ remote.sll_ifindex = interface_index_;
+ remote.sll_hatype = htons(ARPHRD_ETHER);
+ // Use broadcast hardware address.
+ remote.sll_halen = IFHWADDRLEN;
+ memset(remote.sll_addr, 0xff, IFHWADDRLEN);
+
+ size_t result = sockets_->SendTo(raw_socket,
+ packet.GetConstData(),
+ packet.GetLength(),
+ 0,
+ reinterpret_cast<struct sockaddr *>(&remote),
+ sizeof(remote));
+
+ if (result != packet.GetLength()) {
+ PLOG(ERROR) << "Socket sento failed";
+ return false;
+ }
+ return true;
+}
+
+bool SocketUtil::SendUnicastPacket(int udp_socket,
+ const shill::ByteString& packet,
+ uint32_t server_ip) {
+ LOG(INFO) << __func__;
+ struct sockaddr_in remote;
+ memset(&remote, 0, sizeof(remote));
+ remote.sin_family = AF_INET;
+ remote.sin_port = htons(DHCP::kDHCPServerPort);
+ remote.sin_addr.s_addr = htonl(server_ip);
+
+ size_t result = sockets_->SendTo(udp_socket,
+ packet.GetConstData(),
+ packet.GetLength(),
+ 0,
+ reinterpret_cast<struct sockaddr *>(&remote),
+ sizeof(remote));
+
+ if (result != packet.GetLength()) {
+ PLOG(ERROR) << "Socket sento failed";
+ return false;
+ }
+ return true;
+}
+
+} // namespace dhcp_client
diff --git a/socket_util.h b/socket_util.h
new file mode 100644
index 0000000..64e4528
--- /dev/null
+++ b/socket_util.h
@@ -0,0 +1,60 @@
+//
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef DHCP_CLIENT_SOCKET_UTIL_H_
+#define DHCP_CLIENT_SOCKET_UTIL_H_
+
+#include <string>
+
+#include <base/macros.h>
+
+namespace shill {
+
+class ByteString;
+class Sockets;
+
+} // namespace shill
+
+namespace dhcp_client {
+
+class SocketUtil {
+ public:
+ SocketUtil(const std::string& interface_name,
+ unsigned int interface_index);
+ virtual ~SocketUtil();
+ // Create a raw socket and configure it with a UDP socket filter.
+ bool CreateRawSocket(int* raw_socket);
+ // Create a udp socket.
+ bool CreateUdpSocket(int* udp_socket);
+ // Send broadcast packet using a given raw socekt.
+ bool SendBroadcastPacket(int raw_socket,
+ const shill::ByteString& buffer);
+ // Send unicast packet using a given udp socekt.
+ bool SendUnicastPacket(int udp_socket,
+ const shill::ByteString& buffer,
+ uint32_t server_ip);
+ private:
+ // Helper class with wrapped socket relavent functions.
+ shill::Sockets* sockets_;
+ std::string interface_name_;
+ unsigned int interface_index_;
+
+ DISALLOW_COPY_AND_ASSIGN(SocketUtil);
+};
+
+} // namespace dhcp_client
+
+#endif // DHCP_CLIENT_SOCKET_UTIL_H_