From fc398fa2ab1532b0fdc002f8ef8d99a9b723da69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Fri, 22 Dec 2006 20:53:08 +0000 Subject: [PATCH] * 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 --- src/bin/network/ifconfig/ifconfig.cpp | 4 +- src/servers/net/Jamfile | 1 + src/servers/net/NetServer.cpp | 29 +++- src/servers/net/Services.cpp | 225 ++++++++++++++++++++++++++ src/servers/net/Services.h | 50 ++++++ src/servers/net/Settings.cpp | 150 ++++++++++++----- src/servers/net/Settings.h | 11 +- 7 files changed, 420 insertions(+), 50 deletions(-) create mode 100644 src/servers/net/Services.cpp create mode 100644 src/servers/net/Services.h diff --git a/src/bin/network/ifconfig/ifconfig.cpp b/src/bin/network/ifconfig/ifconfig.cpp index 088c0602d9..21a803828c 100644 --- a/src/bin/network/ifconfig/ifconfig.cpp +++ b/src/bin/network/ifconfig/ifconfig.cpp @@ -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 { diff --git a/src/servers/net/Jamfile b/src/servers/net/Jamfile index 8ddbffec96..42a5eae288 100644 --- a/src/servers/net/Jamfile +++ b/src/servers/net/Jamfile @@ -13,6 +13,7 @@ Server net_server : Settings.cpp AutoconfigLooper.cpp DHCPClient.cpp + Services.cpp ; LinkAgainst net_server : diff --git a/src/servers/net/NetServer.cpp b/src/servers/net/NetServer.cpp index a20497f757..13e2677ef8 100644 --- a/src/servers/net/NetServer.cpp +++ b/src/servers/net/NetServer.cpp @@ -9,6 +9,7 @@ #include "AutoconfigLooper.h" #include "NetServer.h" +#include "Services.h" #include "Settings.h" #include @@ -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 - diff --git a/src/servers/net/Services.cpp b/src/servers/net/Services.cpp new file mode 100644 index 0000000000..6e97df3fd1 --- /dev/null +++ b/src/servers/net/Services.cpp @@ -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 + +#include +#include +#include + + +struct service_address { + int socket; + int family; + uint16 port; + sockaddr address; +}; + +typedef vector 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; +} + diff --git a/src/servers/net/Services.h b/src/servers/net/Services.h new file mode 100644 index 0000000000..56eeb210a5 --- /dev/null +++ b/src/servers/net/Services.h @@ -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 +#include + +#include +#include + + +struct service; +typedef std::map ServiceNameMap; +typedef std::map 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 diff --git a/src/servers/net/Settings.cpp b/src/servers/net/Settings.cpp index 3ca38aa7d1..106abc1cce 100644 --- a/src/servers/net/Settings.cpp +++ b/src/servers/net/Settings.cpp @@ -19,6 +19,8 @@ #include +// 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; +} + diff --git a/src/servers/net/Settings.h b/src/servers/net/Settings.h index 1ea6e3830c..e9918c2ae0 100644 --- a/src/servers/net/Settings.h +++ b/src/servers/net/Settings.h @@ -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