diff --git a/src/servers/net/DHCPClient.cpp b/src/servers/net/DHCPClient.cpp
index d5ffd0e..9d88257 100644
a
|
b
|
|
39 | 39 | #define DHCP_CLIENT_PORT 68 |
40 | 40 | #define DHCP_SERVER_PORT 67 |
41 | 41 | |
42 | | #define DEFAULT_TIMEOUT 4 // secs |
43 | | #define MAX_TIMEOUT 64 // secs |
| 42 | #define DEFAULT_TIMEOUT 0.25 // secs |
| 43 | #define MAX_TIMEOUT 64 // secs |
| 44 | |
| 45 | #define AS_USECS(t) (1000000 * t) |
44 | 46 | |
45 | 47 | #define MAX_RETRIES 5 |
46 | 48 | |
… |
… |
struct dhcp_message {
|
152 | 154 | static const char* TypeToString(message_type type); |
153 | 155 | } _PACKED; |
154 | 156 | |
| 157 | struct socket_timeout { |
| 158 | socket_timeout(int socket) |
| 159 | : |
| 160 | timeout(AS_USECS(DEFAULT_TIMEOUT)), |
| 161 | tries(0) |
| 162 | { |
| 163 | UpdateSocket(socket); |
| 164 | } |
| 165 | |
| 166 | time_t timeout; // in micro secs |
| 167 | int tries; |
| 168 | |
| 169 | bool Shift(int socket, bigtime_t stateMaxTime, const char* device); |
| 170 | void UpdateSocket(int socket) const; |
| 171 | }; |
| 172 | |
155 | 173 | #define DHCP_FLAG_BROADCAST 0x8000 |
156 | 174 | |
157 | 175 | #define ARP_HARDWARE_TYPE_ETHER 1 |
… |
… |
dhcp_message::TypeToString(message_type type)
|
417 | 435 | } |
418 | 436 | |
419 | 437 | |
| 438 | void |
| 439 | socket_timeout::UpdateSocket(int socket) const |
| 440 | { |
| 441 | struct timeval value; |
| 442 | value.tv_sec = timeout / 1000000; |
| 443 | value.tv_usec = timeout % 1000000; |
| 444 | setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &value, sizeof(value)); |
| 445 | } |
| 446 | |
| 447 | |
| 448 | bool |
| 449 | socket_timeout::Shift(int socket, bigtime_t stateMaxTime, const char* device) |
| 450 | { |
| 451 | tries++; |
| 452 | timeout += timeout; |
| 453 | if (timeout > AS_USECS(MAX_TIMEOUT)) |
| 454 | timeout = AS_USECS(MAX_TIMEOUT); |
| 455 | |
| 456 | if (tries > MAX_RETRIES) { |
| 457 | if (stateMaxTime == -1) |
| 458 | return false; |
| 459 | bigtime_t remaining = (stateMaxTime - system_time()) / 2 + 1; |
| 460 | timeout = std::min(remaining, (bigtime_t)AS_USECS(MAX_TIMEOUT)); |
| 461 | } |
| 462 | |
| 463 | syslog(LOG_DEBUG, "%s: Timeout shift: %lu secs (try %lu)\n", |
| 464 | device, timeout, tries); |
| 465 | |
| 466 | UpdateSocket(socket); |
| 467 | return true; |
| 468 | } |
| 469 | |
| 470 | |
420 | 471 | // #pragma mark - |
421 | 472 | |
422 | 473 | |
… |
… |
DHCPClient::_StateTransition(int socket, dhcp_state& state)
|
652 | 703 | BNetworkAddress broadcast; |
653 | 704 | broadcast.SetToBroadcast(AF_INET, DHCP_SERVER_PORT); |
654 | 705 | |
655 | | time_t timeout; |
656 | | uint32 tries; |
657 | | _ResetTimeout(socket, state, timeout, tries); |
| 706 | socket_timeout timeout(socket); |
658 | 707 | |
659 | 708 | dhcp_message discover(DHCP_DISCOVER); |
660 | 709 | _PrepareMessage(discover, state); |
… |
… |
DHCPClient::_StateTransition(int socket, dhcp_state& state)
|
684 | 733 | 0, (struct sockaddr*)&from, &fromLength); |
685 | 734 | if (bytesReceived < 0 && errno == B_TIMED_OUT) { |
686 | 735 | // depending on the state, we'll just try again |
687 | | if (!_TimeoutShift(socket, state, timeout, tries)) |
| 736 | if (!_TimeoutShift(socket, state, timeout)) |
688 | 737 | return B_TIMED_OUT; |
689 | 738 | skipRequest = false; |
690 | 739 | continue; |
… |
… |
DHCPClient::_PrepareMessage(dhcp_message& message, dhcp_state state)
|
893 | 942 | } |
894 | 943 | |
895 | 944 | |
896 | | void |
897 | | DHCPClient::_ResetTimeout(int socket, dhcp_state& state, time_t& timeout, |
898 | | uint32& tries) |
899 | | { |
900 | | timeout = DEFAULT_TIMEOUT; |
901 | | tries = 0; |
902 | | |
903 | | struct timeval value; |
904 | | value.tv_sec = timeout; |
905 | | value.tv_usec = rand() % 1000000; |
906 | | setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &value, sizeof(value)); |
907 | | } |
908 | | |
909 | | |
910 | 945 | bool |
911 | | DHCPClient::_TimeoutShift(int socket, dhcp_state& state, time_t& timeout, |
912 | | uint32& tries) |
| 946 | DHCPClient::_TimeoutShift(int socket, dhcp_state& state, |
| 947 | socket_timeout& timeout) |
913 | 948 | { |
914 | | if (state == RENEWING && system_time() > fRebindingTime) { |
915 | | state = REBINDING; |
| 949 | bigtime_t stateMaxTime = -1; |
| 950 | if (state == RENEWING) |
| 951 | stateMaxTime = fRebindingTime; |
| 952 | else if (state == REBINDING) |
| 953 | stateMaxTime = fLeaseTime; |
| 954 | |
| 955 | if (system_time() > stateMaxTime) { |
| 956 | state = state == REBINDING ? INIT : REBINDING; |
916 | 957 | return false; |
917 | 958 | } |
918 | 959 | |
919 | | if (state == REBINDING && system_time() > fLeaseTime) { |
920 | | state = INIT; |
921 | | return false; |
922 | | } |
923 | | |
924 | | tries++; |
925 | | timeout += timeout; |
926 | | if (timeout > MAX_TIMEOUT) |
927 | | timeout = MAX_TIMEOUT; |
928 | | |
929 | | if (tries > MAX_RETRIES) { |
930 | | bigtime_t remaining = 0; |
931 | | if (state == RENEWING) |
932 | | remaining = (fRebindingTime - system_time()) / 2 + 1; |
933 | | else if (state == REBINDING) |
934 | | remaining = (fLeaseTime - system_time()) / 2 + 1; |
935 | | else |
936 | | return false; |
937 | | |
938 | | timeout = std::max(remaining / 1000000, bigtime_t(60)); |
939 | | } |
940 | | |
941 | | syslog(LOG_DEBUG, "%s: Timeout shift: %lu secs (try %lu)\n", |
942 | | Device(), timeout, tries); |
943 | | |
944 | | struct timeval value; |
945 | | value.tv_sec = timeout; |
946 | | value.tv_usec = rand() % 1000000; |
947 | | setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &value, sizeof(value)); |
948 | | |
949 | | return true; |
| 960 | return timeout.Shift(socket, stateMaxTime, Device()); |
950 | 961 | } |
951 | 962 | |
952 | 963 | |
diff --git a/src/servers/net/DHCPClient.h b/src/servers/net/DHCPClient.h
index b0a02d4..63b3bf0 100644
a
|
b
|
|
18 | 18 | |
19 | 19 | class BMessageRunner; |
20 | 20 | class dhcp_message; |
| 21 | class socket_timeout; |
21 | 22 | |
22 | 23 | |
23 | 24 | enum dhcp_state { |
… |
… |
private:
|
55 | 56 | status_t _SendMessage(int socket, dhcp_message& message, |
56 | 57 | const BNetworkAddress& address) const; |
57 | 58 | dhcp_state _CurrentState() const; |
58 | | void _ResetTimeout(int socket, dhcp_state& state, |
59 | | time_t& timeout, uint32& tries); |
60 | 59 | bool _TimeoutShift(int socket, dhcp_state& state, |
61 | | time_t& timeout, uint32& tries); |
| 60 | socket_timeout& timeout); |
62 | 61 | void _RestartLease(bigtime_t lease); |
63 | 62 | |
64 | 63 | static BString _AddressToString(const uint8* data); |