* 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:
@@ -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
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user