Moved more functionality from net_server to NetworkSettings.

* Added (still incomplete) helper classes for the settings messages.
* The net_server now uses these classes for its interfaces, and services.
* Renamed service_address to service_connection, as that better matches
  what it is used for.
This commit is contained in:
Axel Dörfler 2015-02-26 12:05:21 +00:00
parent 7a9c00732a
commit f16f9ee4ee
6 changed files with 683 additions and 382 deletions

View File

@ -9,9 +9,13 @@
#define SETTINGS_H
#include <vector>
#include <Message.h>
#include <Messenger.h>
#include <NetworkAddress.h>
#include <Path.h>
#include <StringList.h>
namespace BNetworkKit {
@ -20,6 +24,7 @@ namespace BNetworkKit {
class BNetworkSettings {
public:
static const uint32 kMsgInterfaceSettingsUpdated = 'SUif';
static const uint32 kMsgNetworkSettingsUpdated = 'SUnw';
static const uint32 kMsgServiceSettingsUpdated = 'SUsv';
public:
@ -88,7 +93,109 @@ private:
};
class BNetworkInterfaceAddressSettings {
public:
BNetworkInterfaceAddressSettings(
const BMessage& data);
~BNetworkInterfaceAddressSettings();
int Family() const;
bool AutoConfigure() const;
const BNetworkAddress&
Address() const;
const BNetworkAddress&
Mask() const;
const BNetworkAddress&
Peer() const;
const BNetworkAddress&
Broadcast() const;
const BNetworkAddress&
Gateway() const;
private:
int32 fFamily;
bool fAutoConfigure;
BNetworkAddress fAddress;
BNetworkAddress fMask;
BNetworkAddress fPeer;
BNetworkAddress fBroadcast;
BNetworkAddress fGateway;
};
class BNetworkInterfaceSettings {
public:
BNetworkInterfaceSettings(
const BMessage& message);
~BNetworkInterfaceSettings();
const char* Name() const;
};
} // namespace BNetworkKit
class BNetworkServiceAddressSettings {
public:
BNetworkServiceAddressSettings();
BNetworkServiceAddressSettings(
const BMessage& data, int family = -1,
int type = -1, int protocol = -1,
int port = -1);
~BNetworkServiceAddressSettings();
int Family() const;
void SetFamily(int family);
int Protocol() const;
void SetProtocol(int protocol);
int Type() const;
void SetType(int type);
const BNetworkAddress&
Address() const;
BNetworkAddress& Address();
status_t GetMessage(BMessage& data);
bool operator==(
const BNetworkServiceAddressSettings& other)
const;
private:
int32 fFamily;
int fProtocol;
int fType;
BNetworkAddress fAddress;
};
class BNetworkServiceSettings {
public:
BNetworkServiceSettings(
const BMessage& message);
~BNetworkServiceSettings();
status_t InitCheck() const;
const char* Name() const;
bool IsStandAlone() const;
int32 CountArguments() const;
const char* ArgumentAt(int32 index) const;
int32 CountAddresses() const;
const BNetworkServiceAddressSettings&
AddressAt(int32 index) const;
private:
const BMessage& fData;
BStringList fArguments;
std::vector<BNetworkServiceAddressSettings>
fAddresses;
};
#endif // SETTINGS_H

View File

@ -9,6 +9,7 @@
#include <NetworkSettings.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -115,6 +116,119 @@ const static settings_template kServicesTemplate[] = {
};
struct address_family {
int family;
const char* name;
const char* identifiers[4];
};
static const address_family kFamilies[] = {
{
AF_INET,
"inet",
{"AF_INET", "inet", "ipv4", NULL},
},
{
AF_INET6,
"inet6",
{"AF_INET6", "inet6", "ipv6", NULL},
},
{ -1, NULL, {NULL} }
};
static int
get_address_family(const char* argument)
{
for (int32 i = 0; kFamilies[i].family >= 0; i++) {
for (int32 j = 0; kFamilies[i].identifiers[j]; j++) {
if (!strcmp(argument, kFamilies[i].identifiers[j])) {
// found a match
return kFamilies[i].family;
}
}
}
return AF_UNSPEC;
}
/*! Parses the \a argument as network \a address for the specified \a family.
If \a family is \c AF_UNSPEC, \a family will be overwritten with the family
of the successfully parsed address.
*/
static bool
parse_address(int32& family, const char* argument, BNetworkAddress& address)
{
if (argument == NULL)
return false;
status_t status = address.SetTo(family, argument, (uint16)0,
B_NO_ADDRESS_RESOLUTION);
if (status != B_OK)
return false;
if (family == AF_UNSPEC) {
// Test if we support the resulting address family
bool supported = false;
for (int32 i = 0; kFamilies[i].family >= 0; i++) {
if (kFamilies[i].family == address.Family()) {
supported = true;
break;
}
}
if (!supported)
return false;
// Take over family from address
family = address.Family();
}
return true;
}
static int
parse_type(const char* string)
{
if (!strcasecmp(string, "stream"))
return SOCK_STREAM;
return SOCK_DGRAM;
}
static int
parse_protocol(const char* string)
{
struct protoent* proto = getprotobyname(string);
if (proto == NULL)
return IPPROTO_TCP;
return proto->p_proto;
}
static int
type_for_protocol(int protocol)
{
// default determined by protocol
switch (protocol) {
case IPPROTO_TCP:
return SOCK_STREAM;
case IPPROTO_UDP:
default:
return SOCK_DGRAM;
}
}
// #pragma mark -
BNetworkSettings::BNetworkSettings()
{
_Load();
@ -384,7 +498,7 @@ BNetworkSettings::_Load(const char* name, uint32* _type)
}
if (_type != NULL)
*_type = kMsgInterfaceSettingsUpdated;
*_type = kMsgNetworkSettingsUpdated;
}
}
if (name == NULL || strcmp(name, kServicesSettingsName) == 0) {
@ -672,3 +786,353 @@ BNetworkSettings::_RemoveItem(BMessage& container, const char* itemField,
return B_ENTRY_NOT_FOUND;
}
// #pragma mark - BNetworkInterfaceAddressSettings
BNetworkInterfaceAddressSettings::BNetworkInterfaceAddressSettings(
const BMessage& data)
{
if (data.FindInt32("family", &fFamily) != B_OK) {
const char* familyString;
if (data.FindString("family", &familyString) == B_OK) {
fFamily = get_address_family(familyString);
if (fFamily == AF_UNSPEC) {
// we don't support this family
fprintf(stderr, "Ignore unknown family: %s\n",
familyString);
return;
}
} else
fFamily = AF_UNSPEC;
}
fAutoConfigure = data.GetBool("auto_config", false);
if (!fAutoConfigure) {
if (parse_address(fFamily, data.GetString("address", NULL), fAddress))
parse_address(fFamily, data.GetString("mask", NULL), fMask);
parse_address(fFamily, data.GetString("peer", NULL), fPeer);
parse_address(fFamily, data.GetString("broadcast", NULL), fBroadcast);
parse_address(fFamily, data.GetString("gateway", NULL), fGateway);
}
}
BNetworkInterfaceAddressSettings::~BNetworkInterfaceAddressSettings()
{
}
int
BNetworkInterfaceAddressSettings::Family() const
{
return fFamily;
}
bool
BNetworkInterfaceAddressSettings::AutoConfigure() const
{
return fAutoConfigure;
}
const BNetworkAddress&
BNetworkInterfaceAddressSettings::Address() const
{
return fAddress;
}
const BNetworkAddress&
BNetworkInterfaceAddressSettings::Mask() const
{
return fMask;
}
const BNetworkAddress&
BNetworkInterfaceAddressSettings::Peer() const
{
return fPeer;
}
const BNetworkAddress&
BNetworkInterfaceAddressSettings::Broadcast() const
{
return fBroadcast;
}
const BNetworkAddress&
BNetworkInterfaceAddressSettings::Gateway() const
{
return fGateway;
}
// #pragma mark - BNetworkServiceAddress
BNetworkServiceAddressSettings::BNetworkServiceAddressSettings()
{
}
BNetworkServiceAddressSettings::BNetworkServiceAddressSettings(
const BMessage& data, int serviceFamily, int serviceType,
int serviceProtocol, int servicePort)
{
// TODO: dump problems in the settings to syslog
if (data.FindInt32("family", &fFamily) != B_OK) {
const char* familyString;
if (data.FindString("family", &familyString) == B_OK) {
fFamily = get_address_family(familyString);
if (fFamily == AF_UNSPEC) {
// we don't support this family
fprintf(stderr, "Ignore unknown family: %s\n",
familyString);
return;
}
} else
fFamily = serviceFamily;
}
if (!parse_address(fFamily, data.GetString("address"), fAddress))
fAddress.SetToWildcard(fFamily);
const char* string;
if (data.FindString("protocol", &string) == B_OK)
fProtocol = parse_protocol(string);
else
fProtocol = serviceProtocol;
if (data.FindString("type", &string) == B_OK)
fType = parse_type(string);
else if (fProtocol != serviceProtocol)
fType = type_for_protocol(fProtocol);
else
fType = serviceType;
fAddress.SetPort(data.GetInt32("port", servicePort));
}
BNetworkServiceAddressSettings::~BNetworkServiceAddressSettings()
{
}
int
BNetworkServiceAddressSettings::Family() const
{
return fFamily;
}
void
BNetworkServiceAddressSettings::SetFamily(int family)
{
fFamily = family;
}
int
BNetworkServiceAddressSettings::Protocol() const
{
return fProtocol;
}
void
BNetworkServiceAddressSettings::SetProtocol(int protocol)
{
fProtocol = protocol;
}
int
BNetworkServiceAddressSettings::Type() const
{
return fType;
}
void
BNetworkServiceAddressSettings::SetType(int type)
{
fType = type;
}
const BNetworkAddress&
BNetworkServiceAddressSettings::Address() const
{
return fAddress;
}
BNetworkAddress&
BNetworkServiceAddressSettings::Address()
{
return fAddress;
}
status_t
BNetworkServiceAddressSettings::GetMessage(BMessage& data)
{
// TODO!
return B_NOT_SUPPORTED;
}
bool
BNetworkServiceAddressSettings::operator==(
const BNetworkServiceAddressSettings& other) const
{
return Family() == other.Family()
&& Type() == other.Type()
&& Protocol() == other.Protocol()
&& Address() == other.Address();
}
// #pragma mark - BNetworkServiceSettings
BNetworkServiceSettings::BNetworkServiceSettings(const BMessage& message)
:
fData(message)
{
// TODO: user/group is currently ignored!
// Default family/port/protocol/type for all addresses
// we default to inet/tcp/port-from-service-name if nothing is specified
const char* string;
if (message.FindString("family", &string) != B_OK)
string = "inet";
int32 serviceFamily = get_address_family(string);
if (serviceFamily == AF_UNSPEC)
serviceFamily = AF_INET;
int32 serviceProtocol;
if (message.FindString("protocol", &string) == B_OK)
serviceProtocol = parse_protocol(string);
else {
string = "tcp";
// we set 'string' here for an eventual call to getservbyname()
// below
serviceProtocol = IPPROTO_TCP;
}
int32 servicePort;
if (message.FindInt32("port", &servicePort) != B_OK) {
struct servent* servent = getservbyname(Name(), string);
if (servent != NULL)
servicePort = ntohs(servent->s_port);
else
servicePort = -1;
}
int32 serviceType = -1;
if (message.FindString("type", &string) == B_OK) {
serviceType = parse_type(string);
} else {
serviceType = type_for_protocol(serviceProtocol);
}
const char* argument;
for (int i = 0; message.FindString("launch", i, &argument) == B_OK; i++) {
fArguments.Add(argument);
}
BMessage addressData;
int32 i = 0;
for (; message.FindMessage("address", i, &addressData) == B_OK; i++) {
BNetworkServiceAddressSettings address(addressData, serviceFamily,
serviceType, serviceProtocol, servicePort);
fAddresses.push_back(address);
}
if (i == 0 && (serviceFamily < 0 || servicePort < 0)) {
// no address specified
printf("service %s has no address specified\n", Name());
return;
}
if (i == 0) {
// no address specified, but family/port were given; add empty address
BNetworkServiceAddressSettings address;
address.SetFamily(serviceFamily);
address.SetType(serviceType);
address.SetProtocol(serviceProtocol);
address.Address().SetToWildcard(serviceFamily, servicePort);
fAddresses.push_back(address);
}
}
BNetworkServiceSettings::~BNetworkServiceSettings()
{
}
status_t
BNetworkServiceSettings::InitCheck() const
{
if (fData.HasString("name") && fData.HasString("launch")
&& CountAddresses() > 0)
return B_OK;
return B_BAD_VALUE;
}
const char*
BNetworkServiceSettings::Name() const
{
return fData.GetString("name");
}
bool
BNetworkServiceSettings::IsStandAlone() const
{
return fData.GetBool("stand_alone");
}
int32
BNetworkServiceSettings::CountArguments() const
{
return fArguments.CountStrings();
}
const char*
BNetworkServiceSettings::ArgumentAt(int32 index) const
{
return fArguments.StringAt(index);
}
int32
BNetworkServiceSettings::CountAddresses() const
{
return fAddresses.size();
}
const BNetworkServiceAddressSettings&
BNetworkServiceSettings::AddressAt(int32 index) const
{
return fAddresses[index];
}

View File

@ -107,28 +107,6 @@ private:
};
struct address_family {
int family;
const char* name;
const char* identifiers[4];
};
static const address_family kFamilies[] = {
{
AF_INET,
"inet",
{"AF_INET", "inet", "ipv4", NULL},
},
{
AF_INET6,
"inet6",
{"AF_INET6", "inet6", "ipv6", NULL},
},
{ -1, NULL, {NULL} }
};
// #pragma mark - private functions
@ -156,61 +134,6 @@ set_80211(const char* name, int32 type, void* data,
}
// #pragma mark - exported functions
int
get_address_family(const char* argument)
{
for (int32 i = 0; kFamilies[i].family >= 0; i++) {
for (int32 j = 0; kFamilies[i].identifiers[j]; j++) {
if (!strcmp(argument, kFamilies[i].identifiers[j])) {
// found a match
return kFamilies[i].family;
}
}
}
return AF_UNSPEC;
}
/*! Parses the \a argument as network \a address for the specified \a family.
If \a family is \c AF_UNSPEC, \a family will be overwritten with the family
of the successfully parsed address.
*/
bool
parse_address(int32& family, const char* argument, BNetworkAddress& address)
{
if (argument == NULL)
return false;
status_t status = address.SetTo(family, argument, (uint16)0,
B_NO_ADDRESS_RESOLUTION);
if (status != B_OK)
return false;
if (family == AF_UNSPEC) {
// Test if we support the resulting address family
bool supported = false;
for (int32 i = 0; kFamilies[i].family >= 0; i++) {
if (kFamilies[i].family == address.Family()) {
supported = true;
break;
}
}
if (!supported)
return false;
// Take over family from address
family = address.Family();
}
return true;
}
// #pragma mark -
@ -254,7 +177,7 @@ NetServer::ReadyToRun()
_BringUpInterfaces();
_StartServices();
BPrivate::BPathMonitor::StartWatching("/dev/net",
BPrivate::BPathMonitor::StartWatching("/dev/net",
B_WATCH_FILES_ONLY | B_WATCH_RECURSIVELY, this);
}
@ -548,60 +471,19 @@ NetServer::_ConfigureInterface(BMessage& message)
BMessage addressMessage;
for (int32 index = 0; message.FindMessage("address", index,
&addressMessage) == B_OK; index++) {
int32 family;
if (addressMessage.FindInt32("family", &family) != B_OK) {
const char* familyString;
if (addressMessage.FindString("family", &familyString) == B_OK) {
if (get_address_family(familyString) == AF_UNSPEC) {
// we don't support this family
fprintf(stderr, "%s: Ignore unknown family: %s\n", Name(),
familyString);
continue;
}
} else
family = AF_UNSPEC;
}
BNetworkInterfaceAddressSettings addressSettings(addressMessage);
// retrieve addresses
bool autoConfig;
if (addressMessage.FindBool("auto_config", &autoConfig) != B_OK)
autoConfig = false;
BNetworkAddress address;
BNetworkAddress mask;
BNetworkAddress broadcast;
BNetworkAddress peer;
BNetworkAddress gateway;
const char* string;
if (!autoConfig) {
if (addressMessage.FindString("address", &string) == B_OK) {
parse_address(family, string, address);
if (addressMessage.FindString("mask", &string) == B_OK)
parse_address(family, string, mask);
}
if (addressMessage.FindString("peer", &string) == B_OK)
parse_address(family, string, peer);
if (addressMessage.FindString("broadcast", &string) == B_OK)
parse_address(family, string, broadcast);
}
if (autoConfig) {
if (addressSettings.AutoConfigure()) {
_QuitLooperForDevice(name);
startAutoConfig = true;
} else if (addressMessage.FindString("gateway", &string) == B_OK
&& parse_address(family, string, gateway)) {
} else if (!addressSettings.Gateway().IsEmpty()) {
// add gateway route, if we're asked for it
interface.RemoveDefaultRoute(family);
interface.RemoveDefaultRoute(addressSettings.Family());
// Try to remove a previous default route, doesn't matter
// if it fails.
status_t status = interface.AddDefaultRoute(gateway);
status_t status = interface.AddDefaultRoute(
addressSettings.Gateway());
if (status != B_OK) {
fprintf(stderr, "%s: Could not add route for %s: %s\n",
Name(), name, strerror(errno));
@ -610,14 +492,17 @@ NetServer::_ConfigureInterface(BMessage& message)
// set address/mask/broadcast/peer
if (!address.IsEmpty() || !mask.IsEmpty() || !broadcast.IsEmpty()) {
if (!addressSettings.Address().IsEmpty()
|| !addressSettings.Mask().IsEmpty()
|| !addressSettings.Broadcast().IsEmpty()
|| !addressSettings.Peer().IsEmpty()) {
BNetworkInterfaceAddress interfaceAddress;
interfaceAddress.SetAddress(address);
interfaceAddress.SetMask(mask);
if (!broadcast.IsEmpty())
interfaceAddress.SetBroadcast(broadcast);
else if (!peer.IsEmpty())
interfaceAddress.SetDestination(peer);
interfaceAddress.SetAddress(addressSettings.Address());
interfaceAddress.SetMask(addressSettings.Mask());
if (!addressSettings.Broadcast().IsEmpty())
interfaceAddress.SetBroadcast(addressSettings.Broadcast());
else if (!addressSettings.Peer().IsEmpty())
interfaceAddress.SetDestination(addressSettings.Peer());
status_t status = interface.SetAddress(interfaceAddress);
if (status != B_OK) {

View File

@ -1,25 +0,0 @@
/*
* Copyright 2006-2010, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, axeld@pinc-software.de
*/
#ifndef NET_SERVER_H
#define NET_SERVER_H
#include <SupportDefs.h>
#include <NetServer.h>
class BNetworkAddress;
int get_address_family(const char* argument);
bool parse_address(int32& family, const char* argument,
BNetworkAddress& address);
#endif // NET_SERVER_H

View File

@ -8,47 +8,50 @@
#include "Services.h"
#include "NetServer.h"
#include <new>
#include <errno.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <Autolock.h>
#include <NetworkAddress.h>
#include <NetworkSettings.h>
#include <errno.h>
#include <netdb.h>
#include <netinet/in.h>
#include <new>
#include <stdlib.h>
#include <strings.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <vector>
using namespace std;
struct service_address {
struct service_connection {
struct service* owner;
int socket;
int family;
int type;
int protocol;
BNetworkAddress address;
BNetworkServiceAddressSettings address;
bool operator==(const struct service_address& other) const;
//service_connection() : owner(NULL), socket(-1) {}
int Family() const { return address.Family(); }
int Protocol() const { return address.Protocol(); }
int Type() const { return address.Type(); }
const BNetworkAddress& Address() const { return address.Address(); }
bool operator==(const struct service_connection& other) const;
};
typedef std::vector<service_address> AddressList;
typedef std::vector<service_connection> ConnectionList;
typedef std::vector<std::string> StringList;
struct service {
std::string name;
StringList arguments;
uid_t user;
gid_t group;
AddressList addresses;
uint32 update;
bool stand_alone;
pid_t process;
std::string name;
StringList arguments;
uid_t user;
gid_t group;
ConnectionList connections;
uint32 update;
bool stand_alone;
pid_t process;
~service();
bool operator!=(const struct service& other) const;
@ -56,52 +59,13 @@ struct service {
};
int
parse_type(const char* string)
{
if (!strcasecmp(string, "stream"))
return SOCK_STREAM;
return SOCK_DGRAM;
}
int
parse_protocol(const char* string)
{
struct protoent* proto = getprotobyname(string);
if (proto == NULL)
return IPPROTO_TCP;
return proto->p_proto;
}
int
type_for_protocol(int protocol)
{
// default determined by protocol
switch (protocol) {
case IPPROTO_TCP:
return SOCK_STREAM;
case IPPROTO_UDP:
default:
return SOCK_DGRAM;
}
}
// #pragma mark -
bool
service_address::operator==(const struct service_address& other) const
service_connection::operator==(const struct service_connection& other) const
{
return family == other.family
&& type == other.type
&& protocol == other.protocol
&& address == other.address;
return address == other.address;
}
@ -111,11 +75,11 @@ service_address::operator==(const struct service_address& other) const
service::~service()
{
// close all open sockets
AddressList::const_iterator iterator = addresses.begin();
for (; iterator != addresses.end(); iterator++) {
const service_address& address = *iterator;
ConnectionList::const_iterator iterator = connections.begin();
for (; iterator != connections.end(); iterator++) {
const service_connection& connection = *iterator;
close(address.socket);
close(connection.socket);
}
}
@ -132,32 +96,33 @@ service::operator==(const struct service& other) const
{
if (name != other.name
|| arguments.size() != other.arguments.size()
|| addresses.size() != other.addresses.size()
|| connections.size() != other.connections.size()
|| stand_alone != other.stand_alone)
return false;
// compare arguments
// Compare arguments
for(size_t i = 0; i < arguments.size(); i++) {
if (arguments[i] != other.arguments[i])
return false;
}
// compare addresses
// Compare connections
AddressList::const_iterator iterator = addresses.begin();
for (; iterator != addresses.end(); iterator++) {
const service_address& address = *iterator;
ConnectionList::const_iterator iterator = connections.begin();
for (; iterator != connections.end(); iterator++) {
const service_connection& connection = *iterator;
// find address in other addresses
// Find address in other addresses
AddressList::const_iterator otherIterator = other.addresses.begin();
for (; otherIterator != other.addresses.end(); otherIterator++) {
if (address == *otherIterator)
ConnectionList::const_iterator otherIterator
= other.connections.begin();
for (; otherIterator != other.connections.end(); otherIterator++) {
if (connection == *otherIterator)
break;
}
if (otherIterator == other.addresses.end())
if (otherIterator == other.connections.end())
return false;
}
@ -268,20 +233,22 @@ Services::_StartService(struct service& service)
// create socket
bool failed = false;
AddressList::iterator iterator = service.addresses.begin();
for (; iterator != service.addresses.end(); iterator++) {
service_address& address = *iterator;
ConnectionList::iterator iterator = service.connections.begin();
for (; iterator != service.connections.end(); iterator++) {
service_connection& connection = *iterator;
address.socket = socket(address.family, address.type, address.protocol);
if (address.socket < 0
|| bind(address.socket, address.address, address.address.Length())
< 0
|| fcntl(address.socket, F_SETFD, FD_CLOEXEC) < 0) {
connection.socket = socket(connection.Family(),
connection.Type(), connection.Protocol());
if (connection.socket < 0
|| bind(connection.socket, connection.Address(),
connection.Address().Length()) < 0
|| fcntl(connection.socket, F_SETFD, FD_CLOEXEC) < 0) {
failed = true;
break;
}
if (address.type == SOCK_STREAM && listen(address.socket, 50) < 0) {
if (connection.Type() == SOCK_STREAM
&& listen(connection.socket, 50) < 0) {
failed = true;
break;
}
@ -297,13 +264,13 @@ Services::_StartService(struct service& service)
fNameMap[service.name] = &service;
service.update = fUpdate;
iterator = service.addresses.begin();
for (; iterator != service.addresses.end(); iterator++) {
service_address& address = *iterator;
iterator = service.connections.begin();
for (; iterator != service.connections.end(); iterator++) {
service_connection& connection = *iterator;
fSocketMap[address.socket] = &address;
_UpdateMinMaxSocket(address.socket);
FD_SET(address.socket, &fSet);
fSocketMap[connection.socket] = &connection;
_UpdateMinMaxSocket(connection.socket);
FD_SET(connection.socket, &fSet);
}
_NotifyListener();
@ -325,17 +292,17 @@ Services::_StopService(struct service& service)
}
if (!service.stand_alone) {
AddressList::const_iterator iterator = service.addresses.begin();
for (; iterator != service.addresses.end(); iterator++) {
const service_address& address = *iterator;
ConnectionList::const_iterator iterator = service.connections.begin();
for (; iterator != service.connections.end(); iterator++) {
const service_connection& connection = *iterator;
ServiceSocketMap::iterator socketIterator
= fSocketMap.find(address.socket);
= fSocketMap.find(connection.socket);
if (socketIterator != fSocketMap.end())
fSocketMap.erase(socketIterator);
close(address.socket);
FD_CLR(address.socket, &fSet);
close(connection.socket);
FD_CLR(connection.socket, &fSet);
}
}
@ -353,129 +320,32 @@ Services::_StopService(struct service& service)
status_t
Services::_ToService(const BMessage& message, struct service*& service)
{
// get mandatory fields
const char* name;
if (message.FindString("name", &name) != B_OK
|| !message.HasString("launch"))
return B_BAD_VALUE;
BNetworkServiceSettings settings(message);
status_t status = settings.InitCheck();
if (status != B_OK)
return status;
service = new (std::nothrow) ::service;
if (service == NULL)
return B_NO_MEMORY;
service->name = name;
const char* argument;
for (int i = 0; message.FindString("launch", i, &argument) == B_OK; i++) {
service->arguments.push_back(argument);
}
service->stand_alone = false;
service->name = settings.Name();
service->stand_alone = settings.IsStandAlone();
service->process = -1;
// TODO: user/group is currently ignored!
// Copy launch arguments
for (int32 i = 0; i < settings.CountArguments(); i++)
service->arguments.push_back(settings.ArgumentAt(i));
// Default family/port/protocol/type for all addresses
// Copy addresses to listen to
for (int32 i = 0; i < settings.CountAddresses(); i++) {
const BNetworkServiceAddressSettings& address = settings.AddressAt(i);
service_connection connection;
connection.owner = service;
connection.socket = -1;
connection.address = address;
// we default to inet/tcp/port-from-service-name if nothing is specified
const char* string;
if (message.FindString("family", &string) != B_OK)
string = "inet";
int32 serviceFamily = get_address_family(string);
if (serviceFamily == AF_UNSPEC)
serviceFamily = AF_INET;
int32 serviceProtocol;
if (message.FindString("protocol", &string) == B_OK)
serviceProtocol = parse_protocol(string);
else {
string = "tcp";
// we set 'string' here for an eventual call to getservbyname()
// below
serviceProtocol = IPPROTO_TCP;
}
int32 servicePort;
if (message.FindInt32("port", &servicePort) != B_OK) {
struct servent* servent = getservbyname(name, string);
if (servent != NULL)
servicePort = ntohs(servent->s_port);
else
servicePort = -1;
}
int32 serviceType = -1;
if (message.FindString("type", &string) == B_OK) {
serviceType = parse_type(string);
} else {
serviceType = type_for_protocol(serviceProtocol);
}
bool standAlone = false;
if (message.FindBool("stand_alone", &standAlone) == B_OK)
service->stand_alone = standAlone;
BMessage address;
int32 i = 0;
for (; message.FindMessage("address", i, &address) == B_OK; i++) {
// TODO: dump problems in the settings to syslog
service_address serviceAddress;
if (address.FindString("family", &string) != B_OK)
continue;
serviceAddress.family = get_address_family(string);
if (serviceAddress.family == AF_UNSPEC)
continue;
if (address.FindString("protocol", &string) == B_OK)
serviceAddress.protocol = parse_protocol(string);
else
serviceAddress.protocol = serviceProtocol;
if (message.FindString("type", &string) == B_OK)
serviceAddress.type = parse_type(string);
else if (serviceAddress.protocol != serviceProtocol)
serviceAddress.type = type_for_protocol(serviceAddress.protocol);
else
serviceAddress.type = serviceType;
if (address.FindString("address", &string) == B_OK) {
if (!parse_address(serviceFamily, string, serviceAddress.address))
continue;
} else
serviceAddress.address.SetToWildcard(serviceFamily);
int32 port;
if (address.FindInt32("port", &port) != B_OK)
port = servicePort;
serviceAddress.address.SetPort(port);
serviceAddress.socket = -1;
serviceAddress.owner = service;
service->addresses.push_back(serviceAddress);
}
if (i == 0 && (serviceFamily < 0 || servicePort < 0)) {
// no address specified
printf("service %s has no address specified\n", name);
delete service;
return B_BAD_VALUE;
}
if (i == 0) {
// no address specified, but family/port were given; add empty address
service_address serviceAddress;
serviceAddress.family = serviceFamily;
serviceAddress.type = serviceType;
serviceAddress.protocol = serviceProtocol;
serviceAddress.address.SetToWildcard(serviceFamily, servicePort);
serviceAddress.socket = -1;
serviceAddress.owner = service;
service->addresses.push_back(serviceAddress);
service->connections.push_back(connection);
}
return B_OK;
@ -614,16 +484,16 @@ Services::_Listener()
if (iterator == fSocketMap.end())
continue;
struct service_address& address = *iterator->second;
struct service_connection& connection = *iterator->second;
int socket;
if (address.type == SOCK_STREAM) {
if (connection.Type() == SOCK_STREAM) {
// accept incoming connection
int value = 1;
ioctl(i, FIONBIO, &value);
// make sure we don't wait for the connection
socket = accept(address.socket, NULL, NULL);
socket = accept(connection.socket, NULL, NULL);
value = 0;
ioctl(i, FIONBIO, &value);
@ -631,11 +501,11 @@ Services::_Listener()
if (socket < 0)
continue;
} else
socket = address.socket;
socket = connection.socket;
// launch this service's handler
_LaunchService(*address.owner, socket);
_LaunchService(*connection.owner, socket);
}
}
return B_OK;

View File

@ -1,5 +1,5 @@
/*
* Copyright 2006-2007, Haiku, Inc. All Rights Reserved.
* Copyright 2006-2015, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
@ -18,9 +18,9 @@
struct service;
struct service_address;
struct service_connection;
typedef std::map<std::string, service*> ServiceNameMap;
typedef std::map<int, service_address*> ServiceSocketMap;
typedef std::map<int, service_connection*> ServiceSocketMap;
class Services : public BHandler {