[haiku-commits] BRANCH pdziepak-github.network [6972b91] src/servers/net

  • From: pdziepak-github.network <community@xxxxxxxxxxxx>
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Thu, 25 Jul 2013 04:15:31 +0200 (CEST)

added 1 changeset to branch 'refs/remotes/pdziepak-github/network'
old head: 0000000000000000000000000000000000000000
new head: 6972b91e17f19950fbf994033846a856bff4b796
overview: https://github.com/pdziepak/Haiku/compare/6972b91

----------------------------------------------------------------------------

6972b91: servers/net: Make DHCP client more RFC 2131 compliant
  
   * The client should enter state REBINDING only when RENEWING times
     out.
   * When in RENEWING or REBINDING state do not give up retrying
     unless the lease expires.
   * Fix bug sending 2^n DHCP requests at n-th lease renewal.
   * Use timeout values and renewal/rebinding times suggested by the
     RFC.
   * Use different XIDs in subsequent transactions.

                                    [ Pawel Dziepak <pdziepak@xxxxxxxxxxx> ]

----------------------------------------------------------------------------

Commit:      6972b91e17f19950fbf994033846a856bff4b796
Author:      Pawel Dziepak <pdziepak@xxxxxxxxxxx>
Date:        Thu Jul 25 01:52:46 2013 UTC

----------------------------------------------------------------------------

3 files changed, 195 insertions(+), 207 deletions(-)
src/servers/net/DHCPClient.cpp | 388 ++++++++++++++++++-------------------
src/servers/net/DHCPClient.h   |  12 +-
src/servers/net/NetServer.cpp  |   2 +

----------------------------------------------------------------------------

diff --git a/src/servers/net/DHCPClient.cpp b/src/servers/net/DHCPClient.cpp
index a2ae864..850861a 100644
--- a/src/servers/net/DHCPClient.cpp
+++ b/src/servers/net/DHCPClient.cpp
@@ -16,6 +16,7 @@
 #include <NetworkDevice.h>
 #include <NetworkInterface.h>
 
+#include <algorithm>
 #include <arpa/inet.h>
 #include <errno.h>
 #include <stdio.h>
@@ -38,8 +39,10 @@
 #define DHCP_CLIENT_PORT       68
 #define DHCP_SERVER_PORT       67
 
-#define DEFAULT_TIMEOUT                2       // secs
-#define MAX_TIMEOUT                    15      // secs
+#define DEFAULT_TIMEOUT                4       // secs
+#define MAX_TIMEOUT                    64      // secs
+
+#define MAX_RETRIES                    5
 
 enum message_opcode {
        BOOT_REQUEST = 1,
@@ -427,10 +430,7 @@ DHCPClient::DHCPClient(BMessenger target, const char* 
device)
        fServer(AF_INET, NULL, DHCP_SERVER_PORT),
        fLeaseTime(0)
 {
-       fStartTime = system_time();
-       fTransactionID = (uint32)fStartTime;
-
-       srand(fTransactionID);
+       fTransactionID = (uint32)system_time() ^ rand();
 
        BNetworkAddress link;
        BNetworkInterface interface(device);
@@ -498,13 +498,22 @@ DHCPClient::Initialize()
 status_t
 DHCPClient::_Negotiate(dhcp_state state)
 {
+       if (state == BOUND)
+               return B_OK;
+
+       fStartTime = system_time();
+       fTransactionID++;
+
+       char hostName[MAXHOSTNAMELEN];
+       if (gethostname(hostName, MAXHOSTNAMELEN) == 0)
+               fHostName.SetTo(hostName, MAXHOSTNAMELEN);
+       else
+               fHostName.Truncate(0);
+
        int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
        if (socket < 0)
                return errno;
 
-       BNetworkAddress local;
-       local.SetToWildcard(AF_INET, DHCP_CLIENT_PORT);
-
        // Enable reusing the port. This is needed in case there is more
        // than 1 interface that needs to be configured. Note that the only 
reason
        // this works is because there is code below to bind to a specific
@@ -512,17 +521,125 @@ DHCPClient::_Negotiate(dhcp_state state)
        int option = 1;
        setsockopt(socket, SOL_SOCKET, SO_REUSEPORT, &option, sizeof(option));
 
+       BNetworkAddress local;
+       local.SetToWildcard(AF_INET, DHCP_CLIENT_PORT);
+
+       option = 1;
+       setsockopt(socket, SOL_SOCKET, SO_BROADCAST, &option, sizeof(option));
+
        if (bind(socket, local, local.Length()) < 0) {
                close(socket);
                return errno;
        }
 
-       BNetworkAddress broadcast;
-       broadcast.SetToBroadcast(AF_INET, DHCP_SERVER_PORT);
+       bigtime_t previousLeaseTime = fLeaseTime;
 
-       option = 1;
-       setsockopt(socket, SOL_SOCKET, SO_BROADCAST, &option, sizeof(option));
+       status_t status = B_OK;
+       while (state != BOUND) {
+               status = _StateTransition(socket, state);
+               if (status != B_OK && (state == SELECTING || state == 
REBOOTING))
+                       break;
+       }
+
+       close(socket);
 
+       if (fLeaseTime == 0)
+               fLeaseTime = previousLeaseTime;
+       if (fLeaseTime == 0)
+               fLeaseTime = 60;
+
+       if (fRenewalTime == 0)
+               fRenewalTime = fLeaseTime / 2;
+       if (fRebindingTime == 0)
+               fRebindingTime = fLeaseTime * 7 / 8;
+       fLeaseTime += fRequestTime;
+       fRenewalTime += fRequestTime;
+       fRebindingTime += fRequestTime;
+       _RestartLease(fRenewalTime);
+
+       fStatus = status;
+       if (status)
+               return status;
+
+       // configure interface
+       BMessage reply;
+       status = Target().SendMessage(&fConfiguration, &reply);
+       if (status == B_OK)
+               status = reply.FindInt32("status", &fStatus);
+
+       // configure resolver
+       reply.MakeEmpty();
+       fResolverConfiguration.AddString("device", Device());
+       status = Target().SendMessage(&fResolverConfiguration, &reply);
+       if (status == B_OK)
+               status = reply.FindInt32("status", &fStatus);
+       return status;
+}
+
+
+status_t
+DHCPClient::_GotMessage(dhcp_state& state, dhcp_message* message)
+{
+       switch (state) {
+               case SELECTING:
+                       if (message->Type() == DHCP_OFFER) {
+                               state = REQUESTING;
+
+                               fAssignedAddress = message->your_address;
+                               syslog(LOG_INFO, "  your_address: %s\n",
+                                               
_AddressToString(fAssignedAddress).String());
+
+                               fConfiguration.MakeEmpty();
+                               fConfiguration.AddString("device", Device());
+                               fConfiguration.AddBool("auto_configured", true);
+
+                               BMessage address;
+                               address.AddString("family", "inet");
+                               address.AddString("address", 
_AddressToString(fAssignedAddress));
+                               fResolverConfiguration.MakeEmpty();
+                               _ParseOptions(*message, address, 
fResolverConfiguration);
+
+                               fConfiguration.AddMessage("address", &address);
+                               return B_OK;
+                       }
+
+                       return B_BAD_VALUE;
+
+               case REBOOTING:
+               case REBINDING:
+               case RENEWING:
+               case REQUESTING:
+                       if (message->Type() == DHCP_ACK) {
+                               // TODO: we might want to configure the stuff, 
don't we?
+                               BMessage address;
+                               fResolverConfiguration.MakeEmpty();
+                               _ParseOptions(*message, address, 
fResolverConfiguration);
+                                       // TODO: currently, only lease time and 
DNS is updated this
+                                       // way
+
+                               // our address request has been acknowledged
+                               state = BOUND;
+
+                               return B_OK;
+                       }
+
+                       if (message->Type() == DHCP_NACK) {
+                               // server reject our request on previous 
assigned address
+                               // back to square one...
+                               fAssignedAddress = 0;
+                               state = INIT;
+                               return B_OK;
+                       }
+
+               default:
+                       return B_BAD_VALUE;
+       }
+}
+
+
+status_t
+DHCPClient::_StateTransition(int socket, dhcp_state& state)
+{
        if (state == INIT) {
                // The local interface does not have an address yet, bind the 
socket
                // to the device directly.
@@ -532,21 +649,12 @@ DHCPClient::_Negotiate(dhcp_state state)
                setsockopt(socket, SOL_SOCKET, SO_BINDTODEVICE, &index, 
sizeof(int));
        }
 
-       bigtime_t previousLeaseTime = fLeaseTime;
-       fLeaseTime = 0;
-       fRenewalTime = 0;
-       fRebindingTime = 0;
+       BNetworkAddress broadcast;
+       broadcast.SetToBroadcast(AF_INET, DHCP_SERVER_PORT);
 
-       status_t status = B_ERROR;
        time_t timeout;
        uint32 tries;
-       _ResetTimeout(socket, timeout, tries);
-
-       char hostName[MAXHOSTNAMELEN];
-       if (gethostname(hostName, MAXHOSTNAMELEN) == 0)
-               fHostName.SetTo(hostName, MAXHOSTNAMELEN);
-       else
-               fHostName.Truncate(0);
+       _ResetTimeout(socket, state, timeout, tries);
 
        dhcp_message discover(DHCP_DISCOVER);
        _PrepareMessage(discover, state);
@@ -554,34 +662,36 @@ DHCPClient::_Negotiate(dhcp_state state)
        dhcp_message request(DHCP_REQUEST);
        _PrepareMessage(request, state);
 
-       // send discover/request message
-       _SendMessage(socket, state == INIT ? discover : request,
-               state != RENEWING ? broadcast : fServer);
-               // no need to check the status; in case of an error we'll just 
send
-               // the message again
-
-       // receive loop until we've got an offer and acknowledged it
+       bool skipRequest = false;
+       dhcp_state originalState = state;
+       fRequestTime = system_time();
+       while (true) {
+               if (!skipRequest) {
+                       _SendMessage(socket, originalState == INIT ? discover : 
request,
+                               originalState == RENEWING ? fServer : 
broadcast);
+
+                       if (originalState == INIT)
+                               state = SELECTING;
+                       else if (originalState == INIT_REBOOT)
+                               state = REBOOTING;
+               }
 
-       while (state != BOUND) {
                char buffer[2048];
                struct sockaddr_in from;
                socklen_t fromLength = sizeof(from);
+
                ssize_t bytesReceived = recvfrom(socket, buffer, sizeof(buffer),
                        0, (struct sockaddr*)&from, &fromLength);
                if (bytesReceived < 0 && errno == B_TIMED_OUT) {
                        // depending on the state, we'll just try again
-                       if (!_TimeoutShift(socket, timeout, tries)) {
-                               close(socket);
+                       if (!_TimeoutShift(socket, state, timeout, tries))
                                return B_TIMED_OUT;
-                       }
-
-                       _SendMessage(socket, state == INIT ? discover : request,
-                               state != RENEWING ? broadcast : fServer);
+                       skipRequest = false;
                        continue;
-
                } else if (bytesReceived < 0)
-                       break;
+                       return errno;
 
+               skipRequest = true;
                dhcp_message* message = (dhcp_message*)buffer;
                if (message->transaction_id != htonl(fTransactionID)
                        || !message->HasOptions()
@@ -591,137 +701,15 @@ DHCPClient::_Negotiate(dhcp_state state)
                        continue;
                }
 
-               // advance from startup state
-               if (state == INIT)
-                       state = SELECTING;
-               else if (state == INIT_REBOOT)
-                       state = REBOOTING;
-
                syslog(LOG_DEBUG, "%s: Received %s from %s\n",
                        Device(), dhcp_message::TypeToString(message->Type()),
                        _AddressToString(from.sin_addr.s_addr).String());
 
-               switch (message->Type()) {
-                       case DHCP_NONE:
-                       default:
-                               // ignore this message
-                               break;
-
-                       case DHCP_OFFER:
-                       {
-                               // first offer wins
-                               if (state != SELECTING)
-                                       break;
-
-                               // collect interface options
-
-                               fAssignedAddress = message->your_address;
-                               syslog(LOG_INFO, "  your_address: %s\n",
-                                               
_AddressToString(fAssignedAddress).String());
-
-                               fConfiguration.MakeEmpty();
-                               fConfiguration.AddString("device", Device());
-                               fConfiguration.AddBool("auto_configured", true);
-
-                               BMessage address;
-                               address.AddString("family", "inet");
-                               address.AddString("address", 
_AddressToString(fAssignedAddress));
-                               fResolverConfiguration.MakeEmpty();
-                               _ParseOptions(*message, address, 
fResolverConfiguration);
-
-                               fConfiguration.AddMessage("address", &address);
-
-                               // request configuration from the server
-
-                               _ResetTimeout(socket, timeout, tries);
-                               state = REQUESTING;
-                               _PrepareMessage(request, state);
-
-                               status = _SendMessage(socket, request, 
broadcast);
-                                       // we're sending a broadcast so that 
all potential offers
-                                       // get an answer
-                               break;
-                       }
-
-                       case DHCP_ACK:
-                       {
-                               if (state != REQUESTING
-                                       && state != REBOOTING
-                                       && state != REBINDING
-                                       && state != RENEWING)
-                                       continue;
-
-                               // TODO: we might want to configure the stuff, 
don't we?
-                               BMessage address;
-                               fResolverConfiguration.MakeEmpty();
-                               _ParseOptions(*message, address, 
fResolverConfiguration);
-                                       // TODO: currently, only lease time and 
DNS is updated this
-                                       // way
-
-                               // our address request has been acknowledged
-                               state = BOUND;
-
-                               // configure interface
-                               BMessage reply;
-                               status = Target().SendMessage(&fConfiguration, 
&reply);
-                               if (status == B_OK)
-                                       status = reply.FindInt32("status", 
&fStatus);
-
-                               // configure resolver
-                               reply.MakeEmpty();
-                               fResolverConfiguration.AddString("device", 
Device());
-                               status = 
Target().SendMessage(&fResolverConfiguration, &reply);
-                               if (status == B_OK)
-                                       status = reply.FindInt32("status", 
&fStatus);
-                               break;
-                       }
-
-                       case DHCP_NACK:
-                               if (state != REQUESTING
-                                       && state != REBOOTING
-                                       && state != REBINDING
-                                       && state != RENEWING)
-                                       continue;
-
-                               if (state == REBOOTING) {
-                                       // server reject our request on 
previous assigned address
-                                       // back to square one...
-                                       fAssignedAddress = 0;
-                               }
-
-                               // try again (maybe we should prefer other 
servers if this
-                               // happens more than once)
-                               status = _SendMessage(socket, discover, 
broadcast);
-                               if (status == B_OK)
-                                       state = INIT;
-                               break;
-               }
-       }
-
-       close(socket);
-
-       if (status == B_OK && fLeaseTime > 0) {
-               // notify early enough when the lease is
-               if (fRenewalTime == 0)
-                       fRenewalTime = fLeaseTime * 2/3;
-               if (fRebindingTime == 0)
-                       fRebindingTime = fLeaseTime * 5/6;
-
-               bigtime_t now = system_time();
-               _RestartLease(fRenewalTime);
-
-               fLeaseTime += now;
-               fRenewalTime += now;
-               fRebindingTime += now;
-                       // make lease times absolute
-       } else {
-               fLeaseTime = previousLeaseTime;
-               bigtime_t now = system_time();
-               fRenewalTime = (fLeaseTime - now) * 2/3 + now;
-               fRebindingTime = (fLeaseTime - now) * 5/6 + now;
+               if (_GotMessage(state, message) == B_OK)
+                       break;
        }
 
-       return status;
+       return B_OK;
 }
 
 
@@ -732,7 +720,7 @@ DHCPClient::_RestartLease(bigtime_t leaseTime)
                return;
 
        BMessage lease(kMsgLeaseTime);
-       fRunner = new BMessageRunner(this, &lease, leaseTime, 1);
+       fRunner = new BMessageRunner(this, &lease, leaseTime - system_time(), 
1);
 }
 
 
@@ -899,7 +887,8 @@ DHCPClient::_PrepareMessage(dhcp_message& message, 
dhcp_state state)
 
 
 void
-DHCPClient::_ResetTimeout(int socket, time_t& timeout, uint32& tries)
+DHCPClient::_ResetTimeout(int socket, dhcp_state& state, time_t& timeout,
+       uint32& tries)
 {
        timeout = DEFAULT_TIMEOUT;
        tries = 0;
@@ -912,15 +901,36 @@ DHCPClient::_ResetTimeout(int socket, time_t& timeout, 
uint32& tries)
 
 
 bool
-DHCPClient::_TimeoutShift(int socket, time_t& timeout, uint32& tries)
+DHCPClient::_TimeoutShift(int socket, dhcp_state& state, time_t& timeout,
+       uint32& tries)
 {
-       timeout += timeout;
-       if (timeout > MAX_TIMEOUT) {
-               timeout = DEFAULT_TIMEOUT;
+       if (state == RENEWING && system_time() > fRebindingTime) {
+               state = REBINDING;
+               return false;
+       }
 
-               if (++tries > 2)
+       if (state == REBINDING && system_time() > fLeaseTime) {
+               state = INIT;
+               return false;
+       }
+               
+       tries++;
+       timeout += timeout;
+       if (timeout > MAX_TIMEOUT)
+               timeout = MAX_TIMEOUT;
+
+       if (tries > MAX_RETRIES) {
+               bigtime_t remaining = 0;
+               if (state == RENEWING)
+                       remaining = (fRebindingTime - system_time()) / 2 + 1;
+               else if (state == REBINDING)
+                       remaining = (fLeaseTime - system_time()) / 2 + 1;
+               else
                        return false;
+
+               timeout = std::max(remaining / 1000000, bigtime_t(60));
        }
+
        syslog(LOG_DEBUG, "%s: Timeout shift: %lu secs (try %lu)\n",
                Device(), timeout, tries);
 
@@ -978,13 +988,12 @@ DHCPClient::_CurrentState() const
 {
        bigtime_t now = system_time();
 
-       if (now > fLeaseTime || fStatus < B_OK)
+       if (now > fLeaseTime || fStatus != B_OK)
                return INIT;
        if (now >= fRebindingTime)
                return REBINDING;
        if (now >= fRenewalTime)
                return RENEWING;
-
        return BOUND;
 }
 
@@ -994,35 +1003,8 @@ DHCPClient::MessageReceived(BMessage* message)
 {
        switch (message->what) {
                case kMsgLeaseTime:
-               {
-                       dhcp_state state = _CurrentState();
-
-                       bigtime_t next;
-                       if (_Negotiate(state) == B_OK) {
-                               switch (state) {
-                                       case RENEWING:
-                                               next = fRebindingTime;
-                                               break;
-                                       case REBINDING:
-                                       default:
-                                               next = fRenewalTime;
-                                               break;
-                               }
-                       } else {
-                               switch (state) {
-                                       case RENEWING:
-                                               next = (fLeaseTime - 
fRebindingTime) / 4 + system_time();
-                                               break;
-                                       case REBINDING:
-                                       default:
-                                               next = (fLeaseTime - 
fRenewalTime) / 4 + system_time();
-                                               break;
-                               }
-                       }
-
-                       _RestartLease(next - system_time());
+                       _Negotiate(_CurrentState());
                        break;
-               }
 
                default:
                        BHandler::MessageReceived(message);
diff --git a/src/servers/net/DHCPClient.h b/src/servers/net/DHCPClient.h
index 9cce7e1..b0a02d4 100644
--- a/src/servers/net/DHCPClient.h
+++ b/src/servers/net/DHCPClient.h
@@ -44,6 +44,9 @@ public:
 
 private:
                        status_t                        _Negotiate(dhcp_state 
state);
+                       status_t                        _GotMessage(dhcp_state& 
state,
+                                                                       
dhcp_message* message);
+                       status_t                        _StateTransition(int 
socket, dhcp_state& state);
                        void                            
_ParseOptions(dhcp_message& message,
                                                                        
BMessage& address,
                                                                        
BMessage& resolverConfiguration);
@@ -52,10 +55,10 @@ private:
                        status_t                        _SendMessage(int 
socket, dhcp_message& message,
                                                                        const 
BNetworkAddress& address) const;
                        dhcp_state                      _CurrentState() const;
-                       void                            _ResetTimeout(int 
socket, time_t& timeout,
-                                                                       uint32& 
tries);
-                       bool                            _TimeoutShift(int 
socket, time_t& timeout,
-                                                                       uint32& 
tries);
+                       void                            _ResetTimeout(int 
socket, dhcp_state& state,
+                                                                       time_t& 
timeout, uint32& tries);
+                       bool                            _TimeoutShift(int 
socket, dhcp_state& state,
+                                                                       time_t& 
timeout, uint32& tries);
                        void                            _RestartLease(bigtime_t 
lease);
 
        static  BString                         _AddressToString(const uint8* 
data);
@@ -71,6 +74,7 @@ private:
                        in_addr_t                       fAssignedAddress;
                        BNetworkAddress         fServer;
                        bigtime_t                       fStartTime;
+                       bigtime_t                       fRequestTime;
                        bigtime_t                       fRenewalTime;
                        bigtime_t                       fRebindingTime;
                        bigtime_t                       fLeaseTime;
diff --git a/src/servers/net/NetServer.cpp b/src/servers/net/NetServer.cpp
index e97f316..de24111 100644
--- a/src/servers/net/NetServer.cpp
+++ b/src/servers/net/NetServer.cpp
@@ -1388,6 +1388,8 @@ NetServer::_ConvertNetworkFromSettings(BMessage& message)
 int
 main(int argc, char** argv)
 {
+       srand(system_time());
+
        status_t status;
        NetServer server(status);
        if (status != B_OK) {


Other related posts:

  • » [haiku-commits] BRANCH pdziepak-github.network [6972b91] src/servers/net - pdziepak-github . network