* 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:
parent
a552ec1396
commit
6cc7630f36
@ -43,11 +43,15 @@ AutoconfigLooper::_ReadyToRun()
|
||||
// start with DHCP
|
||||
|
||||
DHCPClient* client = new DHCPClient(fTarget, fDevice.String());
|
||||
if (client->InitCheck() == B_OK) {
|
||||
AddHandler(client);
|
||||
AddHandler(client);
|
||||
|
||||
if (client->Initialize() == B_OK)
|
||||
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
|
||||
// TODO: have a look at zeroconf
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "NetServer.h"
|
||||
|
||||
#include <Message.h>
|
||||
#include <MessageRunner.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
@ -123,6 +124,8 @@ struct dhcp_message {
|
||||
|
||||
#define ARP_HARDWARE_TYPE_ETHER 1
|
||||
|
||||
const uint32 kMsgLeaseTime = 'lstm';
|
||||
|
||||
|
||||
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)
|
||||
: BHandler("dhcp"),
|
||||
fTarget(target),
|
||||
fDevice(device),
|
||||
fConfiguration(kMsgConfigureInterface)
|
||||
fConfiguration(kMsgConfigureInterface),
|
||||
fRunner(NULL),
|
||||
fLeaseTime(0)
|
||||
{
|
||||
fTransactionID = system_time();
|
||||
|
||||
@ -300,14 +306,49 @@ DHCPClient::DHCPClient(BMessenger target, const char* device)
|
||||
if (fStatus < B_OK)
|
||||
return;
|
||||
|
||||
dhcp_message discover(DHCP_DISCOVER);
|
||||
_PrepareMessage(discover);
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
DHCPClient::~DHCPClient()
|
||||
{
|
||||
if (fStatus != B_OK)
|
||||
return;
|
||||
|
||||
delete fRunner;
|
||||
|
||||
int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (socket < 0) {
|
||||
fStatus = errno;
|
||||
if (socket < 0)
|
||||
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;
|
||||
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;
|
||||
|
||||
if (bind(socket, (struct sockaddr *)&local, sizeof(local)) < 0) {
|
||||
fStatus = errno;
|
||||
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;
|
||||
memset(&broadcast, 0, sizeof(struct sockaddr_in));
|
||||
broadcast.sin_family = AF_INET;
|
||||
@ -337,42 +372,52 @@ DHCPClient::DHCPClient(BMessenger target, const char* device)
|
||||
int option = 1;
|
||||
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);
|
||||
if (fStatus < B_OK) {
|
||||
close(socket);
|
||||
return;
|
||||
status_t status = B_ERROR;
|
||||
time_t timeout;
|
||||
uint32 tries;
|
||||
_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
|
||||
|
||||
enum {
|
||||
INIT,
|
||||
REQUESTING,
|
||||
ACKNOWLEDGED,
|
||||
} state = INIT;
|
||||
|
||||
dhcp_message request(DHCP_REQUEST);
|
||||
// will be filled when handling a DHCP_OFFER
|
||||
|
||||
while (state != ACKNOWLEDGED) {
|
||||
char buffer[2048];
|
||||
ssize_t bytesReceived = recvfrom(socket, buffer, sizeof(buffer),
|
||||
0, NULL, NULL);
|
||||
printf("recvfrom returned: %ld, %s\n", bytesReceived, strerror(errno));
|
||||
if (bytesReceived == B_TIMED_OUT) {
|
||||
// depending on the state, we'll just try again
|
||||
if (!_TimeoutShift(socket)) {
|
||||
fStatus = B_TIMED_OUT;
|
||||
break;
|
||||
if (!_TimeoutShift(socket, timeout, tries)) {
|
||||
close(socket);
|
||||
return B_TIMED_OUT;
|
||||
}
|
||||
|
||||
if (state == INIT)
|
||||
fStatus = _SendMessage(socket, discover, broadcast);
|
||||
status = _SendMessage(socket, discover, broadcast);
|
||||
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;
|
||||
} else if (bytesReceived < B_OK)
|
||||
break;
|
||||
@ -414,11 +459,11 @@ DHCPClient::DHCPClient(BMessenger target, const char* device)
|
||||
|
||||
// request configuration from the server
|
||||
|
||||
_ResetTimeout(socket);
|
||||
_ResetTimeout(socket, timeout, tries);
|
||||
state = REQUESTING;
|
||||
_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
|
||||
break;
|
||||
}
|
||||
@ -428,15 +473,20 @@ DHCPClient::DHCPClient(BMessenger target, const char* device)
|
||||
if (state != REQUESTING)
|
||||
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
|
||||
state = ACKNOWLEDGED;
|
||||
|
||||
// configure interface
|
||||
BMessage reply;
|
||||
target.SendMessage(&fConfiguration, &reply);
|
||||
fTarget.SendMessage(&fConfiguration, &reply);
|
||||
|
||||
if (reply.FindInt32("status", &fStatus) != B_OK)
|
||||
fStatus = B_OK;
|
||||
status = B_OK;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -445,33 +495,36 @@ DHCPClient::DHCPClient(BMessenger target, const char* device)
|
||||
continue;
|
||||
|
||||
// try again (maybe we should prefer other servers if this happens more than once)
|
||||
fStatus = _SendMessage(socket, discover, broadcast);
|
||||
if (fStatus == B_OK)
|
||||
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
|
||||
_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;
|
||||
|
||||
int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (socket < 0)
|
||||
return;
|
||||
|
||||
// release lease
|
||||
|
||||
dhcp_message release(DHCP_RELEASE);
|
||||
_PrepareMessage(release);
|
||||
|
||||
_SendMessage(socket, release, fServer);
|
||||
close(socket);
|
||||
printf("lease expires in %Ld seconds\n", leaseTime / 1000000);
|
||||
BMessage lease(kMsgLeaseTime);
|
||||
fRunner = new BMessageRunner(this, &lease, leaseTime * 5/6, 1);
|
||||
}
|
||||
|
||||
|
||||
@ -508,6 +561,7 @@ DHCPClient::_ParseOptions(dhcp_message& message, BMessage& address)
|
||||
break;
|
||||
case OPTION_ADDRESS_LEASE_TIME:
|
||||
printf("lease time of %lu seconds\n", htonl(*(uint32*)data));
|
||||
fLeaseTime = htonl(*(uint32*)data) * 1000000LL;
|
||||
break;
|
||||
|
||||
case OPTION_HOST_NAME:
|
||||
@ -562,32 +616,32 @@ DHCPClient::_PrepareMessage(dhcp_message& message)
|
||||
|
||||
|
||||
void
|
||||
DHCPClient::_ResetTimeout(int socket)
|
||||
DHCPClient::_ResetTimeout(int socket, time_t& timeout, uint32& tries)
|
||||
{
|
||||
fTimeout = DEFAULT_TIMEOUT;
|
||||
fTries = 0;
|
||||
timeout = DEFAULT_TIMEOUT;
|
||||
tries = 0;
|
||||
|
||||
struct timeval value;
|
||||
value.tv_sec = fTimeout;
|
||||
value.tv_sec = timeout;
|
||||
value.tv_usec = 0;
|
||||
setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &value, sizeof(value));
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
DHCPClient::_TimeoutShift(int socket)
|
||||
DHCPClient::_TimeoutShift(int socket, time_t& timeout, uint32& tries)
|
||||
{
|
||||
fTimeout += fTimeout;
|
||||
if (fTimeout > MAX_TIMEOUT) {
|
||||
fTimeout = DEFAULT_TIMEOUT;
|
||||
timeout += timeout;
|
||||
if (timeout > MAX_TIMEOUT) {
|
||||
timeout = DEFAULT_TIMEOUT;
|
||||
|
||||
if (++fTries > 2)
|
||||
if (++tries > 2)
|
||||
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;
|
||||
value.tv_sec = fTimeout;
|
||||
value.tv_sec = timeout;
|
||||
value.tv_usec = 0;
|
||||
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
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,25 +18,34 @@
|
||||
class BMessageRunner;
|
||||
class dhcp_message;
|
||||
|
||||
enum dhcp_state {
|
||||
INIT,
|
||||
REQUESTING,
|
||||
ACKNOWLEDGED,
|
||||
};
|
||||
|
||||
|
||||
class DHCPClient : public BHandler {
|
||||
public:
|
||||
DHCPClient(BMessenger target, const char* device);
|
||||
virtual ~DHCPClient();
|
||||
|
||||
status_t InitCheck();
|
||||
status_t Initialize();
|
||||
|
||||
virtual void MessageReceived(BMessage* message);
|
||||
|
||||
private:
|
||||
status_t _Negotiate(dhcp_state state);
|
||||
void _ParseOptions(dhcp_message& message, BMessage& address);
|
||||
void _PrepareMessage(dhcp_message& message);
|
||||
status_t _SendMessage(int socket, dhcp_message& message, sockaddr_in& address) const;
|
||||
void _ResetTimeout(int socket);
|
||||
bool _TimeoutShift(int socket);
|
||||
void _ResetTimeout(int socket, time_t& timeout, uint32& tries);
|
||||
bool _TimeoutShift(int socket, time_t& timeout, uint32& tries);
|
||||
void _RestartLease(bigtime_t lease);
|
||||
BString _ToString(const uint8* data) const;
|
||||
BString _ToString(in_addr_t address) const;
|
||||
|
||||
BMessenger fTarget;
|
||||
BString fDevice;
|
||||
BMessage fConfiguration;
|
||||
BMessageRunner* fRunner;
|
||||
@ -44,8 +53,7 @@ class DHCPClient : public BHandler {
|
||||
uint32 fTransactionID;
|
||||
in_addr_t fAssignedAddress;
|
||||
sockaddr_in fServer;
|
||||
time_t fTimeout;
|
||||
uint32 fTries;
|
||||
bigtime_t fLeaseTime;
|
||||
status_t fStatus;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user