C++程序  |  103行  |  3.09 KB

/*
 * Copyright 2017, 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.
 */
#pragma once

#include "interface.h"
#include "message.h"
#include "result.h"
#include "router.h"
#include "socket.h"
#include "timer.h"

#include <netinet/in.h>
#include <stdint.h>

#include <random>


class DhcpClient {
public:
    DhcpClient();

    // Initialize the DHCP client to listen on |interfaceName|.
    Result init(const char* interfaceName);
    Result run();
private:
    enum class State {
        Init,
        Selecting,
        Requesting,
        Bound,
        Renewing,
        Rebinding
    };
    const char* stateToStr(State state);

    // Wait for any pending timeouts
    void waitAndReceive(const sigset_t& pollSignalMask);
    // Create a varying timeout (+- 1 second) based on the next timeout.
    uint32_t calculateTimeoutMillis();
    // Increase the next timeout in a manner that's compliant with the DHCP RFC.
    void increaseTimeout();
    // Move to |state|, the next poll timeout will be zero and the new
    // state will be immediately evaluated.
    void setNextState(State state);
    // Configure network interface based on the DHCP configuration in |msg|.
    bool configureDhcp(const Message& msg);
    // Halt network operations on the network interface for when configuration
    // is not possible and the protocol demands it.
    void haltNetwork();
    // Receive a message on the socket and populate |msg| with the received
    // data. If the message is a valid DHCP message the method returns true. If
    // it's not valid false is returned.
    bool receiveDhcpMessage(Message* msg);

    void sendDhcpDiscover();
    void sendDhcpRequest(in_addr_t destination);
    void sendMessage(const Message& message);
    Result send(in_addr_t source, in_addr_t destination,
                uint16_t sourcePort, uint16_t destinationPort,
                const uint8_t* data, size_t size);

    std::mt19937 mRandomEngine; // Mersenne Twister RNG
    std::uniform_int_distribution<int> mRandomDistribution;

    struct DhcpInfo {
        uint32_t t1;
        uint32_t t2;
        uint32_t leaseTime;
        uint16_t mtu;
        in_addr_t dns[4];
        in_addr_t gateway;
        in_addr_t subnetMask;
        in_addr_t serverId;
        in_addr_t offeredAddress;
    } mDhcpInfo;

    Router mRouter;
    Interface mInterface;
    Message mLastMsg;
    Timer mT1, mT2;
    Socket mSocket;
    State mState;
    uint32_t mNextTimeout;
    bool mFuzzNextTimeout;

    in_addr_t mRequestAddress; // Address we'd like to use in requests
    in_addr_t mServerAddress;  // Server to send request to
};