|
@@ -0,0 +1,549 @@
|
|
|
|
+/*
|
|
|
|
+ * DhcpClient.cpp
|
|
|
|
+ *
|
|
|
|
+ * Created on: Mar 25, 2023
|
|
|
|
+ * Author: ZKSWE Develop Team
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+#include <stdio.h>
|
|
|
|
+#include <stdlib.h>
|
|
|
|
+#include <unistd.h>
|
|
|
|
+#include <errno.h>
|
|
|
|
+#include <string.h>
|
|
|
|
+#include <time.h>
|
|
|
|
+#include <poll.h>
|
|
|
|
+#include <sys/time.h>
|
|
|
|
+#include <sys/socket.h>
|
|
|
|
+#include <sys/types.h>
|
|
|
|
+#include <sys/ioctl.h>
|
|
|
|
+#include <netinet/in.h>
|
|
|
|
+#include <netinet/ip.h>
|
|
|
|
+#include <arpa/inet.h>
|
|
|
|
+#include <linux/udp.h>
|
|
|
|
+#include <linux/if_packet.h>
|
|
|
|
+#include <linux/if_ether.h>
|
|
|
|
+#include "DhcpClient.h"
|
|
|
|
+#include "utils/Log.h"
|
|
|
|
+
|
|
|
|
+namespace net {
|
|
|
|
+
|
|
|
|
+#define PORT_BOOTP_SERVER 67
|
|
|
|
+#define PORT_BOOTP_CLIENT 68
|
|
|
|
+
|
|
|
|
+#define OP_BOOTREQUEST 1
|
|
|
|
+#define OP_BOOTREPLY 2
|
|
|
|
+
|
|
|
|
+#define FLAGS_BROADCAST 0x8000
|
|
|
|
+
|
|
|
|
+#define HTYPE_ETHER 1
|
|
|
|
+
|
|
|
|
+#define DHCP_MSG_FIXED_SIZE 236
|
|
|
|
+
|
|
|
|
+/* first four bytes of options are a cookie to indicate that
|
|
|
|
+** the payload are DHCP options as opposed to some other BOOTP
|
|
|
|
+** extension.
|
|
|
|
+*/
|
|
|
|
+#define OPT_COOKIE1 0x63
|
|
|
|
+#define OPT_COOKIE2 0x82
|
|
|
|
+#define OPT_COOKIE3 0x53
|
|
|
|
+#define OPT_COOKIE4 0x63
|
|
|
|
+
|
|
|
|
+/* BOOTP/DHCP options - see RFC 2132 */
|
|
|
|
+#define OPT_PAD 0
|
|
|
|
+
|
|
|
|
+#define OPT_SUBNET_MASK 1 /* 4 <ipaddr> */
|
|
|
|
+#define OPT_TIME_OFFSET 2 /* 4 <seconds> */
|
|
|
|
+#define OPT_GATEWAY 3 /* 4*n <ipaddr> * n */
|
|
|
|
+#define OPT_DNS 6 /* 4*n <ipaddr> * n */
|
|
|
|
+#define OPT_HOST_NAME 12
|
|
|
|
+#define OPT_DOMAIN_NAME 15 /* n <domainnamestring> */
|
|
|
|
+#define OPT_BROADCAST_ADDR 28 /* 4 <ipaddr> */
|
|
|
|
+
|
|
|
|
+#define OPT_REQUESTED_IP 50 /* 4 <ipaddr> */
|
|
|
|
+#define OPT_LEASE_TIME 51 /* 4 <seconds> */
|
|
|
|
+#define OPT_MESSAGE_TYPE 53 /* 1 <msgtype> */
|
|
|
|
+#define OPT_SERVER_ID 54 /* 4 <ipaddr> */
|
|
|
|
+#define OPT_PARAMETER_LIST 55 /* n <optcode> * n */
|
|
|
|
+#define OPT_MESSAGE 56 /* n <errorstring> */
|
|
|
|
+#define OPT_CLASS_ID 60 /* n <opaque> */
|
|
|
|
+#define OPT_CLIENT_ID 61 /* n <opaque> */
|
|
|
|
+#define OPT_END 255
|
|
|
|
+
|
|
|
|
+/* DHCP message types */
|
|
|
|
+#define DHCPDISCOVER 1
|
|
|
|
+#define DHCPOFFER 2
|
|
|
|
+#define DHCPREQUEST 3
|
|
|
|
+#define DHCPDECLINE 4
|
|
|
|
+#define DHCPACK 5
|
|
|
|
+#define DHCPNAK 6
|
|
|
|
+#define DHCPRELEASE 7
|
|
|
|
+#define DHCPINFORM 8
|
|
|
|
+
|
|
|
|
+#ifndef TEMP_FAILURE_RETRY
|
|
|
|
+#define TEMP_FAILURE_RETRY(exp) ({ \
|
|
|
|
+ long int _rc; \
|
|
|
|
+ do { \
|
|
|
|
+ _rc = (exp); \
|
|
|
|
+ } while (_rc == -1 && errno == EINTR); \
|
|
|
|
+ _rc; })
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+typedef struct {
|
|
|
|
+ uint8_t op; /* BOOTREQUEST / BOOTREPLY */
|
|
|
|
+ uint8_t htype; /* hw addr type */
|
|
|
|
+ uint8_t hlen; /* hw addr len */
|
|
|
|
+ uint8_t hops; /* client set to 0 */
|
|
|
|
+
|
|
|
|
+ uint32_t xid; /* transaction id */
|
|
|
|
+
|
|
|
|
+ uint16_t secs; /* seconds since start of acq */
|
|
|
|
+ uint16_t flags;
|
|
|
|
+
|
|
|
|
+ uint32_t ciaddr; /* client IP addr */
|
|
|
|
+ uint32_t yiaddr; /* your (client) IP addr */
|
|
|
|
+ uint32_t siaddr; /* ip addr of next server */
|
|
|
|
+ /* (DHCPOFFER and DHCPACK) */
|
|
|
|
+ uint32_t giaddr; /* relay agent IP addr */
|
|
|
|
+
|
|
|
|
+ uint8_t chaddr[16]; /* client hw addr */
|
|
|
|
+ char sname[64]; /* asciiz server hostname */
|
|
|
|
+ char file[128]; /* asciiz boot file name */
|
|
|
|
+
|
|
|
|
+ uint8_t options[312]; /* optional parameters */
|
|
|
|
+} dhcp_msg;
|
|
|
|
+
|
|
|
|
+typedef struct {
|
|
|
|
+ uint32_t type;
|
|
|
|
+
|
|
|
|
+ uint32_t ipaddr;
|
|
|
|
+ uint32_t gateway;
|
|
|
|
+ uint32_t prefixLength;
|
|
|
|
+
|
|
|
|
+ uint32_t dns1;
|
|
|
|
+ uint32_t dns2;
|
|
|
|
+
|
|
|
|
+ uint32_t saddr;
|
|
|
|
+ uint32_t lease;
|
|
|
|
+} dhcp_info;
|
|
|
|
+
|
|
|
|
+static bool _s_verbose = true;
|
|
|
|
+
|
|
|
|
+static uint32_t get_sec() {
|
|
|
|
+ struct timespec ts;
|
|
|
|
+ clock_gettime(CLOCK_MONOTONIC, &ts);
|
|
|
|
+ return ts.tv_sec;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int mask_to_prelen(in_addr_t mask) {
|
|
|
|
+ int len = 0;
|
|
|
|
+ uint32_t m = (uint32_t) ntohl(mask);
|
|
|
|
+ while (m & 0x80000000) {
|
|
|
|
+ len++;
|
|
|
|
+ m = m << 1;
|
|
|
|
+ }
|
|
|
|
+ return len;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void macaddr_to_hwaddr(const char *macaddr, uint8_t hwaddr[6]) {
|
|
|
|
+ sscanf(macaddr, "%02x:%02x:%02x:%02x:%02x:%02x",
|
|
|
|
+ hwaddr, hwaddr + 1, hwaddr + 2, hwaddr + 3, hwaddr + 4, hwaddr + 5);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static uint8_t *init_dhcp_msg(dhcp_msg *msg, int type, uint8_t *hwaddr, uint32_t xid) {
|
|
|
|
+ uint8_t *x;
|
|
|
|
+
|
|
|
|
+ memset(msg, 0, sizeof(dhcp_msg));
|
|
|
|
+
|
|
|
|
+ msg->op = OP_BOOTREQUEST;
|
|
|
|
+ msg->htype = HTYPE_ETHER;
|
|
|
|
+ msg->hlen = 6;
|
|
|
|
+ msg->hops = 0;
|
|
|
|
+ msg->xid = xid;
|
|
|
|
+
|
|
|
|
+ memcpy(msg->chaddr, hwaddr, 6);
|
|
|
|
+
|
|
|
|
+ x = msg->options;
|
|
|
|
+
|
|
|
|
+ *x++ = OPT_COOKIE1;
|
|
|
|
+ *x++ = OPT_COOKIE2;
|
|
|
|
+ *x++ = OPT_COOKIE3;
|
|
|
|
+ *x++ = OPT_COOKIE4;
|
|
|
|
+
|
|
|
|
+ *x++ = OPT_MESSAGE_TYPE;
|
|
|
|
+ *x++ = 1;
|
|
|
|
+ *x++ = type;
|
|
|
|
+
|
|
|
|
+ return x;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int init_dhcp_renew_msg(dhcp_msg *msg, uint8_t *hwaddr, uint32_t xid,
|
|
|
|
+ uint32_t ipaddr, uint32_t saddr) {
|
|
|
|
+ uint8_t *x;
|
|
|
|
+
|
|
|
|
+ x = init_dhcp_msg(msg, DHCPREQUEST, hwaddr, xid);
|
|
|
|
+
|
|
|
|
+ msg->ciaddr = ipaddr;
|
|
|
|
+
|
|
|
|
+ *x++ = OPT_CLIENT_ID;
|
|
|
|
+ *x++ = 7;
|
|
|
|
+ *x++ = HTYPE_ETHER;
|
|
|
|
+ memcpy(x, hwaddr, 6);
|
|
|
|
+ x += 6;
|
|
|
|
+
|
|
|
|
+ *x++ = OPT_PARAMETER_LIST;
|
|
|
|
+ *x++ = 4;
|
|
|
|
+ *x++ = OPT_SUBNET_MASK;
|
|
|
|
+ *x++ = OPT_GATEWAY;
|
|
|
|
+ *x++ = OPT_DNS;
|
|
|
|
+ *x++ = OPT_BROADCAST_ADDR;
|
|
|
|
+
|
|
|
|
+ *x++ = OPT_REQUESTED_IP;
|
|
|
|
+ *x++ = 4;
|
|
|
|
+ memcpy(x, &ipaddr, 4);
|
|
|
|
+ x += 4;
|
|
|
|
+
|
|
|
|
+ *x++ = OPT_SERVER_ID;
|
|
|
|
+ *x++ = 4;
|
|
|
|
+ memcpy(x, &saddr, 4);
|
|
|
|
+ x += 4;
|
|
|
|
+
|
|
|
|
+ *x++ = OPT_END;
|
|
|
|
+
|
|
|
|
+ return DHCP_MSG_FIXED_SIZE + (x - msg->options);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static const char *dhcp_type_to_name(uint32_t type) {
|
|
|
|
+ switch (type) {
|
|
|
|
+ case DHCPDISCOVER: return "discover";
|
|
|
|
+ case DHCPOFFER: return "offer";
|
|
|
|
+ case DHCPREQUEST: return "request";
|
|
|
|
+ case DHCPDECLINE: return "decline";
|
|
|
|
+ case DHCPACK: return "ack";
|
|
|
|
+ case DHCPNAK: return "nak";
|
|
|
|
+ case DHCPRELEASE: return "release";
|
|
|
|
+ case DHCPINFORM: return "inform";
|
|
|
|
+ default: return "???";
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void dump_dhcp_info(dhcp_info *info) {
|
|
|
|
+ char addr[20], gway[20], dns[20];
|
|
|
|
+ LOGD("[dhcp] %s (%d) ---\n", dhcp_type_to_name(info->type), info->type);
|
|
|
|
+ inet_ntop(AF_INET, &info->ipaddr, addr, sizeof(addr));
|
|
|
|
+ inet_ntop(AF_INET, &info->gateway, gway, sizeof(gway));
|
|
|
|
+ LOGD("[dhcp] ip %s gw %s prefixLength %d\n", addr, gway, info->prefixLength);
|
|
|
|
+ if (info->dns1) LOGD("[dhcp] dns1: %s\n", inet_ntop(AF_INET, &info->dns1, dns, sizeof(dns)));
|
|
|
|
+ if (info->dns2) LOGD("[dhcp] dns2: %s\n", inet_ntop(AF_INET, &info->dns2, dns, sizeof(dns)));
|
|
|
|
+ LOGD("[dhcp] server %s, lease %d seconds\n", inet_ntop(AF_INET, &info->saddr, addr, sizeof(addr)), info->lease);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int decode_dhcp_msg(dhcp_msg *msg, int len, dhcp_info *info) {
|
|
|
|
+ uint8_t *x;
|
|
|
|
+ uint32_t opt;
|
|
|
|
+ int optlen;
|
|
|
|
+
|
|
|
|
+ memset(info, 0, sizeof(dhcp_info));
|
|
|
|
+ if (len < (DHCP_MSG_FIXED_SIZE + 4)) return -1;
|
|
|
|
+
|
|
|
|
+ len -= (DHCP_MSG_FIXED_SIZE + 4);
|
|
|
|
+
|
|
|
|
+ if (msg->options[0] != OPT_COOKIE1) return -1;
|
|
|
|
+ if (msg->options[1] != OPT_COOKIE2) return -1;
|
|
|
|
+ if (msg->options[2] != OPT_COOKIE3) return -1;
|
|
|
|
+ if (msg->options[3] != OPT_COOKIE4) return -1;
|
|
|
|
+
|
|
|
|
+ x = msg->options + 4;
|
|
|
|
+
|
|
|
|
+ while (len > 2) {
|
|
|
|
+ opt = *x++;
|
|
|
|
+ if (opt == OPT_PAD) {
|
|
|
|
+ len--;
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ if (opt == OPT_END) {
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ optlen = *x++;
|
|
|
|
+ len -= 2;
|
|
|
|
+ if (optlen > len) {
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ switch(opt) {
|
|
|
|
+ case OPT_SUBNET_MASK:
|
|
|
|
+ if (optlen >= 4) {
|
|
|
|
+ in_addr_t mask;
|
|
|
|
+ memcpy(&mask, x, 4);
|
|
|
|
+ info->prefixLength = mask_to_prelen(mask);
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+ case OPT_GATEWAY:
|
|
|
|
+ if (optlen >= 4) memcpy(&info->gateway, x, 4);
|
|
|
|
+ break;
|
|
|
|
+ case OPT_DNS:
|
|
|
|
+ if (optlen >= 4) memcpy(&info->dns1, x + 0, 4);
|
|
|
|
+ if (optlen >= 8) memcpy(&info->dns2, x + 4, 4);
|
|
|
|
+ break;
|
|
|
|
+ case OPT_LEASE_TIME:
|
|
|
|
+ if (optlen >= 4) {
|
|
|
|
+ memcpy(&info->lease, x, 4);
|
|
|
|
+ info->lease = ntohl(info->lease);
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+ case OPT_SERVER_ID:
|
|
|
|
+ if (optlen >= 4) memcpy(&info->saddr, x, 4);
|
|
|
|
+ break;
|
|
|
|
+ case OPT_MESSAGE_TYPE:
|
|
|
|
+ info->type = *x;
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ x += optlen;
|
|
|
|
+ len -= optlen;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ info->ipaddr = msg->yiaddr;
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static bool is_valid_reply(dhcp_msg *msg, dhcp_msg *reply, int sz) {
|
|
|
|
+ if (sz < DHCP_MSG_FIXED_SIZE) {
|
|
|
|
+ if (_s_verbose) {
|
|
|
|
+ LOGD("netcfg: Wrong size %d != %d\n", sz, DHCP_MSG_FIXED_SIZE);
|
|
|
|
+ }
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ if (reply->op != OP_BOOTREPLY) {
|
|
|
|
+ if (_s_verbose) {
|
|
|
|
+ LOGD("netcfg: Wrong Op %d != %d\n", reply->op, OP_BOOTREPLY);
|
|
|
|
+ }
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ if (reply->xid != msg->xid) {
|
|
|
|
+ if (_s_verbose) {
|
|
|
|
+ LOGD("netcfg: Wrong Xid 0x%x != 0x%x\n", ntohl(reply->xid), ntohl(msg->xid));
|
|
|
|
+ }
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ if (reply->htype != msg->htype) {
|
|
|
|
+ if (_s_verbose) {
|
|
|
|
+ LOGD("netcfg: Wrong Htype %d != %d\n", reply->htype, msg->htype);
|
|
|
|
+ }
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ if (reply->hlen != msg->hlen) {
|
|
|
|
+ if (_s_verbose) {
|
|
|
|
+ LOGD("netcfg: Wrong Hlen %d != %d\n", reply->hlen, msg->hlen);
|
|
|
|
+ }
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ if (memcmp(msg->chaddr, reply->chaddr, msg->hlen)) {
|
|
|
|
+ if (_s_verbose) {
|
|
|
|
+ LOGD("netcfg: Wrong chaddr %x != %x\n", *(reply->chaddr),*(msg->chaddr));
|
|
|
|
+ }
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ return true;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+DhcpClient::DhcpClient() : lease_cb_(NULL), record_time_(0), lease_(0), record_lease_(0) {
|
|
|
|
+ wakeup_[0] = wakeup_[1] = -1;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+DhcpClient::~DhcpClient() {
|
|
|
|
+ stop();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void DhcpClient::set_lease_cb(dhcp_lease_cb cb) {
|
|
|
|
+ lease_cb_ = cb;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+bool DhcpClient::start(const char *ip, const char *macaddr, const char *gateway) {
|
|
|
|
+ if (isRunning()) {
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (pipe(wakeup_) < 0) {
|
|
|
|
+ LOGE("[dhcp] create pipe fail\n");
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ip_ = ip;
|
|
|
|
+ macaddr_ = macaddr;
|
|
|
|
+ gateway_ = gateway;
|
|
|
|
+ record_time_ = get_sec();
|
|
|
|
+ lease_ = 60 * 60; // 1 hour
|
|
|
|
+ record_lease_ = 0;
|
|
|
|
+
|
|
|
|
+ LOGD("开始请求dhcp,ip == %s", ip);
|
|
|
|
+ return run("renew");
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void DhcpClient::stop() {
|
|
|
|
+ LOGD("[dhcp] stop +++\n");
|
|
|
|
+ LOGD("正在断开dhcp,ip == %s", ip_.c_str());
|
|
|
|
+
|
|
|
|
+ if (wakeup_[1] >= 0) {
|
|
|
|
+ TEMP_FAILURE_RETRY(write(wakeup_[1], "W", 1));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ requestExitAndWait();
|
|
|
|
+
|
|
|
|
+ if (wakeup_[0] >= 0) {
|
|
|
|
+ close(wakeup_[0]);
|
|
|
|
+ wakeup_[0] = -1;
|
|
|
|
+ }
|
|
|
|
+ if (wakeup_[1] >= 0) {
|
|
|
|
+ close(wakeup_[1]);
|
|
|
|
+ wakeup_[1] = -1;
|
|
|
|
+ }
|
|
|
|
+ LOGD("[dhcp] stop ---\n");
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+bool DhcpClient::threadLoop() {
|
|
|
|
+ uint32_t lease1_2 = lease_ / 2; // 1/2
|
|
|
|
+ uint32_t lease7_8 = lease_ - lease_ / 8; // 7/8
|
|
|
|
+ uint32_t past_time = get_sec() - record_time_;
|
|
|
|
+ bool need_renew = false;
|
|
|
|
+
|
|
|
|
+// LOGD("lease_ %d\n", lease_);
|
|
|
|
+// LOGD("lease1_2 %d\n", lease1_2);
|
|
|
|
+// LOGD("lease7_8 %d\n", lease7_8);
|
|
|
|
+// LOGD("past_time %d\n", past_time);
|
|
|
|
+
|
|
|
|
+ if (past_time > lease_) {
|
|
|
|
+ LOGE("[dhcp] lease time out\n");
|
|
|
|
+ if (lease_cb_) {
|
|
|
|
+ lease_cb_(E_DHCP_LEASE_TYPE_TIMEOUT, this);
|
|
|
|
+ }
|
|
|
|
+ return false;
|
|
|
|
+ } else if (past_time > lease7_8) {
|
|
|
|
+ if (record_lease_ < lease7_8) {
|
|
|
|
+ record_lease_ = lease7_8;
|
|
|
|
+ need_renew = true;
|
|
|
|
+ }
|
|
|
|
+ } else if (past_time > lease1_2) {
|
|
|
|
+ if (record_lease_ < lease1_2) {
|
|
|
|
+ record_lease_ = lease1_2;
|
|
|
|
+ need_renew = true;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (need_renew) {
|
|
|
|
+ bool ret = false;
|
|
|
|
+ for (int i = 0; i < 3; ++i) {
|
|
|
|
+ if (renew()) {
|
|
|
|
+ ret = true;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ sleep(100);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (ret) {
|
|
|
|
+ record_lease_ = 0;
|
|
|
|
+ record_time_ = get_sec();
|
|
|
|
+ LOGD("[dhcp] lease ok\n");
|
|
|
|
+ if (lease_cb_) {
|
|
|
|
+ lease_cb_(E_DHCP_LEASE_TYPE_SUCCESS, this);
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ LOGE("[dhcp] lease err\n");
|
|
|
|
+ if (lease_cb_) {
|
|
|
|
+ lease_cb_(E_DHCP_LEASE_TYPE_FAIL, this);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ struct pollfd ufd = { wakeup_[0], POLLIN, 0 };
|
|
|
|
+ poll(&ufd, 1, 3000);
|
|
|
|
+
|
|
|
|
+ return true;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+bool DhcpClient::renew() {
|
|
|
|
+ int s = -1;
|
|
|
|
+ sockaddr_in saddr;
|
|
|
|
+ socklen_t saddr_len;
|
|
|
|
+ sockaddr_in caddr;
|
|
|
|
+ socklen_t caddr_len;
|
|
|
|
+ struct timeval tv_out;
|
|
|
|
+ uint8_t hwaddr[6];
|
|
|
|
+ dhcp_msg renew_msg;
|
|
|
|
+ dhcp_msg recv_msg;
|
|
|
|
+ ssize_t renew_len;
|
|
|
|
+ ssize_t recv_len;
|
|
|
|
+ dhcp_info di;
|
|
|
|
+ bool ret = false;
|
|
|
|
+
|
|
|
|
+ s = socket(AF_INET, SOCK_DGRAM, 0);
|
|
|
|
+ if (s < 0) {
|
|
|
|
+ LOGE("[dhcp] create socket err\n");
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ saddr_len = sizeof(struct sockaddr_in);
|
|
|
|
+ memset(&saddr, 0, saddr_len);
|
|
|
|
+ saddr.sin_family = AF_INET;
|
|
|
|
+ saddr.sin_port = htons(PORT_BOOTP_SERVER);
|
|
|
|
+ saddr.sin_addr.s_addr = inet_addr(gateway_.c_str());
|
|
|
|
+
|
|
|
|
+ caddr_len = sizeof(struct sockaddr_in);
|
|
|
|
+ memset(&caddr, 0, caddr_len);
|
|
|
|
+ caddr.sin_family = AF_INET;
|
|
|
|
+ caddr.sin_port = htons(PORT_BOOTP_CLIENT);
|
|
|
|
+ caddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
|
|
+
|
|
|
|
+ if (bind(s, (sockaddr *) &caddr, caddr_len) < 0) {
|
|
|
|
+ LOGE("[dhcp] bind err\n");
|
|
|
|
+ goto END;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ tv_out.tv_sec = 2; // 等待2秒
|
|
|
|
+ tv_out.tv_usec = 0;
|
|
|
|
+ if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv_out, sizeof(tv_out)) < 0) {
|
|
|
|
+ LOGE("[dhcp] setsockopt err\n");
|
|
|
|
+ goto END;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ macaddr_to_hwaddr(macaddr_.c_str(), hwaddr);
|
|
|
|
+ renew_len = init_dhcp_renew_msg(&renew_msg, hwaddr, get_sec(), inet_addr(ip_.c_str()), inet_addr(gateway_.c_str()));
|
|
|
|
+ if (sendto(s, &renew_msg, renew_len, 0, (struct sockaddr *) &saddr, saddr_len) < 0) {
|
|
|
|
+ LOGE("[dhcp] sendto err\n");
|
|
|
|
+ goto END;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ recv_len = recvfrom(s, &recv_msg, sizeof(recv_msg), 0, (struct sockaddr *) &saddr, &saddr_len);
|
|
|
|
+ if (recv_len < 0) {
|
|
|
|
+ LOGE("[dhcp] recvfrom err\n");
|
|
|
|
+ goto END;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ LOGD("[dhcp] recv len %d\n", recv_len);
|
|
|
|
+ if (!is_valid_reply(&renew_msg, &recv_msg, recv_len)) {
|
|
|
|
+ goto END;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (decode_dhcp_msg(&recv_msg, recv_len, &di) == -1) {
|
|
|
|
+ LOGE("[dhcp] decode msg err\n");
|
|
|
|
+ goto END;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ dump_dhcp_info(&di);
|
|
|
|
+
|
|
|
|
+ if (di.type != DHCPACK) {
|
|
|
|
+ goto END;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ lease_ = di.lease;
|
|
|
|
+ ret = true;
|
|
|
|
+
|
|
|
|
+END:
|
|
|
|
+ close(s);
|
|
|
|
+
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+}
|