* Implemented lease time renewal.

* The DHCPClient is now added to its looper before doing the negotiation, so that
  it's BMessenger is already valid.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@19478 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2006-12-12 17:55:48 +00:00
parent a552ec1396
commit 6cc7630f36
3 changed files with 148 additions and 81 deletions
+8 -4
View File
@@ -43,11 +43,15 @@ AutoconfigLooper::_ReadyToRun()
// start with DHCP // start with DHCP
DHCPClient* client = new DHCPClient(fTarget, fDevice.String()); DHCPClient* client = new DHCPClient(fTarget, fDevice.String());
if (client->InitCheck() == B_OK) { AddHandler(client);
AddHandler(client);
if (client->Initialize() == B_OK)
return; return;
}
puts("DHCP failed miserably!"); RemoveHandler(client);
delete client;
puts("DHCP failed miserably!");
// DHCP obviously didn't work out, take some default values for now // DHCP obviously didn't work out, take some default values for now
// TODO: have a look at zeroconf // TODO: have a look at zeroconf
+127 -72
View File
@@ -11,6 +11,7 @@
#include "NetServer.h" #include "NetServer.h"
#include <Message.h> #include <Message.h>
#include <MessageRunner.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <errno.h> #include <errno.h>
@@ -123,6 +124,8 @@ struct dhcp_message {
#define ARP_HARDWARE_TYPE_ETHER 1 #define ARP_HARDWARE_TYPE_ETHER 1
const uint32 kMsgLeaseTime = 'lstm';
dhcp_message::dhcp_message(message_type type) dhcp_message::dhcp_message(message_type type)
{ {
@@ -291,8 +294,11 @@ dhcp_message::PutOption(uint8* options, message_option option, uint8* data, uint
DHCPClient::DHCPClient(BMessenger target, const char* device) DHCPClient::DHCPClient(BMessenger target, const char* device)
: BHandler("dhcp"), : BHandler("dhcp"),
fTarget(target),
fDevice(device), fDevice(device),
fConfiguration(kMsgConfigureInterface) fConfiguration(kMsgConfigureInterface),
fRunner(NULL),
fLeaseTime(0)
{ {
fTransactionID = system_time(); fTransactionID = system_time();
@@ -300,14 +306,49 @@ DHCPClient::DHCPClient(BMessenger target, const char* device)
if (fStatus < B_OK) if (fStatus < B_OK)
return; return;
dhcp_message discover(DHCP_DISCOVER); memset(&fServer, 0, sizeof(struct sockaddr_in));
_PrepareMessage(discover); fServer.sin_family = AF_INET;
fServer.sin_len = sizeof(struct sockaddr_in);
fServer.sin_port = htons(DHCP_SERVER_PORT);
}
DHCPClient::~DHCPClient()
{
if (fStatus != B_OK)
return;
delete fRunner;
int socket = ::socket(AF_INET, SOCK_DGRAM, 0); int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
if (socket < 0) { if (socket < 0)
fStatus = errno;
return; return;
}
// release lease
dhcp_message release(DHCP_RELEASE);
_PrepareMessage(release);
_SendMessage(socket, release, fServer);
close(socket);
}
status_t
DHCPClient::Initialize()
{
fStatus = _Negotiate(INIT);
printf("DHCP for %s, status: %s\n", fDevice.String(), strerror(fStatus));
return fStatus;
}
status_t
DHCPClient::_Negotiate(dhcp_state state)
{
int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
if (socket < 0)
return errno;
sockaddr_in local; sockaddr_in local;
memset(&local, 0, sizeof(struct sockaddr_in)); memset(&local, 0, sizeof(struct sockaddr_in));
@@ -317,16 +358,10 @@ DHCPClient::DHCPClient(BMessenger target, const char* device)
local.sin_addr.s_addr = INADDR_ANY; local.sin_addr.s_addr = INADDR_ANY;
if (bind(socket, (struct sockaddr *)&local, sizeof(local)) < 0) { if (bind(socket, (struct sockaddr *)&local, sizeof(local)) < 0) {
fStatus = errno;
close(socket); close(socket);
return; return errno;
} }
memset(&fServer, 0, sizeof(struct sockaddr_in));
fServer.sin_family = AF_INET;
fServer.sin_len = sizeof(struct sockaddr_in);
fServer.sin_port = htons(DHCP_SERVER_PORT);
sockaddr_in broadcast; sockaddr_in broadcast;
memset(&broadcast, 0, sizeof(struct sockaddr_in)); memset(&broadcast, 0, sizeof(struct sockaddr_in));
broadcast.sin_family = AF_INET; broadcast.sin_family = AF_INET;
@@ -337,42 +372,52 @@ DHCPClient::DHCPClient(BMessenger target, const char* device)
int option = 1; int option = 1;
setsockopt(socket, SOL_SOCKET, SO_BROADCAST, &option, sizeof(option)); setsockopt(socket, SOL_SOCKET, SO_BROADCAST, &option, sizeof(option));
_ResetTimeout(socket); dhcp_state initialState = state;
bigtime_t previousLeaseTime = fLeaseTime;
fLeaseTime = 0;
fStatus = _SendMessage(socket, discover, broadcast); status_t status = B_ERROR;
if (fStatus < B_OK) { time_t timeout;
close(socket); uint32 tries;
return; _ResetTimeout(socket, timeout, tries);
dhcp_message discover(DHCP_DISCOVER);
_PrepareMessage(discover);
dhcp_message request(DHCP_REQUEST);
_PrepareMessage(request);
if (state == INIT || state == REQUESTING) {
// send discover message
status = _SendMessage(socket, state == INIT ? discover : request,
state == INIT ? broadcast : fServer);
if (status < B_OK) {
close(socket);
return status;
}
} }
// receive loop until we've got an offer and acknowledged it // receive loop until we've got an offer and acknowledged it
enum {
INIT,
REQUESTING,
ACKNOWLEDGED,
} state = INIT;
dhcp_message request(DHCP_REQUEST);
// will be filled when handling a DHCP_OFFER
while (state != ACKNOWLEDGED) { while (state != ACKNOWLEDGED) {
char buffer[2048]; char buffer[2048];
ssize_t bytesReceived = recvfrom(socket, buffer, sizeof(buffer), ssize_t bytesReceived = recvfrom(socket, buffer, sizeof(buffer),
0, NULL, NULL); 0, NULL, NULL);
printf("recvfrom returned: %ld, %s\n", bytesReceived, strerror(errno));
if (bytesReceived == B_TIMED_OUT) { if (bytesReceived == B_TIMED_OUT) {
// depending on the state, we'll just try again // depending on the state, we'll just try again
if (!_TimeoutShift(socket)) { if (!_TimeoutShift(socket, timeout, tries)) {
fStatus = B_TIMED_OUT; close(socket);
break; return B_TIMED_OUT;
} }
if (state == INIT) if (state == INIT)
fStatus = _SendMessage(socket, discover, broadcast); status = _SendMessage(socket, discover, broadcast);
if (state == REQUESTING) if (state == REQUESTING)
fStatus = _SendMessage(socket, request, broadcast); status = _SendMessage(socket, request, initialState == INIT
? broadcast : fServer);
if (fStatus < B_OK) if (status < B_OK)
break; break;
} else if (bytesReceived < B_OK) } else if (bytesReceived < B_OK)
break; break;
@@ -414,11 +459,11 @@ DHCPClient::DHCPClient(BMessenger target, const char* device)
// request configuration from the server // request configuration from the server
_ResetTimeout(socket); _ResetTimeout(socket, timeout, tries);
state = REQUESTING; state = REQUESTING;
_PrepareMessage(request); _PrepareMessage(request);
fStatus = _SendMessage(socket, request, broadcast); status = _SendMessage(socket, request, broadcast);
// we're sending a broadcast so that all potential offers get an answer // we're sending a broadcast so that all potential offers get an answer
break; break;
} }
@@ -428,15 +473,20 @@ DHCPClient::DHCPClient(BMessenger target, const char* device)
if (state != REQUESTING) if (state != REQUESTING)
continue; continue;
// TODO: we might want to configure the stuff, don't we?
BMessage address;
_ParseOptions(*message, address);
// TODO: currently, only lease time and DNS is updated this way
// our address request has been acknowledged // our address request has been acknowledged
state = ACKNOWLEDGED; state = ACKNOWLEDGED;
// configure interface // configure interface
BMessage reply; BMessage reply;
target.SendMessage(&fConfiguration, &reply); fTarget.SendMessage(&fConfiguration, &reply);
if (reply.FindInt32("status", &fStatus) != B_OK) if (reply.FindInt32("status", &fStatus) != B_OK)
fStatus = B_OK; status = B_OK;
break; break;
} }
@@ -445,33 +495,36 @@ DHCPClient::DHCPClient(BMessenger target, const char* device)
continue; continue;
// try again (maybe we should prefer other servers if this happens more than once) // try again (maybe we should prefer other servers if this happens more than once)
fStatus = _SendMessage(socket, discover, broadcast); status = _SendMessage(socket, discover, broadcast);
if (fStatus == B_OK) if (status == B_OK)
state = INIT; state = INIT;
break; break;
} }
} }
close(socket); close(socket);
if (status == B_OK && fLeaseTime > 0) {
// notify early enough when the lease is
_RestartLease(fLeaseTime * 5/6);
fLeaseTime += system_time();
// make lease time absolute
} else
fLeaseTime = previousLeaseTime;
return status;
} }
DHCPClient::~DHCPClient() void
DHCPClient::_RestartLease(bigtime_t leaseTime)
{ {
if (fStatus != B_OK) if (leaseTime == 0)
return; return;
int socket = ::socket(AF_INET, SOCK_DGRAM, 0); printf("lease expires in %Ld seconds\n", leaseTime / 1000000);
if (socket < 0) BMessage lease(kMsgLeaseTime);
return; fRunner = new BMessageRunner(this, &lease, leaseTime * 5/6, 1);
// release lease
dhcp_message release(DHCP_RELEASE);
_PrepareMessage(release);
_SendMessage(socket, release, fServer);
close(socket);
} }
@@ -508,6 +561,7 @@ DHCPClient::_ParseOptions(dhcp_message& message, BMessage& address)
break; break;
case OPTION_ADDRESS_LEASE_TIME: case OPTION_ADDRESS_LEASE_TIME:
printf("lease time of %lu seconds\n", htonl(*(uint32*)data)); printf("lease time of %lu seconds\n", htonl(*(uint32*)data));
fLeaseTime = htonl(*(uint32*)data) * 1000000LL;
break; break;
case OPTION_HOST_NAME: case OPTION_HOST_NAME:
@@ -562,32 +616,32 @@ DHCPClient::_PrepareMessage(dhcp_message& message)
void void
DHCPClient::_ResetTimeout(int socket) DHCPClient::_ResetTimeout(int socket, time_t& timeout, uint32& tries)
{ {
fTimeout = DEFAULT_TIMEOUT; timeout = DEFAULT_TIMEOUT;
fTries = 0; tries = 0;
struct timeval value; struct timeval value;
value.tv_sec = fTimeout; value.tv_sec = timeout;
value.tv_usec = 0; value.tv_usec = 0;
setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &value, sizeof(value)); setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &value, sizeof(value));
} }
bool bool
DHCPClient::_TimeoutShift(int socket) DHCPClient::_TimeoutShift(int socket, time_t& timeout, uint32& tries)
{ {
fTimeout += fTimeout; timeout += timeout;
if (fTimeout > MAX_TIMEOUT) { if (timeout > MAX_TIMEOUT) {
fTimeout = DEFAULT_TIMEOUT; timeout = DEFAULT_TIMEOUT;
if (++fTries > 2) if (++tries > 2)
return false; return false;
} }
printf("DHCP timeout shift: %lu secs (try %lu)\n", fTimeout, fTries); printf("DHCP timeout shift: %lu secs (try %lu)\n", timeout, tries);
struct timeval value; struct timeval value;
value.tv_sec = fTimeout; value.tv_sec = timeout;
value.tv_usec = 0; value.tv_usec = 0;
setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &value, sizeof(value)); setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &value, sizeof(value));
@@ -624,17 +678,18 @@ DHCPClient::_SendMessage(int socket, dhcp_message& message, sockaddr_in& address
} }
status_t
DHCPClient::InitCheck()
{
printf("DHCP for %s, status: %s\n", fDevice.String(), strerror(fStatus));
return fStatus;
}
void void
DHCPClient::MessageReceived(BMessage* message) DHCPClient::MessageReceived(BMessage* message)
{ {
BHandler::MessageReceived(message); switch (message->what) {
case kMsgLeaseTime:
if (_Negotiate(REQUESTING) != B_OK)
_RestartLease((fLeaseTime - system_time()) / 10);
break;
default:
BHandler::MessageReceived(message);
break;
}
} }
+13 -5
View File
@@ -18,25 +18,34 @@
class BMessageRunner; class BMessageRunner;
class dhcp_message; class dhcp_message;
enum dhcp_state {
INIT,
REQUESTING,
ACKNOWLEDGED,
};
class DHCPClient : public BHandler { class DHCPClient : public BHandler {
public: public:
DHCPClient(BMessenger target, const char* device); DHCPClient(BMessenger target, const char* device);
virtual ~DHCPClient(); virtual ~DHCPClient();
status_t InitCheck(); status_t Initialize();
virtual void MessageReceived(BMessage* message); virtual void MessageReceived(BMessage* message);
private: private:
status_t _Negotiate(dhcp_state state);
void _ParseOptions(dhcp_message& message, BMessage& address); void _ParseOptions(dhcp_message& message, BMessage& address);
void _PrepareMessage(dhcp_message& message); void _PrepareMessage(dhcp_message& message);
status_t _SendMessage(int socket, dhcp_message& message, sockaddr_in& address) const; status_t _SendMessage(int socket, dhcp_message& message, sockaddr_in& address) const;
void _ResetTimeout(int socket); void _ResetTimeout(int socket, time_t& timeout, uint32& tries);
bool _TimeoutShift(int socket); bool _TimeoutShift(int socket, time_t& timeout, uint32& tries);
void _RestartLease(bigtime_t lease);
BString _ToString(const uint8* data) const; BString _ToString(const uint8* data) const;
BString _ToString(in_addr_t address) const; BString _ToString(in_addr_t address) const;
BMessenger fTarget;
BString fDevice; BString fDevice;
BMessage fConfiguration; BMessage fConfiguration;
BMessageRunner* fRunner; BMessageRunner* fRunner;
@@ -44,8 +53,7 @@ class DHCPClient : public BHandler {
uint32 fTransactionID; uint32 fTransactionID;
in_addr_t fAssignedAddress; in_addr_t fAssignedAddress;
sockaddr_in fServer; sockaddr_in fServer;
time_t fTimeout; bigtime_t fLeaseTime;
uint32 fTries;
status_t fStatus; status_t fStatus;
}; };