* Added "services" to the network settings, and refactored the settings class a bit

to be easier extendable with more classes.
* Fixed a bug in the settings that caused updated settings to be appended to the
  existing ones (missing BMessage::MakeEmpty()).
* Started services system, doesn't do anything useful yet (inetd replacement).
* Fixed the bug that caused the loopback default netmask to be incorrectly chosen;
  removed the temporary fix Bruno introduced before. The same bug has been in
  ifconfig where I copied the code from (but wrote it there, too) :-).


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@19609 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2006-12-22 20:53:08 +00:00
parent d2980e876d
commit fc398fa2ab
7 changed files with 420 additions and 50 deletions

View File

@ -526,7 +526,7 @@ configure_interface(int socket, const char* name, char* const* args,
if (!hasMask && hasAddress && kFamilies[familyIndex].family == AF_INET
&& ioctl(socket, SIOCGIFNETMASK, &request, sizeof(struct ifreq)) == 0
&& request.ifr_mask.sa_family == AF_UNSPEC) {
// generate standard netmask if it doesn't have one yet
// generate standard netmask if it doesn't have one yet
sockaddr_in *netmask = (sockaddr_in *)&mask;
netmask->sin_len = sizeof(sockaddr_in);
netmask->sin_family = AF_INET;
@ -537,7 +537,7 @@ configure_interface(int socket, const char* name, char* const* args,
|| (ntohl(net) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) {
// class A, or loopback
netmask->sin_addr.s_addr = IN_CLASSA_NET;
} if (IN_CLASSB(net)) {
} else if (IN_CLASSB(net)) {
// class B
netmask->sin_addr.s_addr = IN_CLASSB_NET;
} else {

View File

@ -13,6 +13,7 @@ Server net_server :
Settings.cpp
AutoconfigLooper.cpp
DHCPClient.cpp
Services.cpp
;
LinkAgainst net_server :

View File

@ -9,6 +9,7 @@
#include "AutoconfigLooper.h"
#include "NetServer.h"
#include "Services.h"
#include "Settings.h"
#include <Alert.h>
@ -56,9 +57,11 @@ class NetServer : public BApplication {
void _ConfigureDevices(int socket, const char* path);
void _ConfigureInterfaces(int socket);
void _BringUpInterfaces();
void _StartServices();
Settings fSettings;
LooperMap fDeviceMap;
BMessenger fServices;
};
@ -212,6 +215,7 @@ NetServer::ReadyToRun()
{
fSettings.StartMonitoring(this);
_BringUpInterfaces();
_StartServices();
}
@ -235,6 +239,15 @@ NetServer::MessageReceived(BMessage* message)
break;
}
case kMsgServiceSettingsUpdated:
{
BMessage update = fSettings.Services();
update.what = kMsgUpdateServices;
fServices.SendMessage(&update);
break;
}
case kMsgConfigureInterface:
{
if (!message->ReturnAddress().IsTargetLocal()) {
@ -455,7 +468,7 @@ NetServer::_ConfigureInterface(int socket, BMessage& interface, bool fromMessage
if (!hasMask && hasAddress && kFamilies[familyIndex].family == AF_INET
&& ioctl(familySocket, SIOCGIFNETMASK, &request, sizeof(struct ifreq)) == 0
&& request.ifr_mask.sa_family == AF_UNSPEC) {
// generate standard netmask if it doesn't have one yet
// generate standard netmask if it doesn't have one yet
sockaddr_in *netmask = (sockaddr_in *)&mask;
netmask->sin_len = sizeof(sockaddr_in);
netmask->sin_family = AF_INET;
@ -466,7 +479,7 @@ NetServer::_ConfigureInterface(int socket, BMessage& interface, bool fromMessage
|| (ntohl(net) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) {
// class A, or loopback
netmask->sin_addr.s_addr = IN_CLASSA_NET;
} if (IN_CLASSB(net)) {
} else if (IN_CLASSB(net)) {
// class B
netmask->sin_addr.s_addr = IN_CLASSB_NET;
} else {
@ -665,7 +678,6 @@ NetServer::_BringUpInterfaces()
BMessage address;
address.AddString("family", "inet");
address.AddString("address", "127.0.0.1");
address.AddString("mask", "255.0.0.0");
interface.AddMessage("address", &address);
_ConfigureInterface(socket, interface);
@ -680,6 +692,17 @@ NetServer::_BringUpInterfaces()
}
void
NetServer::_StartServices()
{
BHandler* services = new (std::nothrow) Services(fSettings.Services());
if (services != NULL) {
AddHandler(services);
fServices = BMessenger(services);
}
}
// #pragma mark -

View File

@ -0,0 +1,225 @@
/*
* Copyright 2006, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, axeld@pinc-software.de
*/
#include "Services.h"
#include "Settings.h"
#include <Autolock.h>
#include <new>
#include <sys/socket.h>
#include <vector>
struct service_address {
int socket;
int family;
uint16 port;
sockaddr address;
};
typedef vector<service_address> AddressList;
struct service {
std::string name;
std::string launch;
int type;
int protocol;
uint16 port;
uid_t user;
gid_t group;
AddressList addresses;
~service();
bool operator!=(const struct service& other);
bool operator==(const struct service& other);
};
service::~service()
{
// close all open sockets
AddressList::const_iterator iterator = addresses.begin();
for (; iterator != addresses.end(); iterator++) {
const service_address& address = *iterator;
close(address.socket);
}
}
bool
service::operator!=(const struct service& other)
{
return !(*this == other);
}
bool
service::operator==(const struct service& other)
{
if (name != other.name
|| launch != other.launch
|| type != other.type
|| protocol != other.protocol
|| port != other.port)
return false;
// TODO: compare addresses!
return true;
}
// #pragma mark -
Services::Services(const BMessage& services)
:
fUpdate(0)
{
_Update(services);
fListener = spawn_thread(_Listener, "services listener", B_NORMAL_PRIORITY, this);
if (fListener >= B_OK)
resume_thread(fListener);
}
Services::~Services()
{
wait_for_thread(fListener, NULL);
}
status_t
Services::InitCheck() const
{
return fListener >= B_OK ? B_OK : fListener;
}
void
Services::MessageReceived(BMessage* message)
{
switch (message->what) {
case kMsgServiceSettingsUpdated:
_Update(*message);
break;
default:
BHandler::MessageReceived(message);
}
}
status_t
Services::_StartService(struct service& service)
{
// add service to maps
fNameMap[service.name] = &service;
AddressList::const_iterator iterator = service.addresses.begin();
for (; iterator != service.addresses.end(); iterator++) {
const service_address& address = *iterator;
fSocketMap[address.socket] = &service;
}
return B_OK;
}
status_t
Services::_StopService(struct service& service)
{
// remove service from maps
{
ServiceNameMap::iterator iterator = fNameMap.find(service.name);
if (iterator != fNameMap.end())
fNameMap.erase(iterator);
}
{
AddressList::const_iterator iterator = service.addresses.begin();
for (; iterator != service.addresses.end(); iterator++) {
const service_address& address = *iterator;
ServiceSocketMap::iterator socketIterator = fSocketMap.find(address.socket);
if (socketIterator != fSocketMap.end())
fSocketMap.erase(socketIterator);
}
}
delete &service;
return B_OK;
}
status_t
Services::_ToService(const BMessage& message, struct service*& service)
{
// get mandatory fields
const char* name;
const char* launch;
if (message.FindString("name", &name) != B_OK
|| message.FindString("launch", &launch) != B_OK)
return B_BAD_VALUE;
service = new (std::nothrow) ::service;
if (service == NULL)
return B_NO_MEMORY;
service->name = name;
service->launch = launch;
// TODO: fill in other fields
return B_OK;
}
void
Services::_Update(const BMessage& services)
{
BAutolock locker(fLock);
fUpdate++;
BMessage message;
for (int32 index = 0; services.FindMessage("service", index,
&message) == B_OK; index++) {
const char* name;
if (message.FindString("name", &name) != B_OK)
continue;
struct service* service;
if (_ToService(message, service) != B_OK)
continue;
ServiceNameMap::iterator iterator = fNameMap.find(name);
if (iterator == fNameMap.end()) {
// this service does not exist yet, start it
_StartService(*service);
} else {
// this service does already exist - check for any changes
if (service != iterator->second) {
_StopService(*iterator->second);
_StartService(*service);
}
}
}
}
/*static*/ status_t
Services::_Listener(void* self)
{
return B_OK;
}

View File

@ -0,0 +1,50 @@
/*
* Copyright 2006, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, axeld@pinc-software.de
*/
#ifndef SERVICES_H
#define SERVICES_H
#include <Handler.h>
#include <Locker.h>
#include <map>
#include <string>
struct service;
typedef std::map<std::string, service*> ServiceNameMap;
typedef std::map<int, service*> ServiceSocketMap;
class Services : public BHandler {
public:
Services(const BMessage& services);
virtual ~Services();
status_t InitCheck() const;
virtual void MessageReceived(BMessage* message);
private:
status_t _StartService(struct service& service);
status_t _StopService(struct service& service);
status_t _ToService(const BMessage& message, struct service*& service);
void _Update(const BMessage& services);
int32 _CompareServices(struct service& a, struct service& b);
static status_t _Listener(void* self);
thread_id fListener;
BLocker fLock;
ServiceNameMap fNameMap;
ServiceSocketMap fSocketMap;
int32 fUpdate;
};
const static uint32 kMsgUpdateServices = 'srvU';
#endif // SERVICES_H

View File

@ -19,6 +19,8 @@
#include <string.h>
// Interface templates
const static settings_template kInterfaceAddressTemplate[] = {
{B_STRING_TYPE, "family", NULL},
{B_STRING_TYPE, "address", NULL},
@ -30,7 +32,7 @@ const static settings_template kInterfaceAddressTemplate[] = {
{0, NULL, NULL}
};
const static settings_template kInterfaceDeviceTemplate[] = {
const static settings_template kInterfaceTemplate[] = {
{B_STRING_TYPE, "device", NULL},
{B_MESSAGE_TYPE, "address", kInterfaceAddressTemplate},
{B_INT32_TYPE, "flags", NULL},
@ -39,8 +41,32 @@ const static settings_template kInterfaceDeviceTemplate[] = {
{0, NULL, NULL}
};
const static settings_template kInterfaceTemplate[] = {
{B_MESSAGE_TYPE, "interface", kInterfaceDeviceTemplate},
const static settings_template kInterfacesTemplate[] = {
{B_MESSAGE_TYPE, "interface", kInterfaceTemplate},
{0, NULL, NULL}
};
// Service templates
const static settings_template kServiceAddressTemplate[] = {
{B_STRING_TYPE, "family", NULL},
{B_STRING_TYPE, "address", NULL},
{B_INT32_TYPE, "port", NULL},
{0, NULL, NULL}
};
const static settings_template kServiceTemplate[] = {
{B_STRING_TYPE, "name", NULL},
{B_MESSAGE_TYPE, "address", kServiceAddressTemplate},
{B_STRING_TYPE, "user", NULL},
{B_STRING_TYPE, "group", NULL},
{B_STRING_TYPE, "launch", NULL},
{B_INT32_TYPE, "port", NULL},
{0, NULL, NULL}
};
const static settings_template kServicesTemplate[] = {
{B_MESSAGE_TYPE, "service", kServiceTemplate},
{0, NULL, NULL}
};
@ -76,7 +102,8 @@ Settings::_GetPath(const char* name, BPath& path)
path.Append("network");
create_directory(path.Path(), 0755);
path.Append(name);
if (name != NULL)
path.Append(name);
return B_OK;
}
@ -147,6 +174,8 @@ status_t
Settings::_ConvertFromDriverSettings(const driver_settings& settings,
const settings_template* settingsTemplate, BMessage& message)
{
message.MakeEmpty();
for (int32 i = 0; i < settings.parameter_count; i++) {
status_t status = _ConvertFromDriverParameter(settings.parameters[i],
settingsTemplate, message);
@ -185,49 +214,67 @@ Settings::_ConvertFromDriverSettings(const char* name,
status_t
Settings::_Load()
Settings::_Load(const char* name, uint32* _type)
{
return _ConvertFromDriverSettings("interfaces", kInterfaceTemplate, fInterfaces);
status_t status = B_ENTRY_NOT_FOUND;
if (name == NULL || !strcmp(name, "interfaces")) {
status = _ConvertFromDriverSettings("interfaces", kInterfacesTemplate,
fInterfaces);
if (status == B_OK && _type != NULL)
*_type = kMsgInterfaceSettingsUpdated;
}
if (name == NULL || !strcmp(name, "services")) {
status = _ConvertFromDriverSettings("services", kServicesTemplate,
fServices);
if (status == B_OK && _type != NULL)
*_type = kMsgServiceSettingsUpdated;
}
return status;
}
status_t
Settings::_StartWatching(const char* name, const BMessenger& target)
{
BPath path;
status_t status = _GetPath(name, path);
if (status < B_OK)
return status;
BNode node;
status = node.SetTo(path.Path());
if (status < B_OK)
return status;
node_ref ref;
status = node.GetNodeRef(&ref);
if (status < B_OK)
return status;
return watch_node(&ref, name != NULL ? B_WATCH_STAT : B_WATCH_DIRECTORY,
target);
}
status_t
Settings::StartMonitoring(const BMessenger& target)
{
if (_IsWatching(target))
return B_OK;
if (_IsWatching())
StopMonitoring(fListener);
fListener = target;
BPath path;
status_t status = _GetPath("interfaces", path);
if (status < B_OK)
return status;
status_t status = _StartWatching(NULL, target);
if (status == B_OK)
status = _StartWatching("interfaces", target);
if (status == B_OK)
status = _StartWatching("services", target);
node_ref ref;
BNode node;
BPath parent;
if (path.GetParent(&parent) == B_OK) {
status = node.SetTo(parent.Path());
if (status < B_OK)
return status;
status = node.GetNodeRef(&ref);
if (status < B_OK)
return status;
status = watch_node(&ref, B_WATCH_DIRECTORY, target);
if (status < B_OK)
return status;
}
status = node.SetTo(path.Path());
if (status < B_OK)
return status;
status = node.GetNodeRef(&ref);
if (status < B_OK)
return status;
return watch_node(&ref, B_WATCH_STAT, target);
return status;
}
@ -252,13 +299,9 @@ Settings::Update(BMessage* message)
if (opcode == B_ENTRY_REMOVED)
return B_OK;
if (!strcmp(name, "interfaces")) {
status_t status = _ConvertFromDriverSettings("interfaces",
kInterfaceTemplate, fInterfaces);
if (status < B_OK)
return status;
BMessage update(kMsgInterfaceSettingsUpdated);
uint32 type;
if (_Load(name, &type) == B_OK) {
BMessage update(type);
fListener.SendMessage(&update);
}
@ -277,3 +320,22 @@ Settings::GetNextInterface(uint32& cookie, BMessage& interface)
return B_OK;
}
status_t
Settings::GetNextService(uint32& cookie, BMessage& service)
{
status_t status = fServices.FindMessage("service", cookie, &service);
if (status < B_OK)
return status;
cookie++;
return B_OK;
}
const BMessage&
Settings::Services() const
{
return fServices;
}

View File

@ -29,15 +29,19 @@ class Settings {
~Settings();
status_t GetNextInterface(uint32& cookie, BMessage& interface);
status_t GetNextService(uint32& cookie, BMessage& service);
const BMessage& Services() const;
status_t StartMonitoring(const BMessenger& target);
status_t StopMonitoring(const BMessenger& target);
status_t Update(BMessage* message);
private:
status_t _Load();
status_t _Load(const char* name = NULL, uint32* _type = NULL);
status_t _GetPath(const char* name, BPath& path);
status_t _StartWatching(const char* name, const BMessenger& target);
const settings_template* _FindSettingsTemplate(const settings_template* settingsTemplate,
const char* name);
status_t _ConvertFromDriverParameter(const driver_parameter& parameter,
@ -47,11 +51,16 @@ class Settings {
status_t _ConvertFromDriverSettings(const char* path,
const settings_template* settingsTemplate, BMessage& message);
bool _IsWatching(const BMessenger& target) const { return fListener == target; }
bool _IsWatching() const { return fListener.IsValid(); }
BMessenger fListener;
BMessage fInterfaces;
BMessage fServices;
bool fUpdated;
};
static const uint32 kMsgInterfaceSettingsUpdated = 'SUif';
static const uint32 kMsgServiceSettingsUpdated = 'SUsv';
#endif // SETTINGS_H